فهرست منبع

validator: properly test producer txs

aggstam 2 سال پیش
والد
کامیت
01fac53e39

+ 6 - 20
src/contract/consensus/tests/stake_unstake.rs

@@ -61,7 +61,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
 
         // Now Alice can stake her owncoin
         let alice_staked_oc =
-            th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 489).await?;
+            th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 21).await?;
 
         // We progress after grace period
         current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
@@ -98,7 +98,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
 
         // Now Alice can stake her unstaked owncoin again to try some mallicious cases
         let alice_staked_oc = th
-            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 15)
+            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 121)
             .await?;
 
         // Alice tries to stake her coin again
@@ -106,7 +106,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
         info!(target: "consensus", "[Malicious] Checking staking coin again");
         info!(target: "consensus", "[Malicious] ===========================");
         let (stake_tx, _, _) = th
-            .stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(15))
+            .stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(121))
             .await?;
         th.execute_erroneous_txs(
             TxAction::ConsensusStake,
@@ -126,14 +126,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
         info!(target: "consensus", "[Malicious] Checking proposal before grace period");
         info!(target: "consensus", "[Malicious] =====================================");
         let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusProposal,
-            &Holder::Alice,
-            &[proposal_tx],
-            current_slot,
-            1,
-        )
-        .await?;
+        th.execute_erroneous_proposal_tx(&Holder::Alice, &proposal_tx, current_slot).await?;
 
         // or be able to unstake the coin
         info!(target: "consensus", "[Malicious] ======================================");
@@ -195,7 +188,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
 
         // Now Alice can stake her unstaked owncoin again
         let alice_staked_oc = th
-            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 65)
+            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 181)
             .await?;
 
         // We progress after grace period
@@ -214,14 +207,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
         info!(target: "consensus", "[Malicious] Checking using unstaked coin in proposal");
         info!(target: "consensus", "[Malicious] ========================================");
         let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusProposal,
-            &Holder::Alice,
-            &[proposal_tx],
-            current_slot,
-            1,
-        )
-        .await?;
+        th.execute_erroneous_proposal_tx(&Holder::Alice, &proposal_tx, current_slot).await?;
 
         // We progress after grace period
         current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;

+ 1 - 1
src/contract/test-harness/src/consensus_genesis_stake.rs

@@ -62,7 +62,7 @@ impl TestHarness {
             pallas::Scalar::random(&mut OsRng),
             pallas::Base::random(&mut OsRng),
             pallas::Scalar::random(&mut OsRng),
-            pallas::Base::from(138),
+            pallas::Base::from(4),
         )?;
 
         let (genesis_stake_params, genesis_stake_proofs) =

+ 26 - 3
src/contract/test-harness/src/consensus_proposal.rs

@@ -111,7 +111,7 @@ impl TestHarness {
 
         let timer = Instant::now();
 
-        wallet.validator.read().await.add_transactions(&[tx.clone()], slot, true).await?;
+        wallet.validator.read().await.add_test_producer_transaction(tx, slot, true).await?;
         wallet.consensus_staked_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
         tx_action_benchmark.verify_times.push(timer.elapsed());
 
@@ -138,9 +138,9 @@ impl TestHarness {
         ) = self.proposal(holder, slot, staked_oc).await?;
 
         for h in holders {
-            info!(target: "consensus", "[{h:?}] ===========================");
+            info!(target: "consensus", "[{h:?}] ================================");
             info!(target: "consensus", "[{h:?}] Executing {holder:?} proposal tx");
-            info!(target: "consensus", "[{h:?}] ===========================");
+            info!(target: "consensus", "[{h:?}] ================================");
             self.execute_proposal_tx(h, &proposal_tx, &proposal_params, current_slot).await?;
         }
 
@@ -158,4 +158,27 @@ impl TestHarness {
 
         Ok(rewarded_staked_oc)
     }
+
+    pub async fn execute_erroneous_proposal_tx(
+        &mut self,
+        holder: &Holder,
+        tx: &Transaction,
+        slot: u64,
+    ) -> Result<()> {
+        let wallet = self.holders.get_mut(holder).unwrap();
+        let tx_action_benchmark =
+            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
+        let timer = Instant::now();
+
+        assert!(wallet
+            .validator
+            .read()
+            .await
+            .add_test_producer_transaction(tx, slot, true)
+            .await
+            .is_err());
+        tx_action_benchmark.verify_times.push(timer.elapsed());
+
+        Ok(())
+    }
 }

+ 51 - 1
src/validator/mod.rs

@@ -43,7 +43,9 @@ pub mod pid;
 
 /// Verification functions
 pub mod verification;
-use verification::{verify_block, verify_genesis_block, verify_transactions};
+use verification::{
+    verify_block, verify_genesis_block, verify_producer_transaction, verify_transactions,
+};
 
 /// Validation functions
 pub mod validation;
@@ -393,6 +395,54 @@ impl Validator {
         Ok(())
     }
 
+    /// Validate a producer `Transaction` and apply it if valid.
+    /// In case the transactions fail, ir will be returned to the caller.
+    /// The function takes a boolean called `write` which tells it to actually write
+    /// the state transitions to the database.
+    /// This should be only used for test purposes.
+    pub async fn add_test_producer_transaction(
+        &self,
+        tx: &Transaction,
+        verifying_slot: u64,
+        write: bool,
+    ) -> Result<()> {
+        debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
+        let overlay = BlockchainOverlay::new(&self.blockchain)?;
+
+        // Generate a time keeper using transaction verifying slot
+        let time_keeper = TimeKeeper::new(
+            self.consensus.time_keeper.genesis_ts,
+            self.consensus.time_keeper.epoch_length,
+            self.consensus.time_keeper.slot_time,
+            verifying_slot,
+        );
+
+        // Verify transaction
+        let mut erroneous_txs = vec![];
+        if let Err(e) = verify_producer_transaction(&overlay, &time_keeper, tx).await {
+            warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {}", e);
+            erroneous_txs.push(tx.clone());
+        }
+
+        let lock = overlay.lock().unwrap();
+        let mut overlay = lock.overlay.lock().unwrap();
+        if !erroneous_txs.is_empty() {
+            warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
+            overlay.purge_new_trees()?;
+            return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
+        }
+
+        if !write {
+            debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
+            overlay.purge_new_trees()?;
+            return Ok(())
+        }
+
+        debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
+        overlay.apply()?;
+        Ok(())
+    }
+
     /// Retrieve all existing blocks and try to apply them
     /// to an in memory overlay to verify their correctness.
     /// Be careful as this will try to load everything in memory.