diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 11260b46..5ca34347 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/associated_token_account.bin b/artifacts/program_methods/associated_token_account.bin new file mode 100644 index 00000000..7b2c40d2 Binary files /dev/null and b/artifacts/program_methods/associated_token_account.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index 6ad55423..e2a9955c 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/clock.bin b/artifacts/program_methods/clock.bin index c3f8af15..d8e971b4 100644 Binary files a/artifacts/program_methods/clock.bin and b/artifacts/program_methods/clock.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index f3e126a4..fa67cec8 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index 153d64fa..ef8be707 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index 2f2cc820..20eb8196 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index bc4583b6..1285fb9b 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index a00f2991..f30c6003 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index 6402d170..7f4b684f 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 3f44174a..3d95f69b 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index 20fcad17..aec2828b 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 2099a180..428f0417 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index 30fb2670..d47081d0 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index 1cf2536e..1a07bf37 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index 908082e6..ba90b184 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index 439ab0fa..f828fab7 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index e666047e..7054ef8f 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index d82d7cb2..f19443de 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index b97a64f7..c4acea82 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index 760a6a17..7044c309 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index 1603437b..c047253c 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/artifacts/test_program_methods/validity_window.bin b/artifacts/test_program_methods/validity_window.bin new file mode 100644 index 00000000..6ce96300 Binary files /dev/null and b/artifacts/test_program_methods/validity_window.bin differ diff --git a/artifacts/test_program_methods/validity_window_chain_caller.bin b/artifacts/test_program_methods/validity_window_chain_caller.bin new file mode 100644 index 00000000..e4e760ba Binary files /dev/null and b/artifacts/test_program_methods/validity_window_chain_caller.bin differ diff --git a/common/src/block.rs b/common/src/block.rs index 11446314..52a62841 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -8,7 +8,7 @@ use crate::{HashType, transaction::NSSATransaction}; pub type MantleMsgId = [u8; 32]; pub type BlockHash = HashType; pub type BlockId = u64; -pub type TimeStamp = u64; +pub use nssa_core::Timestamp; #[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockMeta { @@ -36,7 +36,7 @@ pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: BlockHash, pub hash: BlockHash, - pub timestamp: TimeStamp, + pub timestamp: Timestamp, pub signature: nssa::Signature, } @@ -76,7 +76,7 @@ impl<'de> Deserialize<'de> for Block { pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, - pub timestamp: TimeStamp, + pub timestamp: Timestamp, pub transactions: Vec, } diff --git a/common/src/transaction.rs b/common/src/transaction.rs index b61d317f..ec25a5ad 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -43,15 +43,15 @@ impl NSSATransaction { } } - /// Returns the canonical Block Context Program invocation transaction. - /// Every valid block must end with exactly one occurrence of this transaction. + /// Returns the canonical Block Context Program invocation transaction for the given block + /// timestamp. Every valid block must end with exactly one occurrence of this transaction. #[must_use] - pub fn clock_invocation() -> Self { + pub fn clock_invocation(timestamp: nssa_core::Timestamp) -> Self { let message = nssa::public_transaction::Message::try_new( nssa::program::Program::clock().id(), vec![nssa::CLOCK_PROGRAM_ACCOUNT_ID], vec![], - (), + timestamp, ) .expect("Clock invocation message should always be constructable"); Self::Public(nssa::PublicTransaction::new( diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index 16591a0e..75eace8b 100644 --- a/indexer/core/src/block_store.rs +++ b/indexer/core/src/block_store.rs @@ -119,7 +119,7 @@ impl IndexerStore { pub async fn put_block(&self, mut block: Block, l1_header: HeaderId) -> Result<()> { { - let canonical_clock_tx = NSSATransaction::clock_invocation(); + let expected_clock_tx = NSSATransaction::clock_invocation(block.header.timestamp); // Validate block structure: the last transaction must be the sole clock invocation. let last_tx = block @@ -128,7 +128,7 @@ impl IndexerStore { .last() .ok_or_else(|| anyhow::anyhow!("Block must contain at least one transaction"))?; anyhow::ensure!( - last_tx == &canonical_clock_tx, + last_tx == &expected_clock_tx, "Last transaction in block must be the canonical clock invocation" ); @@ -136,7 +136,7 @@ impl IndexerStore { .body .transactions .iter() - .filter(|tx| *tx == &canonical_clock_tx) + .filter(|tx| *tx == &expected_clock_tx) .count(); anyhow::ensure!( clock_count == 1, @@ -196,7 +196,7 @@ mod tests { let storage = IndexerStore::open_db_with_genesis( home.as_ref(), &genesis_block(), - &nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[]), + &nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[], 0), ) .unwrap(); @@ -214,7 +214,7 @@ mod tests { let storage = IndexerStore::open_db_with_genesis( home.as_ref(), &genesis_block(), - &nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[]), + &nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[], 0), ) .unwrap(); @@ -232,10 +232,12 @@ mod tests { 10, &sign_key, ); - let clock_tx = NSSATransaction::clock_invocation(); + let block_id = u64::try_from(i).unwrap(); + let block_timestamp = block_id.saturating_mul(100); + let clock_tx = NSSATransaction::clock_invocation(block_timestamp); let next_block = common::test_utils::produce_dummy_block( - u64::try_from(i).unwrap(), + block_id, Some(prev_hash), vec![tx, clock_tx], ); diff --git a/indexer/core/src/lib.rs b/indexer/core/src/lib.rs index 16cd7ac9..882affcc 100644 --- a/indexer/core/src/lib.rs +++ b/indexer/core/src/lib.rs @@ -80,7 +80,11 @@ impl IndexerCore { .map(|acc_data| (acc_data.account_id, acc_data.balance)) .collect(); - let mut state = nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments); + let mut state = nssa::V03State::new_with_genesis_accounts( + &init_accs, + &initial_commitments, + genesis_block.header.timestamp, + ); // ToDo: Remove after testnet state.add_pinata_program(PINATA_BASE58.parse().unwrap()); diff --git a/indexer/service/protocol/src/lib.rs b/indexer/service/protocol/src/lib.rs index d61f62a6..f2dd7a94 100644 --- a/indexer/service/protocol/src/lib.rs +++ b/indexer/service/protocol/src/lib.rs @@ -138,7 +138,7 @@ pub struct Account { } pub type BlockId = u64; -pub type TimeStamp = u64; +pub type Timestamp = u64; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub struct Block { @@ -153,7 +153,7 @@ pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: HashType, pub hash: HashType, - pub timestamp: TimeStamp, + pub timestamp: Timestamp, pub signature: Signature, } diff --git a/nssa/core/src/lib.rs b/nssa/core/src/lib.rs index 8014c7ca..2e11d556 100644 --- a/nssa/core/src/lib.rs +++ b/nssa/core/src/lib.rs @@ -3,6 +3,8 @@ reason = "We prefer to group methods by functionality rather than by type for encoding" )] +pub type Timestamp = u64; + pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput}; pub use commitment::{ Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 8151f8cf..001addb7 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -264,7 +264,7 @@ pub mod tests { fn state_for_tests() -> V03State { let (_, _, addr1, addr2) = keys_for_tests(); let initial_data = [(addr1, 10000), (addr2, 20000)]; - V03State::new_with_genesis_accounts(&initial_data, &[]) + V03State::new_with_genesis_accounts(&initial_data, &[], 0) } fn transaction_for_tests() -> PublicTransaction { diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 3c70d1ad..40752e6f 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -121,6 +121,7 @@ impl V03State { pub fn new_with_genesis_accounts( initial_data: &[(AccountId, u128)], initial_commitments: &[nssa_core::Commitment], + genesis_timestamp: nssa_core::Timestamp, ) -> Self { let authenticated_transfer_program = Program::authenticated_transfer_program(); let public_state = initial_data @@ -146,25 +147,30 @@ impl V03State { programs: HashMap::new(), }; + this.insert_program(Program::clock()); + this.insert_clock_accounts(genesis_timestamp); + this.insert_program(Program::authenticated_transfer_program()); this.insert_program(Program::token()); this.insert_program(Program::amm()); - this.insert_program(Program::clock()); - this.public_state.insert( + this + } + + fn insert_clock_accounts(&mut self, genesis_timestamp: nssa_core::Timestamp) { + let mut data = [0u8; 16]; + data[8..].copy_from_slice(&genesis_timestamp.to_le_bytes()); + self.public_state.insert( CLOCK_PROGRAM_ACCOUNT_ID, Account { program_owner: Program::clock().id(), - data: 0_u64 - .to_le_bytes() + data: data .to_vec() .try_into() - .expect("u64 bytes should fit within accounts data"), + .expect("16 bytes should fit within accounts data"), ..Account::default() }, ); - - this } pub(crate) fn insert_program(&mut self, program: Program) { @@ -371,7 +377,7 @@ pub mod tests { program::Program, public_transaction, signature::PrivateKey, - state::MAX_NUMBER_CHAINED_CALLS, + state::{CLOCK_PROGRAM_ACCOUNT_ID, MAX_NUMBER_CHAINED_CALLS}, }; impl V03State { @@ -490,6 +496,7 @@ pub mod tests { let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); let initial_data = [(addr1, 100_u128), (addr2, 151_u128)]; let authenticated_transfers_program = Program::authenticated_transfer_program(); + let clock_program = Program::clock(); let expected_public_state = { let mut this = HashMap::new(); this.insert( @@ -508,6 +515,17 @@ pub mod tests { ..Account::default() }, ); + this.insert( + CLOCK_PROGRAM_ACCOUNT_ID, + Account { + program_owner: clock_program.id(), + data: [0u8; 16] + .to_vec() + .try_into() + .unwrap(), + ..Account::default() + }, + ); this }; let expected_builtin_programs = { @@ -516,12 +534,13 @@ pub mod tests { authenticated_transfers_program.id(), authenticated_transfers_program, ); + this.insert(clock_program.id(), clock_program); this.insert(Program::token().id(), Program::token()); this.insert(Program::amm().id(), Program::amm()); this }; - let state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); assert_eq!(state.public_state, expected_public_state); assert_eq!(state.programs, expected_builtin_programs); @@ -529,7 +548,7 @@ pub mod tests { #[test] fn insert_program() { - let mut state = V03State::new_with_genesis_accounts(&[], &[]); + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0); let program_to_insert = Program::simple_balance_transfer(); let program_id = program_to_insert.id(); assert!(!state.programs.contains_key(&program_id)); @@ -544,7 +563,7 @@ pub mod tests { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); let initial_data = [(account_id, 100_u128)]; - let state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); let expected_account = &state.public_state[&account_id]; let account = state.get_account_by_id(account_id); @@ -555,7 +574,7 @@ pub mod tests { #[test] fn get_account_by_account_id_default_account() { let addr2 = AccountId::new([0; 32]); - let state = V03State::new_with_genesis_accounts(&[], &[]); + let state = V03State::new_with_genesis_accounts(&[], &[], 0); let expected_account = Account::default(); let account = state.get_account_by_id(addr2); @@ -565,7 +584,7 @@ pub mod tests { #[test] fn builtin_programs_getter() { - let state = V03State::new_with_genesis_accounts(&[], &[]); + let state = V03State::new_with_genesis_accounts(&[], &[], 0); let builtin_programs = state.programs(); @@ -577,7 +596,7 @@ pub mod tests { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); let initial_data = [(account_id, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); let from = account_id; let to = AccountId::new([2; 32]); assert_eq!(state.get_account_by_id(to), Account::default()); @@ -597,7 +616,7 @@ pub mod tests { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); let initial_data = [(account_id, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); let from = account_id; let from_key = key; let to = AccountId::new([2; 32]); @@ -621,7 +640,7 @@ pub mod tests { let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); let initial_data = [(account_id1, 100), (account_id2, 200)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); let from = account_id2; let from_key = key2; let to = account_id1; @@ -644,7 +663,7 @@ pub mod tests { let key2 = PrivateKey::try_new([2; 32]).unwrap(); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); let initial_data = [(account_id1, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); let account_id3 = AccountId::new([3; 32]); let balance_to_move = 5; @@ -666,7 +685,7 @@ pub mod tests { fn program_should_fail_if_modifies_nonces() { let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_ids = vec![AccountId::new([1; 32])]; let program_id = Program::nonce_changer_program().id(); let message = @@ -683,7 +702,7 @@ pub mod tests { fn program_should_fail_if_output_accounts_exceed_inputs() { let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_ids = vec![AccountId::new([1; 32])]; let program_id = Program::extra_output_program().id(); let message = @@ -700,7 +719,7 @@ pub mod tests { fn program_should_fail_with_missing_output_accounts() { let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_ids = vec![AccountId::new([1; 32]), AccountId::new([2; 32])]; let program_id = Program::missing_output_program().id(); let message = @@ -717,7 +736,7 @@ pub mod tests { fn program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() { let initial_data = [(AccountId::new([1; 32]), 0)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_id = AccountId::new([1; 32]); let account = state.get_account_by_id(account_id); // Assert the target account only differs from the default account in the program owner @@ -740,7 +759,7 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_balance() { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]) + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([255; 32]); @@ -764,7 +783,7 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]) + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([254; 32]); @@ -788,7 +807,7 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_data() { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]) + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([253; 32]); @@ -813,7 +832,7 @@ pub mod tests { fn program_should_fail_if_transfers_balance_from_non_owned_account() { let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let sender_account_id = AccountId::new([1; 32]); let receiver_account_id = AccountId::new([2; 32]); let balance_to_move: u128 = 1; @@ -840,7 +859,7 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_data_of_non_owned_account() { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]) + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([255; 32]); @@ -866,7 +885,7 @@ pub mod tests { fn program_should_fail_if_does_not_preserve_total_balance_by_minting() { let initial_data = []; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_id = AccountId::new([1; 32]); let program_id = Program::minter().id(); @@ -883,7 +902,7 @@ pub mod tests { #[test] fn program_should_fail_if_does_not_preserve_total_balance_by_burning() { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]) + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0) .with_test_programs() .with_account_owned_by_burner_program(); let program_id = Program::burner().id(); @@ -1075,7 +1094,7 @@ pub mod tests { let recipient_keys = test_private_account_keys_1(); let mut state = - V03State::new_with_genesis_accounts(&[(sender_keys.account_id(), 200)], &[]); + V03State::new_with_genesis_accounts(&[(sender_keys.account_id(), 200)], &[], 0); let balance_to_move = 37; @@ -1123,7 +1142,7 @@ pub mod tests { }; let recipient_keys = test_private_account_keys_2(); - let mut state = V03State::new_with_genesis_accounts(&[], &[]) + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0) .with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; @@ -1193,6 +1212,7 @@ pub mod tests { let mut state = V03State::new_with_genesis_accounts( &[(recipient_keys.account_id(), recipient_initial_balance)], &[], + 0, ) .with_private_account(&sender_keys, &sender_private_account); @@ -2144,7 +2164,7 @@ pub mod tests { }; let recipient_keys = test_private_account_keys_2(); - let mut state = V03State::new_with_genesis_accounts(&[], &[]) + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0) .with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; @@ -2229,7 +2249,7 @@ pub mod tests { let initial_balance = 100; let initial_data = [(account_id, initial_balance)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let from = account_id; let from_key = key; let to = AccountId::new([2; 32]); @@ -2270,7 +2290,7 @@ pub mod tests { let initial_balance = 1000; let initial_data = [(from, initial_balance), (to, 0)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let from_key = key; let amount: u128 = 37; let instruction: (u128, ProgramId, u32, Option) = ( @@ -2315,7 +2335,7 @@ pub mod tests { let initial_balance = 100; let initial_data = [(from, initial_balance), (to, 0)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let from_key = key; let amount: u128 = 0; let instruction: (u128, ProgramId, u32, Option) = ( @@ -2353,7 +2373,7 @@ pub mod tests { let initial_balance = 1000; let initial_data = [(from, initial_balance), (to, 0)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let amount: u128 = 58; let instruction: (u128, ProgramId, u32, Option) = ( amount, @@ -2399,7 +2419,7 @@ pub mod tests { let initial_balance = 100; let initial_data = [(account_id, initial_balance)]; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let from = account_id; let from_key = key; let to = AccountId::new([2; 32]); @@ -2474,6 +2494,7 @@ pub mod tests { let mut state = V03State::new_with_genesis_accounts( &[], &[from_commitment.clone(), to_commitment.clone()], + 0, ) .with_test_programs(); let amount: u128 = 37; @@ -2580,7 +2601,7 @@ pub mod tests { ..Account::default() }; - let mut state = V03State::new_with_genesis_accounts(&[], &[]); + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0); state.add_pinata_token_program(pinata_definition_id); // Execution of the token program to create new token for the pinata token @@ -2641,7 +2662,7 @@ pub mod tests { #[test] fn claiming_mechanism_cannot_claim_initialied_accounts() { let claimer = Program::claimer(); - let mut state = V03State::new_with_genesis_accounts(&[], &[]).with_test_programs(); + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0).with_test_programs(); let account_id = AccountId::new([2; 32]); // Insert an account with non-default program owner @@ -2682,6 +2703,7 @@ pub mod tests { (recipient_id, recipient_init_balance), ], &[], + 0, ); state.insert_program(Program::modified_transfer_program()); @@ -2731,7 +2753,7 @@ pub mod tests { #[test] fn private_authorized_uninitialized_account() { - let mut state = V03State::new_with_genesis_accounts(&[], &[]); + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0); // Set up keys for the authorized private account let private_keys = test_private_account_keys_1(); @@ -2783,7 +2805,7 @@ pub mod tests { #[test] fn private_account_claimed_then_used_without_init_flag_should_fail() { - let mut state = V03State::new_with_genesis_accounts(&[], &[]).with_test_programs(); + let mut state = V03State::new_with_genesis_accounts(&[], &[], 0).with_test_programs(); // Set up keys for the private account let private_keys = test_private_account_keys_1(); @@ -2864,7 +2886,7 @@ pub mod tests { fn public_changer_claimer_no_data_change_no_claim_succeeds() { let initial_data = []; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_id = AccountId::new([1; 32]); let program_id = Program::changer_claimer().id(); // Don't change data (None) and don't claim (false) @@ -2888,7 +2910,7 @@ pub mod tests { fn public_changer_claimer_data_change_no_claim_fails() { let initial_data = []; let mut state = - V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let account_id = AccountId::new([1; 32]); let program_id = Program::changer_claimer().id(); // Change data but don't claim (false) - should fail @@ -2985,6 +3007,7 @@ pub mod tests { let state = V03State::new_with_genesis_accounts( &[(sender_account.account_id, sender_account.account.balance)], std::slice::from_ref(&recipient_commitment), + 0, ) .with_test_programs(); @@ -3018,7 +3041,7 @@ pub mod tests { let account_id_1 = AccountId::new([1; 32]); let account_id_2 = AccountId::new([2; 32]); let initial_data = [(account_id_1, 100_u128), (account_id_2, 151_u128)]; - let state = V03State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + let state = V03State::new_with_genesis_accounts(&initial_data, &[], 0).with_test_programs(); let bytes = borsh::to_vec(&state).unwrap(); let state_from_bytes: V03State = borsh::from_slice(&bytes).unwrap(); assert_eq!(state, state_from_bytes); diff --git a/program_methods/guest/src/bin/clock.rs b/program_methods/guest/src/bin/clock.rs index d07df4cd..b9d679f1 100644 --- a/program_methods/guest/src/bin/clock.rs +++ b/program_methods/guest/src/bin/clock.rs @@ -1,12 +1,12 @@ use nssa_core::program::{AccountPostState, ProgramInput, read_nssa_inputs, write_nssa_outputs}; -type Instruction = (); +type Instruction = nssa_core::Timestamp; fn main() { let ( ProgramInput { pre_states, - instruction: (), + instruction: timestamp, }, instruction_words, ) = read_nssa_inputs::(); @@ -16,20 +16,24 @@ fn main() { }; let account_pre = &pre.account; - let account_pre_data = account_pre.data.clone(); - let clock = - u64::from_le_bytes(account_pre_data.into_inner().try_into().expect( - "Block context program account data should be the LE encoding of a u64 integer", - )); + let account_pre_data = account_pre.data.clone().into_inner(); + let block_id = u64::from_le_bytes( + account_pre_data[..8] + .try_into() + .expect("Block context program account data should contain a LE-encoded block_id u64"), + ); let mut account_post = account_pre.clone(); - account_post.data = clock + let next_block_id = block_id .checked_add(1) - .expect("Next timestap should be within u64 boundaries") - .to_le_bytes() + .expect("Next block id should be within u64 boundaries"); + let mut data = [0u8; 16]; + data[..8].copy_from_slice(&next_block_id.to_le_bytes()); + data[8..].copy_from_slice(×tamp.to_le_bytes()); + account_post.data = data .to_vec() .try_into() - .expect("u64 byte length should fit in account data"); + .expect("16 bytes should fit in account data"); let post = AccountPostState::new(account_post); diff --git a/programs/amm/src/tests.rs b/programs/amm/src/tests.rs index d5c8e7b0..01c543ff 100644 --- a/programs/amm/src/tests.rs +++ b/programs/amm/src/tests.rs @@ -2638,7 +2638,7 @@ fn new_definition_lp_symmetric_amounts() { fn state_for_amm_tests() -> V03State { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); state.force_insert_account( IdForExeTests::pool_definition_id(), AccountsForExeTests::pool_definition_init(), @@ -2681,7 +2681,7 @@ fn state_for_amm_tests() -> V03State { fn state_for_amm_tests_with_new_def() -> V03State { let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, &[]); + let mut state = V03State::new_with_genesis_accounts(&initial_data, &[], 0); state.force_insert_account( IdForExeTests::token_a_definition_id(), AccountsForExeTests::token_a_definition_account(), diff --git a/sequencer/core/src/block_store.rs b/sequencer/core/src/block_store.rs index 9c4c875a..46f71797 100644 --- a/sequencer/core/src/block_store.rs +++ b/sequencer/core/src/block_store.rs @@ -150,7 +150,7 @@ mod tests { let retrieved_tx = node_store.get_transaction_by_hash(tx.hash()); assert_eq!(None, retrieved_tx); // Add the block with the transaction - let dummy_state = V03State::new_with_genesis_accounts(&[], &[]); + let dummy_state = V03State::new_with_genesis_accounts(&[], &[], 0); node_store.update(&block, [1; 32], &dummy_state).unwrap(); // Try again let retrieved_tx = node_store.get_transaction_by_hash(tx.hash()); @@ -209,7 +209,7 @@ mod tests { let block_hash = block.header.hash; let block_msg_id = [1; 32]; - let dummy_state = V03State::new_with_genesis_accounts(&[], &[]); + let dummy_state = V03State::new_with_genesis_accounts(&[], &[], 0); node_store .update(&block, block_msg_id, &dummy_state) .unwrap(); @@ -244,7 +244,7 @@ mod tests { let block = common::test_utils::produce_dummy_block(1, None, vec![tx]); let block_id = block.header.block_id; - let dummy_state = V03State::new_with_genesis_accounts(&[], &[]); + let dummy_state = V03State::new_with_genesis_accounts(&[], &[], 0); node_store.update(&block, [1; 32], &dummy_state).unwrap(); // Verify initial status is Pending diff --git a/sequencer/core/src/lib.rs b/sequencer/core/src/lib.rs index 0afad05a..25334ede 100644 --- a/sequencer/core/src/lib.rs +++ b/sequencer/core/src/lib.rs @@ -121,7 +121,11 @@ impl SequencerCore SequencerCore { valid_transactions.push(clock_nssa_tx); } @@ -724,7 +728,7 @@ mod tests { .unwrap(); // Only one user tx should be included; the clock tx is always appended last. - assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation()]); + assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation(block.header.timestamp)]); } #[tokio::test] @@ -750,7 +754,7 @@ mod tests { .get_block_at_id(sequencer.chain_height) .unwrap() .unwrap(); - assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation()]); + assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation(block.header.timestamp)]); // Add same transaction should fail mempool_handle.push(tx.clone()).await.unwrap(); @@ -763,7 +767,7 @@ mod tests { .unwrap() .unwrap(); // The replay is rejected, so only the clock tx is in the block. - assert_eq!(block.body.transactions, vec![NSSATransaction::clock_invocation()]); + assert_eq!(block.body.transactions, vec![NSSATransaction::clock_invocation(block.header.timestamp)]); } #[tokio::test] @@ -798,7 +802,7 @@ mod tests { .get_block_at_id(sequencer.chain_height) .unwrap() .unwrap(); - assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation()]); + assert_eq!(block.body.transactions, vec![tx.clone(), NSSATransaction::clock_invocation(block.header.timestamp)]); } // Instantiating a new sequencer from the same config. This should load the existing block @@ -928,7 +932,7 @@ mod tests { ); assert_eq!( new_block.body.transactions, - vec![tx, NSSATransaction::clock_invocation()], + vec![tx, NSSATransaction::clock_invocation(new_block.header.timestamp)], "New block should contain the submitted transaction and the clock invocation" ); } @@ -954,7 +958,7 @@ mod tests { )) }; mempool_handle - .push(NSSATransaction::clock_invocation()) + .push(NSSATransaction::clock_invocation(0)) .await .unwrap(); mempool_handle.push(crafted_clock_tx).await.unwrap(); @@ -969,7 +973,7 @@ mod tests { .unwrap(); // Both transactions were dropped. Only the system-appended clock tx remains. - assert_eq!(block.body.transactions, vec![NSSATransaction::clock_invocation()]); + assert_eq!(block.body.transactions, vec![NSSATransaction::clock_invocation(block.header.timestamp)]); } #[tokio::test] diff --git a/storage/src/indexer.rs b/storage/src/indexer.rs index 8eb40ef4..c398300e 100644 --- a/storage/src/indexer.rs +++ b/storage/src/indexer.rs @@ -990,7 +990,7 @@ mod tests { } fn initial_state() -> V03State { - nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[]) + nssa::V03State::new_with_genesis_accounts(&[(acc1(), 10000), (acc2(), 20000)], &[], 0) } fn transfer(amount: u128, nonce: u128, direction: bool) -> NSSATransaction {