Răsfoiți Sursa

script/research/streamlet_rust: Moved tx confirmation to block finalization

aggstam 4 ani în urmă
părinte
comite
32daa3cf3e

+ 17 - 7
script/research/streamlet/node.py

@@ -50,6 +50,16 @@ class Node:
 				longest_notarized_chain = blockchain
 				length = len(blockchain.blocks)
 		return longest_notarized_chain
+		
+	def get_unproposed_transactions(self):
+		''' Node retrieves all unconfiremd transactions not proposed in previous blocks. '''
+		unproposed_transactions = self.unconfirmed_transactions
+		for blockchain in self.node_blockchains:
+			for block in blockchain.blocks:
+				for transaction in block.txs:
+						if transaction in unproposed_transactions:
+							unproposed_transactions.remove(transaction)
+		return unproposed_transactions
 
 	def propose_block(self, epoch, nodes):
 		''' Node generates a block for that epoch, containing all uncorfirmed transactions.
@@ -57,8 +67,9 @@ class Node:
 			Node signs the block, and broadcasts it to rest nodes. '''
 	
 		longest_notarized_chain = self.find_longest_notarized_chain()
+		unproposed_transactions = self.get_unproposed_transactions()
 		proposed_block = copy.deepcopy(Block(
-			hash(longest_notarized_chain.blocks[-1]), epoch, self.unconfirmed_transactions))
+			hash(longest_notarized_chain.blocks[-1]), epoch, unproposed_transactions))
 		signed_proposed_block = copy.deepcopy(
 			utils.sign_message(
 				self.password,
@@ -139,6 +150,7 @@ class Node:
 		''' For the provided block, node checks if the blockchain it extends can be finalized.
 			Consensus finalization logic: If node has observed the notarization of 3 consecutive
 			blocks in a fork chain, it finalizes (appends to canonical blockchain) all blocks up to the middle block.
+			When a block gets finalized, the transactions it contains are removed from nodes unconfirmed transactions list.
 			When fork chain blocks are finalized, rest fork chains not starting by those blocks are removed. '''
 		
 		if block in self.canonical_blockchain.blocks:
@@ -152,6 +164,9 @@ class Node:
 				for block in blockchain.blocks[:-1]:
 					block.finalized = True
 					self.canonical_blockchain.blocks.append(block)
+					for transaction in block.txs:
+						if transaction in self.unconfirmed_transactions:
+							self.unconfirmed_transactions.remove(transaction)
 				for node_blockchain in self.node_blockchains:
 					if node_blockchain.blocks[-len(blockchain.blocks[:-1]):] != blockchain.blocks[:-1]:
 						self.node_blockchains.remove(node_blockchain)
@@ -163,9 +178,7 @@ class Node:
 			First, sender is verified using their public key.
 			Block is searched in nodes blockchains.
 			If the vote wasn't received before, it is appended to block votes list.
-			When a node sees 2n/3 votes for a block it notarizes it.
-			When a block gets notarized, the transactions it contains are removed from
-			nodes unconfirmed transactions list.
+			When a node sees 2n/3 votes for a block it notarizes it.			
 			Finally, we check if the notarization of the block can finalize parent blocks
 			in its blockchain. '''
 	
@@ -178,7 +191,4 @@ class Node:
 			vote_block.votes.append(vote)
 		if not vote_block.notarized and len(vote_block.votes) > (2 * len(nodes) / 3):
 			vote_block.notarized = True
-			for transaction in vote_block.txs:
-				if transaction in self.unconfirmed_transactions:
-					self.unconfirmed_transactions.remove(transaction)
 			self.check_blockchain_finalization(vote_block)

+ 13 - 13
script/research/streamlet_rust/src/lib.rs

@@ -39,7 +39,7 @@ mod tests {
         let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
         node1.receive_transaction(tx.clone());
         node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
+        let tx = node2.generate_transaction(token_id, 300, &node1_public_key).unwrap();
         node2.receive_transaction(tx.clone());
         node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
@@ -78,15 +78,15 @@ mod tests {
         thread::sleep(Duration::new(5, 0));
 
         // Next round.
-        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
+        let tx = node0.generate_transaction(token_id, 400, &node1_public_key).unwrap();
         node0.receive_transaction(tx.clone());
         node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
-        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
+        let tx = node1.generate_transaction(token_id, 500, &node2_public_key).unwrap();
         node1.receive_transaction(tx.clone());
         node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
-        node2.receive_transaction(tx.clone());
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
+        //let tx = node2.generate_transaction(token_id, 600, &node1_public_key).unwrap();
+        //node2.receive_transaction(tx.clone());
+        //node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
         // Each node checks if they are the epoch leader. Leader will propose the block.
         let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
@@ -123,15 +123,15 @@ mod tests {
         thread::sleep(Duration::new(5, 0));
 
         // Next round.
-        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
+        let tx = node0.generate_transaction(token_id, 700, &node1_public_key).unwrap();
         node0.receive_transaction(tx.clone());
         node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
-        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
-        node1.receive_transaction(tx.clone());
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
-        node2.receive_transaction(tx.clone());
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
+        //let tx = node1.generate_transaction(token_id, 800, &node2_public_key).unwrap();
+        //node1.receive_transaction(tx.clone());
+        //node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
+        //let tx = node2.generate_transaction(token_id, 900, &node1_public_key).unwrap();
+        //node2.receive_transaction(tx.clone());
+        //node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
         // Each node checks if they are the epoch leader. Leader will propose the block.
         let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {

+ 28 - 19
script/research/streamlet_rust/src/structures/node.rs

@@ -117,6 +117,23 @@ impl Node {
         self.id == leader
     }
 
+    /// Node retrieves all unconfiremd transactions not proposed in previous blocks.
+    pub fn get_unproposed_transactions(&self) -> Vec<Transaction> {
+        let mut unproposed_transactions = self.unconfirmed_transactions.clone();
+        for blockchain in &self.node_blockchains {
+            for block in &blockchain.blocks {
+                for transaction in &block.txs {
+                    if let Some(pos) =
+                        unproposed_transactions.iter().position(|txs| *txs == *transaction)
+                    {
+                        unproposed_transactions.remove(pos);
+                    }
+                }
+            }
+        }
+        unproposed_transactions
+    }
+
     /// Node generates a block proposal(mapped as Vote) for the current epoch,
     /// containing all uncorfirmed transactions.
     /// Block extends the longest notarized blockchain the node holds.
@@ -125,8 +142,9 @@ impl Node {
         let longest_notarized_chain = self.find_longest_notarized_chain();
         let mut hasher = DefaultHasher::new();
         longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher);
+        let unproposed_transactions = self.get_unproposed_transactions();
         let proposed_block =
-            Block::new(hasher.finish().to_string(), epoch, self.unconfirmed_transactions.clone());
+            Block::new(hasher.finish().to_string(), epoch, unproposed_transactions);
         let signed_block = self.secret_key.sign(proposed_block.signature_encode().as_bytes());
         (self.public_key, Vote::new(signed_block, proposed_block, self.id))
     }
@@ -221,16 +239,11 @@ impl Node {
     /// nodes unconfirmed transactions list.
     /// Finally, we check if the notarization of the block can finalize parent blocks
     ///	in its blockchain.
-    pub fn receive_vote(
-        &mut self,
-        node_public_key: &PublicKey,
-        vote: &Vote,
-        nodes_count: usize,
-    ) -> Option<Vote> {
+    pub fn receive_vote(&mut self, node_public_key: &PublicKey, vote: &Vote, nodes_count: usize) {
         assert!(node_public_key.verify(vote.block.signature_encode().as_bytes(), &vote.vote));
         let vote_block = self.find_block(&vote.block);
         if vote_block == None {
-            return self.vote_block(&vote.block)
+            panic!("Received vote for unknown block.");
         }
 
         let (unwrapped_vote_block, blockchain_index) = vote_block.unwrap();
@@ -242,19 +255,8 @@ impl Node {
             unwrapped_vote_block.votes.len() > (2 * nodes_count / 3)
         {
             unwrapped_vote_block.notarized = true;
-
-            for transaction in unwrapped_vote_block.txs.clone() {
-                let txs_clone = transaction.clone();
-                if let Some(pos) =
-                    self.unconfirmed_transactions.iter().position(|txs| *txs == txs_clone)
-                {
-                    self.unconfirmed_transactions.remove(pos);
-                }
-            }
-
             self.check_blockchain_finalization(blockchain_index);
         }
-        None
     }
 
     /// Node searches it the blockchains it holds for provided block.
@@ -302,6 +304,13 @@ impl Node {
                 for block in &mut blockchain.blocks[..(consecutive_notarized - 1)] {
                     block.finalized = true;
                     finalized_blocks.push(block.clone());
+                    for transaction in block.txs.clone() {
+                        if let Some(pos) =
+                            self.unconfirmed_transactions.iter().position(|txs| *txs == transaction)
+                        {
+                            self.unconfirmed_transactions.remove(pos);
+                        }
+                    }
                 }
                 blockchain.blocks.drain(0..(consecutive_notarized - 1));
                 for block in &finalized_blocks {