2024-11-28 22:05:14 +02:00
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
2025-07-29 15:22:28 -03:00
|
|
|
use accounts::account_core::address::{self, AccountAddress};
|
2024-11-25 07:26:16 +02:00
|
|
|
use anyhow::Result;
|
2025-04-16 16:17:53 +03:00
|
|
|
use common::{
|
2025-08-05 14:59:20 +03:00
|
|
|
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-09 16:03:30 +03:00
|
|
|
use sequencer_store::SequecerChainStore;
|
2025-04-16 16:17:53 +03:00
|
|
|
use serde::{Deserialize, Serialize};
|
2024-11-25 07:26:16 +02:00
|
|
|
|
|
|
|
|
pub mod config;
|
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-08-08 16:53:15 -03:00
|
|
|
pub mempool: MemPool<nssa::PublicTransaction>,
|
2024-11-25 07:26:16 +02:00
|
|
|
pub sequencer_config: SequencerConfig,
|
|
|
|
|
pub chain_height: u64,
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-29 14:20:03 +03:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2024-11-28 22:05:14 +02:00
|
|
|
pub enum TransactionMalformationErrorKind {
|
|
|
|
|
PublicTransactionChangedPrivateData { tx: TreeHashType },
|
|
|
|
|
PrivateTransactionChangedPublicData { tx: TreeHashType },
|
|
|
|
|
TxHashAlreadyPresentInTree { tx: TreeHashType },
|
|
|
|
|
NullifierAlreadyPresentInTree { tx: TreeHashType },
|
|
|
|
|
UTXOCommitmentAlreadyPresentInTree { tx: TreeHashType },
|
2025-08-07 15:19:06 -03:00
|
|
|
MempoolFullForRound,
|
2025-01-24 09:10:42 +02:00
|
|
|
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 },
|
2025-07-28 16:09:03 -03:00
|
|
|
NonceMismatch { tx: TreeHashType },
|
2025-07-22 15:22:20 +03:00
|
|
|
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-08-08 16:53:15 -03:00
|
|
|
mempool: MemPool::default(),
|
2024-11-25 07:26:16 +02:00
|
|
|
chain_height: config.genesis_id,
|
|
|
|
|
sequencer_config: config,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 12:26:19 +02:00
|
|
|
pub fn transaction_pre_check(
|
2024-11-28 22:05:14 +02:00
|
|
|
&mut self,
|
2025-08-07 15:19:06 -03:00
|
|
|
tx: nssa::PublicTransaction,
|
|
|
|
|
// tx_roots: [[u8; 32]; 2],
|
|
|
|
|
) -> Result<nssa::PublicTransaction, TransactionMalformationErrorKind> {
|
|
|
|
|
// TODO: Stateless checks here
|
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-08-07 15:19:06 -03:00
|
|
|
transaction: nssa::PublicTransaction,
|
|
|
|
|
// _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 {
|
2025-08-07 15:19:06 -03:00
|
|
|
return Err(TransactionMalformationErrorKind::MempoolFullForRound);
|
2025-07-16 08:43:05 -03:00
|
|
|
}
|
2025-01-22 12:26:19 +02:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
let authenticated_tx = self.transaction_pre_check(transaction)?;
|
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-08-08 16:53:15 -03:00
|
|
|
tx: nssa::PublicTransaction,
|
2025-08-07 15:19:06 -03:00
|
|
|
) -> Result<nssa::PublicTransaction, ()> {
|
|
|
|
|
self.store.state.transition_from_public_transaction(&tx)?;
|
2024-11-28 22:05:14 +02:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
// self.store.pub_tx_store.add_tx(mempool_tx.auth_tx);
|
2024-11-28 22:05:14 +02:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
Ok(tx)
|
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-07-29 12:50:30 -03:00
|
|
|
let valid_transactions = transactions
|
|
|
|
|
.into_iter()
|
2025-08-08 16:53:15 -03:00
|
|
|
.filter_map(|tx| self.execute_check_transaction_on_state(tx).ok())
|
2025-07-29 12:50:30 -03:00
|
|
|
.collect();
|
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-29 12:50:30 -03:00
|
|
|
transactions: valid_transactions,
|
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
|
|
|
};
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let block = hashable_data.into();
|
2024-11-25 07:26:16 +02:00
|
|
|
|
|
|
|
|
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 {
|
2025-07-29 14:20:03 +03:00
|
|
|
use crate::config::AccountInitialData;
|
|
|
|
|
|
2025-01-27 13:42:11 +01:00
|
|
|
use super::*;
|
2025-08-07 15:19:06 -03:00
|
|
|
use nssa::Program;
|
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-29 14:20:03 +03:00
|
|
|
initial_accounts: Vec<AccountInitialData>,
|
2025-07-14 13:17:46 +03:00
|
|
|
) -> SequencerConfig {
|
2025-07-29 15:29:00 -03:00
|
|
|
let tempdir = tempfile::tempdir().unwrap();
|
|
|
|
|
let home = tempdir.path().to_path_buf();
|
2025-01-27 13:42:11 +01:00
|
|
|
|
|
|
|
|
SequencerConfig {
|
2025-07-29 15:29:00 -03:00
|
|
|
home,
|
2025-01-27 13:42:11 +01:00
|
|
|
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-29 14:20:03 +03:00
|
|
|
let acc1_addr = vec![
|
2025-08-07 15:19:06 -03:00
|
|
|
// 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
|
|
|
|
|
// 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215,
|
|
|
|
|
1; 32
|
2025-07-29 14:20:03 +03:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let acc2_addr = vec![
|
2025-08-07 15:19:06 -03:00
|
|
|
// 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
|
|
|
|
|
// 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100,
|
|
|
|
|
2; 32
|
2025-07-29 14:20:03 +03:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let initial_acc1 = AccountInitialData {
|
|
|
|
|
addr: hex::encode(acc1_addr),
|
|
|
|
|
balance: 10000,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let initial_acc2 = AccountInitialData {
|
|
|
|
|
addr: hex::encode(acc2_addr),
|
|
|
|
|
balance: 20000,
|
|
|
|
|
};
|
2025-07-25 10:00:27 +03:00
|
|
|
|
|
|
|
|
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-08-09 06:36:13 -03:00
|
|
|
// fn create_dummy_transaction() -> nssa::PublicTransaction {
|
|
|
|
|
// let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
|
|
|
|
|
// let addresses = vec![];
|
|
|
|
|
// let nonces = vec![];
|
|
|
|
|
// let instruction_data = 0;
|
|
|
|
|
// let message =
|
|
|
|
|
// nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
|
|
|
|
|
// let private_key = nssa::PrivateKey::new(1);
|
|
|
|
|
// let witness_set =
|
|
|
|
|
// nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
|
|
|
|
|
// nssa::PublicTransaction::new(message, witness_set)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// fn create_dummy_transaction_native_token_transfer(
|
|
|
|
|
// from: [u8; 32],
|
|
|
|
|
// nonce: u128,
|
|
|
|
|
// to: [u8; 32],
|
|
|
|
|
// balance_to_move: u128,
|
|
|
|
|
// signing_key: nssa::PrivateKey,
|
|
|
|
|
// ) -> nssa::PublicTransaction {
|
|
|
|
|
// let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
|
|
|
|
|
// let nonces = vec![nonce];
|
|
|
|
|
// let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
|
|
|
|
|
// let message =
|
|
|
|
|
// nssa::public_transaction::Message::new(program_id, addresses, nonces, balance_to_move);
|
|
|
|
|
// let witness_set =
|
|
|
|
|
// nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
|
|
|
|
|
// nssa::PublicTransaction::new(message, witness_set)
|
|
|
|
|
// }
|
2025-07-29 14:20:03 +03:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
fn create_signing_key_for_account1() -> nssa::PrivateKey {
|
|
|
|
|
// let pub_sign_key_acc1 = [
|
|
|
|
|
// 133, 143, 177, 187, 252, 66, 237, 236, 234, 252, 244, 138, 5, 151, 3, 99, 217, 231,
|
|
|
|
|
// 112, 217, 77, 211, 58, 218, 176, 68, 99, 53, 152, 228, 198, 190,
|
|
|
|
|
// ];
|
|
|
|
|
//
|
|
|
|
|
// let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1);
|
|
|
|
|
// SigningKey::from_bytes(field_bytes).unwrap()
|
|
|
|
|
nssa::PrivateKey::new(1)
|
2025-07-29 14:20:03 +03:00
|
|
|
}
|
|
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
fn create_signing_key_for_account2() -> nssa::PrivateKey {
|
|
|
|
|
// let pub_sign_key_acc2 = [
|
|
|
|
|
// 54, 90, 62, 225, 71, 225, 228, 148, 143, 53, 210, 23, 137, 158, 171, 156, 48, 7, 139,
|
|
|
|
|
// 52, 117, 242, 214, 7, 99, 29, 122, 184, 59, 116, 144, 107,
|
|
|
|
|
// ];
|
|
|
|
|
//
|
|
|
|
|
// let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2);
|
|
|
|
|
// SigningKey::from_bytes(field_bytes).unwrap()
|
|
|
|
|
nssa::PrivateKey::new(2)
|
2025-07-29 14:20:03 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-18 13:56:09 +03:00
|
|
|
fn common_setup(sequencer: &mut SequencerCore) {
|
2025-08-09 06:36:13 -03:00
|
|
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(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-29 14:20:03 +03:00
|
|
|
let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
2025-07-14 10:43:35 +03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
let balance_acc_1 = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc1_addr))
|
|
|
|
|
.balance;
|
|
|
|
|
let balance_acc_2 = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc2_addr))
|
|
|
|
|
.balance;
|
2025-07-14 10:43:35 +03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
assert_eq!(10000, balance_acc_1);
|
|
|
|
|
assert_eq!(20000, balance_acc_2);
|
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() {
|
2025-07-29 14:20:03 +03:00
|
|
|
let acc1_addr = vec![
|
|
|
|
|
13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
|
|
|
|
|
68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 42, 42, 42,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let acc2_addr = vec![
|
|
|
|
|
151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
|
|
|
|
|
135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 42, 42, 42,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let initial_acc1 = AccountInitialData {
|
|
|
|
|
addr: hex::encode(acc1_addr),
|
|
|
|
|
balance: 10000,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let initial_acc2 = AccountInitialData {
|
|
|
|
|
addr: hex::encode(acc2_addr),
|
|
|
|
|
balance: 20000,
|
|
|
|
|
};
|
2025-07-25 10:00:27 +03:00
|
|
|
|
|
|
|
|
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-29 14:20:03 +03:00
|
|
|
let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
2025-07-14 13:17:46 +03:00
|
|
|
|
|
|
|
|
assert_eq!(
|
2025-07-29 14:20:03 +03:00
|
|
|
10000,
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc1_addr))
|
|
|
|
|
.balance
|
2025-07-14 13:17:46 +03:00
|
|
|
);
|
|
|
|
|
assert_eq!(
|
2025-07-29 14:20:03 +03:00
|
|
|
20000,
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc2_addr))
|
|
|
|
|
.balance
|
2025-07-14 13:17:46 +03:00
|
|
|
);
|
2025-01-27 13:43:17 +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-08-09 06:36:13 -03:00
|
|
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
2025-08-07 15:19:06 -03:00
|
|
|
// let tx_roots = sequencer.get_tree_roots();
|
|
|
|
|
let result = sequencer.transaction_pre_check(tx);
|
2025-01-27 13:44:07 +01:00
|
|
|
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-29 14:20:03 +03:00
|
|
|
#[test]
|
|
|
|
|
fn test_transaction_pre_check_native_transfer_valid() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key1 = create_signing_key_for_account1();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 10, sign_key1,
|
|
|
|
|
);
|
2025-08-07 15:19:06 -03:00
|
|
|
let result = sequencer.transaction_pre_check(tx);
|
2025-07-29 14:20:03 +03:00
|
|
|
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_transaction_pre_check_native_transfer_other_signature() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key2 = create_signing_key_for_account2();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 10, sign_key2,
|
|
|
|
|
);
|
2025-08-07 15:19:06 -03:00
|
|
|
// let tx_roots = sequencer.get_tree_roots();
|
|
|
|
|
let tx = sequencer.transaction_pre_check(tx).unwrap();
|
2025-07-29 14:20:03 +03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
let result = sequencer.execute_check_transaction_on_state(tx);
|
2025-08-07 15:19:06 -03:00
|
|
|
|
|
|
|
|
assert_eq!(result.err().unwrap(), ());
|
2025-07-29 14:20:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_transaction_pre_check_native_transfer_sent_too_much() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key1 = create_signing_key_for_account1();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 10000000, sign_key1,
|
|
|
|
|
);
|
2025-08-07 15:19:06 -03:00
|
|
|
// let tx_roots = sequencer.get_tree_roots();
|
|
|
|
|
let result = sequencer.transaction_pre_check(tx);
|
2025-07-29 14:20:03 +03:00
|
|
|
|
2025-07-29 15:04:38 +03:00
|
|
|
//Passed pre-check
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
let result = sequencer.execute_check_transaction_on_state(result.unwrap());
|
2025-07-29 14:20:03 +03:00
|
|
|
let is_failed_at_balance_mismatch = matches!(
|
|
|
|
|
result.err().unwrap(),
|
2025-08-07 15:19:06 -03:00
|
|
|
// TransactionMalformationErrorKind::BalanceMismatch { tx: _ }
|
|
|
|
|
()
|
2025-07-29 14:20:03 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert!(is_failed_at_balance_mismatch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_transaction_execute_native_transfer() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key1 = create_signing_key_for_account1();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 100, sign_key1,
|
|
|
|
|
);
|
2025-07-29 14:20:03 +03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.execute_check_transaction_on_state(tx).unwrap();
|
2025-07-29 14:20:03 +03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
let bal_from = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc1))
|
|
|
|
|
.balance;
|
|
|
|
|
let bal_to = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.state
|
|
|
|
|
.get_account_by_address(&nssa::Address::new(acc2))
|
|
|
|
|
.balance;
|
2025-07-29 14:20:03 +03:00
|
|
|
|
|
|
|
|
assert_eq!(bal_from, 9900);
|
|
|
|
|
assert_eq!(bal_to, 20100);
|
|
|
|
|
}
|
|
|
|
|
|
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-08-09 06:36:13 -03:00
|
|
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
2025-08-07 15:19:06 -03:00
|
|
|
// let tx_roots = sequencer.get_tree_roots();
|
2025-01-27 13:44:30 +01:00
|
|
|
|
|
|
|
|
// Fill the mempool
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(tx.clone());
|
2025-01-27 13:44:30 +01:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
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-08-09 06:36:13 -03:00
|
|
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
2025-01-27 13:44:45 +01:00
|
|
|
|
2025-08-07 15:19:06 -03:00
|
|
|
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
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-08-09 06:36:13 -03:00
|
|
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(tx);
|
2025-01-27 13:45:01 +01:00
|
|
|
|
|
|
|
|
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]
|
2025-07-29 15:41:57 -03:00
|
|
|
fn test_replay_transactions_are_rejected_in_the_same_block() {
|
|
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
|
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key1 = create_signing_key_for_account1();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 100, sign_key1,
|
|
|
|
|
);
|
2025-07-29 15:41:57 -03:00
|
|
|
|
2025-08-08 16:53:15 -03:00
|
|
|
let tx_original = tx.clone();
|
|
|
|
|
let tx_replay = tx.clone();
|
2025-07-29 15:41:57 -03:00
|
|
|
// Pushing two copies of the same tx to the mempool
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(tx_original);
|
|
|
|
|
sequencer.mempool.push_item(tx_replay);
|
2025-07-29 15:41:57 -03:00
|
|
|
|
|
|
|
|
// Create block
|
|
|
|
|
let current_height = sequencer
|
|
|
|
|
.produce_new_block_with_mempool_transactions()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let block = sequencer
|
|
|
|
|
.store
|
|
|
|
|
.block_store
|
|
|
|
|
.get_block_at_id(current_height)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Only one should be included in the block
|
|
|
|
|
assert_eq!(block.transactions, vec![tx.clone()]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_replay_transactions_are_rejected_in_different_blocks() {
|
2025-07-28 15:21:35 -03:00
|
|
|
let config = setup_sequencer_config();
|
|
|
|
|
let mut sequencer = SequencerCore::start_from_config(config);
|
|
|
|
|
|
2025-07-29 12:50:30 -03:00
|
|
|
common_setup(&mut sequencer);
|
|
|
|
|
|
|
|
|
|
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let sign_key1 = create_signing_key_for_account1();
|
|
|
|
|
|
2025-08-05 14:59:20 +03:00
|
|
|
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
|
|
|
|
acc1, 0, acc2, 100, sign_key1,
|
|
|
|
|
);
|
2025-07-28 15:21:35 -03:00
|
|
|
|
|
|
|
|
// The transaction should be included the first time
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(tx.clone());
|
2025-07-28 15:21:35 -03:00
|
|
|
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
|
2025-08-08 16:53:15 -03:00
|
|
|
sequencer.mempool.push_item(tx);
|
2025-07-28 15:21:35 -03:00
|
|
|
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
|
|
|
}
|