Преглед изворни кода

blockchain/Block: moved producer tx at last position of blocks' txs vec

aggstam пре 2 година
родитељ
комит
eca2c7e175

+ 6 - 2
bin/darkfid2/src/tests/harness.rs

@@ -22,6 +22,7 @@ use darkfi::{
     blockchain::{BlockInfo, Header},
     net::Settings,
     rpc::jsonrpc::JsonSubscriber,
+    tx::Transaction,
     util::time::TimeKeeper,
     validator::{pid::slot_pid_output, Validator, ValidatorConfig},
     Result,
@@ -64,9 +65,13 @@ impl Harness {
         // Generate default genesis block
         let mut genesis_block = BlockInfo::default();
 
+        // Retrieve genesis producer transaction
+        let producer_tx = genesis_block.txs.pop().unwrap();
+
         // Append genesis transactions and calculate their total
         genesis_block.txs.push(genesis_stake_tx);
         genesis_block.txs.push(genesis_mint_tx);
+        genesis_block.txs.push(producer_tx);
         let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?;
         genesis_block.slots[0].total_tokens = genesis_txs_total;
 
@@ -201,9 +206,8 @@ impl Harness {
         // Generate block
         let block = BlockInfo::new(
             header,
-            vec![],
+            vec![Transaction::default()],
             previous.signature,
-            previous.proposal.clone(),
             previous.eta,
             slots,
         );

+ 12 - 1
bin/darkfid2/src/utils.rs

@@ -41,10 +41,16 @@ use crate::proto::{ProtocolBlock, ProtocolProposal, ProtocolSync, ProtocolTx};
 /// Auxiliary function to calculate the total amount of minted tokens in provided
 /// genesis transactions set. This includes both staked and normal tokens.
 /// If a non-genesis transaction is found, execution fails.
+/// Set must also include the genesis transaction(empty) at last position.
 pub fn genesis_txs_total(txs: &[Transaction]) -> Result<u64> {
     let mut total = 0;
 
-    for tx in txs {
+    if txs.is_empty() {
+        return Ok(total)
+    }
+
+    // Iterate transactions, exluding producer(last) one
+    for tx in &txs[..txs.len() - 1] {
         // Transaction must contain a single Consensus::GenesisStake or Money::GenesisMint call
         if tx.calls.len() != 1 {
             return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
@@ -69,6 +75,11 @@ pub fn genesis_txs_total(txs: &[Transaction]) -> Result<u64> {
         total += value;
     }
 
+    let tx = txs.last().unwrap();
+    if tx != &Transaction::default() {
+        return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
+    }
+
     Ok(total)
 }
 

+ 3 - 11
src/blockchain/block_store.rs

@@ -49,8 +49,6 @@ pub struct Block {
     pub txs: Vec<blake3::Hash>,
     /// Block producer signature
     pub signature: Signature,
-    /// Proposal transaction
-    pub proposal: Transaction,
     /// Block producer ETA
     pub eta: pallas::Base,
     /// Slots up until this block
@@ -62,12 +60,11 @@ impl Block {
         header: blake3::Hash,
         txs: Vec<blake3::Hash>,
         signature: Signature,
-        proposal: Transaction,
         eta: pallas::Base,
         slots: Vec<u64>,
     ) -> Self {
         let magic = BLOCK_MAGIC_BYTES;
-        Self { magic, header, txs, signature, proposal, eta, slots }
+        Self { magic, header, txs, signature, eta, slots }
     }
 
     /// Calculate the block hash
@@ -87,8 +84,6 @@ pub struct BlockInfo {
     pub txs: Vec<Transaction>,
     /// Block producer signature
     pub signature: Signature,
-    /// Proposal transaction
-    pub proposal: Transaction,
     /// Block producer ETA
     pub eta: pallas::Base,
     /// Slots payload
@@ -102,9 +97,8 @@ impl Default for BlockInfo {
         Self {
             magic,
             header: Header::default(),
-            txs: vec![],
+            txs: vec![Transaction::default()],
             signature: Signature::dummy(),
-            proposal: Transaction::default(),
             eta: pallas::Base::ZERO,
             slots: vec![Slot::default()],
         }
@@ -116,12 +110,11 @@ impl BlockInfo {
         header: Header,
         txs: Vec<Transaction>,
         signature: Signature,
-        proposal: Transaction,
         eta: pallas::Base,
         slots: Vec<Slot>,
     ) -> Self {
         let magic = BLOCK_MAGIC_BYTES;
-        Self { magic, header, txs, signature, proposal, eta, slots }
+        Self { magic, header, txs, signature, eta, slots }
     }
 
     /// Calculate the block hash
@@ -140,7 +133,6 @@ impl From<BlockInfo> for Block {
             header: block_info.header.headerhash().unwrap(),
             txs,
             signature: block_info.signature,
-            proposal: block_info.proposal,
             eta: block_info.eta,
             slots,
         }

+ 2 - 16
src/blockchain/mod.rs

@@ -192,14 +192,7 @@ impl Blockchain {
             let slots = self.slots.get(&block.slots, true)?;
             let slots = slots.iter().map(|x| x.clone().unwrap()).collect();
 
-            let info = BlockInfo::new(
-                header,
-                txs,
-                block.signature,
-                block.proposal.clone(),
-                block.eta,
-                slots,
-            );
+            let info = BlockInfo::new(header, txs, block.signature, block.eta, slots);
             ret.push(info);
         }
 
@@ -514,14 +507,7 @@ impl BlockchainOverlay {
             let slots = self.slots.get(&block.slots, true)?;
             let slots = slots.iter().map(|x| x.clone().unwrap()).collect();
 
-            let info = BlockInfo::new(
-                header,
-                txs,
-                block.signature,
-                block.proposal.clone(),
-                block.eta,
-                slots,
-            );
+            let info = BlockInfo::new(header, txs, block.signature, block.eta, slots);
             ret.push(info);
         }
 

+ 3 - 0
src/error.rs

@@ -360,6 +360,9 @@ pub enum Error {
     #[error("Block with order number {0} not found in database")]
     BlockNumberNotFound(u64),
 
+    #[error("Block {0} contains 0 transactions")]
+    BlockContainsNoTransactions(String),
+
     #[error("Verifying slot missmatch")]
     VerifyingSlotMissmatch(),
 

+ 7 - 10
src/validator/consensus.rs

@@ -128,8 +128,11 @@ impl Consensus {
         }
         let fork = &self.forks[fork_index];
 
-        // Grab forks' unproposed transactions and their root
-        let unproposed_txs = fork.unproposed_txs(&self.blockchain, &time_keeper).await?;
+        // Grab forks' unproposed transactions
+        let mut unproposed_txs = fork.unproposed_txs(&self.blockchain, &time_keeper).await?;
+        unproposed_txs.push(proposal_tx);
+
+        // Calculate transactions tree root
         let mut tree = MerkleTree::new(100);
         // The following is pretty weird, so something better should be done.
         for tx in &unproposed_txs {
@@ -158,14 +161,8 @@ impl Consensus {
         let signature = secret_key.sign(&mut OsRng, &header.headerhash()?.as_bytes()[..]);
 
         // Generate the block and its proposal
-        let block = BlockInfo::new(
-            header,
-            unproposed_txs,
-            signature,
-            proposal_tx,
-            slot.last_eta,
-            fork.slots.clone(),
-        );
+        let block =
+            BlockInfo::new(header, unproposed_txs, signature, slot.last_eta, fork.slots.clone());
         let proposal = Proposal::new(block);
 
         Ok(proposal)

+ 23 - 9
src/validator/verification.rs

@@ -70,19 +70,26 @@ pub async fn verify_genesis_block(
         return Err(Error::SlotIsInvalid(genesis_slot.id))
     }
 
-    // Verify there is not reward
+    // Verify there is no reward
     if genesis_slot.reward != 0 {
         return Err(Error::SlotIsInvalid(genesis_slot.id))
     }
 
-    // Genesis transaction must be the Transaction::default() one (empty)
-    if block.proposal != Transaction::default() {
+    // Verify transactions vector contains at least one(producers) transaction
+    if block.txs.is_empty() {
+        return Err(Error::BlockContainsNoTransactions(block_hash))
+    }
+
+    // Genesis transaction must be the Transaction::default() one(empty)
+    let tx = block.txs.last().unwrap();
+    if tx != &Transaction::default() {
         error!(target: "validator::verification::verify_genesis_block", "Genesis proposal transaction is not default one");
-        return Err(TxVerifyFailed::ErroneousTxs(vec![block.proposal.clone()]).into())
+        return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
     }
 
-    // Verify transactions
-    let erroneous_txs = verify_transactions(overlay, time_keeper, &block.txs).await?;
+    // Verify transactions, exluding producer(last) one
+    let txs = &block.txs[..block.txs.len() - 1];
+    let erroneous_txs = verify_transactions(overlay, time_keeper, txs).await?;
     if !erroneous_txs.is_empty() {
         warn!(target: "validator::verification::verify_genesis_block", "Erroneous transactions found in set");
         overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
@@ -121,14 +128,21 @@ pub async fn verify_block(
     // Validate block, using its previous
     validate_block(block, previous, expected_reward)?;
 
+    // Verify transactions vector contains at least one(producers) transaction
+    if block.txs.is_empty() {
+        return Err(Error::BlockContainsNoTransactions(block_hash))
+    }
+
     // Validate proposal transaction if not in testing mode
     if !testing_mode {
-        verify_proposal_transaction(overlay, time_keeper, &block.proposal).await?;
+        let tx = block.txs.last().unwrap();
+        verify_proposal_transaction(overlay, time_keeper, tx).await?;
         verify_producer_signature(block)?;
     }
 
-    // Verify transactions
-    let erroneous_txs = verify_transactions(overlay, time_keeper, &block.txs).await?;
+    // Verify transactions, exluding producer(last) one
+    let txs = &block.txs[..block.txs.len() - 1];
+    let erroneous_txs = verify_transactions(overlay, time_keeper, txs).await?;
     if !erroneous_txs.is_empty() {
         warn!(target: "validator::verification::verify_block", "Erroneous transactions found in set");
         overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;

+ 1 - 8
tests/blockchain.rs

@@ -82,14 +82,7 @@ impl Harness {
         let header =
             Header::new(previous_hash, previous.header.epoch, id, timestamp, previous.header.root);
 
-        BlockInfo::new(
-            header,
-            vec![],
-            previous.signature,
-            previous.proposal.clone(),
-            previous.eta,
-            vec![slot],
-        )
+        BlockInfo::new(header, previous.txs.clone(), previous.signature, previous.eta, vec![slot])
     }
 
     fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {