mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-06-29 18:39:30 +00:00
test(cross-zone): add ping_receiver and a single-zone inbox dispatch test
This commit is contained in:
parent
30bd869ac2
commit
42078d0305
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -4524,6 +4524,7 @@ dependencies = [
|
||||
"borsh",
|
||||
"bridge_core",
|
||||
"clock_core",
|
||||
"cross_zone_inbox_core",
|
||||
"env_logger",
|
||||
"faucet_core",
|
||||
"hex",
|
||||
@ -4531,6 +4532,7 @@ dependencies = [
|
||||
"k256",
|
||||
"lee_core",
|
||||
"log",
|
||||
"ping_core",
|
||||
"rand 0.8.6",
|
||||
"risc0-binfmt",
|
||||
"risc0-build",
|
||||
@ -7133,6 +7135,14 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "ping_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lee_core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
@ -7409,6 +7419,7 @@ dependencies = [
|
||||
"cross_zone_outbox_core",
|
||||
"faucet_core",
|
||||
"lee_core",
|
||||
"ping_core",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
"token_core",
|
||||
|
||||
@ -26,6 +26,7 @@ members = [
|
||||
"programs/vault/core",
|
||||
"programs/cross_zone_outbox/core",
|
||||
"programs/cross_zone_inbox/core",
|
||||
"programs/ping/core",
|
||||
"lez/sequencer/core",
|
||||
"lez/sequencer/service",
|
||||
"lez/sequencer/service/protocol",
|
||||
@ -84,6 +85,7 @@ bridge_core = { path = "programs/bridge/core" }
|
||||
vault_core = { path = "programs/vault/core" }
|
||||
cross_zone_outbox_core = { path = "programs/cross_zone_outbox/core" }
|
||||
cross_zone_inbox_core = { path = "programs/cross_zone_inbox/core" }
|
||||
ping_core = { path = "programs/ping/core" }
|
||||
test_program_methods = { path = "test_program_methods" }
|
||||
testnet_initial_state = { path = "lez/testnet_initial_state" }
|
||||
keycard_wallet = { path = "lez/keycard_wallet" }
|
||||
|
||||
BIN
artifacts/program_methods/ping_receiver.bin
Normal file
BIN
artifacts/program_methods/ping_receiver.bin
Normal file
Binary file not shown.
@ -34,6 +34,8 @@ risc0-binfmt = "3.0.2"
|
||||
lee_core = { workspace = true, features = ["test_utils"] }
|
||||
token_core.workspace = true
|
||||
authenticated_transfer_core.workspace = true
|
||||
cross_zone_inbox_core.workspace = true
|
||||
ping_core.workspace = true
|
||||
test_program_methods.workspace = true
|
||||
|
||||
env_logger.workspace = true
|
||||
|
||||
104
lee/state_machine/src/cross_zone_dispatch_tests.rs
Normal file
104
lee/state_machine/src/cross_zone_dispatch_tests.rs
Normal file
@ -0,0 +1,104 @@
|
||||
#![expect(
|
||||
clippy::tests_outside_test_module,
|
||||
clippy::arithmetic_side_effects,
|
||||
reason = "We don't care about these in tests"
|
||||
)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use cross_zone_inbox_core::{
|
||||
CrossZoneMessage, InboxConfig, Instruction, inbox_config_account_id,
|
||||
inbox_seen_shard_account_id,
|
||||
};
|
||||
use lee_core::account::Account;
|
||||
use ping_core::{ReceiverInstruction, ping_record_pda};
|
||||
|
||||
use crate::{
|
||||
V03State,
|
||||
program::Program,
|
||||
public_transaction::{Message, WitnessSet},
|
||||
validated_state_diff::ValidatedStateDiff,
|
||||
};
|
||||
|
||||
/// Drives `cross_zone_inbox::Dispatch` directly through the state machine
|
||||
/// (no watcher) and asserts the message is delivered to `ping_receiver`, which
|
||||
/// records the payload into its own PDA.
|
||||
#[test]
|
||||
fn inbox_dispatch_delivers_payload_to_ping_receiver() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0);
|
||||
// ping_receiver is a throwaway demo target, registered only in this test state.
|
||||
state.insert_program(Program::ping_receiver());
|
||||
|
||||
let inbox_id = Program::cross_zone_inbox().id();
|
||||
let receiver_id = Program::ping_receiver().id();
|
||||
|
||||
let self_zone = [1_u8; 32];
|
||||
let src_zone = [2_u8; 32];
|
||||
let src_block_id = 5;
|
||||
|
||||
// Seed the inbox config account (inbox-owned) allowing src_zone -> ping_receiver.
|
||||
let mut allowed_targets = BTreeMap::new();
|
||||
allowed_targets.insert(src_zone, vec![receiver_id]);
|
||||
let config = InboxConfig {
|
||||
self_zone,
|
||||
allowed_peers: BTreeMap::new(),
|
||||
allowed_targets,
|
||||
};
|
||||
let config_id = inbox_config_account_id(inbox_id);
|
||||
state.force_insert_account(
|
||||
config_id,
|
||||
Account {
|
||||
program_owner: inbox_id,
|
||||
balance: 0_u128,
|
||||
data: config
|
||||
.to_bytes()
|
||||
.try_into()
|
||||
.expect("config fits in account data"),
|
||||
nonce: 0_u128.into(),
|
||||
},
|
||||
);
|
||||
|
||||
// The payload is the ping_receiver instruction, serialized as risc0 words in
|
||||
// little-endian bytes (the contract the inbox reverses when forwarding).
|
||||
let inner = b"hello-cross-zone".to_vec();
|
||||
let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record {
|
||||
payload: inner.clone(),
|
||||
})
|
||||
.expect("serialize ping instruction");
|
||||
let payload: Vec<u8> = words.iter().flat_map(|word| word.to_le_bytes()).collect();
|
||||
|
||||
let msg = CrossZoneMessage {
|
||||
src_zone,
|
||||
src_block_id,
|
||||
src_tx_index: 0,
|
||||
src_program_id: [9_u32; 8],
|
||||
target_program_id: receiver_id,
|
||||
payload,
|
||||
l1_inclusion_witness: None,
|
||||
};
|
||||
|
||||
let seen_id = inbox_seen_shard_account_id(inbox_id, &src_zone, src_block_id);
|
||||
let record_id = ping_record_pda(receiver_id);
|
||||
|
||||
let message = Message::try_new(
|
||||
inbox_id,
|
||||
vec![config_id, seen_id, record_id],
|
||||
vec![],
|
||||
Instruction::Dispatch(msg),
|
||||
)
|
||||
.expect("build dispatch message");
|
||||
let tx = crate::PublicTransaction::new(message, WitnessSet::from_raw_parts(vec![]));
|
||||
|
||||
let diff = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0)
|
||||
.expect("dispatch must validate and execute");
|
||||
let public_diff = diff.public_diff();
|
||||
|
||||
let record = public_diff
|
||||
.get(&record_id)
|
||||
.expect("ping record account must change");
|
||||
assert_eq!(
|
||||
record.data.clone().into_inner(),
|
||||
inner,
|
||||
"ping_receiver must record the delivered payload"
|
||||
);
|
||||
}
|
||||
@ -33,6 +33,9 @@ mod signature;
|
||||
mod state;
|
||||
mod validated_state_diff;
|
||||
|
||||
#[cfg(test)]
|
||||
mod cross_zone_dispatch_tests;
|
||||
|
||||
pub mod program_methods {
|
||||
include!(concat!(env!("OUT_DIR"), "/program_methods/mod.rs"));
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ use crate::{
|
||||
AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID,
|
||||
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, BRIDGE_ELF, BRIDGE_ID, CLOCK_ELF,
|
||||
CLOCK_ID, CROSS_ZONE_INBOX_ELF, CROSS_ZONE_INBOX_ID, CROSS_ZONE_OUTBOX_ELF,
|
||||
CROSS_ZONE_OUTBOX_ID, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, TOKEN_ID,
|
||||
VAULT_ELF, VAULT_ID,
|
||||
CROSS_ZONE_OUTBOX_ID, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, PING_RECEIVER_ELF,
|
||||
PING_RECEIVER_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID,
|
||||
},
|
||||
};
|
||||
|
||||
@ -190,6 +190,14 @@ impl Program {
|
||||
elf: CROSS_ZONE_INBOX_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ping_receiver() -> Self {
|
||||
Self {
|
||||
id: PING_RECEIVER_ID,
|
||||
elf: PING_RECEIVER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||
|
||||
@ -711,6 +711,11 @@ pub mod tests {
|
||||
this.insert(Program::vault().id(), Program::vault());
|
||||
this.insert(Program::faucet().id(), Program::faucet());
|
||||
this.insert(Program::bridge().id(), Program::bridge());
|
||||
this.insert(
|
||||
Program::cross_zone_outbox().id(),
|
||||
Program::cross_zone_outbox(),
|
||||
);
|
||||
this.insert(Program::cross_zone_inbox().id(), Program::cross_zone_inbox());
|
||||
this
|
||||
};
|
||||
|
||||
|
||||
@ -22,5 +22,6 @@ bridge_core.workspace = true
|
||||
vault_core.workspace = true
|
||||
cross_zone_outbox_core.workspace = true
|
||||
cross_zone_inbox_core.workspace = true
|
||||
ping_core.workspace = true
|
||||
risc0-zkvm.workspace = true
|
||||
serde = { workspace = true, default-features = false }
|
||||
|
||||
47
program_methods/guest/src/bin/ping_receiver.rs
Normal file
47
program_methods/guest/src/bin/ping_receiver.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use lee_core::{
|
||||
account::AccountWithMetadata,
|
||||
program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs},
|
||||
};
|
||||
use ping_core::{ReceiverInstruction, ping_record_pda, ping_record_seed};
|
||||
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
pre_states,
|
||||
instruction,
|
||||
},
|
||||
instruction_words,
|
||||
) = read_lee_inputs::<ReceiverInstruction>();
|
||||
|
||||
assert!(
|
||||
caller_program_id.is_some(),
|
||||
"ping_receiver is only callable through a chained call"
|
||||
);
|
||||
|
||||
let payload = match instruction {
|
||||
ReceiverInstruction::Record { payload } => payload,
|
||||
};
|
||||
|
||||
let [record] = <[AccountWithMetadata; 1]>::try_from(pre_states)
|
||||
.expect("Record requires exactly 1 account");
|
||||
assert_eq!(
|
||||
record.account_id,
|
||||
ping_record_pda(self_program_id),
|
||||
"Account must be the ping record PDA"
|
||||
);
|
||||
|
||||
let mut post_account = record.account.clone();
|
||||
post_account.data = payload.try_into().expect("payload fits in account data");
|
||||
let post = AccountPostState::new_claimed_if_default(post_account, Claim::Pda(ping_record_seed()));
|
||||
|
||||
ProgramOutput::new(
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
instruction_words,
|
||||
vec![record],
|
||||
vec![post],
|
||||
)
|
||||
.write();
|
||||
}
|
||||
12
programs/ping/core/Cargo.toml
Normal file
12
programs/ping/core/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "ping_core"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lee_core.workspace = true
|
||||
serde = { workspace = true, features = ["alloc"] }
|
||||
25
programs/ping/core/src/lib.rs
Normal file
25
programs/ping/core/src/lib.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use lee_core::{
|
||||
account::AccountId,
|
||||
program::{PdaSeed, ProgramId},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const PING_RECORD_SEED: [u8; 32] = *b"/LEZ/v0.3/PingRecord/0000000000/";
|
||||
|
||||
/// Instruction delivered to `ping_receiver` by the inbox: record the payload.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ReceiverInstruction {
|
||||
Record { payload: Vec<u8> },
|
||||
}
|
||||
|
||||
/// The account a `ping_receiver` records the latest delivered payload into.
|
||||
#[must_use]
|
||||
pub fn ping_record_pda(receiver_id: ProgramId) -> AccountId {
|
||||
AccountId::for_public_pda(&receiver_id, &ping_record_seed())
|
||||
}
|
||||
|
||||
/// Seed of the record PDA, exposed so the guest can claim the account.
|
||||
#[must_use]
|
||||
pub fn ping_record_seed() -> PdaSeed {
|
||||
PdaSeed::new(PING_RECORD_SEED)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user