mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-04-08 12:13:24 +00:00
add more clock accounts
This commit is contained in:
parent
d6a92f443e
commit
d8ffa22b81
Binary file not shown.
@ -49,7 +49,11 @@ impl NSSATransaction {
|
||||
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![
|
||||
nssa::CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
nssa::CLOCK_10_PROGRAM_ACCOUNT_ID,
|
||||
nssa::CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
],
|
||||
vec![],
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@ -16,7 +16,9 @@ pub use program_deployment_transaction::ProgramDeploymentTransaction;
|
||||
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
|
||||
pub use public_transaction::PublicTransaction;
|
||||
pub use signature::{PrivateKey, PublicKey, Signature};
|
||||
pub use state::{CLOCK_PROGRAM_ACCOUNT_ID, V03State};
|
||||
pub use state::{
|
||||
CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, CLOCK_01_PROGRAM_ACCOUNT_ID, V03State,
|
||||
};
|
||||
|
||||
pub mod encoding;
|
||||
pub mod error;
|
||||
|
||||
@ -16,9 +16,15 @@ use crate::{
|
||||
|
||||
pub const MAX_NUMBER_CHAINED_CALLS: usize = 10;
|
||||
|
||||
pub const CLOCK_PROGRAM_ACCOUNT_ID: AccountId =
|
||||
pub const CLOCK_01_PROGRAM_ACCOUNT_ID: AccountId =
|
||||
AccountId::new(*b"/LEZ/ClockProgramAccount/0000001");
|
||||
|
||||
pub const CLOCK_10_PROGRAM_ACCOUNT_ID: AccountId =
|
||||
AccountId::new(*b"/LEZ/ClockProgramAccount/0000010");
|
||||
|
||||
pub const CLOCK_50_PROGRAM_ACCOUNT_ID: AccountId =
|
||||
AccountId::new(*b"/LEZ/ClockProgramAccount/0000050");
|
||||
|
||||
#[derive(Clone, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
|
||||
pub struct CommitmentSet {
|
||||
@ -160,17 +166,24 @@ impl V03State {
|
||||
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: data
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("16 bytes should fit within accounts data"),
|
||||
..Account::default()
|
||||
},
|
||||
);
|
||||
let clock_program_id = Program::clock().id();
|
||||
for account_id in [
|
||||
CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_10_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
] {
|
||||
self.public_state.insert(
|
||||
account_id,
|
||||
Account {
|
||||
program_owner: clock_program_id,
|
||||
data: data
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("16 bytes should fit within accounts data"),
|
||||
..Account::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert_program(&mut self, program: Program) {
|
||||
@ -377,7 +390,10 @@ pub mod tests {
|
||||
program::Program,
|
||||
public_transaction,
|
||||
signature::PrivateKey,
|
||||
state::{CLOCK_PROGRAM_ACCOUNT_ID, MAX_NUMBER_CHAINED_CALLS},
|
||||
state::{
|
||||
CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
MAX_NUMBER_CHAINED_CALLS,
|
||||
},
|
||||
};
|
||||
|
||||
impl V03State {
|
||||
@ -515,17 +531,23 @@ 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()
|
||||
},
|
||||
);
|
||||
for account_id in [
|
||||
CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_10_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
] {
|
||||
this.insert(
|
||||
account_id,
|
||||
Account {
|
||||
program_owner: clock_program.id(),
|
||||
data: [0u8; 16]
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
..Account::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
this
|
||||
};
|
||||
let expected_builtin_programs = {
|
||||
@ -684,7 +706,11 @@ pub mod tests {
|
||||
fn clock_transaction(timestamp: nssa_core::Timestamp) -> PublicTransaction {
|
||||
let message = public_transaction::Message::try_new(
|
||||
Program::clock().id(),
|
||||
vec![CLOCK_PROGRAM_ACCOUNT_ID],
|
||||
vec![
|
||||
CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_10_PROGRAM_ACCOUNT_ID,
|
||||
CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
],
|
||||
vec![],
|
||||
timestamp,
|
||||
)
|
||||
@ -695,11 +721,11 @@ pub mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn clock_account_data(state: &V03State) -> (u64, nssa_core::Timestamp) {
|
||||
let data = state
|
||||
.get_account_by_id(CLOCK_PROGRAM_ACCOUNT_ID)
|
||||
.data
|
||||
.into_inner();
|
||||
fn clock_account_data(
|
||||
state: &V03State,
|
||||
account_id: AccountId,
|
||||
) -> (u64, nssa_core::Timestamp) {
|
||||
let data = state.get_account_by_id(account_id).data.into_inner();
|
||||
let block_id = u64::from_le_bytes(data[..8].try_into().unwrap());
|
||||
let timestamp = u64::from_le_bytes(data[8..].try_into().unwrap());
|
||||
(block_id, timestamp)
|
||||
@ -710,7 +736,7 @@ pub mod tests {
|
||||
let genesis_timestamp = 1_000_000u64;
|
||||
let state = V03State::new_with_genesis_accounts(&[], &[], genesis_timestamp);
|
||||
|
||||
let (block_id, timestamp) = clock_account_data(&state);
|
||||
let (block_id, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
|
||||
assert_eq!(block_id, 0);
|
||||
assert_eq!(timestamp, genesis_timestamp);
|
||||
@ -723,7 +749,7 @@ pub mod tests {
|
||||
let tx = clock_transaction(1234);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
|
||||
let (block_id, _) = clock_account_data(&state);
|
||||
let (block_id, _) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(block_id, 1);
|
||||
}
|
||||
|
||||
@ -735,7 +761,7 @@ pub mod tests {
|
||||
let tx = clock_transaction(block_timestamp);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
|
||||
let (_, timestamp) = clock_account_data(&state);
|
||||
let (_, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(timestamp, block_timestamp);
|
||||
}
|
||||
|
||||
@ -747,12 +773,90 @@ pub mod tests {
|
||||
let tx = clock_transaction(expected_block_id * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
|
||||
let (block_id, timestamp) = clock_account_data(&state);
|
||||
let (block_id, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(block_id, expected_block_id);
|
||||
assert_eq!(timestamp, expected_block_id * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clock_10_account_not_updated_when_block_id_not_multiple_of_10() {
|
||||
let genesis_timestamp = 0u64;
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], genesis_timestamp);
|
||||
|
||||
// Run 9 clock ticks (block_ids 1..=9), none of which are multiples of 10.
|
||||
for tick in 1u64..=9 {
|
||||
let tx = clock_transaction(tick * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
}
|
||||
|
||||
let (block_id_10, timestamp_10) =
|
||||
clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID);
|
||||
// The 10-block account should still reflect genesis state.
|
||||
assert_eq!(block_id_10, 0);
|
||||
assert_eq!(timestamp_10, genesis_timestamp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clock_10_account_updated_when_block_id_is_multiple_of_10() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
|
||||
// Run 10 clock ticks so block_id reaches 10.
|
||||
for tick in 1u64..=10 {
|
||||
let tx = clock_transaction(tick * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
}
|
||||
|
||||
let (block_id_1, timestamp_1) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
let (block_id_10, timestamp_10) =
|
||||
clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(block_id_1, 10);
|
||||
assert_eq!(block_id_10, 10);
|
||||
assert_eq!(timestamp_10, timestamp_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clock_50_account_only_updated_at_multiples_of_50() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
|
||||
// After 49 ticks the 50-block account should be unchanged.
|
||||
for tick in 1u64..=49 {
|
||||
let tx = clock_transaction(tick * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
}
|
||||
let (block_id_50, _) = clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(block_id_50, 0);
|
||||
|
||||
// Tick 50 — now the 50-block account should update.
|
||||
let tx = clock_transaction(50 * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
let (block_id_50, timestamp_50) =
|
||||
clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID);
|
||||
assert_eq!(block_id_50, 50);
|
||||
assert_eq!(timestamp_50, 50 * 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_three_clock_accounts_updated_at_multiple_of_50() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
|
||||
// Advance to block 50 (a multiple of both 10 and 50).
|
||||
for tick in 1u64..=50 {
|
||||
let tx = clock_transaction(tick * 1000);
|
||||
state.transition_from_public_transaction(&tx).unwrap();
|
||||
}
|
||||
|
||||
let (block_id_1, ts_1) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID);
|
||||
let (block_id_10, ts_10) = clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID);
|
||||
let (block_id_50, ts_50) = clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID);
|
||||
|
||||
assert_eq!(block_id_1, 50);
|
||||
assert_eq!(block_id_10, 50);
|
||||
assert_eq!(block_id_50, 50);
|
||||
assert_eq!(ts_1, ts_10);
|
||||
assert_eq!(ts_1, ts_50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn program_should_fail_if_modifies_nonces() {
|
||||
let initial_data = [(AccountId::new([1; 32]), 100)];
|
||||
|
||||
@ -1,7 +1,29 @@
|
||||
use nssa_core::program::{AccountPostState, ProgramInput, read_nssa_inputs, write_nssa_outputs};
|
||||
use nssa_core::{
|
||||
account::AccountWithMetadata,
|
||||
program::{AccountPostState, ProgramInput, read_nssa_inputs, write_nssa_outputs},
|
||||
};
|
||||
|
||||
type Instruction = nssa_core::Timestamp;
|
||||
|
||||
fn update_if_multiple(
|
||||
pre: AccountWithMetadata,
|
||||
divisor: u64,
|
||||
current_block_id: u64,
|
||||
updated_data: [u8; 16],
|
||||
) -> (AccountWithMetadata, AccountPostState) {
|
||||
if current_block_id % divisor == 0 {
|
||||
let mut post_account = pre.account.clone();
|
||||
post_account.data = updated_data
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("16 bytes should fit in account data");
|
||||
(pre, AccountPostState::new(post_account))
|
||||
} else {
|
||||
let post = AccountPostState::new(pre.account.clone());
|
||||
(pre, post)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
@ -11,31 +33,33 @@ fn main() {
|
||||
instruction_words,
|
||||
) = read_nssa_inputs::<Instruction>();
|
||||
|
||||
let Ok([pre]) = <[_; 1]>::try_from(pre_states) else {
|
||||
let Ok([pre_01, pre_10, pre_50]) = <[_; 3]>::try_from(pre_states) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let account_pre = &pre.account;
|
||||
let account_pre_data = account_pre.data.clone().into_inner();
|
||||
let block_id = u64::from_le_bytes(
|
||||
account_pre_data[..8]
|
||||
let prev_block_id = u64::from_le_bytes(
|
||||
pre_01.account.data.clone().into_inner()[..8]
|
||||
.try_into()
|
||||
.expect("Block context program account data should contain a LE-encoded block_id u64"),
|
||||
.expect("Clock account data should contain a LE-encoded block_id u64"),
|
||||
);
|
||||
|
||||
let mut account_post = account_pre.clone();
|
||||
let next_block_id = block_id
|
||||
let current_block_id = prev_block_id
|
||||
.checked_add(1)
|
||||
.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("16 bytes should fit in account data");
|
||||
|
||||
let post = AccountPostState::new(account_post);
|
||||
let updated_data = {
|
||||
let mut data = [0u8; 16];
|
||||
data[..8].copy_from_slice(¤t_block_id.to_le_bytes());
|
||||
data[8..].copy_from_slice(×tamp.to_le_bytes());
|
||||
data
|
||||
};
|
||||
|
||||
write_nssa_outputs(instruction_words, vec![pre], vec![post]);
|
||||
let (pre_01, post_01) = update_if_multiple(pre_01, 1, current_block_id, updated_data);
|
||||
let (pre_10, post_10) = update_if_multiple(pre_10, 10, current_block_id, updated_data);
|
||||
let (pre_50, post_50) = update_if_multiple(pre_50, 50, current_block_id, updated_data);
|
||||
|
||||
write_nssa_outputs(
|
||||
instruction_words,
|
||||
vec![pre_01, pre_10, pre_50],
|
||||
vec![post_01, post_10, post_50],
|
||||
);
|
||||
}
|
||||
|
||||
@ -207,7 +207,22 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
|
||||
.expect("Timestamp must be positive");
|
||||
|
||||
let clock_program_id = nssa::program::Program::clock().id();
|
||||
let clock_account_pre = self.state.get_account_by_id(nssa::CLOCK_PROGRAM_ACCOUNT_ID);
|
||||
let clock_accounts_pre = [
|
||||
(
|
||||
nssa::CLOCK_01_PROGRAM_ACCOUNT_ID,
|
||||
self.state.get_account_by_id(nssa::CLOCK_01_PROGRAM_ACCOUNT_ID),
|
||||
),
|
||||
(
|
||||
nssa::CLOCK_10_PROGRAM_ACCOUNT_ID,
|
||||
self.state
|
||||
.get_account_by_id(nssa::CLOCK_10_PROGRAM_ACCOUNT_ID),
|
||||
),
|
||||
(
|
||||
nssa::CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||
self.state
|
||||
.get_account_by_id(nssa::CLOCK_50_PROGRAM_ACCOUNT_ID),
|
||||
),
|
||||
];
|
||||
|
||||
while let Some(tx) = self.mempool.pop() {
|
||||
let tx_hash = tx.hash();
|
||||
@ -217,9 +232,9 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
|
||||
// - any PP tx that declares a modified post-state for the clock account.
|
||||
let touches_system = match &tx {
|
||||
NSSATransaction::Public(p) => p.message().program_id == clock_program_id,
|
||||
NSSATransaction::PrivacyPreserving(pp) => pp
|
||||
.public_post_state_for(&nssa::CLOCK_PROGRAM_ACCOUNT_ID)
|
||||
.is_some_and(|post| post != &clock_account_pre),
|
||||
NSSATransaction::PrivacyPreserving(pp) => clock_accounts_pre
|
||||
.iter()
|
||||
.any(|(id, pre)| pp.public_post_state_for(id).is_some_and(|post| post != pre)),
|
||||
NSSATransaction::ProgramDeployment(_) => false,
|
||||
};
|
||||
if touches_system {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user