Remove SlashVote per #349

This commit is contained in:
Luke Parker
2023-08-21 23:48:33 -04:00
parent 718c44d50e
commit c65bb70741
9 changed files with 59 additions and 369 deletions

View File

@@ -19,10 +19,10 @@ use crate::{
transaction::Transaction as TransactionTrait,
TransactionError, Transaction, ProvidedError, ProvidedTransactions, merkle, BlockError, Block,
Blockchain,
tendermint::{TendermintNetwork, Validators, tx::TendermintTx, Signer, TendermintBlock},
tendermint::{TendermintNetwork, Validators, Signer, TendermintBlock},
tests::{
ProvidedTransaction, SignedTransaction, random_provided_transaction, p2p::DummyP2p,
new_genesis, random_vote_tx, random_evidence_tx,
new_genesis, random_evidence_tx,
},
};
@@ -149,34 +149,6 @@ fn invalid_block() {
// signature (which it explicitly isn't allowed to anyways)
assert_eq!(block.header.transactions, merkle(&[block.transactions[0].hash()]));
}
{
// Invalid vote signature
let mut blockchain = blockchain.clone();
let vote_tx = random_vote_tx(&mut OsRng, genesis);
assert!(blockchain.add_transaction::<N>(
true,
Transaction::Tendermint(vote_tx),
validators.clone()
));
let mut block = blockchain.build_block::<N>(validators.clone());
blockchain.verify_block::<N>(&block, validators.clone()).unwrap();
match &mut block.transactions[0] {
Transaction::Tendermint(tx) => match tx {
TendermintTx::SlashVote(vote) => {
vote.sig.signature.s += <Ristretto as Ciphersuite>::F::ONE;
}
_ => panic!("non-vote tx found"),
},
_ => panic!("non-tendermint tx found"),
}
assert!(blockchain.verify_block::<N>(&block, validators.clone()).is_err());
// Make sure this isn't because the merkle changed due to the transaction hash including the
// signature (which it explicitly isn't allowed to anyways)
assert_eq!(block.header.transactions, merkle(&[block.transactions[0].hash()]));
}
}
#[test]
@@ -281,61 +253,6 @@ fn provided_transaction() {
assert!(blockchain.add_block::<N>(&block, vec![], validators.clone()).is_err());
}
#[test]
fn tendermint_vote_tx() {
let genesis = new_genesis();
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
let (_, mut blockchain) = new_blockchain::<SignedTransaction>(genesis, &[]);
let test = |blockchain: &mut Blockchain<MemDb, SignedTransaction>,
mempool: Vec<Transaction<SignedTransaction>>| {
let tip = blockchain.tip();
for tx in mempool.clone() {
let Transaction::Tendermint(tx) = tx else {
panic!("non-tendermint tx found");
};
assert!(blockchain.add_transaction::<N>(
true,
Transaction::Tendermint(tx),
validators.clone()
));
}
let block = blockchain.build_block::<N>(validators.clone());
assert_eq!(blockchain.tip(), tip);
assert_eq!(block.header.parent, tip);
// Make sure all transactions were included
for bt in &block.transactions {
assert!(mempool.contains(bt));
}
// Make sure the merkle was correct
// Uses block.transactions instead of mempool as order may differ between the two
assert_eq!(
block.header.transactions,
merkle(&block.transactions.iter().map(Transaction::hash).collect::<Vec<_>>()),
);
// Verify and add the block
blockchain.verify_block::<N>(&block, validators.clone()).unwrap();
assert!(blockchain.add_block::<N>(&block, vec![], validators.clone()).is_ok());
assert_eq!(blockchain.tip(), block.hash());
};
// test with single tx
let tx = random_vote_tx(&mut OsRng, genesis);
test(&mut blockchain, vec![Transaction::Tendermint(tx)]);
// test with multiple txs
let mut mempool: Vec<Transaction<SignedTransaction>> = vec![];
for _ in 0 .. 5 {
mempool.push(Transaction::Tendermint(random_vote_tx(&mut OsRng, genesis)));
}
test(&mut blockchain, mempool);
}
#[tokio::test]
async fn tendermint_evidence_tx() {
let genesis = new_genesis();
@@ -397,8 +314,8 @@ async fn tendermint_evidence_tx() {
test(&mut blockchain, mempool, validators);
}
#[test]
fn block_tx_ordering() {
#[tokio::test]
async fn block_tx_ordering() {
#[derive(Debug, PartialEq, Eq, Clone)]
enum SignedTx {
Signed(Box<SignedTransaction>),
@@ -451,10 +368,10 @@ fn block_tx_ordering() {
let genesis = new_genesis();
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
// signer
let signer = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0).1.signer;
let validators = Arc::new(Validators::new(genesis, vec![(signer, 1)]).unwrap());
let (_, mut blockchain) = new_blockchain::<SignedTx>(genesis, &[signer]);
let tip = blockchain.tip();
@@ -469,7 +386,13 @@ fn block_tx_ordering() {
assert!(blockchain.add_transaction::<N>(true, signed_tx.clone(), validators.clone()));
mempool.push(signed_tx);
let unsigned_tx = Transaction::Tendermint(random_vote_tx(&mut OsRng, genesis));
let unsigned_tx = Transaction::Tendermint(
random_evidence_tx::<N>(
Signer::new(genesis, key.clone()).into(),
TendermintBlock(vec![u8::try_from(i).unwrap()]),
)
.await,
);
assert!(blockchain.add_transaction::<N>(true, unsigned_tx.clone(), validators.clone()));
mempool.push(unsigned_tx);

View File

@@ -13,9 +13,7 @@ use crate::{
transaction::Transaction as TransactionTrait,
tendermint::{TendermintBlock, Validators, Signer, TendermintNetwork},
ACCOUNT_MEMPOOL_LIMIT, Transaction, Mempool,
tests::{
SignedTransaction, signed_transaction, p2p::DummyP2p, random_vote_tx, random_evidence_tx,
},
tests::{SignedTransaction, signed_transaction, p2p::DummyP2p, random_evidence_tx},
};
type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
@@ -55,17 +53,6 @@ async fn mempool_addition() {
));
assert_eq!(mempool.next_nonce(&signer), Some(1));
// add a tendermint vote tx
let vote_tx = random_vote_tx(&mut OsRng, genesis);
assert!(mempool.add::<N>(
&blockchain_next_nonces,
true,
Transaction::Tendermint(vote_tx.clone()),
validators.clone(),
unsigned_in_chain,
commit,
));
// add a tendermint evidence tx
let evidence_tx =
random_evidence_tx::<N>(Signer::new(genesis, key.clone()).into(), TendermintBlock(vec![]))
@@ -91,14 +78,6 @@ async fn mempool_addition() {
unsigned_in_chain,
commit,
));
assert!(!mempool.add::<N>(
&blockchain_next_nonces,
true,
Transaction::Tendermint(vote_tx.clone()),
validators.clone(),
unsigned_in_chain,
commit,
));
assert!(!mempool.add::<N>(
&blockchain_next_nonces,
true,
@@ -146,18 +125,17 @@ async fn mempool_addition() {
assert_eq!(mempool.next_nonce(&second_signer), Some(3));
// Getting a block should work
assert_eq!(mempool.block(&blockchain_next_nonces, unsigned_in_chain).len(), 5);
assert_eq!(mempool.block(&blockchain_next_nonces, unsigned_in_chain).len(), 4);
// If the blockchain says an account had its nonce updated, it should cause a prune
blockchain_next_nonces.insert(signer, 1);
let mut block = mempool.block(&blockchain_next_nonces, unsigned_in_chain);
assert_eq!(block.len(), 4);
assert_eq!(block.len(), 3);
assert!(!block.iter().any(|tx| tx.hash() == first_tx.hash()));
assert_eq!(mempool.txs(), &block.drain(..).map(|tx| (tx.hash(), tx)).collect::<HashMap<_, _>>());
// Removing should also successfully prune
mempool.remove(&tx.hash());
mempool.remove(&vote_tx.hash());
assert_eq!(
mempool.txs(),

View File

@@ -22,10 +22,7 @@ use ::tendermint::{
use crate::{
transaction::{Signed, TransactionError, TransactionKind, Transaction, verify_transaction},
ReadWrite,
tendermint::{
tx::{SlashVote, VoteSignature, TendermintTx},
Validators, Signer,
},
tendermint::{tx::TendermintTx, Validators, Signer},
};
#[cfg(test)]
@@ -205,19 +202,3 @@ pub async fn random_evidence_tx<N: Network>(
let signed = signed_from_data::<N>(signer, signer_id, 0, 0, data).await;
TendermintTx::SlashEvidence((signed, None::<SignedMessageFor<N>>).encode())
}
pub fn random_vote_tx<R: RngCore + CryptoRng>(rng: &mut R, genesis: [u8; 32]) -> TendermintTx {
// private key
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut *rng));
// vote data
let mut id = [0u8; 13];
let mut target = [0u8; 32];
rng.fill_bytes(&mut id);
rng.fill_bytes(&mut target);
let mut tx = TendermintTx::SlashVote(SlashVote { id, target, sig: VoteSignature::default() });
tx.sign(rng, genesis, &key);
tx
}

View File

@@ -4,7 +4,6 @@ use zeroize::Zeroizing;
use rand::{RngCore, rngs::OsRng};
use ciphersuite::{Ristretto, Ciphersuite, group::ff::Field};
use schnorr::SchnorrSignature;
use scale::Encode;
@@ -24,54 +23,25 @@ use crate::{
TendermintBlock, Signer, Validators, TendermintNetwork,
},
tests::{
p2p::DummyP2p, SignedTransaction, new_genesis, random_evidence_tx, random_vote_tx,
tendermint_meta, signed_from_data,
p2p::DummyP2p, SignedTransaction, random_evidence_tx, tendermint_meta, signed_from_data,
},
};
type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
#[test]
fn vote_tx() {
let genesis = new_genesis();
let mut tx = random_vote_tx(&mut OsRng, genesis);
let commit = |_: u32| -> Option<Commit<Arc<Validators>>> {
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
};
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
// should pass
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
if let TendermintTx::SlashVote(vote) = &mut tx {
vote.sig.signature = SchnorrSignature::read(&mut [0; 64].as_slice()).unwrap();
} else {
panic!("SlashVote TX wasn't SlashVote");
}
// should fail
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators, commit).is_err());
}
#[tokio::test]
async fn serialize_tendermint() {
// make a tendermint tx with random evidence
let (genesis, signer, _, _) = tendermint_meta().await;
let (_, signer, _, _) = tendermint_meta().await;
let tx = random_evidence_tx::<N>(signer.into(), TendermintBlock(vec![])).await;
let res = TendermintTx::read::<&[u8]>(&mut tx.serialize().as_ref()).unwrap();
assert_eq!(res, tx);
// with vote tx
let vote_tx = random_vote_tx(&mut OsRng, genesis);
let vote_res = TendermintTx::read::<&[u8]>(&mut vote_tx.serialize().as_ref()).unwrap();
assert_eq!(vote_res, vote_tx);
}
#[tokio::test]
async fn invalid_valid_round() {
// signer
let (genesis, signer, signer_id, validators) = tendermint_meta().await;
let (_, signer, signer_id, validators) = tendermint_meta().await;
let commit = |_: u32| -> Option<Commit<Arc<Validators>>> {
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
};
@@ -87,13 +57,13 @@ async fn invalid_valid_round() {
// This should be invalid evidence if a valid valid round is specified
let (_, tx) = valid_round_tx(None).await;
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
// If an invalid valid round is specified (>= current), this should be invalid evidence
let (mut signed, tx) = valid_round_tx(Some(RoundNumber(0))).await;
// should pass
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
// change the signature
let mut random_sig = [0u8; 64];
@@ -102,12 +72,12 @@ async fn invalid_valid_round() {
let tx = TendermintTx::SlashEvidence((signed.clone(), None::<SignedMessageFor<N>>).encode());
// should fail
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators, commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators, commit).is_err());
}
#[tokio::test]
async fn invalid_precommit_signature() {
let (genesis, signer, signer_id, validators) = tendermint_meta().await;
let (_, signer, signer_id, validators) = tendermint_meta().await;
let commit = |i: u32| -> Option<Commit<Arc<Validators>>> {
assert_eq!(i, 0);
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
@@ -124,8 +94,7 @@ async fn invalid_precommit_signature() {
};
// Empty Precommit should fail.
assert!(verify_tendermint_tx::<N>(&precommit(None).await.1, genesis, validators.clone(), commit)
.is_err());
assert!(verify_tendermint_tx::<N>(&precommit(None).await.1, validators.clone(), commit).is_err());
// valid precommit signature should fail.
let block_id = [0x22u8; 32];
@@ -136,7 +105,6 @@ async fn invalid_precommit_signature() {
assert!(verify_tendermint_tx::<N>(
&precommit(Some((block_id, signer.clone().sign(&commit_msg).await))).await.1,
genesis,
validators.clone(),
commit
)
@@ -145,20 +113,20 @@ async fn invalid_precommit_signature() {
// any other signature can be used as evidence.
{
let (mut signed, tx) = precommit(Some((block_id, signer.sign(&[]).await))).await;
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
// So long as we can authenticate where it came from
let mut random_sig = [0u8; 64];
OsRng.fill_bytes(&mut random_sig);
signed.sig = random_sig;
let tx = TendermintTx::SlashEvidence((signed.clone(), None::<SignedMessageFor<N>>).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators, commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators, commit).is_err());
}
}
#[tokio::test]
async fn evidence_with_prevote() {
let (genesis, signer, signer_id, validators) = tendermint_meta().await;
let (_, signer, signer_id, validators) = tendermint_meta().await;
let commit = |_: u32| -> Option<Commit<Arc<Validators>>> {
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
};
@@ -179,7 +147,7 @@ async fn evidence_with_prevote() {
// No prevote message should be valid as slash evidence at this time
for prevote in [prevote(None).await, prevote(Some([0x22u8; 32])).await] {
assert!(verify_tendermint_tx::<N>(&prevote, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&prevote, validators.clone(), commit).is_err());
}
}
@@ -202,23 +170,23 @@ async fn conflicting_msgs_evidence_tx() {
// non-conflicting data should fail
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(&signed_1)).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
// conflicting data should pass
let signed_2 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
// Except if it has a distinct round number, as we don't check cross-round conflicts
// (except for Precommit)
let signed_2 = signed_for_b_r(0, 1, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap_err();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap_err();
// Proposals for different block numbers should also fail as evidence
let signed_2 = signed_for_b_r(1, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap_err();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap_err();
}
// Prevote
@@ -226,23 +194,23 @@ async fn conflicting_msgs_evidence_tx() {
// non-conflicting data should fail
let signed_1 = signed_for_b_r(0, 0, Data::Prevote(Some([0x11; 32]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(&signed_1)).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
// conflicting data should pass
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(Some([0x22; 32]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
// Except if it has a distinct round number, as we don't check cross-round conflicts
// (except for Precommit)
let signed_2 = signed_for_b_r(0, 1, Data::Prevote(Some([0x22; 32]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap_err();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap_err();
// Proposals for different block numbers should also fail as evidence
let signed_2 = signed_for_b_r(1, 0, Data::Prevote(Some([0x22; 32]))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap_err();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap_err();
}
// Precommit
@@ -251,17 +219,17 @@ async fn conflicting_msgs_evidence_tx() {
let signed_1 = signed_for_b_r(0, 0, Data::Precommit(Some(([0x11; 32], sig)))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(&signed_1)).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
// For precommit, the round number is ignored
let signed_2 = signed_for_b_r(0, 1, Data::Precommit(Some(([0x22; 32], sig)))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
// Yet the block number isn't
let signed_2 = signed_for_b_r(1, 0, Data::Precommit(Some(([0x22; 32], sig)))).await;
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
}
// msgs from different senders should fail
@@ -290,7 +258,7 @@ async fn conflicting_msgs_evidence_tx() {
let validators =
Arc::new(Validators::new(genesis, vec![(signer_pub, 1), (signer_pub_2, 1)]).unwrap());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators, commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators, commit).is_err());
}
// msgs with different steps should fail
@@ -298,6 +266,6 @@ async fn conflicting_msgs_evidence_tx() {
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![]))).await;
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(None)).await;
let tx = TendermintTx::SlashEvidence((signed_1, Some(signed_2)).encode());
assert!(verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).is_err());
assert!(verify_tendermint_tx::<N>(&tx, validators.clone(), commit).is_err());
}
}