mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-04-03 17:53:09 +00:00
feat: extend ValidityWindow with Unix timestamp bounds
This commit is contained in:
parent
b8bb6913be
commit
5c592312f9
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -1019,19 +1019,12 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-io"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b"
|
||||
dependencies = [
|
||||
"bitcoin-io",
|
||||
"hex-conservative",
|
||||
]
|
||||
|
||||
@ -3977,7 +3970,6 @@ dependencies = [
|
||||
"nssa",
|
||||
"nssa_core",
|
||||
"rand 0.8.5",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"sha2",
|
||||
"thiserror 2.0.18",
|
||||
@ -5269,13 +5261,13 @@ dependencies = [
|
||||
"env_logger",
|
||||
"hex",
|
||||
"hex-literal 1.1.0",
|
||||
"k256",
|
||||
"log",
|
||||
"nssa_core",
|
||||
"rand 0.8.5",
|
||||
"risc0-binfmt",
|
||||
"risc0-build",
|
||||
"risc0-zkvm",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"sha2",
|
||||
@ -7086,26 +7078,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand 0.9.2",
|
||||
"secp256k1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "3.7.0"
|
||||
|
||||
@ -4,6 +4,7 @@ use nssa::{AccountId, V03State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{HashType, block::BlockId};
|
||||
use nssa_core::program::Timestamp;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub enum NSSATransaction {
|
||||
@ -69,11 +70,14 @@ impl NSSATransaction {
|
||||
self,
|
||||
state: &mut V03State,
|
||||
block_id: BlockId,
|
||||
timestamp_ms: Timestamp,
|
||||
) -> Result<Self, nssa::error::NssaError> {
|
||||
match &self {
|
||||
Self::Public(tx) => state.transition_from_public_transaction(tx, block_id),
|
||||
Self::Public(tx) => {
|
||||
state.transition_from_public_transaction(tx, block_id, timestamp_ms)
|
||||
}
|
||||
Self::PrivacyPreserving(tx) => {
|
||||
state.transition_from_privacy_preserving_transaction(tx, block_id)
|
||||
state.transition_from_privacy_preserving_transaction(tx, block_id, timestamp_ms)
|
||||
}
|
||||
Self::ProgramDeployment(tx) => state.transition_from_program_deployment_transaction(tx),
|
||||
}
|
||||
|
||||
@ -183,6 +183,25 @@ pub fn TransactionPage() -> impl IntoView {
|
||||
signatures_and_public_keys: _,
|
||||
proof,
|
||||
} = witness_set;
|
||||
let (block_from, block_to, ts_from, ts_to) = validity_window.0;
|
||||
let block_part = match (block_from, block_to) {
|
||||
(Some(start), Some(end)) => format!("block {start}..{end}"),
|
||||
(Some(start), None) => format!("block {start}.."),
|
||||
(None, Some(end)) => format!("block ..{end}"),
|
||||
(None, None) => String::new(),
|
||||
};
|
||||
let ts_part = match (ts_from, ts_to) {
|
||||
(Some(start), Some(end)) => format!("ts {start}..{end}"),
|
||||
(Some(start), None) => format!("ts {start}.."),
|
||||
(None, Some(end)) => format!("ts ..{end}"),
|
||||
(None, None) => String::new(),
|
||||
};
|
||||
let validity_window_formatted = match (block_part.is_empty(), ts_part.is_empty()) {
|
||||
(true, true) => "unbounded".to_owned(),
|
||||
(false, true) => block_part,
|
||||
(true, false) => ts_part,
|
||||
(false, false) => format!("{block_part}, {ts_part}"),
|
||||
};
|
||||
|
||||
let proof_len = proof.map_or(0, |p| p.0.len());
|
||||
view! {
|
||||
|
||||
@ -125,7 +125,7 @@ impl IndexerStore {
|
||||
transaction
|
||||
.clone()
|
||||
.transaction_stateless_check()?
|
||||
.execute_check_on_state(&mut state_guard, block.header.block_id)?;
|
||||
.execute_check_on_state(&mut state_guard, block.header.block_id, block.header.timestamp)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -302,7 +302,12 @@ impl From<nssa::privacy_preserving_transaction::message::Message> for PrivacyPre
|
||||
.into_iter()
|
||||
.map(|(n, d)| (n.into(), d.into()))
|
||||
.collect(),
|
||||
validity_window: validity_window.into(),
|
||||
validity_window: ValidityWindow((
|
||||
validity_window.from(),
|
||||
validity_window.to(),
|
||||
validity_window.from_timestamp(),
|
||||
validity_window.to_timestamp(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,7 +302,9 @@ pub struct Nullifier(
|
||||
);
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ValidityWindow(pub (Option<BlockId>, Option<BlockId>));
|
||||
pub struct ValidityWindow(
|
||||
pub (Option<BlockId>, Option<BlockId>, Option<TimeStamp>, Option<TimeStamp>),
|
||||
);
|
||||
|
||||
impl Display for ValidityWindow {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
||||
@ -124,7 +124,7 @@ impl MockIndexerService {
|
||||
indexer_service_protocol::Nullifier([tx_idx as u8; 32]),
|
||||
CommitmentSetDigest([0xff; 32]),
|
||||
)],
|
||||
validity_window: ValidityWindow((None, None)),
|
||||
validity_window: ValidityWindow((None, None, None, None)),
|
||||
},
|
||||
witness_set: WitnessSet {
|
||||
signatures_and_public_keys: vec![],
|
||||
|
||||
@ -172,6 +172,8 @@ impl AccountPostState {
|
||||
}
|
||||
|
||||
pub type BlockId = u64;
|
||||
/// Unix timestamp in milliseconds.
|
||||
pub type Timestamp = u64;
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
@ -181,6 +183,8 @@ pub type BlockId = u64;
|
||||
pub struct ValidityWindow {
|
||||
from: Option<BlockId>,
|
||||
to: Option<BlockId>,
|
||||
from_timestamp: Option<Timestamp>,
|
||||
to_timestamp: Option<Timestamp>,
|
||||
}
|
||||
|
||||
impl ValidityWindow {
|
||||
@ -190,11 +194,24 @@ impl ValidityWindow {
|
||||
Self {
|
||||
from: None,
|
||||
to: None,
|
||||
from_timestamp: None,
|
||||
to_timestamp: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Valid for block IDs in the range [from, to) and timestamps in [from_timestamp, to_timestamp).
|
||||
/// A `None` bound on either side is treated as unbounded in that direction.
|
||||
#[must_use]
|
||||
pub fn is_valid_for(&self, block_id: BlockId, timestamp_ms: Timestamp) -> bool {
|
||||
self.from.is_none_or(|start| block_id >= start)
|
||||
&& self.to.is_none_or(|end| block_id < end)
|
||||
&& self.from_timestamp.is_none_or(|t| timestamp_ms >= t)
|
||||
&& self.to_timestamp.is_none_or(|t| timestamp_ms < t)
|
||||
}
|
||||
|
||||
/// Returns `true` if `id` falls within the half-open range `[from, to)`.
|
||||
/// A `None` bound on either side is treated as unbounded in that direction.
|
||||
/// Ignores timestamp bounds.
|
||||
#[must_use]
|
||||
pub fn is_valid_for_block_id(&self, id: BlockId) -> bool {
|
||||
self.from.is_none_or(|start| id >= start) && self.to.is_none_or(|end| id < end)
|
||||
@ -205,10 +222,14 @@ impl ValidityWindow {
|
||||
if let (Some(from_id), Some(until_id)) = (self.from, self.to)
|
||||
&& from_id >= until_id
|
||||
{
|
||||
Err(InvalidWindow)
|
||||
} else {
|
||||
Ok(())
|
||||
return Err(InvalidWindow);
|
||||
}
|
||||
if let (Some(from_ts), Some(until_ts)) = (self.from_timestamp, self.to_timestamp)
|
||||
&& from_ts >= until_ts
|
||||
{
|
||||
return Err(InvalidWindow);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inclusive lower bound. `None` means the window starts at the beginning of the chain.
|
||||
@ -222,6 +243,16 @@ impl ValidityWindow {
|
||||
pub const fn end(&self) -> Option<BlockId> {
|
||||
self.to
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn from_timestamp(&self) -> Option<Timestamp> {
|
||||
self.from_timestamp
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn to_timestamp(&self) -> Option<Timestamp> {
|
||||
self.to_timestamp
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(Option<BlockId>, Option<BlockId>)> for ValidityWindow {
|
||||
@ -231,6 +262,37 @@ impl TryFrom<(Option<BlockId>, Option<BlockId>)> for ValidityWindow {
|
||||
let this = Self {
|
||||
from: value.0,
|
||||
to: value.1,
|
||||
from_timestamp: None,
|
||||
to_timestamp: None,
|
||||
};
|
||||
this.check_window()?;
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
Option<BlockId>,
|
||||
Option<BlockId>,
|
||||
Option<Timestamp>,
|
||||
Option<Timestamp>,
|
||||
)> for ValidityWindow
|
||||
{
|
||||
type Error = InvalidWindow;
|
||||
|
||||
fn try_from(
|
||||
value: (
|
||||
Option<BlockId>,
|
||||
Option<BlockId>,
|
||||
Option<Timestamp>,
|
||||
Option<Timestamp>,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let this = Self {
|
||||
from: value.0,
|
||||
to: value.1,
|
||||
from_timestamp: value.2,
|
||||
to_timestamp: value.3,
|
||||
};
|
||||
this.check_window()?;
|
||||
Ok(this)
|
||||
@ -328,6 +390,18 @@ impl ProgramOutput {
|
||||
self.validity_window = window.try_into()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn valid_from_timestamp(mut self, ts: Option<Timestamp>) -> Result<Self, InvalidWindow> {
|
||||
self.validity_window.from_timestamp = ts;
|
||||
self.validity_window.check_window()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn valid_until_timestamp(mut self, ts: Option<Timestamp>) -> Result<Self, InvalidWindow> {
|
||||
self.validity_window.to_timestamp = ts;
|
||||
self.validity_window.check_window()?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of a number as `lo + hi * 2^128`.
|
||||
|
||||
@ -7,7 +7,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, AccountWithMetadata},
|
||||
program::{BlockId, ValidityWindow},
|
||||
program::{BlockId, Timestamp, ValidityWindow},
|
||||
};
|
||||
use sha2::{Digest as _, digest::FixedOutput as _};
|
||||
|
||||
@ -37,6 +37,7 @@ impl PrivacyPreservingTransaction {
|
||||
&self,
|
||||
state: &V03State,
|
||||
block_id: BlockId,
|
||||
timestamp_ms: Timestamp,
|
||||
) -> Result<HashMap<AccountId, Account>, NssaError> {
|
||||
let message = &self.message;
|
||||
let witness_set = &self.witness_set;
|
||||
@ -94,7 +95,7 @@ impl PrivacyPreservingTransaction {
|
||||
}
|
||||
|
||||
// Verify validity window
|
||||
if !message.validity_window.is_valid_for_block_id(block_id) {
|
||||
if !message.validity_window.is_valid_for(block_id, timestamp_ms) {
|
||||
return Err(NssaError::OutOfValidityWindow);
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use log::debug;
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::{BlockId, ChainedCall, Claim, DEFAULT_PROGRAM_ID, validate_execution},
|
||||
program::{BlockId, ChainedCall, Claim, DEFAULT_PROGRAM_ID, Timestamp, validate_execution},
|
||||
};
|
||||
use sha2::{Digest as _, digest::FixedOutput as _};
|
||||
|
||||
@ -71,6 +71,7 @@ impl PublicTransaction {
|
||||
&self,
|
||||
state: &V03State,
|
||||
block_id: BlockId,
|
||||
timestamp_ms: Timestamp,
|
||||
) -> Result<HashMap<AccountId, Account>, NssaError> {
|
||||
let message = self.message();
|
||||
let witness_set = self.witness_set();
|
||||
@ -197,7 +198,7 @@ impl PublicTransaction {
|
||||
ensure!(
|
||||
program_output
|
||||
.validity_window
|
||||
.is_valid_for_block_id(block_id),
|
||||
.is_valid_for(block_id, timestamp_ms),
|
||||
NssaError::OutOfValidityWindow
|
||||
);
|
||||
|
||||
@ -388,7 +389,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key1]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1, 0);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
|
||||
@ -408,7 +409,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1, 0);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
|
||||
@ -429,7 +430,7 @@ pub mod tests {
|
||||
let mut witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
witness_set.signatures_and_public_keys[0].0 = Signature::new_for_tests([1; 64]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1, 0);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
|
||||
@ -449,7 +450,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1, 0);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
|
||||
@ -465,7 +466,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state, 1, 0);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier,
|
||||
account::{Account, AccountId, Nonce},
|
||||
program::{BlockId, ProgramId},
|
||||
program::{BlockId, ProgramId, Timestamp},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -159,8 +159,9 @@ impl V03State {
|
||||
&mut self,
|
||||
tx: &PublicTransaction,
|
||||
block_id: BlockId,
|
||||
timestamp_ms: Timestamp,
|
||||
) -> Result<(), NssaError> {
|
||||
let state_diff = tx.validate_and_produce_public_state_diff(self, block_id)?;
|
||||
let state_diff = tx.validate_and_produce_public_state_diff(self, block_id, timestamp_ms)?;
|
||||
|
||||
#[expect(
|
||||
clippy::iter_over_hash_type,
|
||||
@ -184,9 +185,10 @@ impl V03State {
|
||||
&mut self,
|
||||
tx: &PrivacyPreservingTransaction,
|
||||
block_id: BlockId,
|
||||
timestamp_ms: Timestamp,
|
||||
) -> Result<(), NssaError> {
|
||||
// 1. Verify the transaction satisfies acceptance criteria
|
||||
let public_state_diff = tx.validate_and_produce_public_state_diff(self, block_id)?;
|
||||
let public_state_diff = tx.validate_and_produce_public_state_diff(self, block_id, timestamp_ms)?;
|
||||
|
||||
let message = tx.message();
|
||||
|
||||
@ -341,7 +343,7 @@ pub mod tests {
|
||||
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
|
||||
encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey},
|
||||
program::{BlockId, PdaSeed, ProgramId, ValidityWindow},
|
||||
program::{BlockId, PdaSeed, ProgramId, Timestamp, ValidityWindow},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -576,7 +578,7 @@ pub mod tests {
|
||||
let balance_to_move = 5;
|
||||
|
||||
let tx = transfer_transaction(from, &key, 0, to, &to_key, 0, balance_to_move);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
assert_eq!(state.get_account_by_id(from).balance, 95);
|
||||
assert_eq!(state.get_account_by_id(to).balance, 5);
|
||||
@ -598,7 +600,7 @@ pub mod tests {
|
||||
assert!(state.get_account_by_id(from).balance < balance_to_move);
|
||||
|
||||
let tx = transfer_transaction(from, &from_key, 0, to, &to_key, 0, balance_to_move);
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
|
||||
assert_eq!(state.get_account_by_id(from).balance, 100);
|
||||
@ -623,7 +625,7 @@ pub mod tests {
|
||||
let balance_to_move = 8;
|
||||
|
||||
let tx = transfer_transaction(from, &from_key, 0, to, &to_key, 0, balance_to_move);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
assert_eq!(state.get_account_by_id(from).balance, 192);
|
||||
assert_eq!(state.get_account_by_id(to).balance, 108);
|
||||
@ -652,7 +654,7 @@ pub mod tests {
|
||||
0,
|
||||
balance_to_move,
|
||||
);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
let balance_to_move = 3;
|
||||
let tx = transfer_transaction(
|
||||
account_id2,
|
||||
@ -663,7 +665,7 @@ pub mod tests {
|
||||
0,
|
||||
balance_to_move,
|
||||
);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
assert_eq!(state.get_account_by_id(account_id1).balance, 95);
|
||||
assert_eq!(state.get_account_by_id(account_id2).balance, 2);
|
||||
@ -685,7 +687,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -702,7 +704,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -719,7 +721,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -743,7 +745,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -767,7 +769,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -791,7 +793,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -815,7 +817,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -843,7 +845,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -868,7 +870,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -886,7 +888,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -915,7 +917,7 @@ pub mod tests {
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -1108,7 +1110,7 @@ pub mod tests {
|
||||
assert!(!state.private_state.0.contains(&expected_new_commitment));
|
||||
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1, 0)
|
||||
.unwrap();
|
||||
|
||||
let sender_post = state.get_account_by_id(sender_keys.account_id());
|
||||
@ -1178,7 +1180,7 @@ pub mod tests {
|
||||
assert!(!state.private_state.1.contains(&expected_new_nullifier));
|
||||
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1, 0)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(state.public_state, previous_public_state);
|
||||
@ -1242,7 +1244,7 @@ pub mod tests {
|
||||
assert!(!state.private_state.1.contains(&expected_new_nullifier));
|
||||
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1, 0)
|
||||
.unwrap();
|
||||
|
||||
let recipient_post = state.get_account_by_id(recipient_keys.account_id());
|
||||
@ -2170,7 +2172,7 @@ pub mod tests {
|
||||
);
|
||||
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1, 0)
|
||||
.unwrap();
|
||||
|
||||
let sender_private_account = Account {
|
||||
@ -2188,7 +2190,7 @@ pub mod tests {
|
||||
&state,
|
||||
);
|
||||
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, 1);
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))));
|
||||
let NssaError::InvalidInput(error_message) = result.err().unwrap() else {
|
||||
@ -2266,7 +2268,7 @@ pub mod tests {
|
||||
public_transaction::WitnessSet::for_message(&message, &[&from_key, &to_key]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let recipient_post = state.get_account_by_id(to);
|
||||
|
||||
@ -2361,7 +2363,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let from_post = state.get_account_by_id(from);
|
||||
let to_post = state.get_account_by_id(to);
|
||||
@ -2401,7 +2403,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(NssaError::MaxChainedCallsDepthExceeded)
|
||||
@ -2442,7 +2444,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let from_post = state.get_account_by_id(from);
|
||||
let to_post = state.get_account_by_id(to);
|
||||
@ -2499,7 +2501,7 @@ pub mod tests {
|
||||
public_transaction::WitnessSet::for_message(&message, &[&from_key, &to_key]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let from_post = state.get_account_by_id(from);
|
||||
let to_post = state.get_account_by_id(to);
|
||||
@ -2690,7 +2692,7 @@ pub mod tests {
|
||||
let transaction = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&transaction, 1)
|
||||
.transition_from_privacy_preserving_transaction(&transaction, 1, 0)
|
||||
.unwrap();
|
||||
|
||||
// Assert
|
||||
@ -2706,6 +2708,85 @@ pub mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pda_mechanism_with_pinata_token_program() {
|
||||
let pinata_token = Program::pinata_token();
|
||||
let token = Program::token();
|
||||
|
||||
let pinata_definition_id = AccountId::new([1; 32]);
|
||||
let pinata_token_definition_id = AccountId::new([2; 32]);
|
||||
// Total supply of pinata token will be in an account under a PDA.
|
||||
let pinata_token_holding_id = AccountId::from((&pinata_token.id(), &PdaSeed::new([0; 32])));
|
||||
let winner_token_holding_id = AccountId::new([3; 32]);
|
||||
|
||||
let expected_winner_account_holding = token_core::TokenHolding::Fungible {
|
||||
definition_id: pinata_token_definition_id,
|
||||
balance: 150,
|
||||
};
|
||||
let expected_winner_token_holding_post = Account {
|
||||
program_owner: token.id(),
|
||||
data: Data::from(&expected_winner_account_holding),
|
||||
..Account::default()
|
||||
};
|
||||
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
state.add_pinata_token_program(pinata_definition_id);
|
||||
|
||||
// Execution of the token program to create new token for the pinata token
|
||||
// definition and supply accounts
|
||||
let total_supply: u128 = 10_000_000;
|
||||
let instruction = token_core::Instruction::NewFungibleDefinition {
|
||||
name: String::from("PINATA"),
|
||||
total_supply,
|
||||
};
|
||||
let message = public_transaction::Message::try_new(
|
||||
token.id(),
|
||||
vec![pinata_token_definition_id, pinata_token_holding_id],
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
// Execution of winner's token holding account initialization
|
||||
let instruction = token_core::Instruction::InitializeAccount;
|
||||
let message = public_transaction::Message::try_new(
|
||||
token.id(),
|
||||
vec![pinata_token_definition_id, winner_token_holding_id],
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
// Submit a solution to the pinata program to claim the prize
|
||||
let solution: u128 = 989_106;
|
||||
let message = public_transaction::Message::try_new(
|
||||
pinata_token.id(),
|
||||
vec![
|
||||
pinata_definition_id,
|
||||
pinata_token_holding_id,
|
||||
winner_token_holding_id,
|
||||
],
|
||||
vec![],
|
||||
solution,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let winner_token_holding_post = state.get_account_by_id(winner_token_holding_id);
|
||||
assert_eq!(
|
||||
winner_token_holding_post,
|
||||
expected_winner_token_holding_post
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claiming_mechanism_cannot_claim_initialied_accounts() {
|
||||
let claimer = Program::claimer();
|
||||
@ -2727,7 +2808,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
@ -2773,7 +2854,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&sender_key]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let res = state.transition_from_public_transaction(&tx, 1);
|
||||
let res = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
assert!(matches!(res, Err(NssaError::InvalidProgramBehavior)));
|
||||
|
||||
let sender_post = state.get_account_by_id(sender_id);
|
||||
@ -2842,7 +2923,7 @@ pub mod tests {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, 1);
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, 1, 0);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let nullifier = Nullifier::for_account_initialization(&private_keys.npk());
|
||||
@ -2942,7 +3023,7 @@ pub mod tests {
|
||||
// Claim should succeed
|
||||
assert!(
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 1, 0)
|
||||
.is_ok()
|
||||
);
|
||||
|
||||
@ -2991,7 +3072,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
// Should succeed - no changes made, no claim needed
|
||||
assert!(result.is_ok());
|
||||
@ -3016,7 +3097,7 @@ pub mod tests {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx, 1);
|
||||
let result = state.transition_from_public_transaction(&tx, 1, 0);
|
||||
|
||||
// Should fail - cannot modify data without claiming the account
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
@ -3154,17 +3235,18 @@ pub mod tests {
|
||||
let account_ids = vec![pre.account_id];
|
||||
let nonces = vec![];
|
||||
let program_id = validity_window_program.id();
|
||||
let instruction = (validity_window.0, validity_window.1, None::<Timestamp>, None::<Timestamp>);
|
||||
let message = public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
validity_window,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
PublicTransaction::new(message, witness_set)
|
||||
};
|
||||
let result = state.transition_from_public_transaction(&tx, block_id);
|
||||
let result = state.transition_from_public_transaction(&tx, block_id, 0);
|
||||
let is_inside_validity_window = match (validity_window.start(), validity_window.end()) {
|
||||
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
||||
(Some(s), None) => s <= block_id,
|
||||
@ -3205,9 +3287,10 @@ pub mod tests {
|
||||
let shared_secret = SharedSecretKey::new(&esk, &account_keys.vpk());
|
||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||
|
||||
let instruction = (validity_window.0, validity_window.1, None::<Timestamp>, None::<Timestamp>);
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
vec![pre],
|
||||
Program::serialize_instruction(validity_window).unwrap(),
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
vec![2],
|
||||
vec![(account_keys.npk(), shared_secret)],
|
||||
vec![],
|
||||
@ -3227,7 +3310,7 @@ pub mod tests {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
PrivacyPreservingTransaction::new(message, witness_set)
|
||||
};
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, block_id);
|
||||
let result = state.transition_from_privacy_preserving_transaction(&tx, block_id, 0);
|
||||
let is_inside_validity_window = match (validity_window.start(), validity_window.end()) {
|
||||
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
||||
(Some(s), None) => s <= block_id,
|
||||
|
||||
@ -38,10 +38,21 @@ impl ExecutionState {
|
||||
.iter()
|
||||
.filter_map(|output| output.validity_window.end())
|
||||
.min();
|
||||
let valid_from_ts = program_outputs
|
||||
.iter()
|
||||
.filter_map(|output| output.validity_window.from_timestamp())
|
||||
.max();
|
||||
let valid_until_ts = program_outputs
|
||||
.iter()
|
||||
.filter_map(|output| output.validity_window.to_timestamp())
|
||||
.min();
|
||||
|
||||
let validity_window = (valid_from_id, valid_until_id).try_into().expect(
|
||||
"There should be non empty intersection in the program output validity windows",
|
||||
);
|
||||
let validity_window =
|
||||
(valid_from_id, valid_until_id, valid_from_ts, valid_until_ts)
|
||||
.try_into()
|
||||
.expect(
|
||||
"There should be non empty intersection in the program output validity windows",
|
||||
);
|
||||
|
||||
let mut execution_state = Self {
|
||||
pre_states: Vec::new(),
|
||||
|
||||
@ -2733,7 +2733,7 @@ fn simple_amm_remove() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -2814,7 +2814,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -2898,7 +2898,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -2971,7 +2971,7 @@ fn simple_amm_new_definition_uninitialized_pool() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -3033,7 +3033,7 @@ fn simple_amm_add() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -3090,7 +3090,7 @@ fn simple_amm_swap_1() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
@ -3140,7 +3140,7 @@ fn simple_amm_swap_2() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 1).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
let pool_post = state.get_account_by_id(IdForExeTests::pool_definition_id());
|
||||
let vault_a_post = state.get_account_by_id(IdForExeTests::vault_a_id());
|
||||
|
||||
@ -162,17 +162,24 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
|
||||
(sequencer_core, mempool_handle)
|
||||
}
|
||||
|
||||
fn next_block_timestamp_ms(&self) -> nssa_core::program::Timestamp {
|
||||
u64::try_from(chrono::Utc::now().timestamp_millis())
|
||||
.expect("Timestamp must be positive")
|
||||
}
|
||||
|
||||
fn execute_check_transaction_on_state(
|
||||
&mut self,
|
||||
tx: NSSATransaction,
|
||||
) -> Result<NSSATransaction, nssa::error::NssaError> {
|
||||
let block_id = self.next_block_id();
|
||||
let timestamp_ms = self.next_block_timestamp_ms();
|
||||
match &tx {
|
||||
NSSATransaction::Public(tx) => self
|
||||
.state
|
||||
.transition_from_public_transaction(tx, self.next_block_id()),
|
||||
.transition_from_public_transaction(tx, block_id, timestamp_ms),
|
||||
NSSATransaction::PrivacyPreserving(tx) => self
|
||||
.state
|
||||
.transition_from_privacy_preserving_transaction(tx, self.next_block_id()),
|
||||
.transition_from_privacy_preserving_transaction(tx, block_id, timestamp_ms),
|
||||
NSSATransaction::ProgramDeployment(tx) => self
|
||||
.state
|
||||
.transition_from_program_deployment_transaction(tx),
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
use nssa_core::program::{
|
||||
AccountPostState, ProgramInput, ProgramOutput, ValidityWindow, read_nssa_inputs,
|
||||
AccountPostState, BlockId, ProgramInput, ProgramOutput, Timestamp, read_nssa_inputs,
|
||||
};
|
||||
|
||||
type Instruction = ValidityWindow;
|
||||
type Instruction = (
|
||||
Option<BlockId>,
|
||||
Option<BlockId>,
|
||||
Option<Timestamp>,
|
||||
Option<Timestamp>,
|
||||
);
|
||||
|
||||
fn main() {
|
||||
let (
|
||||
@ -24,6 +29,7 @@ fn main() {
|
||||
vec![pre],
|
||||
vec![AccountPostState::new(post)],
|
||||
)
|
||||
.with_validity_window(validity_window)
|
||||
.try_with_validity_window(validity_window)
|
||||
.unwrap()
|
||||
.write();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user