add timestamp to clock

This commit is contained in:
Sergio Chouhy 2026-03-30 23:50:54 -03:00
parent 3324bcf391
commit 7078e403ed
37 changed files with 126 additions and 87 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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<NSSATransaction>,
}

View File

@ -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(

View File

@ -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],
);

View File

@ -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());

View File

@ -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,
}

View File

@ -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,

View File

@ -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 {

View File

@ -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<PdaSeed>) = (
@ -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<PdaSeed>) = (
@ -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<PdaSeed>) = (
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);

View File

@ -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::<Instruction>();
@ -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(&timestamp.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);

View File

@ -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(),

View File

@ -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

View File

@ -121,7 +121,11 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect();
nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments)
nssa::V03State::new_with_genesis_accounts(
&init_accs,
&initial_commitments,
genesis_block.header.timestamp,
)
};
#[cfg(feature = "testnet")]
@ -268,7 +272,7 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
}
// Append the Block Context Program invocation as the mandatory last transaction.
match self.execute_check_transaction_on_state(NSSATransaction::clock_invocation()) {
match self.execute_check_transaction_on_state(NSSATransaction::clock_invocation(curr_time)) {
Ok(clock_nssa_tx) => {
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]

View File

@ -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 {