2024-11-28 22:05:14 +02:00
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
2025-07-09 16:03:30 +03:00
|
|
|
use accounts::account_core::AccountAddress;
|
2024-11-25 07:26:16 +02:00
|
|
|
use anyhow::Result;
|
2025-04-16 16:17:53 +03:00
|
|
|
use common::{
|
2024-11-28 22:05:14 +02:00
|
|
|
block::{Block, HashableBlockData},
|
2025-07-24 16:05:27 +03:00
|
|
|
execution_input::PublicNativeTokenSend,
|
2024-11-28 22:05:14 +02:00
|
|
|
merkle_tree_public::TreeHashType,
|
|
|
|
|
nullifier::UTXONullifier,
|
2025-07-16 11:36:20 -03:00
|
|
|
transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind},
|
2024-11-28 22:05:14 +02:00
|
|
|
utxo_commitment::UTXOCommitment,
|
|
|
|
|
};
|
2025-04-16 16:17:53 +03:00
|
|
|
use config::SequencerConfig;
|
|
|
|
|
use mempool::MemPool;
|
2025-07-16 11:54:11 -03:00
|
|
|
use mempool_transaction::MempoolTransaction;
|
2025-07-09 16:03:30 +03:00
|
|
|
use sequencer_store::SequecerChainStore;
|
2025-04-16 16:17:53 +03:00
|
|
|
use serde::{Deserialize, Serialize};
|
2025-07-25 10:00:27 +03:00
|
|
|
use tiny_keccak::{Hasher, Keccak};
|
2024-11-25 07:26:16 +02:00
|
|
|
|
|
|
|
|
pub mod config;
|
2025-07-16 11:54:11 -03:00
|
|
|
pub mod mempool_transaction;
|
2025-04-16 16:17:53 +03:00
|
|
|
pub mod sequencer_store;
|
2024-11-25 07:26:16 +02:00
|
|
|
|
|
|
|
|
pub struct SequencerCore {
|
|
|
|
|
pub store: SequecerChainStore,
|
2025-07-14 15:45:20 -03:00
|
|
|
pub mempool: MemPool<MempoolTransaction>,
|
2024-11-25 07:26:16 +02:00
|
|
|
pub sequencer_config: SequencerConfig,
|
|
|
|
|
pub chain_height: u64,
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:05:14 +02:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub enum TransactionMalformationErrorKind {
|
|
|
|
|
PublicTransactionChangedPrivateData { tx: TreeHashType },
|
|
|
|
|
PrivateTransactionChangedPublicData { tx: TreeHashType },
|
|
|
|
|
TxHashAlreadyPresentInTree { tx: TreeHashType },
|
|
|
|
|
NullifierAlreadyPresentInTree { tx: TreeHashType },
|
|
|
|
|
UTXOCommitmentAlreadyPresentInTree { tx: TreeHashType },
|
2025-01-24 09:10:42 +02:00
|
|
|
MempoolFullForRound { tx: TreeHashType },
|
|
|
|
|
ChainStateFurtherThanTransactionState { tx: TreeHashType },
|
2024-11-28 22:05:14 +02:00
|
|
|
FailedToInsert { tx: TreeHashType, details: String },
|
2025-07-14 15:45:20 -03:00
|
|
|
InvalidSignature,
|
2025-07-25 10:00:27 +03:00
|
|
|
IncorrectSender,
|
2025-07-22 15:22:20 +03:00
|
|
|
BalanceMismatch { tx: TreeHashType },
|
|
|
|
|
FailedToDecode { tx: TreeHashType },
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for TransactionMalformationErrorKind {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f, "{self:#?}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::error::Error for TransactionMalformationErrorKind {}
|
|
|
|
|
|
2024-11-25 07:26:16 +02:00
|
|
|
impl SequencerCore {
|
|
|
|
|
pub fn start_from_config(config: SequencerConfig) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
store: SequecerChainStore::new_with_genesis(
|
|
|
|
|
&config.home,
|
|
|
|
|
config.genesis_id,
|
|
|
|
|
config.is_genesis_random,
|
2025-07-14 10:43:35 +03:00
|
|
|
&config.initial_accounts,
|
2024-11-25 07:26:16 +02:00
|
|
|
),
|
2025-07-14 15:45:20 -03:00
|
|
|
mempool: MemPool::<MempoolTransaction>::default(),
|
2024-11-25 07:26:16 +02:00
|
|
|
chain_height: config.genesis_id,
|
|
|
|
|
sequencer_config: config,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 09:04:04 +03:00
|
|
|
pub fn get_tree_roots(&self) -> [[u8; 32]; 2] {
|
2025-01-24 09:10:42 +02:00
|
|
|
[
|
2025-01-31 10:02:09 +02:00
|
|
|
self.store
|
|
|
|
|
.utxo_commitments_store
|
|
|
|
|
.get_root()
|
|
|
|
|
.unwrap_or([0; 32]),
|
2025-01-31 09:54:19 +02:00
|
|
|
self.store.pub_tx_store.get_root().unwrap_or([0; 32]),
|
2025-01-24 09:10:42 +02:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 12:26:19 +02:00
|
|
|
pub fn transaction_pre_check(
|
2024-11-28 22:05:14 +02:00
|
|
|
&mut self,
|
2025-07-16 11:36:20 -03:00
|
|
|
tx: Transaction,
|
2025-05-23 09:04:04 +03:00
|
|
|
tx_roots: [[u8; 32]; 2],
|
2025-07-14 15:45:20 -03:00
|
|
|
) -> Result<AuthenticatedTransaction, TransactionMalformationErrorKind> {
|
|
|
|
|
let tx = tx
|
|
|
|
|
.into_authenticated()
|
|
|
|
|
.map_err(|_| TransactionMalformationErrorKind::InvalidSignature)?;
|
2025-07-16 08:43:05 -03:00
|
|
|
|
2025-07-14 08:45:38 -03:00
|
|
|
let TransactionBody {
|
2024-11-28 22:05:14 +02:00
|
|
|
tx_kind,
|
|
|
|
|
ref execution_input,
|
|
|
|
|
ref execution_output,
|
|
|
|
|
ref utxo_commitments_created_hashes,
|
|
|
|
|
ref nullifier_created_hashes,
|
2024-11-29 12:28:08 +02:00
|
|
|
..
|
2025-07-16 11:54:11 -03:00
|
|
|
} = tx.transaction().body();
|
2025-01-24 09:10:42 +02:00
|
|
|
|
2025-07-14 15:45:20 -03:00
|
|
|
let tx_hash = *tx.hash();
|
2025-01-24 09:10:42 +02:00
|
|
|
|
2025-07-23 17:44:40 +03:00
|
|
|
let mempool_size = self.mempool.len();
|
|
|
|
|
|
|
|
|
|
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
|
|
|
|
return Err(TransactionMalformationErrorKind::MempoolFullForRound { tx: tx_hash });
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 09:10:42 +02:00
|
|
|
let curr_sequencer_roots = self.get_tree_roots();
|
|
|
|
|
|
|
|
|
|
if tx_roots != curr_sequencer_roots {
|
|
|
|
|
return Err(
|
|
|
|
|
TransactionMalformationErrorKind::ChainStateFurtherThanTransactionState {
|
2025-07-23 17:44:40 +03:00
|
|
|
tx: tx_hash,
|
2025-01-24 09:10:42 +02:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:05:14 +02:00
|
|
|
//Sanity check
|
|
|
|
|
match tx_kind {
|
|
|
|
|
TxKind::Public => {
|
|
|
|
|
if !utxo_commitments_created_hashes.is_empty()
|
|
|
|
|
|| !nullifier_created_hashes.is_empty()
|
|
|
|
|
{
|
|
|
|
|
//Public transactions can not make private operations.
|
|
|
|
|
return Err(
|
|
|
|
|
TransactionMalformationErrorKind::PublicTransactionChangedPrivateData {
|
2025-07-23 17:44:40 +03:00
|
|
|
tx: tx_hash,
|
2024-11-28 22:05:14 +02:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TxKind::Private => {
|
|
|
|
|
if !execution_input.is_empty() || !execution_output.is_empty() {
|
|
|
|
|
//Not entirely necessary, but useful simplification for a future.
|
|
|
|
|
//This way only shielded and deshielded transactions can be used for interaction
|
|
|
|
|
//between public and private state.
|
|
|
|
|
return Err(
|
|
|
|
|
TransactionMalformationErrorKind::PrivateTransactionChangedPublicData {
|
2025-07-23 17:44:40 +03:00
|
|
|
tx: tx_hash,
|
2024-11-28 22:05:14 +02:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-25 10:00:27 +03:00
|
|
|
//Correct sender check
|
|
|
|
|
if let Ok(native_transfer_action) =
|
|
|
|
|
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
|
|
|
|
|
{
|
|
|
|
|
let mut output = [0; 32];
|
|
|
|
|
let mut keccak_hasher = Keccak::v256();
|
2025-07-25 19:46:23 +03:00
|
|
|
keccak_hasher.update(&tx.transaction().public_key.to_sec1_bytes());
|
2025-07-25 10:00:27 +03:00
|
|
|
keccak_hasher.finalize(&mut output);
|
|
|
|
|
|
|
|
|
|
if native_transfer_action.from != output {
|
|
|
|
|
return Err(TransactionMalformationErrorKind::IncorrectSender);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:05:14 +02:00
|
|
|
//Tree checks
|
2025-07-23 17:44:40 +03:00
|
|
|
let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some();
|
2025-06-18 15:58:15 +03:00
|
|
|
let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| {
|
|
|
|
|
self.store.nullifier_store.contains(&UTXONullifier {
|
|
|
|
|
utxo_hash: *nullifier_hash,
|
2024-11-28 22:05:14 +02:00
|
|
|
})
|
2025-06-18 15:58:15 +03:00
|
|
|
});
|
|
|
|
|
let utxo_commitments_check =
|
|
|
|
|
utxo_commitments_created_hashes
|
|
|
|
|
.iter()
|
|
|
|
|
.any(|utxo_commitment_hash| {
|
|
|
|
|
self.store
|
|
|
|
|
.utxo_commitments_store
|
|
|
|
|
.get_tx(*utxo_commitment_hash)
|
|
|
|
|
.is_some()
|
|
|
|
|
});
|
2024-11-28 22:05:14 +02:00
|
|
|
|
|
|
|
|
if tx_tree_check {
|
2025-07-10 12:16:05 -03:00
|
|
|
return Err(
|
2025-07-14 15:45:20 -03:00
|
|
|
TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: *tx.hash() },
|
2025-07-10 12:16:05 -03:00
|
|
|
);
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nullifier_tree_check {
|
|
|
|
|
return Err(
|
2025-07-14 15:45:20 -03:00
|
|
|
TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: *tx.hash() },
|
2024-11-28 22:05:14 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if utxo_commitments_check {
|
|
|
|
|
return Err(
|
2025-07-10 12:16:05 -03:00
|
|
|
TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree {
|
2025-07-14 15:45:20 -03:00
|
|
|
tx: *tx.hash(),
|
2025-07-10 12:16:05 -03:00
|
|
|
},
|
2024-11-28 22:05:14 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-14 15:45:20 -03:00
|
|
|
Ok(tx)
|
2025-01-22 12:26:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn push_tx_into_mempool_pre_check(
|
|
|
|
|
&mut self,
|
2025-07-16 11:36:20 -03:00
|
|
|
transaction: Transaction,
|
2025-05-23 09:04:04 +03:00
|
|
|
tx_roots: [[u8; 32]; 2],
|
2025-01-22 12:26:19 +02:00
|
|
|
) -> Result<(), TransactionMalformationErrorKind> {
|
2025-07-16 08:43:05 -03:00
|
|
|
let mempool_size = self.mempool.len();
|
|
|
|
|
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
|
|
|
|
return Err(TransactionMalformationErrorKind::MempoolFullForRound {
|
2025-07-16 11:54:11 -03:00
|
|
|
tx: transaction.body().hash(),
|
2025-07-16 08:43:05 -03:00
|
|
|
});
|
|
|
|
|
}
|
2025-01-22 12:26:19 +02:00
|
|
|
|
2025-07-16 11:36:20 -03:00
|
|
|
let authenticated_tx = self.transaction_pre_check(transaction, tx_roots)?;
|
2025-01-22 12:26:19 +02:00
|
|
|
|
2025-07-16 08:43:05 -03:00
|
|
|
self.mempool.push_item(authenticated_tx.into());
|
2025-01-22 12:26:19 +02:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn execute_check_transaction_on_state(
|
|
|
|
|
&mut self,
|
2025-07-16 11:54:11 -03:00
|
|
|
mempool_tx: &MempoolTransaction,
|
2025-01-22 12:26:19 +02:00
|
|
|
) -> Result<(), TransactionMalformationErrorKind> {
|
2025-07-14 08:45:38 -03:00
|
|
|
let TransactionBody {
|
2025-01-22 12:26:19 +02:00
|
|
|
ref utxo_commitments_created_hashes,
|
|
|
|
|
ref nullifier_created_hashes,
|
2025-07-24 16:05:27 +03:00
|
|
|
execution_input,
|
2025-01-22 12:26:19 +02:00
|
|
|
..
|
2025-07-16 11:54:11 -03:00
|
|
|
} = mempool_tx.auth_tx.transaction().body();
|
2025-01-22 12:26:19 +02:00
|
|
|
|
2025-07-24 16:05:27 +03:00
|
|
|
let tx_hash = *mempool_tx.auth_tx.hash();
|
|
|
|
|
|
|
|
|
|
//Balance check
|
|
|
|
|
if let Ok(native_transfer_action) =
|
|
|
|
|
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
|
|
|
|
|
{
|
|
|
|
|
let from_balance = self
|
|
|
|
|
.store
|
|
|
|
|
.acc_store
|
|
|
|
|
.get_account_balance(&native_transfer_action.from);
|
|
|
|
|
let to_balance = self
|
|
|
|
|
.store
|
|
|
|
|
.acc_store
|
|
|
|
|
.get_account_balance(&native_transfer_action.to);
|
|
|
|
|
|
|
|
|
|
if from_balance >= native_transfer_action.balance_to_move {
|
|
|
|
|
self.store.acc_store.set_account_balance(
|
|
|
|
|
&native_transfer_action.from,
|
|
|
|
|
from_balance - native_transfer_action.balance_to_move,
|
|
|
|
|
);
|
|
|
|
|
self.store.acc_store.set_account_balance(
|
|
|
|
|
&native_transfer_action.to,
|
|
|
|
|
to_balance + native_transfer_action.balance_to_move,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:05:14 +02:00
|
|
|
for utxo_comm in utxo_commitments_created_hashes {
|
|
|
|
|
self.store
|
|
|
|
|
.utxo_commitments_store
|
2025-07-14 15:45:20 -03:00
|
|
|
.add_tx(&UTXOCommitment { hash: *utxo_comm });
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-22 00:13:17 +03:00
|
|
|
for nullifier in nullifier_created_hashes.iter() {
|
2025-05-23 09:07:53 +03:00
|
|
|
self.store.nullifier_store.insert(UTXONullifier {
|
|
|
|
|
utxo_hash: *nullifier,
|
|
|
|
|
});
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-16 11:54:11 -03:00
|
|
|
self.store
|
|
|
|
|
.pub_tx_store
|
|
|
|
|
.add_tx(mempool_tx.auth_tx.transaction());
|
2024-11-28 22:05:14 +02:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-09 16:03:30 +03:00
|
|
|
pub fn register_account(&mut self, account_addr: AccountAddress) {
|
|
|
|
|
self.store.acc_store.register_account(account_addr);
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Produces new block from transactions in mempool
|
|
|
|
|
pub fn produce_new_block_with_mempool_transactions(&mut self) -> Result<u64> {
|
2025-05-15 11:38:37 +03:00
|
|
|
let new_block_height = self.chain_height + 1;
|
|
|
|
|
|
2024-11-25 07:26:16 +02:00
|
|
|
let transactions = self
|
|
|
|
|
.mempool
|
|
|
|
|
.pop_size(self.sequencer_config.max_num_tx_in_block);
|
|
|
|
|
|
2025-05-23 09:04:04 +03:00
|
|
|
for tx in &transactions {
|
2025-07-23 17:44:40 +03:00
|
|
|
self.execute_check_transaction_on_state(tx)?;
|
2024-11-28 22:05:14 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-29 12:28:08 +02:00
|
|
|
let prev_block_hash = self
|
|
|
|
|
.store
|
|
|
|
|
.block_store
|
|
|
|
|
.get_block_at_id(self.chain_height)?
|
2024-12-29 14:11:47 +02:00
|
|
|
.hash;
|
2024-11-29 12:28:08 +02:00
|
|
|
|
2024-11-25 07:26:16 +02:00
|
|
|
let hashable_data = HashableBlockData {
|
2025-05-15 11:38:37 +03:00
|
|
|
block_id: new_block_height,
|
2024-11-29 12:28:08 +02:00
|
|
|
prev_block_id: self.chain_height,
|
2025-07-14 15:45:20 -03:00
|
|
|
transactions: transactions
|
|
|
|
|
.into_iter()
|
2025-07-16 11:54:11 -03:00
|
|
|
.map(|tx_mem| tx_mem.auth_tx.transaction().clone())
|
2025-07-14 15:45:20 -03:00
|
|
|
.collect(),
|
2024-11-25 07:26:16 +02:00
|
|
|
data: vec![],
|
2024-11-29 12:28:08 +02:00
|
|
|
prev_block_hash,
|
2024-11-25 07:26:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let block = Block::produce_block_from_hashable_data(hashable_data);
|
|
|
|
|
|
|
|
|
|
self.store.block_store.put_block_at_id(block)?;
|
|
|
|
|
|
2025-07-28 15:21:35 -03:00
|
|
|
self.chain_height = new_block_height;
|
2024-11-25 07:26:16 +02:00
|
|
|
|
2025-07-28 15:21:35 -03:00
|
|
|
Ok(self.chain_height)
|
2024-11-25 07:26:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-27 13:42:11 +01:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2025-04-18 08:15:29 -04:00
|
|
|
use std::path::PathBuf;
|
2025-01-27 13:42:11 +01:00
|
|
|
|
2025-07-25 10:00:27 +03:00
|
|
|
use accounts::account_core::AccountForSerialization;
|
2025-07-16 11:36:20 -03:00
|
|
|
use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind};
|
2025-07-16 11:54:11 -03:00
|
|
|
use mempool_transaction::MempoolTransaction;
|
2025-01-27 13:42:11 +01:00
|
|
|
use rand::Rng;
|
2025-04-09 02:20:27 -04:00
|
|
|
use secp256k1_zkp::Tweak;
|
2025-01-27 13:42:11 +01:00
|
|
|
|
2025-07-14 13:17:46 +03:00
|
|
|
fn setup_sequencer_config_variable_initial_accounts(
|
2025-07-25 10:00:27 +03:00
|
|
|
initial_accounts: Vec<AccountForSerialization>,
|
2025-07-14 13:17:46 +03:00
|
|
|
) -> SequencerConfig {
|
2025-01-27 13:42:11 +01:00
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
let random_u8: u8 = rng.gen();
|
|
|
|
|
|
2025-06-18 17:26:57 +03:00
|
|
|
let path_str = format!("/tmp/sequencer_{random_u8:?}");
|
2025-01-27 13:42:11 +01:00
|
|
|
|
|
|
|
|
SequencerConfig {
|
|
|
|
|
home: PathBuf::from(path_str),
|
|
|
|
|
override_rust_log: Some("info".to_string()),
|
|
|
|
|
genesis_id: 1,
|
|
|
|
|
is_genesis_random: false,
|
|
|
|
|
max_num_tx_in_block: 10,
|
|
|
|
|
block_create_timeout_millis: 1000,
|
|
|
|
|
port: 8080,
|
2025-07-14 13:17:46 +03:00
|
|
|
initial_accounts,
|
2025-01-27 13:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-17 08:09:27 +03:00
|
|
|
fn setup_sequencer_config() -> SequencerConfig {
|
2025-07-25 10:00:27 +03:00
|
|
|
let initial_acc1 = serde_json::from_str(r#"{
|
|
|
|
|
"address": [
|
|
|
|
|
244,
|
|
|
|
|
55,
|
|
|
|
|
238,
|
|
|
|
|
205,
|
|
|
|
|
74,
|
|
|
|
|
115,
|
|
|
|
|
179,
|
|
|
|
|
192,
|
|
|
|
|
65,
|
|
|
|
|
186,
|
|
|
|
|
166,
|
|
|
|
|
169,
|
|
|
|
|
221,
|
|
|
|
|
45,
|
|
|
|
|
6,
|
|
|
|
|
57,
|
|
|
|
|
200,
|
|
|
|
|
65,
|
|
|
|
|
195,
|
|
|
|
|
70,
|
|
|
|
|
118,
|
|
|
|
|
252,
|
|
|
|
|
206,
|
|
|
|
|
100,
|
|
|
|
|
215,
|
|
|
|
|
250,
|
|
|
|
|
72,
|
|
|
|
|
230,
|
|
|
|
|
19,
|
|
|
|
|
71,
|
|
|
|
|
217,
|
|
|
|
|
249
|
|
|
|
|
],
|
|
|
|
|
"balance": 10,
|
|
|
|
|
"key_holder": {
|
|
|
|
|
"address": [
|
|
|
|
|
244,
|
|
|
|
|
55,
|
|
|
|
|
238,
|
|
|
|
|
205,
|
|
|
|
|
74,
|
|
|
|
|
115,
|
|
|
|
|
179,
|
|
|
|
|
192,
|
|
|
|
|
65,
|
|
|
|
|
186,
|
|
|
|
|
166,
|
|
|
|
|
169,
|
|
|
|
|
221,
|
|
|
|
|
45,
|
|
|
|
|
6,
|
|
|
|
|
57,
|
|
|
|
|
200,
|
|
|
|
|
65,
|
|
|
|
|
195,
|
|
|
|
|
70,
|
|
|
|
|
118,
|
|
|
|
|
252,
|
|
|
|
|
206,
|
|
|
|
|
100,
|
|
|
|
|
215,
|
|
|
|
|
250,
|
|
|
|
|
72,
|
|
|
|
|
230,
|
|
|
|
|
19,
|
|
|
|
|
71,
|
|
|
|
|
217,
|
|
|
|
|
249
|
|
|
|
|
],
|
|
|
|
|
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
|
|
|
|
"pub_account_signing_key": [
|
|
|
|
|
244,
|
|
|
|
|
88,
|
|
|
|
|
134,
|
|
|
|
|
61,
|
|
|
|
|
35,
|
|
|
|
|
209,
|
|
|
|
|
229,
|
|
|
|
|
101,
|
|
|
|
|
85,
|
|
|
|
|
35,
|
|
|
|
|
140,
|
|
|
|
|
140,
|
|
|
|
|
192,
|
|
|
|
|
226,
|
|
|
|
|
83,
|
|
|
|
|
83,
|
|
|
|
|
190,
|
|
|
|
|
189,
|
|
|
|
|
110,
|
|
|
|
|
8,
|
|
|
|
|
89,
|
|
|
|
|
127,
|
|
|
|
|
147,
|
|
|
|
|
142,
|
|
|
|
|
157,
|
|
|
|
|
204,
|
|
|
|
|
51,
|
|
|
|
|
109,
|
|
|
|
|
189,
|
|
|
|
|
92,
|
|
|
|
|
144,
|
|
|
|
|
68
|
|
|
|
|
],
|
|
|
|
|
"top_secret_key_holder": {
|
|
|
|
|
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
|
|
|
|
},
|
|
|
|
|
"utxo_secret_key_holder": {
|
|
|
|
|
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
|
|
|
|
|
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
|
|
|
|
|
},
|
|
|
|
|
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
|
2025-07-17 08:09:27 +03:00
|
|
|
},
|
2025-07-25 10:00:27 +03:00
|
|
|
"utxos": {}
|
|
|
|
|
}"#).unwrap();
|
|
|
|
|
|
|
|
|
|
let initial_acc2 = serde_json::from_str(r#"{
|
|
|
|
|
"address": [
|
|
|
|
|
72,
|
|
|
|
|
169,
|
|
|
|
|
70,
|
|
|
|
|
237,
|
|
|
|
|
1,
|
|
|
|
|
96,
|
|
|
|
|
35,
|
|
|
|
|
157,
|
|
|
|
|
25,
|
|
|
|
|
15,
|
|
|
|
|
83,
|
|
|
|
|
18,
|
|
|
|
|
52,
|
|
|
|
|
206,
|
|
|
|
|
202,
|
|
|
|
|
63,
|
|
|
|
|
48,
|
|
|
|
|
59,
|
|
|
|
|
173,
|
|
|
|
|
76,
|
|
|
|
|
78,
|
|
|
|
|
7,
|
|
|
|
|
254,
|
|
|
|
|
229,
|
|
|
|
|
28,
|
|
|
|
|
45,
|
|
|
|
|
194,
|
|
|
|
|
79,
|
|
|
|
|
6,
|
|
|
|
|
89,
|
|
|
|
|
58,
|
|
|
|
|
85
|
|
|
|
|
],
|
|
|
|
|
"balance": 100,
|
|
|
|
|
"key_holder": {
|
|
|
|
|
"address": [
|
|
|
|
|
72,
|
|
|
|
|
169,
|
|
|
|
|
70,
|
|
|
|
|
237,
|
|
|
|
|
1,
|
|
|
|
|
96,
|
|
|
|
|
35,
|
|
|
|
|
157,
|
|
|
|
|
25,
|
|
|
|
|
15,
|
|
|
|
|
83,
|
|
|
|
|
18,
|
|
|
|
|
52,
|
|
|
|
|
206,
|
|
|
|
|
202,
|
|
|
|
|
63,
|
|
|
|
|
48,
|
|
|
|
|
59,
|
|
|
|
|
173,
|
|
|
|
|
76,
|
|
|
|
|
78,
|
|
|
|
|
7,
|
|
|
|
|
254,
|
|
|
|
|
229,
|
|
|
|
|
28,
|
|
|
|
|
45,
|
|
|
|
|
194,
|
|
|
|
|
79,
|
|
|
|
|
6,
|
|
|
|
|
89,
|
|
|
|
|
58,
|
|
|
|
|
85
|
|
|
|
|
],
|
|
|
|
|
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
|
|
|
|
"pub_account_signing_key": [
|
|
|
|
|
136,
|
|
|
|
|
105,
|
|
|
|
|
9,
|
|
|
|
|
53,
|
|
|
|
|
180,
|
|
|
|
|
145,
|
|
|
|
|
64,
|
|
|
|
|
5,
|
|
|
|
|
235,
|
|
|
|
|
174,
|
|
|
|
|
62,
|
|
|
|
|
211,
|
|
|
|
|
206,
|
|
|
|
|
116,
|
|
|
|
|
185,
|
|
|
|
|
24,
|
|
|
|
|
214,
|
|
|
|
|
62,
|
|
|
|
|
244,
|
|
|
|
|
64,
|
|
|
|
|
224,
|
|
|
|
|
59,
|
|
|
|
|
120,
|
|
|
|
|
150,
|
|
|
|
|
30,
|
|
|
|
|
249,
|
|
|
|
|
160,
|
|
|
|
|
46,
|
|
|
|
|
189,
|
|
|
|
|
254,
|
|
|
|
|
47,
|
|
|
|
|
244
|
|
|
|
|
],
|
|
|
|
|
"top_secret_key_holder": {
|
|
|
|
|
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
|
|
|
|
},
|
|
|
|
|
"utxo_secret_key_holder": {
|
|
|
|
|
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
|
|
|
|
|
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
|
|
|
|
|
},
|
|
|
|
|
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
|
2025-07-17 08:09:27 +03:00
|
|
|
},
|
2025-07-25 10:00:27 +03:00
|
|
|
"utxos": {}
|
|
|
|
|
}"#).unwrap();
|
|
|
|
|
|
|
|
|
|
let initial_accounts = vec![initial_acc1, initial_acc2];
|
2025-07-17 08:09:27 +03:00
|
|
|
|
|
|
|
|
setup_sequencer_config_variable_initial_accounts(initial_accounts)
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:42:27 +01:00
|
|
|
fn create_dummy_transaction(
|
|
|
|
|
nullifier_created_hashes: Vec<[u8; 32]>,
|
|
|
|
|
utxo_commitments_spent_hashes: Vec<[u8; 32]>,
|
|
|
|
|
utxo_commitments_created_hashes: Vec<[u8; 32]>,
|
|
|
|
|
) -> Transaction {
|
2025-04-09 02:03:01 -04:00
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
|
2025-07-14 15:45:20 -03:00
|
|
|
let body = TransactionBody {
|
2025-01-27 13:42:27 +01:00
|
|
|
tx_kind: TxKind::Private,
|
|
|
|
|
execution_input: vec![],
|
|
|
|
|
execution_output: vec![],
|
|
|
|
|
utxo_commitments_spent_hashes,
|
|
|
|
|
utxo_commitments_created_hashes,
|
|
|
|
|
nullifier_created_hashes,
|
|
|
|
|
execution_proof_private: "dummy_proof".to_string(),
|
|
|
|
|
encoded_data: vec![],
|
|
|
|
|
ephemeral_pub_key: vec![10, 11, 12],
|
2025-04-09 01:29:35 -04:00
|
|
|
commitment: vec![],
|
|
|
|
|
tweak: Tweak::new(&mut rng),
|
|
|
|
|
secret_r: [0; 32],
|
2025-04-24 15:51:34 +03:00
|
|
|
sc_addr: "sc_addr".to_string(),
|
|
|
|
|
state_changes: (serde_json::Value::Null, 0),
|
2025-07-14 15:45:20 -03:00
|
|
|
};
|
2025-07-16 11:36:20 -03:00
|
|
|
Transaction::new(body, SignaturePrivateKey::random(&mut rng))
|
2025-01-27 13:42:27 +01:00
|
|
|
}
|
|
|
|
|
|
2025-06-18 13:56:09 +03:00
|
|
|
fn common_setup(sequencer: &mut SequencerCore) {
|
2025-07-23 15:53:00 +03:00
|
|
|
let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]);
|
2025-07-21 17:58:02 -03:00
|
|
|
let mempool_tx = MempoolTransaction {
|
2025-07-16 11:54:11 -03:00
|
|
|
auth_tx: tx.into_authenticated().unwrap(),
|
2025-07-14 15:45:20 -03:00
|
|
|
};
|
2025-07-21 17:58:02 -03:00
|
|
|
sequencer.mempool.push_item(mempool_tx);
|
2025-01-27 13:42:43 +01:00
|
|
|
|
2025-06-18 13:56:09 +03:00
|
|
|
sequencer
|
|
|
|
|
.produce_new_block_with_mempool_transactions()
|
|
|
|
|
.unwrap();
|
2025-01-27 13:42:43 +01:00
|
|
|
}
|
2025-01-27 13:42:11 +01:00
|
|
|
|
2025-01-27 13:43:17 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_start_from_config() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let sequencer = SequencerCore::start_from_config(config.clone());
|
|
|
|
|
|
|
|
|
|
assert_eq!(sequencer.chain_height, config.genesis_id);
|
|
|
|
|
assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10);
|
|
|
|
|
assert_eq!(sequencer.sequencer_config.port, 8080);
|
2025-07-14 10:43:35 +03:00
|
|
|
|
2025-07-25 10:00:27 +03:00
|
|
|
let acc1_addr = config.initial_accounts[0].address;
|
|
|
|
|
let acc2_addr = config.initial_accounts[1].address;
|
2025-07-14 10:43:35 +03:00
|
|
|
|
|
|
|
|
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
|
|
|
|
|
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
10,
|
2025-07-23 15:16:53 +03:00
|
|
|
sequencer.store.acc_store.get_account_balance(&acc1_addr)
|
2025-07-14 10:43:35 +03:00
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
100,
|
2025-07-23 15:16:53 +03:00
|
|
|
sequencer.store.acc_store.get_account_balance(&acc2_addr)
|
2025-07-14 10:43:35 +03:00
|
|
|
);
|
2025-01-27 13:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-14 13:17:46 +03:00
|
|
|
#[test]
|
2025-07-25 10:00:27 +03:00
|
|
|
fn test_start_different_intial_accounts_balances() {
|
|
|
|
|
let initial_acc1 = serde_json::from_str(r#"{
|
|
|
|
|
"address": [
|
|
|
|
|
244,
|
|
|
|
|
55,
|
|
|
|
|
238,
|
|
|
|
|
205,
|
|
|
|
|
74,
|
|
|
|
|
115,
|
|
|
|
|
179,
|
|
|
|
|
192,
|
|
|
|
|
65,
|
|
|
|
|
186,
|
|
|
|
|
166,
|
|
|
|
|
169,
|
|
|
|
|
221,
|
|
|
|
|
45,
|
|
|
|
|
6,
|
|
|
|
|
57,
|
|
|
|
|
200,
|
|
|
|
|
65,
|
|
|
|
|
195,
|
|
|
|
|
70,
|
|
|
|
|
118,
|
|
|
|
|
252,
|
|
|
|
|
206,
|
|
|
|
|
100,
|
|
|
|
|
215,
|
|
|
|
|
250,
|
|
|
|
|
72,
|
|
|
|
|
230,
|
|
|
|
|
19,
|
|
|
|
|
71,
|
|
|
|
|
217,
|
|
|
|
|
249
|
|
|
|
|
],
|
|
|
|
|
"balance": 1000,
|
|
|
|
|
"key_holder": {
|
|
|
|
|
"address": [
|
|
|
|
|
244,
|
|
|
|
|
55,
|
|
|
|
|
238,
|
|
|
|
|
205,
|
|
|
|
|
74,
|
|
|
|
|
115,
|
|
|
|
|
179,
|
|
|
|
|
192,
|
|
|
|
|
65,
|
|
|
|
|
186,
|
|
|
|
|
166,
|
|
|
|
|
169,
|
|
|
|
|
221,
|
|
|
|
|
45,
|
|
|
|
|
6,
|
|
|
|
|
57,
|
|
|
|
|
200,
|
|
|
|
|
65,
|
|
|
|
|
195,
|
|
|
|
|
70,
|
|
|
|
|
118,
|
|
|
|
|
252,
|
|
|
|
|
206,
|
|
|
|
|
100,
|
|
|
|
|
215,
|
|
|
|
|
250,
|
|
|
|
|
72,
|
|
|
|
|
230,
|
|
|
|
|
19,
|
|
|
|
|
71,
|
|
|
|
|
217,
|
|
|
|
|
249
|
|
|
|
|
],
|
|
|
|
|
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
|
|
|
|
"pub_account_signing_key": [
|
|
|
|
|
244,
|
|
|
|
|
88,
|
|
|
|
|
134,
|
|
|
|
|
61,
|
|
|
|
|
35,
|
|
|
|
|
209,
|
|
|
|
|
229,
|
|
|
|
|
101,
|
|
|
|
|
85,
|
|
|
|
|
35,
|
|
|
|
|
140,
|
|
|
|
|
140,
|
|
|
|
|
192,
|
|
|
|
|
226,
|
|
|
|
|
83,
|
|
|
|
|
83,
|
|
|
|
|
190,
|
|
|
|
|
189,
|
|
|
|
|
110,
|
|
|
|
|
8,
|
|
|
|
|
89,
|
|
|
|
|
127,
|
|
|
|
|
147,
|
|
|
|
|
142,
|
|
|
|
|
157,
|
|
|
|
|
204,
|
|
|
|
|
51,
|
|
|
|
|
109,
|
|
|
|
|
189,
|
|
|
|
|
92,
|
|
|
|
|
144,
|
|
|
|
|
68
|
|
|
|
|
],
|
|
|
|
|
"top_secret_key_holder": {
|
|
|
|
|
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
|
|
|
|
},
|
|
|
|
|
"utxo_secret_key_holder": {
|
|
|
|
|
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
|
|
|
|
|
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
|
|
|
|
|
},
|
|
|
|
|
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
|
2025-07-14 13:17:46 +03:00
|
|
|
},
|
2025-07-25 10:00:27 +03:00
|
|
|
"utxos": {}
|
|
|
|
|
}"#).unwrap();
|
|
|
|
|
|
|
|
|
|
let initial_acc2 = serde_json::from_str(r#"{
|
|
|
|
|
"address": [
|
|
|
|
|
72,
|
|
|
|
|
169,
|
|
|
|
|
70,
|
|
|
|
|
237,
|
|
|
|
|
1,
|
|
|
|
|
96,
|
|
|
|
|
35,
|
|
|
|
|
157,
|
|
|
|
|
25,
|
|
|
|
|
15,
|
|
|
|
|
83,
|
|
|
|
|
18,
|
|
|
|
|
52,
|
|
|
|
|
206,
|
|
|
|
|
202,
|
|
|
|
|
63,
|
|
|
|
|
48,
|
|
|
|
|
59,
|
|
|
|
|
173,
|
|
|
|
|
76,
|
|
|
|
|
78,
|
|
|
|
|
7,
|
|
|
|
|
254,
|
|
|
|
|
229,
|
|
|
|
|
28,
|
|
|
|
|
45,
|
|
|
|
|
194,
|
|
|
|
|
79,
|
|
|
|
|
6,
|
|
|
|
|
89,
|
|
|
|
|
58,
|
|
|
|
|
85
|
|
|
|
|
],
|
|
|
|
|
"balance": 1000,
|
|
|
|
|
"key_holder": {
|
|
|
|
|
"address": [
|
|
|
|
|
72,
|
|
|
|
|
169,
|
|
|
|
|
70,
|
|
|
|
|
237,
|
|
|
|
|
1,
|
|
|
|
|
96,
|
|
|
|
|
35,
|
|
|
|
|
157,
|
|
|
|
|
25,
|
|
|
|
|
15,
|
|
|
|
|
83,
|
|
|
|
|
18,
|
|
|
|
|
52,
|
|
|
|
|
206,
|
|
|
|
|
202,
|
|
|
|
|
63,
|
|
|
|
|
48,
|
|
|
|
|
59,
|
|
|
|
|
173,
|
|
|
|
|
76,
|
|
|
|
|
78,
|
|
|
|
|
7,
|
|
|
|
|
254,
|
|
|
|
|
229,
|
|
|
|
|
28,
|
|
|
|
|
45,
|
|
|
|
|
194,
|
|
|
|
|
79,
|
|
|
|
|
6,
|
|
|
|
|
89,
|
|
|
|
|
58,
|
|
|
|
|
85
|
|
|
|
|
],
|
|
|
|
|
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
|
|
|
|
"pub_account_signing_key": [
|
|
|
|
|
136,
|
|
|
|
|
105,
|
|
|
|
|
9,
|
|
|
|
|
53,
|
|
|
|
|
180,
|
|
|
|
|
145,
|
|
|
|
|
64,
|
|
|
|
|
5,
|
|
|
|
|
235,
|
|
|
|
|
174,
|
|
|
|
|
62,
|
|
|
|
|
211,
|
|
|
|
|
206,
|
|
|
|
|
116,
|
|
|
|
|
185,
|
|
|
|
|
24,
|
|
|
|
|
214,
|
|
|
|
|
62,
|
|
|
|
|
244,
|
|
|
|
|
64,
|
|
|
|
|
224,
|
|
|
|
|
59,
|
|
|
|
|
120,
|
|
|
|
|
150,
|
|
|
|
|
30,
|
|
|
|
|
249,
|
|
|
|
|
160,
|
|
|
|
|
46,
|
|
|
|
|
189,
|
|
|
|
|
254,
|
|
|
|
|
47,
|
|
|
|
|
244
|
|
|
|
|
],
|
|
|
|
|
"top_secret_key_holder": {
|
|
|
|
|
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
|
|
|
|
},
|
|
|
|
|
"utxo_secret_key_holder": {
|
|
|
|
|
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
|
|
|
|
|
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
|
|
|
|
|
},
|
|
|
|
|
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
|
2025-07-14 13:17:46 +03:00
|
|
|
},
|
2025-07-25 10:00:27 +03:00
|
|
|
"utxos": {}
|
|
|
|
|
}"#).unwrap();
|
|
|
|
|
|
|
|
|
|
let initial_accounts = vec![initial_acc1, initial_acc2];
|
2025-07-14 13:17:46 +03:00
|
|
|
|
2025-07-17 08:09:27 +03:00
|
|
|
let intial_accounts_len = initial_accounts.len();
|
|
|
|
|
|
2025-07-14 13:17:46 +03:00
|
|
|
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts);
|
|
|
|
|
let sequencer = SequencerCore::start_from_config(config.clone());
|
|
|
|
|
|
2025-07-25 10:00:27 +03:00
|
|
|
let acc1_addr = config.initial_accounts[0].address;
|
|
|
|
|
let acc2_addr = config.initial_accounts[1].address;
|
2025-07-14 13:17:46 +03:00
|
|
|
|
|
|
|
|
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
|
|
|
|
|
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
|
|
|
|
|
|
2025-07-17 08:09:27 +03:00
|
|
|
assert_eq!(sequencer.store.acc_store.len(), intial_accounts_len);
|
|
|
|
|
|
2025-07-14 13:17:46 +03:00
|
|
|
assert_eq!(
|
|
|
|
|
1000,
|
2025-07-23 15:16:53 +03:00
|
|
|
sequencer.store.acc_store.get_account_balance(&acc1_addr)
|
2025-07-14 13:17:46 +03:00
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
1000,
|
2025-07-23 15:16:53 +03:00
|
|
|
sequencer.store.acc_store.get_account_balance(&acc2_addr)
|
2025-07-14 13:17:46 +03:00
|
|
|
);
|
2025-01-27 13:43:17 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:43:45 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_get_tree_roots() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let roots = sequencer.get_tree_roots();
|
2025-05-23 09:10:34 +03:00
|
|
|
assert_eq!(roots.len(), 2); // Should return two roots
|
2025-01-27 13:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:44:07 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_transaction_pre_check_pass() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
2025-07-23 15:53:00 +03:00
|
|
|
let tx = create_dummy_transaction(vec![[91; 32]], vec![[71; 32]], vec![[81; 32]]);
|
2025-01-27 13:44:07 +01:00
|
|
|
let tx_roots = sequencer.get_tree_roots();
|
2025-07-14 15:45:20 -03:00
|
|
|
let result = sequencer.transaction_pre_check(tx, tx_roots);
|
2025-01-27 13:44:07 +01:00
|
|
|
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:44:30 +01:00
|
|
|
#[test]
|
2025-07-16 10:04:23 -03:00
|
|
|
fn test_push_tx_into_mempool_fails_mempool_full() {
|
2025-01-27 13:44:30 +01:00
|
|
|
let config = SequencerConfig {
|
|
|
|
|
max_num_tx_in_block: 1,
|
|
|
|
|
..setup_sequencer_config()
|
|
|
|
|
};
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
2025-07-23 15:53:00 +03:00
|
|
|
let tx = create_dummy_transaction(vec![[92; 32]], vec![[72; 32]], vec![[82; 32]]);
|
2025-01-27 13:44:30 +01:00
|
|
|
let tx_roots = sequencer.get_tree_roots();
|
|
|
|
|
|
|
|
|
|
// Fill the mempool
|
2025-07-14 15:45:20 -03:00
|
|
|
let dummy_tx = MempoolTransaction {
|
2025-07-16 11:54:11 -03:00
|
|
|
auth_tx: tx.clone().into_authenticated().unwrap(),
|
2025-07-14 15:45:20 -03:00
|
|
|
};
|
2025-01-27 13:44:30 +01:00
|
|
|
sequencer.mempool.push_item(dummy_tx);
|
|
|
|
|
|
2025-07-16 10:04:23 -03:00
|
|
|
let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots);
|
2025-01-27 13:44:30 +01:00
|
|
|
|
|
|
|
|
assert!(matches!(
|
|
|
|
|
result,
|
|
|
|
|
Err(TransactionMalformationErrorKind::MempoolFullForRound { .. })
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:44:45 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_push_tx_into_mempool_pre_check() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
2025-07-23 15:53:00 +03:00
|
|
|
let tx = create_dummy_transaction(vec![[93; 32]], vec![[73; 32]], vec![[83; 32]]);
|
2025-01-27 13:44:45 +01:00
|
|
|
let tx_roots = sequencer.get_tree_roots();
|
|
|
|
|
|
2025-07-14 15:45:20 -03:00
|
|
|
let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots);
|
2025-01-27 13:44:45 +01:00
|
|
|
assert!(result.is_ok());
|
|
|
|
|
assert_eq!(sequencer.mempool.len(), 1);
|
|
|
|
|
}
|
2025-01-27 13:43:17 +01:00
|
|
|
|
2025-01-27 13:45:01 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_produce_new_block_with_mempool_transactions() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
2025-07-28 15:21:35 -03:00
|
|
|
let genesis_height = sequencer.chain_height;
|
2025-01-27 13:45:01 +01:00
|
|
|
|
2025-07-23 15:53:00 +03:00
|
|
|
let tx = create_dummy_transaction(vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]);
|
2025-07-14 15:45:20 -03:00
|
|
|
let tx_mempool = MempoolTransaction {
|
2025-07-16 11:54:11 -03:00
|
|
|
auth_tx: tx.into_authenticated().unwrap(),
|
2025-07-14 15:45:20 -03:00
|
|
|
};
|
2025-01-27 13:45:01 +01:00
|
|
|
sequencer.mempool.push_item(tx_mempool);
|
|
|
|
|
|
|
|
|
|
let block_id = sequencer.produce_new_block_with_mempool_transactions();
|
|
|
|
|
assert!(block_id.is_ok());
|
2025-07-28 15:21:35 -03:00
|
|
|
assert_eq!(block_id.unwrap(), genesis_height + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_replay_transactions_are_rejected() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
let tx = create_dummy_transaction(vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]);
|
|
|
|
|
|
|
|
|
|
// The transaction should be included the first time
|
|
|
|
|
let tx_mempool_original = MempoolTransaction {
|
|
|
|
|
auth_tx: tx.clone().into_authenticated().unwrap(),
|
|
|
|
|
};
|
|
|
|
|
sequencer.mempool.push_item(tx_mempool_original);
|
|
|
|
|
let current_height = sequencer
|
|
|
|
|
.produce_new_block_with_mempool_transactions()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let block = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.block_store
|
|
|
|
|
.get_block_at_id(current_height)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(block.transactions, vec![tx.clone()]);
|
|
|
|
|
|
|
|
|
|
// Add same transaction should fail
|
|
|
|
|
let tx_mempool_replay = MempoolTransaction {
|
|
|
|
|
auth_tx: tx.into_authenticated().unwrap(),
|
|
|
|
|
};
|
|
|
|
|
sequencer.mempool.push_item(tx_mempool_replay);
|
|
|
|
|
let current_height = sequencer
|
|
|
|
|
.produce_new_block_with_mempool_transactions()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let block = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.block_store
|
|
|
|
|
.get_block_at_id(current_height)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert!(block.transactions.is_empty());
|
2025-01-27 13:45:01 +01:00
|
|
|
}
|
2025-01-27 13:51:27 +01:00
|
|
|
}
|