mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-08 00:03:09 +00:00
add test and refactor chain_caller program
This commit is contained in:
parent
449ba3e3a9
commit
e61a971790
@ -16,6 +16,12 @@ pub struct ProgramInput<T> {
|
|||||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
|
||||||
pub struct PdaSeed([u8; 32]);
|
pub struct PdaSeed([u8; 32]);
|
||||||
|
|
||||||
|
impl PdaSeed {
|
||||||
|
pub fn new(value: [u8; 32]) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "host")]
|
#[cfg(feature = "host")]
|
||||||
impl From<(&ProgramId, &PdaSeed)> for AccountId {
|
impl From<(&ProgramId, &PdaSeed)> for AccountId {
|
||||||
fn from(value: (&ProgramId, &PdaSeed)) -> Self {
|
fn from(value: (&ProgramId, &PdaSeed)) -> Self {
|
||||||
|
|||||||
@ -250,7 +250,7 @@ pub mod tests {
|
|||||||
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
|
||||||
account::{Account, AccountId, AccountWithMetadata, Nonce},
|
account::{Account, AccountId, AccountWithMetadata, Nonce},
|
||||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar},
|
encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar},
|
||||||
program::ProgramId,
|
program::{PdaSeed, ProgramId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -2092,14 +2092,18 @@ pub mod tests {
|
|||||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
let from = AccountId::from(&PublicKey::new_from_private_key(&key));
|
let from = AccountId::from(&PublicKey::new_from_private_key(&key));
|
||||||
let to = AccountId::new([2; 32]);
|
let to = AccountId::new([2; 32]);
|
||||||
let initial_balance = 100;
|
let initial_balance = 1000;
|
||||||
let initial_data = [(from, initial_balance), (to, 0)];
|
let initial_data = [(from, initial_balance), (to, 0)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let from_key = key;
|
let from_key = key;
|
||||||
let amount: u128 = 0;
|
let amount: u128 = 37;
|
||||||
let instruction: (u128, ProgramId, u32) =
|
let instruction: (u128, ProgramId, u32, Option<PdaSeed>) = (
|
||||||
(amount, Program::authenticated_transfer_program().id(), 2);
|
amount,
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
2,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
let expected_to_post = Account {
|
let expected_to_post = Account {
|
||||||
program_owner: Program::authenticated_transfer_program().id(),
|
program_owner: Program::authenticated_transfer_program().id(),
|
||||||
@ -2139,10 +2143,11 @@ pub mod tests {
|
|||||||
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let from_key = key;
|
let from_key = key;
|
||||||
let amount: u128 = 0;
|
let amount: u128 = 0;
|
||||||
let instruction: (u128, ProgramId, u32) = (
|
let instruction: (u128, ProgramId, u32, Option<PdaSeed>) = (
|
||||||
amount,
|
amount,
|
||||||
Program::authenticated_transfer_program().id(),
|
Program::authenticated_transfer_program().id(),
|
||||||
MAX_NUMBER_CHAINED_CALLS as u32 + 1,
|
MAX_NUMBER_CHAINED_CALLS as u32 + 1,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let message = public_transaction::Message::try_new(
|
let message = public_transaction::Message::try_new(
|
||||||
@ -2162,4 +2167,47 @@ pub mod tests {
|
|||||||
Err(NssaError::MaxChainedCallsDepthExceeded)
|
Err(NssaError::MaxChainedCallsDepthExceeded)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_execution_that_requires_authentication_of_a_program_derived_account_id_succeeds() {
|
||||||
|
let chain_caller = Program::chain_caller();
|
||||||
|
let pda_seed = PdaSeed::new([37; 32]);
|
||||||
|
let from = AccountId::from((&chain_caller.id(), &pda_seed));
|
||||||
|
let to = AccountId::new([2; 32]);
|
||||||
|
let initial_balance = 1000;
|
||||||
|
let initial_data = [(from, initial_balance), (to, 0)];
|
||||||
|
let mut state =
|
||||||
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
|
let amount: u128 = 58;
|
||||||
|
let instruction: (u128, ProgramId, u32, Option<PdaSeed>) = (
|
||||||
|
amount,
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
1,
|
||||||
|
Some(pda_seed),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected_to_post = Account {
|
||||||
|
program_owner: Program::authenticated_transfer_program().id(),
|
||||||
|
balance: amount, // The `chain_caller` chains the program twice
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = public_transaction::Message::try_new(
|
||||||
|
chain_caller.id(),
|
||||||
|
vec![to, from], // The chain_caller program permutes the account order in the chain
|
||||||
|
// call
|
||||||
|
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).unwrap();
|
||||||
|
|
||||||
|
let from_post = state.get_account_by_id(&from);
|
||||||
|
let to_post = state.get_account_by_id(&to);
|
||||||
|
// The `chain_caller` program calls the program twice
|
||||||
|
assert_eq!(from_post.balance, initial_balance - amount);
|
||||||
|
assert_eq!(to_post, expected_to_post);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,45 +1,51 @@
|
|||||||
use nssa_core::program::{
|
use nssa_core::program::{
|
||||||
ChainedCall, ProgramId, ProgramInput, read_nssa_inputs, write_nssa_outputs_with_chained_call,
|
ChainedCall, PdaSeed, ProgramId, ProgramInput, read_nssa_inputs,
|
||||||
|
write_nssa_outputs_with_chained_call,
|
||||||
};
|
};
|
||||||
use risc0_zkvm::serde::to_vec;
|
use risc0_zkvm::serde::to_vec;
|
||||||
|
|
||||||
type Instruction = (u128, ProgramId, u32);
|
type Instruction = (u128, ProgramId, u32, Option<PdaSeed>);
|
||||||
|
|
||||||
/// A program that calls another program `num_chain_calls` times.
|
/// A program that calls another program `num_chain_calls` times.
|
||||||
/// It permutes the order of the input accounts on the subsequent call
|
/// It permutes the order of the input accounts on the subsequent call
|
||||||
|
/// The `ProgramId` in the instruction must be the program_id of the authenticated transfers program
|
||||||
fn main() {
|
fn main() {
|
||||||
let ProgramInput {
|
let ProgramInput {
|
||||||
pre_states,
|
pre_states,
|
||||||
instruction: (balance, program_id, num_chain_calls),
|
instruction: (balance, auth_transfer_id, num_chain_calls, pda_seed),
|
||||||
} = read_nssa_inputs::<Instruction>();
|
} = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
let [sender_pre, receiver_pre] = match pre_states.try_into() {
|
let [recipient_pre, sender_pre] = match pre_states.try_into() {
|
||||||
Ok(array) => array,
|
Ok(array) => array,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let instruction_data = to_vec(&balance).unwrap();
|
let instruction_data = to_vec(&balance).unwrap();
|
||||||
|
|
||||||
let mut chained_call = vec![
|
let mut running_recipient_pre = recipient_pre.clone();
|
||||||
ChainedCall {
|
let mut running_sender_pre = sender_pre.clone();
|
||||||
program_id,
|
|
||||||
instruction_data: instruction_data.clone(),
|
|
||||||
pre_states: vec![receiver_pre.clone(), sender_pre.clone()], // <- Account order permutation here
|
|
||||||
pda_seeds: vec![]
|
|
||||||
};
|
|
||||||
num_chain_calls as usize - 1
|
|
||||||
];
|
|
||||||
|
|
||||||
chained_call.push(ChainedCall {
|
if pda_seed.is_some() {
|
||||||
program_id,
|
running_sender_pre.is_authorized = true;
|
||||||
instruction_data,
|
}
|
||||||
pre_states: vec![receiver_pre.clone(), sender_pre.clone()], // <- Account order permutation here
|
|
||||||
pda_seeds: vec![],
|
let mut chained_calls = Vec::new();
|
||||||
});
|
for _i in 0..num_chain_calls {
|
||||||
|
let new_chained_call = ChainedCall {
|
||||||
|
program_id: auth_transfer_id,
|
||||||
|
instruction_data: instruction_data.clone(),
|
||||||
|
pre_states: vec![running_sender_pre.clone(), running_recipient_pre.clone()], // <- Account order permutation here
|
||||||
|
pda_seeds: pda_seed.iter().cloned().collect(),
|
||||||
|
};
|
||||||
|
chained_calls.push(new_chained_call);
|
||||||
|
|
||||||
|
running_sender_pre.account.balance -= balance;
|
||||||
|
running_recipient_pre.account.balance += balance;
|
||||||
|
}
|
||||||
|
|
||||||
write_nssa_outputs_with_chained_call(
|
write_nssa_outputs_with_chained_call(
|
||||||
vec![sender_pre.clone(), receiver_pre.clone()],
|
vec![recipient_pre.clone(), sender_pre.clone()],
|
||||||
vec![sender_pre.account, receiver_pre.account],
|
vec![recipient_pre.account, sender_pre.account],
|
||||||
chained_call,
|
chained_calls,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user