mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Remove SlashVote per #349
This commit is contained in:
@@ -76,20 +76,6 @@ async fn handle_block<
|
|||||||
|
|
||||||
// TODO: disconnect the node from network/ban from further participation in Tributary
|
// TODO: disconnect the node from network/ban from further participation in Tributary
|
||||||
}
|
}
|
||||||
TributaryTransaction::Tendermint(TendermintTx::SlashVote(vote)) => {
|
|
||||||
// TODO: make sure same signer doesn't vote twice
|
|
||||||
|
|
||||||
// increment the counter for this vote
|
|
||||||
let vote_key = TributaryDb::<D>::slash_vote_key(genesis, vote.id, vote.target);
|
|
||||||
let mut count = txn.get(&vote_key).map_or(0, |c| u32::from_le_bytes(c.try_into().unwrap()));
|
|
||||||
count += 1; // TODO: Increase by weight, not by 1
|
|
||||||
txn.put(vote_key, count.to_le_bytes());
|
|
||||||
|
|
||||||
// TODO: Check if a supermajority of validators, by weight, voted, and increment slash
|
|
||||||
// points if so
|
|
||||||
// If a node has a certain number more than the median slash points, the node should be
|
|
||||||
// removed
|
|
||||||
}
|
|
||||||
TributaryTransaction::Application(tx) => {
|
TributaryTransaction::Application(tx) => {
|
||||||
handle_application_tx::<D, _, _, _>(
|
handle_application_tx::<D, _, _, _>(
|
||||||
tx,
|
tx,
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ impl<T: TransactionTrait> Block<T> {
|
|||||||
// use this pattern of verifying tendermint Txs and app txs differently?
|
// use this pattern of verifying tendermint Txs and app txs differently?
|
||||||
match tx {
|
match tx {
|
||||||
Transaction::Tendermint(tx) => {
|
Transaction::Tendermint(tx) => {
|
||||||
match verify_tendermint_tx::<N>(tx, genesis, schema.clone(), &commit) {
|
match verify_tendermint_tx::<N>(tx, schema.clone(), &commit) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => Err(BlockError::TransactionError(e))?,
|
Err(e) => Err(BlockError::TransactionError(e))?,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verify the tx
|
// verify the tx
|
||||||
if verify_tendermint_tx::<N>(tendermint_tx, self.genesis, schema, commit).is_err() {
|
if verify_tendermint_tx::<N>(tendermint_tx, schema, commit).is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use async_trait::async_trait;
|
|||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
use zeroize::{Zeroize, Zeroizing};
|
use zeroize::{Zeroize, Zeroizing};
|
||||||
|
|
||||||
use rand::{SeedableRng, seq::SliceRandom, rngs::OsRng};
|
use rand::{SeedableRng, seq::SliceRandom};
|
||||||
use rand_chacha::ChaCha12Rng;
|
use rand_chacha::ChaCha12Rng;
|
||||||
|
|
||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
@@ -43,11 +43,11 @@ use tokio::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
TENDERMINT_MESSAGE, TRANSACTION_MESSAGE, BLOCK_MESSAGE, ReadWrite,
|
TENDERMINT_MESSAGE, TRANSACTION_MESSAGE, BLOCK_MESSAGE, ReadWrite,
|
||||||
transaction::Transaction as TransactionTrait, Transaction, BlockHeader, Block, BlockError,
|
transaction::Transaction as TransactionTrait, Transaction, BlockHeader, Block, BlockError,
|
||||||
Blockchain, P2p, tendermint::tx::SlashVote,
|
Blockchain, P2p,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod tx;
|
pub mod tx;
|
||||||
use tx::{TendermintTx, VoteSignature};
|
use tx::TendermintTx;
|
||||||
|
|
||||||
const DST: &[u8] = b"Tributary Tendermint Commit Aggregator";
|
const DST: &[u8] = b"Tributary Tendermint Commit Aggregator";
|
||||||
|
|
||||||
@@ -312,21 +312,17 @@ impl<D: Db, T: TransactionTrait, P: P2p> Network for TendermintNetwork<D, T, P>
|
|||||||
);
|
);
|
||||||
|
|
||||||
let signer = self.signer();
|
let signer = self.signer();
|
||||||
let tx = match slash_event {
|
let Some(tx) = (match slash_event {
|
||||||
SlashEvent::WithEvidence(m1, m2) => {
|
SlashEvent::WithEvidence(m1, m2) => {
|
||||||
// create an unsigned evidence tx
|
// create an unsigned evidence tx
|
||||||
TendermintTx::SlashEvidence((m1, m2).encode())
|
Some(TendermintTx::SlashEvidence((m1, m2).encode()))
|
||||||
}
|
}
|
||||||
SlashEvent::Id(reason, block, round) => {
|
SlashEvent::Id(_reason, _block, _round) => {
|
||||||
// create a signed vote tx
|
// TODO: Increase locally observed slash points
|
||||||
let mut tx = TendermintTx::SlashVote(SlashVote {
|
None
|
||||||
id: (reason, block, round).encode().try_into().unwrap(),
|
|
||||||
target: validator.encode().try_into().unwrap(),
|
|
||||||
sig: VoteSignature::default(),
|
|
||||||
});
|
|
||||||
tx.sign(&mut OsRng, signer.genesis, &signer.key);
|
|
||||||
tx
|
|
||||||
}
|
}
|
||||||
|
}) else {
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// add tx to blockchain and broadcast to peers
|
// add tx to blockchain and broadcast to peers
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
use core::ops::Deref;
|
use std::io;
|
||||||
use std::{io, vec, default::Default};
|
|
||||||
|
|
||||||
use scale::Decode;
|
use scale::Decode;
|
||||||
|
|
||||||
use zeroize::Zeroizing;
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use blake2::{Digest, Blake2s256, Blake2b512};
|
use ciphersuite::{Ciphersuite, Ristretto};
|
||||||
|
|
||||||
use rand::{RngCore, CryptoRng};
|
|
||||||
|
|
||||||
use ciphersuite::{
|
|
||||||
group::{GroupEncoding, ff::Field},
|
|
||||||
Ciphersuite, Ristretto,
|
|
||||||
};
|
|
||||||
use schnorr::SchnorrSignature;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
transaction::{Transaction, TransactionKind, TransactionError},
|
transaction::{Transaction, TransactionKind, TransactionError},
|
||||||
@@ -28,72 +19,10 @@ use tendermint::{
|
|||||||
ext::{Network, Commit, RoundNumber, SignatureScheme},
|
ext::{Network, Commit, RoundNumber, SignatureScheme},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Signing data for a slash vote.
|
|
||||||
///
|
|
||||||
/// The traditional Signed uses a nonce, whereas votes aren't required/expected to be ordered.
|
|
||||||
/// Accordingly, a simple uniqueness check works instead.
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct VoteSignature {
|
|
||||||
pub signer: <Ristretto as Ciphersuite>::G,
|
|
||||||
pub signature: SchnorrSignature<Ristretto>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReadWrite for VoteSignature {
|
|
||||||
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
|
||||||
let signer = Ristretto::read_G(reader)?;
|
|
||||||
let signature = SchnorrSignature::<Ristretto>::read(reader)?;
|
|
||||||
|
|
||||||
Ok(VoteSignature { signer, signature })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&self.signer.to_bytes())?;
|
|
||||||
self.signature.write(writer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for VoteSignature {
|
|
||||||
fn default() -> Self {
|
|
||||||
VoteSignature {
|
|
||||||
signer: Ristretto::generator(),
|
|
||||||
signature: SchnorrSignature::<Ristretto>::read(&mut [0; 64].as_slice()).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A vote to slash a malicious validator.
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct SlashVote {
|
|
||||||
pub id: [u8; 13], // vote id(slash event id)
|
|
||||||
pub target: [u8; 32], // who to slash
|
|
||||||
pub sig: VoteSignature, // signature
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReadWrite for SlashVote {
|
|
||||||
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
|
||||||
let mut id = [0; 13];
|
|
||||||
let mut target = [0; 32];
|
|
||||||
reader.read_exact(&mut id)?;
|
|
||||||
reader.read_exact(&mut target)?;
|
|
||||||
let sig = VoteSignature::read(reader)?;
|
|
||||||
|
|
||||||
Ok(SlashVote { id, target, sig })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
||||||
writer.write_all(&self.id)?;
|
|
||||||
writer.write_all(&self.target)?;
|
|
||||||
self.sig.write(writer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum TendermintTx {
|
pub enum TendermintTx {
|
||||||
SlashEvidence(Vec<u8>),
|
SlashEvidence(Vec<u8>),
|
||||||
// TODO: should the SlashVote.sig be directly in the enum
|
|
||||||
// like as in (SlashVote, sig) since the sig is sig of the tx.
|
|
||||||
SlashVote(SlashVote),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadWrite for TendermintTx {
|
impl ReadWrite for TendermintTx {
|
||||||
@@ -126,10 +55,6 @@ impl ReadWrite for TendermintTx {
|
|||||||
}
|
}
|
||||||
Ok(TendermintTx::SlashEvidence(data))
|
Ok(TendermintTx::SlashEvidence(data))
|
||||||
}
|
}
|
||||||
1 => {
|
|
||||||
let vote = SlashVote::read(reader)?;
|
|
||||||
Ok(TendermintTx::SlashVote(vote))
|
|
||||||
}
|
|
||||||
_ => Err(io::Error::new(io::ErrorKind::Other, "invalid transaction type")),
|
_ => Err(io::Error::new(io::ErrorKind::Other, "invalid transaction type")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,10 +66,6 @@ impl ReadWrite for TendermintTx {
|
|||||||
writer.write_all(&u32::try_from(ev.len()).unwrap().to_le_bytes())?;
|
writer.write_all(&u32::try_from(ev.len()).unwrap().to_le_bytes())?;
|
||||||
writer.write_all(ev)
|
writer.write_all(ev)
|
||||||
}
|
}
|
||||||
TendermintTx::SlashVote(vote) => {
|
|
||||||
writer.write_all(&[1])?;
|
|
||||||
vote.write(writer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,32 +78,12 @@ impl Transaction for TendermintTx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn hash(&self) -> [u8; 32] {
|
fn hash(&self) -> [u8; 32] {
|
||||||
let mut tx = self.serialize();
|
Blake2s256::digest(self.serialize()).into()
|
||||||
if let TendermintTx::SlashVote(vote) = self {
|
|
||||||
// Make sure the part we're cutting off is the signature
|
|
||||||
assert_eq!(tx.drain((tx.len() - 64) ..).collect::<Vec<_>>(), vote.sig.signature.serialize());
|
|
||||||
}
|
|
||||||
Blake2s256::digest(tx).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sig_hash(&self, genesis: [u8; 32]) -> <Ristretto as Ciphersuite>::F {
|
fn sig_hash(&self, _genesis: [u8; 32]) -> <Ristretto as Ciphersuite>::F {
|
||||||
match self {
|
match self {
|
||||||
TendermintTx::SlashEvidence(_) => panic!("sig_hash called on slash evidence transaction"),
|
TendermintTx::SlashEvidence(_) => panic!("sig_hash called on slash evidence transaction"),
|
||||||
TendermintTx::SlashVote(vote) => {
|
|
||||||
let signature = &vote.sig.signature;
|
|
||||||
<Ristretto as Ciphersuite>::F::from_bytes_mod_order_wide(
|
|
||||||
&Blake2b512::digest(
|
|
||||||
[
|
|
||||||
b"Tributary Slash Vote",
|
|
||||||
genesis.as_ref(),
|
|
||||||
&self.hash(),
|
|
||||||
signature.R.to_bytes().as_ref(),
|
|
||||||
]
|
|
||||||
.concat(),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,34 +92,6 @@ impl Transaction for TendermintTx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TendermintTx {
|
|
||||||
// Sign a transaction
|
|
||||||
pub fn sign<R: RngCore + CryptoRng>(
|
|
||||||
&mut self,
|
|
||||||
rng: &mut R,
|
|
||||||
genesis: [u8; 32],
|
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
|
||||||
) {
|
|
||||||
fn signature(tx: &mut TendermintTx) -> Option<&mut VoteSignature> {
|
|
||||||
match tx {
|
|
||||||
TendermintTx::SlashVote(vote) => Some(&mut vote.sig),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signature(self).unwrap().signer = Ristretto::generator() * key.deref();
|
|
||||||
|
|
||||||
let sig_nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(rng));
|
|
||||||
signature(self).unwrap().signature.R =
|
|
||||||
<Ristretto as Ciphersuite>::generator() * sig_nonce.deref();
|
|
||||||
|
|
||||||
let sig_hash = self.sig_hash(genesis);
|
|
||||||
|
|
||||||
signature(self).unwrap().signature =
|
|
||||||
SchnorrSignature::<Ristretto>::sign(key, sig_nonce, sig_hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_evidence<N: Network>(
|
pub fn decode_evidence<N: Network>(
|
||||||
mut ev: &[u8],
|
mut ev: &[u8],
|
||||||
) -> Result<(SignedMessageFor<N>, Option<SignedMessageFor<N>>), TransactionError> {
|
) -> Result<(SignedMessageFor<N>, Option<SignedMessageFor<N>>), TransactionError> {
|
||||||
@@ -234,13 +107,13 @@ pub fn decode_evidence<N: Network>(
|
|||||||
// re-implements an entire foreign library's checks for malicious behavior).
|
// re-implements an entire foreign library's checks for malicious behavior).
|
||||||
pub(crate) fn verify_tendermint_tx<N: Network>(
|
pub(crate) fn verify_tendermint_tx<N: Network>(
|
||||||
tx: &TendermintTx,
|
tx: &TendermintTx,
|
||||||
genesis: [u8; 32],
|
|
||||||
schema: N::SignatureScheme,
|
schema: N::SignatureScheme,
|
||||||
commit: impl Fn(u32) -> Option<Commit<N::SignatureScheme>>,
|
commit: impl Fn(u32) -> Option<Commit<N::SignatureScheme>>,
|
||||||
) -> Result<(), TransactionError> {
|
) -> Result<(), TransactionError> {
|
||||||
tx.verify()?;
|
tx.verify()?;
|
||||||
|
|
||||||
match tx {
|
match tx {
|
||||||
|
// TODO: Only allow one evidence per validator, since evidence is fatal
|
||||||
TendermintTx::SlashEvidence(ev) => {
|
TendermintTx::SlashEvidence(ev) => {
|
||||||
let (first, second) = decode_evidence::<N>(ev)?;
|
let (first, second) = decode_evidence::<N>(ev)?;
|
||||||
|
|
||||||
@@ -332,21 +205,6 @@ pub(crate) fn verify_tendermint_tx<N: Network>(
|
|||||||
_ => Err(TransactionError::InvalidContent)?,
|
_ => Err(TransactionError::InvalidContent)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TendermintTx::SlashVote(vote) => {
|
|
||||||
// TODO: verify the target is actually one of our validators?
|
|
||||||
// this shouldn't be a problem because if the target isn't valid, no one else
|
|
||||||
// gonna vote on it. But we still have to think about spam votes.
|
|
||||||
|
|
||||||
// TODO: we need to check signer is a participant
|
|
||||||
|
|
||||||
// TODO: Move this into the standalone TendermintTx verify
|
|
||||||
let sig = &vote.sig;
|
|
||||||
// verify the tx signature
|
|
||||||
// TODO: Use Schnorr half-aggregation and a batch verification here
|
|
||||||
if !sig.signature.verify(sig.signer, tx.sig_hash(genesis)) {
|
|
||||||
Err(TransactionError::InvalidSignature)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ use crate::{
|
|||||||
transaction::Transaction as TransactionTrait,
|
transaction::Transaction as TransactionTrait,
|
||||||
TransactionError, Transaction, ProvidedError, ProvidedTransactions, merkle, BlockError, Block,
|
TransactionError, Transaction, ProvidedError, ProvidedTransactions, merkle, BlockError, Block,
|
||||||
Blockchain,
|
Blockchain,
|
||||||
tendermint::{TendermintNetwork, Validators, tx::TendermintTx, Signer, TendermintBlock},
|
tendermint::{TendermintNetwork, Validators, Signer, TendermintBlock},
|
||||||
tests::{
|
tests::{
|
||||||
ProvidedTransaction, SignedTransaction, random_provided_transaction, p2p::DummyP2p,
|
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)
|
// signature (which it explicitly isn't allowed to anyways)
|
||||||
assert_eq!(block.header.transactions, merkle(&[block.transactions[0].hash()]));
|
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]
|
#[test]
|
||||||
@@ -281,61 +253,6 @@ fn provided_transaction() {
|
|||||||
assert!(blockchain.add_block::<N>(&block, vec![], validators.clone()).is_err());
|
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]
|
#[tokio::test]
|
||||||
async fn tendermint_evidence_tx() {
|
async fn tendermint_evidence_tx() {
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
@@ -397,8 +314,8 @@ async fn tendermint_evidence_tx() {
|
|||||||
test(&mut blockchain, mempool, validators);
|
test(&mut blockchain, mempool, validators);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn block_tx_ordering() {
|
async fn block_tx_ordering() {
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
enum SignedTx {
|
enum SignedTx {
|
||||||
Signed(Box<SignedTransaction>),
|
Signed(Box<SignedTransaction>),
|
||||||
@@ -451,10 +368,10 @@ fn block_tx_ordering() {
|
|||||||
|
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
||||||
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
|
|
||||||
|
|
||||||
// signer
|
// signer
|
||||||
let signer = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0).1.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 (_, mut blockchain) = new_blockchain::<SignedTx>(genesis, &[signer]);
|
||||||
let tip = blockchain.tip();
|
let tip = blockchain.tip();
|
||||||
@@ -469,7 +386,13 @@ fn block_tx_ordering() {
|
|||||||
assert!(blockchain.add_transaction::<N>(true, signed_tx.clone(), validators.clone()));
|
assert!(blockchain.add_transaction::<N>(true, signed_tx.clone(), validators.clone()));
|
||||||
mempool.push(signed_tx);
|
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()));
|
assert!(blockchain.add_transaction::<N>(true, unsigned_tx.clone(), validators.clone()));
|
||||||
mempool.push(unsigned_tx);
|
mempool.push(unsigned_tx);
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ use crate::{
|
|||||||
transaction::Transaction as TransactionTrait,
|
transaction::Transaction as TransactionTrait,
|
||||||
tendermint::{TendermintBlock, Validators, Signer, TendermintNetwork},
|
tendermint::{TendermintBlock, Validators, Signer, TendermintNetwork},
|
||||||
ACCOUNT_MEMPOOL_LIMIT, Transaction, Mempool,
|
ACCOUNT_MEMPOOL_LIMIT, Transaction, Mempool,
|
||||||
tests::{
|
tests::{SignedTransaction, signed_transaction, p2p::DummyP2p, random_evidence_tx},
|
||||||
SignedTransaction, signed_transaction, p2p::DummyP2p, random_vote_tx, random_evidence_tx,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
|
type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
|
||||||
@@ -55,17 +53,6 @@ async fn mempool_addition() {
|
|||||||
));
|
));
|
||||||
assert_eq!(mempool.next_nonce(&signer), Some(1));
|
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
|
// add a tendermint evidence tx
|
||||||
let evidence_tx =
|
let evidence_tx =
|
||||||
random_evidence_tx::<N>(Signer::new(genesis, key.clone()).into(), TendermintBlock(vec![]))
|
random_evidence_tx::<N>(Signer::new(genesis, key.clone()).into(), TendermintBlock(vec![]))
|
||||||
@@ -91,14 +78,6 @@ async fn mempool_addition() {
|
|||||||
unsigned_in_chain,
|
unsigned_in_chain,
|
||||||
commit,
|
commit,
|
||||||
));
|
));
|
||||||
assert!(!mempool.add::<N>(
|
|
||||||
&blockchain_next_nonces,
|
|
||||||
true,
|
|
||||||
Transaction::Tendermint(vote_tx.clone()),
|
|
||||||
validators.clone(),
|
|
||||||
unsigned_in_chain,
|
|
||||||
commit,
|
|
||||||
));
|
|
||||||
assert!(!mempool.add::<N>(
|
assert!(!mempool.add::<N>(
|
||||||
&blockchain_next_nonces,
|
&blockchain_next_nonces,
|
||||||
true,
|
true,
|
||||||
@@ -146,18 +125,17 @@ async fn mempool_addition() {
|
|||||||
assert_eq!(mempool.next_nonce(&second_signer), Some(3));
|
assert_eq!(mempool.next_nonce(&second_signer), Some(3));
|
||||||
|
|
||||||
// Getting a block should work
|
// 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
|
// If the blockchain says an account had its nonce updated, it should cause a prune
|
||||||
blockchain_next_nonces.insert(signer, 1);
|
blockchain_next_nonces.insert(signer, 1);
|
||||||
let mut block = mempool.block(&blockchain_next_nonces, unsigned_in_chain);
|
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!(!block.iter().any(|tx| tx.hash() == first_tx.hash()));
|
||||||
assert_eq!(mempool.txs(), &block.drain(..).map(|tx| (tx.hash(), tx)).collect::<HashMap<_, _>>());
|
assert_eq!(mempool.txs(), &block.drain(..).map(|tx| (tx.hash(), tx)).collect::<HashMap<_, _>>());
|
||||||
|
|
||||||
// Removing should also successfully prune
|
// Removing should also successfully prune
|
||||||
mempool.remove(&tx.hash());
|
mempool.remove(&tx.hash());
|
||||||
mempool.remove(&vote_tx.hash());
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mempool.txs(),
|
mempool.txs(),
|
||||||
|
|||||||
@@ -22,10 +22,7 @@ use ::tendermint::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
transaction::{Signed, TransactionError, TransactionKind, Transaction, verify_transaction},
|
transaction::{Signed, TransactionError, TransactionKind, Transaction, verify_transaction},
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
tendermint::{
|
tendermint::{tx::TendermintTx, Validators, Signer},
|
||||||
tx::{SlashVote, VoteSignature, TendermintTx},
|
|
||||||
Validators, Signer,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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;
|
let signed = signed_from_data::<N>(signer, signer_id, 0, 0, data).await;
|
||||||
TendermintTx::SlashEvidence((signed, None::<SignedMessageFor<N>>).encode())
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use zeroize::Zeroizing;
|
|||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
|
|
||||||
use ciphersuite::{Ristretto, Ciphersuite, group::ff::Field};
|
use ciphersuite::{Ristretto, Ciphersuite, group::ff::Field};
|
||||||
use schnorr::SchnorrSignature;
|
|
||||||
|
|
||||||
use scale::Encode;
|
use scale::Encode;
|
||||||
|
|
||||||
@@ -24,54 +23,25 @@ use crate::{
|
|||||||
TendermintBlock, Signer, Validators, TendermintNetwork,
|
TendermintBlock, Signer, Validators, TendermintNetwork,
|
||||||
},
|
},
|
||||||
tests::{
|
tests::{
|
||||||
p2p::DummyP2p, SignedTransaction, new_genesis, random_evidence_tx, random_vote_tx,
|
p2p::DummyP2p, SignedTransaction, random_evidence_tx, tendermint_meta, signed_from_data,
|
||||||
tendermint_meta, signed_from_data,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
|
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]
|
#[tokio::test]
|
||||||
async fn serialize_tendermint() {
|
async fn serialize_tendermint() {
|
||||||
// make a tendermint tx with random evidence
|
// 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 tx = random_evidence_tx::<N>(signer.into(), TendermintBlock(vec![])).await;
|
||||||
let res = TendermintTx::read::<&[u8]>(&mut tx.serialize().as_ref()).unwrap();
|
let res = TendermintTx::read::<&[u8]>(&mut tx.serialize().as_ref()).unwrap();
|
||||||
assert_eq!(res, tx);
|
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]
|
#[tokio::test]
|
||||||
async fn invalid_valid_round() {
|
async fn invalid_valid_round() {
|
||||||
// signer
|
// 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>>> {
|
let commit = |_: u32| -> Option<Commit<Arc<Validators>>> {
|
||||||
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
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
|
// This should be invalid evidence if a valid valid round is specified
|
||||||
let (_, tx) = valid_round_tx(None).await;
|
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
|
// If an invalid valid round is specified (>= current), this should be invalid evidence
|
||||||
let (mut signed, tx) = valid_round_tx(Some(RoundNumber(0))).await;
|
let (mut signed, tx) = valid_round_tx(Some(RoundNumber(0))).await;
|
||||||
|
|
||||||
// should pass
|
// should pass
|
||||||
verify_tendermint_tx::<N>(&tx, genesis, validators.clone(), commit).unwrap();
|
verify_tendermint_tx::<N>(&tx, validators.clone(), commit).unwrap();
|
||||||
|
|
||||||
// change the signature
|
// change the signature
|
||||||
let mut random_sig = [0u8; 64];
|
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());
|
let tx = TendermintTx::SlashEvidence((signed.clone(), None::<SignedMessageFor<N>>).encode());
|
||||||
|
|
||||||
// should fail
|
// 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]
|
#[tokio::test]
|
||||||
async fn invalid_precommit_signature() {
|
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>>> {
|
let commit = |i: u32| -> Option<Commit<Arc<Validators>>> {
|
||||||
assert_eq!(i, 0);
|
assert_eq!(i, 0);
|
||||||
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
||||||
@@ -124,8 +94,7 @@ async fn invalid_precommit_signature() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Empty Precommit should fail.
|
// Empty Precommit should fail.
|
||||||
assert!(verify_tendermint_tx::<N>(&precommit(None).await.1, genesis, validators.clone(), commit)
|
assert!(verify_tendermint_tx::<N>(&precommit(None).await.1, validators.clone(), commit).is_err());
|
||||||
.is_err());
|
|
||||||
|
|
||||||
// valid precommit signature should fail.
|
// valid precommit signature should fail.
|
||||||
let block_id = [0x22u8; 32];
|
let block_id = [0x22u8; 32];
|
||||||
@@ -136,7 +105,6 @@ async fn invalid_precommit_signature() {
|
|||||||
|
|
||||||
assert!(verify_tendermint_tx::<N>(
|
assert!(verify_tendermint_tx::<N>(
|
||||||
&precommit(Some((block_id, signer.clone().sign(&commit_msg).await))).await.1,
|
&precommit(Some((block_id, signer.clone().sign(&commit_msg).await))).await.1,
|
||||||
genesis,
|
|
||||||
validators.clone(),
|
validators.clone(),
|
||||||
commit
|
commit
|
||||||
)
|
)
|
||||||
@@ -145,20 +113,20 @@ async fn invalid_precommit_signature() {
|
|||||||
// any other signature can be used as evidence.
|
// any other signature can be used as evidence.
|
||||||
{
|
{
|
||||||
let (mut signed, tx) = precommit(Some((block_id, signer.sign(&[]).await))).await;
|
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
|
// So long as we can authenticate where it came from
|
||||||
let mut random_sig = [0u8; 64];
|
let mut random_sig = [0u8; 64];
|
||||||
OsRng.fill_bytes(&mut random_sig);
|
OsRng.fill_bytes(&mut random_sig);
|
||||||
signed.sig = random_sig;
|
signed.sig = random_sig;
|
||||||
let tx = TendermintTx::SlashEvidence((signed.clone(), None::<SignedMessageFor<N>>).encode());
|
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]
|
#[tokio::test]
|
||||||
async fn evidence_with_prevote() {
|
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>>> {
|
let commit = |_: u32| -> Option<Commit<Arc<Validators>>> {
|
||||||
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
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
|
// No prevote message should be valid as slash evidence at this time
|
||||||
for prevote in [prevote(None).await, prevote(Some([0x22u8; 32])).await] {
|
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
|
// non-conflicting data should fail
|
||||||
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
|
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());
|
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
|
// conflicting data should pass
|
||||||
let signed_2 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
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());
|
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 if it has a distinct round number, as we don't check cross-round conflicts
|
||||||
// (except for Precommit)
|
// (except for Precommit)
|
||||||
let signed_2 = signed_for_b_r(0, 1, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
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());
|
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
|
// 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 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());
|
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
|
// Prevote
|
||||||
@@ -226,23 +194,23 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
// non-conflicting data should fail
|
// non-conflicting data should fail
|
||||||
let signed_1 = signed_for_b_r(0, 0, Data::Prevote(Some([0x11; 32]))).await;
|
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());
|
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
|
// conflicting data should pass
|
||||||
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(Some([0x22; 32]))).await;
|
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());
|
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 if it has a distinct round number, as we don't check cross-round conflicts
|
||||||
// (except for Precommit)
|
// (except for Precommit)
|
||||||
let signed_2 = signed_for_b_r(0, 1, Data::Prevote(Some([0x22; 32]))).await;
|
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());
|
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
|
// 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 signed_2 = signed_for_b_r(1, 0, Data::Prevote(Some([0x22; 32]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence((&signed_1, Some(signed_2)).encode());
|
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
|
// 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 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());
|
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
|
// For precommit, the round number is ignored
|
||||||
let signed_2 = signed_for_b_r(0, 1, Data::Precommit(Some(([0x22; 32], sig)))).await;
|
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());
|
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
|
// Yet the block number isn't
|
||||||
let signed_2 = signed_for_b_r(1, 0, Data::Precommit(Some(([0x22; 32], sig)))).await;
|
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());
|
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
|
// msgs from different senders should fail
|
||||||
@@ -290,7 +258,7 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
let validators =
|
let validators =
|
||||||
Arc::new(Validators::new(genesis, vec![(signer_pub, 1), (signer_pub_2, 1)]).unwrap());
|
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
|
// 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_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 signed_2 = signed_for_b_r(0, 0, Data::Prevote(None)).await;
|
||||||
let tx = TendermintTx::SlashEvidence((signed_1, Some(signed_2)).encode());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user