mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 12:49:23 +00:00
Only allow designated participants to send transactions
This commit is contained in:
@@ -92,12 +92,11 @@ fn duplicate_nonces() {
|
||||
insert(NonceTransaction::new(0, 0));
|
||||
insert(NonceTransaction::new(i, 1));
|
||||
|
||||
let nonces = HashMap::new();
|
||||
let res = Block::new(LAST, &ProvidedTransactions::new(), mempool).verify(
|
||||
GENESIS,
|
||||
LAST,
|
||||
HashSet::new(),
|
||||
nonces,
|
||||
HashMap::from([(<Ristretto as Ciphersuite>::G::identity(), 0)]),
|
||||
);
|
||||
if i == 1 {
|
||||
res.unwrap();
|
||||
@@ -125,13 +124,14 @@ fn unsorted_nonces() {
|
||||
// Create and verify the block
|
||||
const GENESIS: [u8; 32] = [0xff; 32];
|
||||
const LAST: [u8; 32] = [0x01; 32];
|
||||
let nonces = HashMap::from([(<Ristretto as Ciphersuite>::G::identity(), 0)]);
|
||||
Block::new(LAST, &ProvidedTransactions::new(), mempool.clone())
|
||||
.verify(GENESIS, LAST, HashSet::new(), HashMap::new())
|
||||
.verify(GENESIS, LAST, HashSet::new(), nonces.clone())
|
||||
.unwrap();
|
||||
|
||||
let skip = NonceTransaction::new(65, 0);
|
||||
mempool.insert(skip.hash(), skip);
|
||||
assert!(Block::new(LAST, &ProvidedTransactions::new(), mempool)
|
||||
.verify(GENESIS, LAST, HashSet::new(), HashMap::new())
|
||||
.verify(GENESIS, LAST, HashSet::new(), nonces)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
@@ -12,19 +12,25 @@ use crate::{
|
||||
tests::{ProvidedTransaction, SignedTransaction, random_provided_transaction},
|
||||
};
|
||||
|
||||
fn new_blockchain<T: Transaction>() -> ([u8; 32], Blockchain<T>) {
|
||||
fn new_genesis() -> [u8; 32] {
|
||||
let mut genesis = [0; 32];
|
||||
OsRng.fill_bytes(&mut genesis);
|
||||
genesis
|
||||
}
|
||||
|
||||
let blockchain = Blockchain::new(genesis);
|
||||
fn new_blockchain<T: Transaction>(
|
||||
genesis: [u8; 32],
|
||||
participants: &[<Ristretto as Ciphersuite>::G],
|
||||
) -> Blockchain<T> {
|
||||
let blockchain = Blockchain::new(genesis, participants);
|
||||
assert_eq!(blockchain.tip(), genesis);
|
||||
|
||||
(genesis, blockchain)
|
||||
blockchain
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_addition() {
|
||||
let (genesis, mut blockchain) = new_blockchain::<SignedTransaction>();
|
||||
let genesis = new_genesis();
|
||||
let mut blockchain = new_blockchain::<SignedTransaction>(genesis, &[]);
|
||||
let block = blockchain.build_block(HashMap::new());
|
||||
assert_eq!(block.header.parent, genesis);
|
||||
assert_eq!(block.header.transactions, [0; 32]);
|
||||
@@ -35,7 +41,8 @@ fn block_addition() {
|
||||
|
||||
#[test]
|
||||
fn invalid_block() {
|
||||
let (genesis, blockchain) = new_blockchain::<SignedTransaction>();
|
||||
let genesis = new_genesis();
|
||||
let blockchain = new_blockchain::<SignedTransaction>(genesis, &[]);
|
||||
|
||||
let block = blockchain.build_block(HashMap::new());
|
||||
|
||||
@@ -55,10 +62,36 @@ fn invalid_block() {
|
||||
}
|
||||
|
||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||
|
||||
// Not a participant
|
||||
{
|
||||
// Manually create the block to bypass build_block's checks
|
||||
let block = Block::new(
|
||||
blockchain.tip(),
|
||||
&ProvidedTransactions::new(),
|
||||
HashMap::from([(tx.hash(), tx.clone())]),
|
||||
);
|
||||
assert_eq!(block.header.transactions, merkle(&[tx.hash()]));
|
||||
assert!(blockchain.verify_block(&block).is_err());
|
||||
}
|
||||
|
||||
// Run the rest of the tests with them as a participant
|
||||
let blockchain = new_blockchain(genesis, &[tx.1.signer]);
|
||||
|
||||
// Re-run the not a participant block to make sure it now works
|
||||
{
|
||||
let block = Block::new(
|
||||
blockchain.tip(),
|
||||
&ProvidedTransactions::new(),
|
||||
HashMap::from([(tx.hash(), tx.clone())]),
|
||||
);
|
||||
assert_eq!(block.header.transactions, merkle(&[tx.hash()]));
|
||||
blockchain.verify_block(&block).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
// Add a valid transaction
|
||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||
let mut block = blockchain.build_block(HashMap::from([(tx.hash(), tx.clone())]));
|
||||
assert_eq!(block.header.transactions, merkle(&[tx.hash()]));
|
||||
blockchain.verify_block(&block).unwrap();
|
||||
@@ -79,7 +112,6 @@ fn invalid_block() {
|
||||
|
||||
{
|
||||
// Invalid signature
|
||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||
let mut block = blockchain.build_block(HashMap::from([(tx.hash(), tx)]));
|
||||
blockchain.verify_block(&block).unwrap();
|
||||
block.transactions[0].1.signature.s += <Ristretto as Ciphersuite>::F::ONE;
|
||||
@@ -93,11 +125,14 @@ fn invalid_block() {
|
||||
|
||||
#[test]
|
||||
fn signed_transaction() {
|
||||
let (genesis, mut blockchain) = new_blockchain::<SignedTransaction>();
|
||||
let genesis = new_genesis();
|
||||
|
||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||
let signer = tx.1.signer;
|
||||
assert_eq!(blockchain.next_nonce(signer), 0);
|
||||
|
||||
let mut blockchain = new_blockchain::<SignedTransaction>(genesis, &[signer]);
|
||||
assert_eq!(blockchain.next_nonce(signer), Some(0));
|
||||
|
||||
let test = |blockchain: &mut Blockchain<SignedTransaction>, mempool: HashMap<_, _>| {
|
||||
let mut hashes = mempool.keys().cloned().collect::<HashSet<_>>();
|
||||
@@ -126,7 +161,7 @@ fn signed_transaction() {
|
||||
|
||||
// Test with a single nonce
|
||||
test(&mut blockchain, HashMap::from([(tx.hash(), tx)]));
|
||||
assert_eq!(blockchain.next_nonce(signer), 1);
|
||||
assert_eq!(blockchain.next_nonce(signer), Some(1));
|
||||
|
||||
// Test with a flood of nonces
|
||||
let mut mempool = HashMap::new();
|
||||
@@ -140,12 +175,12 @@ fn signed_transaction() {
|
||||
mempool.insert(tx.hash(), tx);
|
||||
}
|
||||
test(&mut blockchain, mempool);
|
||||
assert_eq!(blockchain.next_nonce(signer), 64);
|
||||
assert_eq!(blockchain.next_nonce(signer), Some(64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provided_transaction() {
|
||||
let (_, mut blockchain) = new_blockchain::<ProvidedTransaction>();
|
||||
let mut blockchain = new_blockchain::<ProvidedTransaction>(new_genesis(), &[]);
|
||||
|
||||
let tx = random_provided_transaction(&mut OsRng);
|
||||
let mut txs = ProvidedTransactions::new();
|
||||
|
||||
@@ -27,17 +27,18 @@ fn mempool_addition() {
|
||||
assert_eq!(mempool.next_nonce(&signer), None);
|
||||
|
||||
// Add TX 0
|
||||
assert!(mempool.add(&HashMap::new(), first_tx.clone()));
|
||||
let mut blockchain_next_nonces = HashMap::from([(signer, 0)]);
|
||||
assert!(mempool.add(&blockchain_next_nonces, first_tx.clone()));
|
||||
assert_eq!(mempool.next_nonce(&signer), Some(1));
|
||||
|
||||
// Adding it again should fail
|
||||
assert!(!mempool.add(&HashMap::new(), first_tx.clone()));
|
||||
assert!(!mempool.add(&blockchain_next_nonces, first_tx.clone()));
|
||||
|
||||
// Do the same with the next nonce
|
||||
let second_tx = signed_transaction(&mut OsRng, genesis, &key, 1);
|
||||
assert!(mempool.add(&HashMap::new(), second_tx.clone()));
|
||||
assert!(mempool.add(&blockchain_next_nonces, second_tx.clone()));
|
||||
assert_eq!(mempool.next_nonce(&signer), Some(2));
|
||||
assert!(!mempool.add(&HashMap::new(), second_tx.clone()));
|
||||
assert!(!mempool.add(&blockchain_next_nonces, second_tx.clone()));
|
||||
|
||||
// If the mempool doesn't have a nonce for an account, it should successfully use the
|
||||
// blockchain's
|
||||
@@ -45,18 +46,16 @@ fn mempool_addition() {
|
||||
let tx = signed_transaction(&mut OsRng, genesis, &second_key, 2);
|
||||
let second_signer = tx.1.signer;
|
||||
assert_eq!(mempool.next_nonce(&second_signer), None);
|
||||
let mut blockchain_nonces = HashMap::from([(second_signer, 2)]);
|
||||
assert!(mempool.add(&blockchain_nonces, tx.clone()));
|
||||
blockchain_next_nonces.insert(second_signer, 2);
|
||||
assert!(mempool.add(&blockchain_next_nonces, tx.clone()));
|
||||
assert_eq!(mempool.next_nonce(&second_signer), Some(3));
|
||||
|
||||
// Getting a block should work
|
||||
let block = mempool.block(&HashMap::new());
|
||||
assert_eq!(block, mempool.block(&blockchain_nonces));
|
||||
assert_eq!(block.len(), 3);
|
||||
assert_eq!(mempool.block(&blockchain_next_nonces).len(), 3);
|
||||
|
||||
// If the blockchain says an account had its nonce updated, it should cause a prune
|
||||
blockchain_nonces.insert(signer, 1);
|
||||
let block = mempool.block(&blockchain_nonces);
|
||||
blockchain_next_nonces.insert(signer, 1);
|
||||
let block = mempool.block(&blockchain_next_nonces);
|
||||
assert_eq!(block.len(), 2);
|
||||
assert!(!block.contains_key(&first_tx.hash()));
|
||||
assert_eq!(mempool.txs(), &block);
|
||||
|
||||
Reference in New Issue
Block a user