validator: properly test producer txs

This commit is contained in:
aggstam
2023-09-15 00:51:22 +03:00
parent ade055d3db
commit 01fac53e39
4 changed files with 84 additions and 25 deletions

View File

@@ -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;

View File

@@ -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) =

View File

@@ -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(())
}
}

View File

@@ -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.