Jelajahi Sumber

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

aggstam 4 tahun lalu
induk
melakukan
32daa3cf3e

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

@@ -50,6 +50,16 @@ class Node:
 				longest_notarized_chain = blockchain
 				longest_notarized_chain = blockchain
 				length = len(blockchain.blocks)
 				length = len(blockchain.blocks)
 		return longest_notarized_chain
 		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):
 	def propose_block(self, epoch, nodes):
 		''' Node generates a block for that epoch, containing all uncorfirmed transactions.
 		''' 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. '''
 			Node signs the block, and broadcasts it to rest nodes. '''
 	
 	
 		longest_notarized_chain = self.find_longest_notarized_chain()
 		longest_notarized_chain = self.find_longest_notarized_chain()
+		unproposed_transactions = self.get_unproposed_transactions()
 		proposed_block = copy.deepcopy(Block(
 		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(
 		signed_proposed_block = copy.deepcopy(
 			utils.sign_message(
 			utils.sign_message(
 				self.password,
 				self.password,
@@ -139,6 +150,7 @@ class Node:
 		''' For the provided block, node checks if the blockchain it extends can be finalized.
 		''' 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
 			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.
 			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. '''
 			When fork chain blocks are finalized, rest fork chains not starting by those blocks are removed. '''
 		
 		
 		if block in self.canonical_blockchain.blocks:
 		if block in self.canonical_blockchain.blocks:
@@ -152,6 +164,9 @@ class Node:
 				for block in blockchain.blocks[:-1]:
 				for block in blockchain.blocks[:-1]:
 					block.finalized = True
 					block.finalized = True
 					self.canonical_blockchain.blocks.append(block)
 					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:
 				for node_blockchain in self.node_blockchains:
 					if node_blockchain.blocks[-len(blockchain.blocks[:-1]):] != blockchain.blocks[:-1]:
 					if node_blockchain.blocks[-len(blockchain.blocks[:-1]):] != blockchain.blocks[:-1]:
 						self.node_blockchains.remove(node_blockchain)
 						self.node_blockchains.remove(node_blockchain)
@@ -163,9 +178,7 @@ class Node:
 			First, sender is verified using their public key.
 			First, sender is verified using their public key.
 			Block is searched in nodes blockchains.
 			Block is searched in nodes blockchains.
 			If the vote wasn't received before, it is appended to block votes list.
 			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
 			Finally, we check if the notarization of the block can finalize parent blocks
 			in its blockchain. '''
 			in its blockchain. '''
 	
 	
@@ -178,7 +191,4 @@ class Node:
 			vote_block.votes.append(vote)
 			vote_block.votes.append(vote)
 		if not vote_block.notarized and len(vote_block.votes) > (2 * len(nodes) / 3):
 		if not vote_block.notarized and len(vote_block.votes) > (2 * len(nodes) / 3):
 			vote_block.notarized = True
 			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)
 			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();
         let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
         node1.receive_transaction(tx.clone());
         node1.receive_transaction(tx.clone());
         node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
         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.receive_transaction(tx.clone());
         node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
         node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
 
@@ -78,15 +78,15 @@ mod tests {
         thread::sleep(Duration::new(5, 0));
         thread::sleep(Duration::new(5, 0));
 
 
         // Next round.
         // 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.receive_transaction(tx.clone());
         node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
         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.receive_transaction(tx.clone());
         node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
         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.
         // 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) {
         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));
         thread::sleep(Duration::new(5, 0));
 
 
         // Next round.
         // 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.receive_transaction(tx.clone());
         node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
         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.
         // 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) {
         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
         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,
     /// Node generates a block proposal(mapped as Vote) for the current epoch,
     /// containing all uncorfirmed transactions.
     /// containing all uncorfirmed transactions.
     /// Block extends the longest notarized blockchain the node holds.
     /// 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 longest_notarized_chain = self.find_longest_notarized_chain();
         let mut hasher = DefaultHasher::new();
         let mut hasher = DefaultHasher::new();
         longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher);
         longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher);
+        let unproposed_transactions = self.get_unproposed_transactions();
         let proposed_block =
         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());
         let signed_block = self.secret_key.sign(proposed_block.signature_encode().as_bytes());
         (self.public_key, Vote::new(signed_block, proposed_block, self.id))
         (self.public_key, Vote::new(signed_block, proposed_block, self.id))
     }
     }
@@ -221,16 +239,11 @@ impl Node {
     /// nodes unconfirmed transactions list.
     /// nodes unconfirmed transactions list.
     /// Finally, we check if the notarization of the block can finalize parent blocks
     /// Finally, we check if the notarization of the block can finalize parent blocks
     ///	in its blockchain.
     ///	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));
         assert!(node_public_key.verify(vote.block.signature_encode().as_bytes(), &vote.vote));
         let vote_block = self.find_block(&vote.block);
         let vote_block = self.find_block(&vote.block);
         if vote_block == None {
         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();
         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.votes.len() > (2 * nodes_count / 3)
         {
         {
             unwrapped_vote_block.notarized = true;
             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);
             self.check_blockchain_finalization(blockchain_index);
         }
         }
-        None
     }
     }
 
 
     /// Node searches it the blockchains it holds for provided block.
     /// 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)] {
                 for block in &mut blockchain.blocks[..(consecutive_notarized - 1)] {
                     block.finalized = true;
                     block.finalized = true;
                     finalized_blocks.push(block.clone());
                     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));
                 blockchain.blocks.drain(0..(consecutive_notarized - 1));
                 for block in &finalized_blocks {
                 for block in &finalized_blocks {