mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-01 13:53:13 +00:00
add tests for timestamp validity windows
This commit is contained in:
parent
caf74b8346
commit
fba95ca2a8
@ -344,7 +344,7 @@ pub mod tests {
|
|||||||
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||||
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
|
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
|
||||||
encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey},
|
encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey},
|
||||||
program::{BlockId, PdaSeed, ProgramId, ValidityWindow},
|
program::{BlockId, PdaSeed, ProgramId, Timestamp, ValidityWindow},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -3021,7 +3021,7 @@ pub mod tests {
|
|||||||
validity_window: (Option<BlockId>, Option<BlockId>),
|
validity_window: (Option<BlockId>, Option<BlockId>),
|
||||||
block_id: BlockId,
|
block_id: BlockId,
|
||||||
) {
|
) {
|
||||||
let validity_window: ValidityWindow<BlockId> = validity_window.try_into().unwrap();
|
let block_validity_window: ValidityWindow<BlockId> = validity_window.try_into().unwrap();
|
||||||
let validity_window_program = Program::validity_window();
|
let validity_window_program = Program::validity_window();
|
||||||
let account_keys = test_public_account_keys_1();
|
let account_keys = test_public_account_keys_1();
|
||||||
let pre = AccountWithMetadata::new(Account::default(), false, account_keys.account_id());
|
let pre = AccountWithMetadata::new(Account::default(), false, account_keys.account_id());
|
||||||
@ -3030,7 +3030,7 @@ pub mod tests {
|
|||||||
let account_ids = vec![pre.account_id];
|
let account_ids = vec![pre.account_id];
|
||||||
let nonces = vec![];
|
let nonces = vec![];
|
||||||
let program_id = validity_window_program.id();
|
let program_id = validity_window_program.id();
|
||||||
let instruction = validity_window;
|
let instruction = (block_validity_window, ValidityWindow::<Timestamp>::new_unbounded());
|
||||||
let message =
|
let message =
|
||||||
public_transaction::Message::try_new(program_id, account_ids, nonces, instruction)
|
public_transaction::Message::try_new(program_id, account_ids, nonces, instruction)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -3038,7 +3038,7 @@ pub mod tests {
|
|||||||
PublicTransaction::new(message, witness_set)
|
PublicTransaction::new(message, witness_set)
|
||||||
};
|
};
|
||||||
let result = state.transition_from_public_transaction(&tx, block_id, 0);
|
let result = state.transition_from_public_transaction(&tx, block_id, 0);
|
||||||
let is_inside_validity_window = match (validity_window.start(), validity_window.end()) {
|
let is_inside_validity_window = match (block_validity_window.start(), block_validity_window.end()) {
|
||||||
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
||||||
(Some(s), None) => s <= block_id,
|
(Some(s), None) => s <= block_id,
|
||||||
(None, Some(e)) => block_id < e,
|
(None, Some(e)) => block_id < e,
|
||||||
@ -3051,6 +3051,56 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 3; "at upper bound")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 2; "inside range")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 0; "below range")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 1; "at lower bound")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 4; "above range")]
|
||||||
|
#[test_case::test_case((Some(1), None), 1; "lower bound only - at bound")]
|
||||||
|
#[test_case::test_case((Some(1), None), 10; "lower bound only - above")]
|
||||||
|
#[test_case::test_case((Some(1), None), 0; "lower bound only - below")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 3; "upper bound only - at bound")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 0; "upper bound only - below")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 4; "upper bound only - above")]
|
||||||
|
#[test_case::test_case((None, None), 0; "no bounds - always valid")]
|
||||||
|
#[test_case::test_case((None, None), 100; "no bounds - always valid 2")]
|
||||||
|
fn timestamp_validity_window_works_in_public_transactions(
|
||||||
|
validity_window: (Option<Timestamp>, Option<Timestamp>),
|
||||||
|
timestamp_ms: Timestamp,
|
||||||
|
) {
|
||||||
|
let timestamp_validity_window: ValidityWindow<Timestamp> =
|
||||||
|
validity_window.try_into().unwrap();
|
||||||
|
let validity_window_program = Program::validity_window();
|
||||||
|
let account_keys = test_public_account_keys_1();
|
||||||
|
let pre = AccountWithMetadata::new(Account::default(), false, account_keys.account_id());
|
||||||
|
let mut state = V03State::new_with_genesis_accounts(&[], &[]).with_test_programs();
|
||||||
|
let tx = {
|
||||||
|
let account_ids = vec![pre.account_id];
|
||||||
|
let nonces = vec![];
|
||||||
|
let program_id = validity_window_program.id();
|
||||||
|
let instruction =
|
||||||
|
(ValidityWindow::<BlockId>::new_unbounded(), timestamp_validity_window);
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, account_ids, nonces, instruction)
|
||||||
|
.unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
PublicTransaction::new(message, witness_set)
|
||||||
|
};
|
||||||
|
let result = state.transition_from_public_transaction(&tx, 1, timestamp_ms);
|
||||||
|
let is_inside_validity_window =
|
||||||
|
match (timestamp_validity_window.start(), timestamp_validity_window.end()) {
|
||||||
|
(Some(s), Some(e)) => s <= timestamp_ms && timestamp_ms < e,
|
||||||
|
(Some(s), None) => s <= timestamp_ms,
|
||||||
|
(None, Some(e)) => timestamp_ms < e,
|
||||||
|
(None, None) => true,
|
||||||
|
};
|
||||||
|
if is_inside_validity_window {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
} else {
|
||||||
|
assert!(matches!(result, Err(NssaError::OutOfValidityWindow)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test_case::test_case((Some(1), Some(3)), 3; "at upper bound")]
|
#[test_case::test_case((Some(1), Some(3)), 3; "at upper bound")]
|
||||||
#[test_case::test_case((Some(1), Some(3)), 2; "inside range")]
|
#[test_case::test_case((Some(1), Some(3)), 2; "inside range")]
|
||||||
#[test_case::test_case((Some(1), Some(3)), 0; "below range")]
|
#[test_case::test_case((Some(1), Some(3)), 0; "below range")]
|
||||||
@ -3068,7 +3118,7 @@ pub mod tests {
|
|||||||
validity_window: (Option<BlockId>, Option<BlockId>),
|
validity_window: (Option<BlockId>, Option<BlockId>),
|
||||||
block_id: BlockId,
|
block_id: BlockId,
|
||||||
) {
|
) {
|
||||||
let validity_window: ValidityWindow<BlockId> = validity_window.try_into().unwrap();
|
let block_validity_window: ValidityWindow<BlockId> = validity_window.try_into().unwrap();
|
||||||
let validity_window_program = Program::validity_window();
|
let validity_window_program = Program::validity_window();
|
||||||
let account_keys = test_private_account_keys_1();
|
let account_keys = test_private_account_keys_1();
|
||||||
let pre = AccountWithMetadata::new(Account::default(), false, &account_keys.npk());
|
let pre = AccountWithMetadata::new(Account::default(), false, &account_keys.npk());
|
||||||
@ -3078,7 +3128,7 @@ pub mod tests {
|
|||||||
let shared_secret = SharedSecretKey::new(&esk, &account_keys.vpk());
|
let shared_secret = SharedSecretKey::new(&esk, &account_keys.vpk());
|
||||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
let instruction = validity_window;
|
let instruction = (block_validity_window, ValidityWindow::<Timestamp>::new_unbounded());
|
||||||
let (output, proof) = circuit::execute_and_prove(
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
vec![pre],
|
vec![pre],
|
||||||
Program::serialize_instruction(instruction).unwrap(),
|
Program::serialize_instruction(instruction).unwrap(),
|
||||||
@ -3102,12 +3152,80 @@ pub mod tests {
|
|||||||
PrivacyPreservingTransaction::new(message, witness_set)
|
PrivacyPreservingTransaction::new(message, witness_set)
|
||||||
};
|
};
|
||||||
let result = state.transition_from_privacy_preserving_transaction(&tx, block_id, 0);
|
let result = state.transition_from_privacy_preserving_transaction(&tx, block_id, 0);
|
||||||
let is_inside_validity_window = match (validity_window.start(), validity_window.end()) {
|
let is_inside_validity_window =
|
||||||
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
match (block_validity_window.start(), block_validity_window.end()) {
|
||||||
(Some(s), None) => s <= block_id,
|
(Some(s), Some(e)) => s <= block_id && block_id < e,
|
||||||
(None, Some(e)) => block_id < e,
|
(Some(s), None) => s <= block_id,
|
||||||
(None, None) => true,
|
(None, Some(e)) => block_id < e,
|
||||||
|
(None, None) => true,
|
||||||
|
};
|
||||||
|
if is_inside_validity_window {
|
||||||
|
assert!(result.is_ok());
|
||||||
|
} else {
|
||||||
|
assert!(matches!(result, Err(NssaError::OutOfValidityWindow)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 3; "at upper bound")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 2; "inside range")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 0; "below range")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 1; "at lower bound")]
|
||||||
|
#[test_case::test_case((Some(1), Some(3)), 4; "above range")]
|
||||||
|
#[test_case::test_case((Some(1), None), 1; "lower bound only - at bound")]
|
||||||
|
#[test_case::test_case((Some(1), None), 10; "lower bound only - above")]
|
||||||
|
#[test_case::test_case((Some(1), None), 0; "lower bound only - below")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 3; "upper bound only - at bound")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 0; "upper bound only - below")]
|
||||||
|
#[test_case::test_case((None, Some(3)), 4; "upper bound only - above")]
|
||||||
|
#[test_case::test_case((None, None), 0; "no bounds - always valid")]
|
||||||
|
#[test_case::test_case((None, None), 100; "no bounds - always valid 2")]
|
||||||
|
fn timestamp_validity_window_works_in_privacy_preserving_transactions(
|
||||||
|
validity_window: (Option<Timestamp>, Option<Timestamp>),
|
||||||
|
timestamp_ms: Timestamp,
|
||||||
|
) {
|
||||||
|
let timestamp_validity_window: ValidityWindow<Timestamp> =
|
||||||
|
validity_window.try_into().unwrap();
|
||||||
|
let validity_window_program = Program::validity_window();
|
||||||
|
let account_keys = test_private_account_keys_1();
|
||||||
|
let pre = AccountWithMetadata::new(Account::default(), false, &account_keys.npk());
|
||||||
|
let mut state = V03State::new_with_genesis_accounts(&[], &[]).with_test_programs();
|
||||||
|
let tx = {
|
||||||
|
let esk = [3; 32];
|
||||||
|
let shared_secret = SharedSecretKey::new(&esk, &account_keys.vpk());
|
||||||
|
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||||
|
|
||||||
|
let instruction =
|
||||||
|
(ValidityWindow::<BlockId>::new_unbounded(), timestamp_validity_window);
|
||||||
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
|
vec![pre],
|
||||||
|
Program::serialize_instruction(instruction).unwrap(),
|
||||||
|
vec![2],
|
||||||
|
vec![(account_keys.npk(), shared_secret)],
|
||||||
|
vec![],
|
||||||
|
vec![None],
|
||||||
|
&validity_window_program.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let message = Message::try_from_circuit_output(
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
vec![(account_keys.npk(), account_keys.vpk(), epk)],
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
|
PrivacyPreservingTransaction::new(message, witness_set)
|
||||||
};
|
};
|
||||||
|
let result = state.transition_from_privacy_preserving_transaction(&tx, 1, timestamp_ms);
|
||||||
|
let is_inside_validity_window =
|
||||||
|
match (timestamp_validity_window.start(), timestamp_validity_window.end()) {
|
||||||
|
(Some(s), Some(e)) => s <= timestamp_ms && timestamp_ms < e,
|
||||||
|
(Some(s), None) => s <= timestamp_ms,
|
||||||
|
(None, Some(e)) => timestamp_ms < e,
|
||||||
|
(None, None) => true,
|
||||||
|
};
|
||||||
if is_inside_validity_window {
|
if is_inside_validity_window {
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
use nssa_core::program::{
|
use nssa_core::program::{
|
||||||
AccountPostState, BlockId, ProgramInput, ProgramOutput, ValidityWindow, read_nssa_inputs,
|
AccountPostState, BlockId, ProgramInput, ProgramOutput, Timestamp, ValidityWindow,
|
||||||
|
read_nssa_inputs,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Instruction = ValidityWindow<BlockId>;
|
type Instruction = (ValidityWindow<BlockId>, ValidityWindow<Timestamp>);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (
|
let (
|
||||||
ProgramInput {
|
ProgramInput {
|
||||||
pre_states,
|
pre_states,
|
||||||
instruction: block_validity_window,
|
instruction: (block_validity_window, timestamp_validity_window),
|
||||||
},
|
},
|
||||||
instruction_words,
|
instruction_words,
|
||||||
) = read_nssa_inputs::<Instruction>();
|
) = read_nssa_inputs::<Instruction>();
|
||||||
@ -25,5 +26,6 @@ fn main() {
|
|||||||
vec![AccountPostState::new(post)],
|
vec![AccountPostState::new(post)],
|
||||||
)
|
)
|
||||||
.with_block_validity_window(block_validity_window)
|
.with_block_validity_window(block_validity_window)
|
||||||
|
.with_timestamp_validity_window(timestamp_validity_window)
|
||||||
.write();
|
.write();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use nssa_core::program::{
|
use nssa_core::program::{
|
||||||
AccountPostState, BlockId, ChainedCall, ProgramId, ProgramInput, ProgramOutput, ValidityWindow,
|
AccountPostState, BlockId, ChainedCall, ProgramId, ProgramInput, ProgramOutput, Timestamp,
|
||||||
read_nssa_inputs,
|
ValidityWindow, read_nssa_inputs,
|
||||||
};
|
};
|
||||||
use risc0_zkvm::serde::to_vec;
|
use risc0_zkvm::serde::to_vec;
|
||||||
|
|
||||||
@ -9,6 +9,8 @@ use risc0_zkvm::serde::to_vec;
|
|||||||
///
|
///
|
||||||
/// Instruction: (`window`, `chained_program_id`, `chained_window`)
|
/// Instruction: (`window`, `chained_program_id`, `chained_window`)
|
||||||
/// The initial output uses `window` and chains to `chained_program_id` with `chained_window`.
|
/// The initial output uses `window` and chains to `chained_program_id` with `chained_window`.
|
||||||
|
/// The chained program (validity_window) expects `(ValidityWindow<BlockId>, ValidityWindow<Timestamp>)`
|
||||||
|
/// so an unbounded timestamp window is appended automatically.
|
||||||
type Instruction = (ValidityWindow<BlockId>, ProgramId, ValidityWindow<BlockId>);
|
type Instruction = (ValidityWindow<BlockId>, ProgramId, ValidityWindow<BlockId>);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -23,7 +25,11 @@ fn main() {
|
|||||||
let [pre] = <[_; 1]>::try_from(pre_states.clone()).expect("Expected exactly one pre state");
|
let [pre] = <[_; 1]>::try_from(pre_states.clone()).expect("Expected exactly one pre state");
|
||||||
let post = pre.account.clone();
|
let post = pre.account.clone();
|
||||||
|
|
||||||
let chained_instruction = to_vec(&chained_block_validity_window).unwrap();
|
let chained_instruction = to_vec(&(
|
||||||
|
chained_block_validity_window,
|
||||||
|
ValidityWindow::<Timestamp>::new_unbounded(),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
let chained_call = ChainedCall {
|
let chained_call = ChainedCall {
|
||||||
program_id: chained_program_id,
|
program_id: chained_program_id,
|
||||||
instruction_data: chained_instruction,
|
instruction_data: chained_instruction,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user