Merge pull request #524 from logos-blockchain/arjentix/refactor-lee-lez

Decouple last parts of LEZ from LEE
This commit is contained in:
Daniil Polyakov 2026-06-24 23:46:43 +03:00 committed by GitHub
commit 64f8444a67
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
244 changed files with 2991 additions and 2518 deletions

View File

@ -104,7 +104,7 @@ jobs:
- name: Lint programs - name: Lint programs
env: env:
RISC0_SKIP_BUILD: "1" RISC0_SKIP_BUILD: "1"
run: cargo clippy -p "*programs" -- -D warnings run: cargo clippy -p "*program" -- -D warnings
unit-tests: unit-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest

198
Cargo.lock generated
View File

@ -123,6 +123,7 @@ dependencies = [
"amm_core", "amm_core",
"lee", "lee",
"lee_core", "lee_core",
"programs",
"token_core", "token_core",
] ]
@ -513,6 +514,24 @@ version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4858a9d740c5007a9069007c3b4e91152d0506f13c1b31dd49051fd537656156" checksum = "4858a9d740c5007a9069007c3b4e91152d0506f13c1b31dd49051fd537656156"
[[package]]
name = "associated_token_account_core"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
"serde",
]
[[package]]
name = "associated_token_account_program"
version = "0.1.0"
dependencies = [
"associated_token_account_core",
"lee_core",
"token_core",
]
[[package]] [[package]]
name = "astral-tokio-tar" name = "astral-tokio-tar"
version = "0.6.2" version = "0.6.2"
@ -665,24 +684,6 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "ata_core"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
"serde",
]
[[package]]
name = "ata_program"
version = "0.1.0"
dependencies = [
"ata_core",
"lee_core",
"token_core",
]
[[package]] [[package]]
name = "atomic-polyfill" name = "atomic-polyfill"
version = "1.0.3" version = "1.0.3"
@ -758,6 +759,14 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "authenticated_transfer_program"
version = "0.1.0"
dependencies = [
"authenticated_transfer_core",
"lee_core",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.1" version = "1.5.1"
@ -1145,6 +1154,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bridge_program"
version = "0.1.0"
dependencies = [
"authenticated_transfer_core",
"bridge_core",
"lee_core",
"vault_core",
]
[[package]] [[package]]
name = "bs58" name = "bs58"
version = "0.5.1" version = "0.5.1"
@ -1154,6 +1173,14 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "build_utils"
version = "0.1.0"
dependencies = [
"anyhow",
"risc0-binfmt",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.20.3" version = "3.20.3"
@ -1452,6 +1479,14 @@ dependencies = [
"lee_core", "lee_core",
] ]
[[package]]
name = "clock_program"
version = "0.1.0"
dependencies = [
"clock_core",
"lee_core",
]
[[package]] [[package]]
name = "cmov" name = "cmov"
version = "0.5.4" version = "0.5.4"
@ -1514,9 +1549,11 @@ dependencies = [
"lee_core", "lee_core",
"log", "log",
"logos-blockchain-common-http-client", "logos-blockchain-common-http-client",
"programs",
"serde", "serde",
"serde_with", "serde_with",
"sha2", "sha2",
"system_accounts",
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
@ -1932,7 +1969,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"amm_core", "amm_core",
"anyhow", "anyhow",
"ata_core", "associated_token_account_core",
"authenticated_transfer_core", "authenticated_transfer_core",
"borsh", "borsh",
"clap", "clap",
@ -1940,9 +1977,11 @@ dependencies = [
"criterion", "criterion",
"lee", "lee",
"lee_core", "lee_core",
"programs",
"risc0-zkvm", "risc0-zkvm",
"serde", "serde",
"serde_json", "serde_json",
"test_programs",
"token_core", "token_core",
] ]
@ -2640,6 +2679,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "faucet_program"
version = "0.1.0"
dependencies = [
"authenticated_transfer_core",
"faucet_core",
"lee_core",
"vault_core",
]
[[package]] [[package]]
name = "fd-lock" name = "fd-lock"
version = "4.0.4" version = "4.0.4"
@ -3959,7 +4008,7 @@ name = "integration_tests"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ata_core", "associated_token_account_core",
"authenticated_transfer_core", "authenticated_transfer_core",
"borsh", "borsh",
"bridge_core", "bridge_core",
@ -3980,12 +4029,15 @@ dependencies = [
"logos-blockchain-key-management-system-service", "logos-blockchain-key-management-system-service",
"logos-blockchain-zone-sdk", "logos-blockchain-zone-sdk",
"num-bigint 0.4.6", "num-bigint 0.4.6",
"programs",
"reqwest", "reqwest",
"sequencer_core", "sequencer_core",
"sequencer_service_rpc", "sequencer_service_rpc",
"serde_json", "serde_json",
"system_accounts",
"tempfile", "tempfile",
"test_fixtures", "test_fixtures",
"test_programs",
"token_core", "token_core",
"tokio", "tokio",
"vault_core", "vault_core",
@ -4499,12 +4551,9 @@ name = "lee"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"authenticated_transfer_core",
"borsh", "borsh",
"bridge_core", "build_utils",
"clock_core",
"env_logger", "env_logger",
"faucet_core",
"hex", "hex",
"hex-literal 1.1.0", "hex-literal 1.1.0",
"k256", "k256",
@ -4512,13 +4561,12 @@ dependencies = [
"log", "log",
"rand 0.8.6", "rand 0.8.6",
"risc0-binfmt", "risc0-binfmt",
"risc0-build",
"risc0-zkvm", "risc0-zkvm",
"serde", "serde",
"serde_with", "serde_with",
"sha2", "sha2",
"test-case", "test-case",
"test_program_methods", "test_methods",
"thiserror 2.0.18", "thiserror 2.0.18",
"token_core", "token_core",
] ]
@ -7112,6 +7160,23 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pinata_program"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
]
[[package]]
name = "pinata_token_program"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
"token_core",
]
[[package]] [[package]]
name = "pkcs1" name = "pkcs1"
version = "0.7.5" version = "0.7.5"
@ -7265,6 +7330,14 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "privacy_preserving_circuit_program"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "3.5.0" version = "3.5.0"
@ -7366,28 +7439,22 @@ dependencies = [
"wallet", "wallet",
] ]
[[package]]
name = "program_methods"
version = "0.1.0"
dependencies = [
"risc0-build",
]
[[package]] [[package]]
name = "programs" name = "programs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"amm_core", "amm_core",
"amm_program", "amm_program",
"ata_core", "associated_token_account_core",
"ata_program", "associated_token_account_program",
"authenticated_transfer_core", "authenticated_transfer_core",
"bridge_core", "bridge_core",
"build_utils",
"clock_core", "clock_core",
"faucet_core", "faucet_core",
"lee",
"lee_core", "lee_core",
"risc0-zkvm", "risc0-zkvm",
"serde",
"token_core", "token_core",
"token_program", "token_program",
"vault_core", "vault_core",
@ -8842,14 +8909,17 @@ dependencies = [
"logos-blockchain-zone-sdk", "logos-blockchain-zone-sdk",
"mempool", "mempool",
"num-bigint 0.4.6", "num-bigint 0.4.6",
"programs",
"rand 0.8.6", "rand 0.8.6",
"risc0-zkvm", "risc0-zkvm",
"serde", "serde",
"serde_json", "serde_json",
"storage", "storage",
"system_accounts",
"tempfile", "tempfile",
"test_program_methods", "test_programs",
"testnet_initial_state", "testnet_initial_state",
"token_core",
"tokio", "tokio",
"url", "url",
"vault_core", "vault_core",
@ -8870,6 +8940,7 @@ dependencies = [
"lee", "lee",
"log", "log",
"mempool", "mempool",
"programs",
"sequencer_core", "sequencer_core",
"sequencer_service_protocol", "sequencer_service_protocol",
"sequencer_service_rpc", "sequencer_service_rpc",
@ -9388,7 +9459,9 @@ dependencies = [
"borsh", "borsh",
"common", "common",
"lee", "lee",
"programs",
"rocksdb", "rocksdb",
"system_accounts",
"tempfile", "tempfile",
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
@ -9541,6 +9614,17 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "system_accounts"
version = "0.1.0"
dependencies = [
"bridge_core",
"clock_core",
"faucet_core",
"lee_core",
"programs",
]
[[package]] [[package]]
name = "tachys" name = "tachys"
version = "0.2.15" version = "0.2.15"
@ -9663,6 +9747,7 @@ dependencies = [
"lee", "lee",
"lee_core", "lee_core",
"log", "log",
"programs",
"sequencer_core", "sequencer_core",
"sequencer_service", "sequencer_service",
"sequencer_service_rpc", "sequencer_service_rpc",
@ -9676,14 +9761,23 @@ dependencies = [
] ]
[[package]] [[package]]
name = "test_program_methods" name = "test_methods"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"risc0-build", "risc0-build",
] ]
[[package]] [[package]]
name = "test_programs" name = "test_methods_guests"
version = "0.1.0"
dependencies = [
"lee_core",
"risc0-zkvm",
"serde",
]
[[package]]
name = "test_program_guests"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"authenticated_transfer_core", "authenticated_transfer_core",
@ -9691,7 +9785,14 @@ dependencies = [
"faucet_core", "faucet_core",
"lee_core", "lee_core",
"risc0-zkvm", "risc0-zkvm",
"serde", ]
[[package]]
name = "test_programs"
version = "0.1.0"
dependencies = [
"lee",
"risc0-build",
] ]
[[package]] [[package]]
@ -9731,11 +9832,12 @@ dependencies = [
name = "testnet_initial_state" name = "testnet_initial_state"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"common",
"key_protocol", "key_protocol",
"lee", "lee",
"lee_core", "lee_core",
"programs",
"serde", "serde",
"system_accounts",
] ]
[[package]] [[package]]
@ -10693,6 +10795,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "vault_program"
version = "0.1.0"
dependencies = [
"authenticated_transfer_core",
"lee_core",
"vault_core",
]
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -10721,8 +10832,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"amm_core", "amm_core",
"anyhow", "anyhow",
"associated_token_account_core",
"async-stream", "async-stream",
"ata_core",
"authenticated_transfer_core", "authenticated_transfer_core",
"base58", "base58",
"bincode", "bincode",
@ -10744,6 +10855,7 @@ dependencies = [
"lee_core", "lee_core",
"log", "log",
"optfield", "optfield",
"programs",
"pyo3", "pyo3",
"rand 0.8.6", "rand 0.8.6",
"rpassword", "rpassword",
@ -10751,6 +10863,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"system_accounts",
"tempfile", "tempfile",
"testnet_initial_state", "testnet_initial_state",
"thiserror 2.0.18", "thiserror 2.0.18",
@ -10771,6 +10884,7 @@ dependencies = [
"key_protocol", "key_protocol",
"lee", "lee",
"lee_core", "lee_core",
"programs",
"risc0-zkvm", "risc0-zkvm",
"sequencer_service_rpc", "sequencer_service_rpc",
"serde_json", "serde_json",

View File

@ -5,25 +5,17 @@ license = "MIT or Apache-2.0"
resolver = "3" resolver = "3"
members = [ members = [
"integration_tests", "integration_tests",
"lez/storage", "lez/storage",
"lee/key_protocol", "lee/key_protocol",
"lee/state_machine", "lee/state_machine",
"lee/state_machine/core", "lee/state_machine/core",
"lez/mempool", "lee/privacy_preserving_circuit",
"lez/wallet", "lee/state_machine/test_methods",
"lez/wallet-ffi", "lee/state_machine/test_methods/guest",
"lez/common",
"programs/amm/core", "lez",
"programs/amm", "lez/system_accounts",
"programs/clock/core",
"programs/token/core",
"programs/token",
"programs/associated_token_account/core",
"programs/associated_token_account",
"programs/authenticated_transfer/core",
"programs/faucet/core",
"programs/bridge/core",
"programs/vault/core",
"lez/sequencer/core", "lez/sequencer/core",
"lez/sequencer/service", "lez/sequencer/service",
"lez/sequencer/service/protocol", "lez/sequencer/service/protocol",
@ -33,18 +25,36 @@ members = [
"lez/indexer/service/protocol", "lez/indexer/service/protocol",
"lez/indexer/service/rpc", "lez/indexer/service/rpc",
"lez/explorer_service", "lez/explorer_service",
"program_methods", "lez/testnet_initial_state",
"program_methods/guest", "lez/indexer/ffi",
"test_program_methods", "lez/keycard_wallet",
"test_program_methods/guest", "lez/mempool",
"lez/wallet",
"lez/wallet-ffi",
"lez/common",
"lez/programs",
"lez/programs/amm",
"lez/programs/associated_token_account",
"lez/programs/authenticated_transfer",
"lez/programs/bridge",
"lez/programs/clock",
"lez/programs/faucet",
"lez/programs/pinata",
"lez/programs/pinata_token",
"lez/programs/token",
"lez/programs/vault",
"test_programs",
"test_programs/guest",
"examples/program_deployment", "examples/program_deployment",
"examples/program_deployment/methods", "examples/program_deployment/methods",
"examples/program_deployment/methods/guest", "examples/program_deployment/methods/guest",
"lez/testnet_initial_state",
"lez/indexer/ffi", "build_utils",
"lez",
"lez/keycard_wallet",
"test_fixtures", "test_fixtures",
"tools/cycle_bench", "tools/cycle_bench",
"tools/crypto_primitives_bench", "tools/crypto_primitives_bench",
"tools/integration_bench", "tools/integration_bench",
@ -69,18 +79,23 @@ wallet = { path = "lez/wallet" }
wallet-ffi = { path = "lez/wallet-ffi", default-features = false } wallet-ffi = { path = "lez/wallet-ffi", default-features = false }
indexer_ffi = { path = "lez/indexer/ffi" } indexer_ffi = { path = "lez/indexer/ffi" }
lez = { path = "lez" } lez = { path = "lez" }
clock_core = { path = "programs/clock/core" } programs = { path = "lez/programs", default-features = false, features = [
token_core = { path = "programs/token/core" } "artifacts",
token_program = { path = "programs/token" } ] }
amm_core = { path = "programs/amm/core" } system_accounts = { path = "lez/system_accounts" }
amm_program = { path = "programs/amm" } clock_core = { path = "lez/programs/clock/core" }
ata_core = { path = "programs/associated_token_account/core" } token_core = { path = "lez/programs/token/core" }
ata_program = { path = "programs/associated_token_account" } token_program = { path = "lez/programs/token" }
authenticated_transfer_core = { path = "programs/authenticated_transfer/core" } amm_core = { path = "lez/programs/amm/core" }
faucet_core = { path = "programs/faucet/core" } amm_program = { path = "lez/programs/amm" }
bridge_core = { path = "programs/bridge/core" } associated_token_account_core = { path = "lez/programs/associated_token_account/core" }
vault_core = { path = "programs/vault/core" } ata_program = { path = "lez/programs/associated_token_account" }
test_program_methods = { path = "test_program_methods" } authenticated_transfer_core = { path = "lez/programs/authenticated_transfer/core" }
faucet_core = { path = "lez/programs/faucet/core" }
bridge_core = { path = "lez/programs/bridge/core" }
vault_core = { path = "lez/programs/vault/core" }
build_utils = { path = "build_utils" }
test_programs = { path = "test_programs" }
testnet_initial_state = { path = "lez/testnet_initial_state" } testnet_initial_state = { path = "lez/testnet_initial_state" }
keycard_wallet = { path = "lez/keycard_wallet" } keycard_wallet = { path = "lez/keycard_wallet" }
test_fixtures = { path = "test_fixtures" } test_fixtures = { path = "test_fixtures" }

View File

@ -4,19 +4,25 @@ default:
@just --list @just --list
# ---- Configuration ---- # ---- Configuration ----
METHODS_PATH := "program_methods"
TEST_METHODS_PATH := "test_program_methods"
ARTIFACTS := "artifacts" ARTIFACTS := "artifacts"
# Build risc0 program artifacts. # Build risc0 program artifacts.
build-artifacts: build-artifacts:
@echo "🔨 Building artifacts" @echo "🔨 Building artifacts"
@for methods_path in {{METHODS_PATH}} {{TEST_METHODS_PATH}}; do \ @rm -rf {{ARTIFACTS}}
echo "Building artifacts for $methods_path"; \ @just build-artifact lee/privacy_preserving_circuit
CARGO_TARGET_DIR=target/$methods_path cargo risczero build --manifest-path $methods_path/guest/Cargo.toml; \ @just build-artifact lez/programs programs
mkdir -p {{ARTIFACTS}}/$methods_path; \
cp target/$methods_path/riscv32im-risc0-zkvm-elf/docker/*.bin {{ARTIFACTS}}/$methods_path; \ build-artifact methods_path features="":
done @echo "Building artifacts for {{methods_path}}"
@rm -rf target/{{methods_path}}/riscv32im-risc0-zkvm-elf/docker/*.bin
@if [ "{{features}}" = "" ]; then \
CARGO_TARGET_DIR=target/{{methods_path}} cargo risczero build --manifest-path {{methods_path}}/Cargo.toml; \
else \
CARGO_TARGET_DIR=target/{{methods_path}} cargo risczero build --no-default-features --features {{features}} --manifest-path {{methods_path}}/Cargo.toml; \
fi
@mkdir -p {{ARTIFACTS}}/{{methods_path}}
@cp target/{{methods_path}}/riscv32im-risc0-zkvm-elf/docker/*.bin {{ARTIFACTS}}/{{methods_path}}
# Format codebase. # Format codebase.
fmt: fmt:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

11
build_utils/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "build_utils"
version = "0.1.0"
edition = "2024"
license = { workspace = true }
[lints]
[dependencies]
anyhow.workspace = true
risc0-binfmt = "3.0.2"

69
build_utils/src/lib.rs Normal file
View File

@ -0,0 +1,69 @@
//! Utilities for build-scripts.
use std::{env, fmt::Write as _, fs, path::PathBuf};
use anyhow::{Context as _, Result, bail};
/// Include artifact binaries as byte arrays and their corresponding image IDs as u32 arrays in a
/// generated Rust module.
///
/// The `artifacts_sub_dir` parameter specifies the subdirectory under `artifacts/`.
///
/// Caller should include resulting module as follows:
///
/// ```
/// mod guests {
/// include!(concat!(env!("OUT_DIR"), "/artifacts_sub_dir/mod.rs"));
/// }
/// ```
pub fn include_artifacts(artifacts_sub_dir: &str) -> Result<()> {
let manifest_dir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR"));
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
let mod_dir = out_dir.join(artifacts_sub_dir);
let mod_file = mod_dir.join("mod.rs");
let artifacts_dir = manifest_dir.join(format!("../artifacts/{artifacts_sub_dir}/"));
println!("cargo:rerun-if-changed={}", artifacts_dir.display());
let bins = fs::read_dir(&artifacts_dir)
.with_context(|| {
format!(
"Failed to read {} artifacts directory",
artifacts_dir.display()
)
})?
.filter_map(Result::ok)
.filter(|e| e.path().extension().is_some_and(|ext| ext == "bin"))
.collect::<Vec<_>>();
if bins.is_empty() {
bail!("No .bin files found in {}", artifacts_dir.display());
}
fs::create_dir_all(&mod_dir)
.with_context(|| format!("Failed to create directory {}", mod_dir.display()))?;
let mut src = String::new();
for entry in bins {
let path = entry.path();
let name = path.file_stem().unwrap().to_string_lossy();
let bytecode =
fs::read(&path).with_context(|| format!("Failed to read {}", path.display()))?;
let image_id: [u32; 8] = risc0_binfmt::compute_image_id(&bytecode)
.with_context(|| format!("Failed to compute image ID for {}", path.display()))?
.into();
write!(
src,
"pub const {}_ELF: &[u8] = include_bytes!(r#\"{}\"#);\n\
#[expect(clippy::unreadable_literal, reason = \"Generated image IDs from risc0 are cryptographic hashes represented as u32 arrays\")]\n\
pub const {}_ID: [u32; 8] = {:?};\n",
name.to_uppercase(),
path.display(),
name.to_uppercase(),
image_id
)?;
}
fs::write(&mod_file, src).with_context(|| format!("Failed to write {}", mod_file.display()))?;
println!("cargo:warning=Generated module at {}", mod_file.display());
Ok(())
}

View File

@ -46,7 +46,7 @@ export EXAMPLE_PROGRAMS_BUILD_DIR=$(pwd)/target/riscv32im-risc0-zkvm-elf/docker
> [!IMPORTANT] > [!IMPORTANT]
> **All remaining commands must be run from the `examples/program_deployment` directory.** > **All remaining commands must be run from the `examples/program_deployment` directory.**
# 3. Hello world example # 3. Hello world example
The Hello world program reads an arbitrary sequence of bytes from its instruction and appends them to the data field of the input account. The Hello world program reads an arbitrary sequence of bytes from its instruction and appends them to the data field of the input account.
Execution succeeds only if the account is: Execution succeeds only if the account is:
@ -211,7 +211,7 @@ This is the account that the program will claim and write data into.
### 3. Loading the program bytecode ### 3. Loading the program bytecode
```rust ```rust
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
``` ```
The Risc0 ELF is read from disk and wrapped in a Program object, which can be used to compute the program ID. The ID is used by the node to identify which program is invoked by the transaction. The Risc0 ELF is read from disk and wrapped in a Program object, which can be used to compute the program ID. The ID is used by the node to identify which program is invoked by the transaction.
@ -266,7 +266,7 @@ The relevant part for this tutorial is the account id `7EDHyxejuynBpmbLuiEym9HMU
> [!NOTE] > [!NOTE]
> As with public accounts, you can use the `--label` option to assign a label: `wallet account new private --label "my-private-account"`. > As with public accounts, you can use the `--label` option to assign a label: `wallet account new private --label "my-private-account"`.
You can check it's uninitialized with You can check it's uninitialized with
```bash ```bash
wallet account get --account-id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr wallet account get --account-id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr
@ -452,7 +452,7 @@ Because these operations may involve multiple accounts, we'll see how public and
> See `methods/guest/src/bin/hello_world_with_move_function.rs`. The program just reads the instruction bytes and updates the accounts state. > See `methods/guest/src/bin/hello_world_with_move_function.rs`. The program just reads the instruction bytes and updates the accounts state.
> All privacy handling happens on the runner side. When constructing the transaction, the runner decides which accounts are public or private and prepares the appropriate proofs. The program itself can't differentiate between privacy modes. > All privacy handling happens on the runner side. When constructing the transaction, the runner decides which accounts are public or private and prepares the appropriate proofs. The program itself can't differentiate between privacy modes.
Let's start by deploying the program Let's start by deploying the program
```bash ```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin
``` ```
@ -486,7 +486,7 @@ Output:
Generated new account with account_id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU at path /1 Generated new account with account_id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU at path /1
``` ```
Let's execute the write function Let's execute the write function
```bash ```bash
cargo run --bin run_hello_world_with_move_function \ cargo run --bin run_hello_world_with_move_function \

View File

@ -43,7 +43,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
// Define the desired greeting in ASCII // Define the desired greeting in ASCII
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];

View File

@ -39,7 +39,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
// Define the desired greeting in ASCII // Define the desired greeting in ASCII
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];

View File

@ -43,7 +43,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
let instruction_data = (); let instruction_data = ();
let nonces = vec![]; let nonces = vec![];

View File

@ -44,9 +44,9 @@ async fn main() {
// Load the program and its dependencies (the hellow world program) // Load the program and its dependencies (the hellow world program)
let simple_tail_call_bytecode: Vec<u8> = std::fs::read(simple_tail_call_path).unwrap(); let simple_tail_call_bytecode: Vec<u8> = std::fs::read(simple_tail_call_path).unwrap();
let simple_tail_call = Program::new(simple_tail_call_bytecode).unwrap(); let simple_tail_call = Program::new(simple_tail_call_bytecode.into()).unwrap();
let hello_world_bytecode: Vec<u8> = std::fs::read(hello_world_path).unwrap(); let hello_world_bytecode: Vec<u8> = std::fs::read(hello_world_path).unwrap();
let hello_world = Program::new(hello_world_bytecode).unwrap(); let hello_world = Program::new(hello_world_bytecode.into()).unwrap();
let dependencies: HashMap<ProgramId, Program> = let dependencies: HashMap<ProgramId, Program> =
std::iter::once((hello_world.id(), hello_world)).collect(); std::iter::once((hello_world.id(), hello_world)).collect();
let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies); let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies);

View File

@ -45,7 +45,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
// Load signing keys to provide authorization // Load signing keys to provide authorization
let signing_key = wallet_core let signing_key = wallet_core

View File

@ -43,7 +43,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
// Compute the PDA to pass it as input account to the public execution // Compute the PDA to pass it as input account to the public execution
let pda = AccountId::for_public_pda(&program.id(), &PDA_SEED); let pda = AccountId::for_public_pda(&program.id(), &PDA_SEED);

View File

@ -63,7 +63,7 @@ async fn main() {
// Load the program // Load the program
let bytecode: Vec<u8> = std::fs::read(cli.program_path).unwrap(); let bytecode: Vec<u8> = std::fs::read(cli.program_path).unwrap();
let program = Program::new(bytecode).unwrap(); let program = Program::new(bytecode.into()).unwrap();
// Initialize wallet // Initialize wallet
let wallet_core = WalletCore::from_env().unwrap(); let wallet_core = WalletCore::from_env().unwrap();

View File

@ -9,7 +9,6 @@ workspace = true
[dependencies] [dependencies]
test_fixtures.workspace = true test_fixtures.workspace = true
lee_core = { workspace = true, features = ["host"] } lee_core = { workspace = true, features = ["host"] }
lee.workspace = true lee.workspace = true
authenticated_transfer_core.workspace = true authenticated_transfer_core.workspace = true
@ -19,7 +18,7 @@ common.workspace = true
key_protocol.workspace = true key_protocol.workspace = true
serde_json.workspace = true serde_json.workspace = true
token_core.workspace = true token_core.workspace = true
ata_core.workspace = true associated_token_account_core.workspace = true
vault_core.workspace = true vault_core.workspace = true
faucet_core.workspace = true faucet_core.workspace = true
bridge_core.workspace = true bridge_core.workspace = true
@ -28,6 +27,9 @@ sequencer_service_rpc = { workspace = true, features = ["client"] }
wallet-ffi.workspace = true wallet-ffi.workspace = true
indexer_ffi.workspace = true indexer_ffi.workspace = true
indexer_service_protocol.workspace = true indexer_service_protocol.workspace = true
system_accounts.workspace = true
programs.workspace = true
test_programs.workspace = true
logos-blockchain-http-api-common.workspace = true logos-blockchain-http-api-common.workspace = true
logos-blockchain-core.workspace = true logos-blockchain-core.workspace = true

View File

@ -10,7 +10,7 @@ use log::info;
pub use test_fixtures::*; pub use test_fixtures::*;
/// Maximum time to wait for the indexer to catch up to the sequencer. /// Maximum time to wait for the indexer to catch up to the sequencer.
pub const L2_TO_L1_TIMEOUT: Duration = Duration::from_mins(6); pub const L2_TO_L1_TIMEOUT: Duration = Duration::from_mins(7);
/// Poll the indexer until its last finalized block id reaches the sequencer's /// Poll the indexer until its last finalized block id reaches the sequencer's
/// current last block id or until [`L2_TO_L1_TIMEOUT`] elapses. /// current last block id or until [`L2_TO_L1_TIMEOUT`] elapses.

View File

@ -6,7 +6,7 @@
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use integration_tests::{TestContext, private_mention}; use integration_tests::{TestContext, private_mention};
use key_protocol::key_management::KeyChain; use key_protocol::key_management::KeyChain;
use lee::{Data, program::Program}; use lee::Data;
use lee_core::account::Nonce; use lee_core::account::Nonce;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
@ -31,7 +31,7 @@ async fn get_existing_account() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(account.balance, 10000); assert_eq!(account.balance, 10000);
assert!(account.data.is_empty()); assert!(account.data.is_empty());
@ -158,7 +158,7 @@ async fn import_private_account() -> Result<()> {
let key_chain = KeyChain::new_os_random(); let key_chain = KeyChain::new_os_random();
let account_id = lee::AccountId::from((&key_chain.nullifier_public_key, 0)); let account_id = lee::AccountId::from((&key_chain.nullifier_public_key, 0));
let account = lee::Account { let account = lee::Account {
program_owner: Program::authenticated_transfer_program().id(), program_owner: programs::authenticated_transfer().id(),
balance: 777, balance: 777,
data: Data::default(), data: Data::default(),
nonce: Nonce::default(), nonce: Nonce::default(),
@ -218,7 +218,7 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<(
serde_json::to_string(&key_chain).context("Failed to serialize key chain")?; serde_json::to_string(&key_chain).context("Failed to serialize key chain")?;
let initial_account = lee::Account { let initial_account = lee::Account {
program_owner: Program::authenticated_transfer_program().id(), program_owner: programs::authenticated_transfer().id(),
balance: 100, balance: 100,
data: Data::default(), data: Data::default(),
nonce: Nonce::default(), nonce: Nonce::default(),
@ -237,7 +237,7 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<(
.await?; .await?;
let updated_account = lee::Account { let updated_account = lee::Account {
program_owner: Program::authenticated_transfer_program().id(), program_owner: programs::authenticated_transfer().id(),
balance: 999, balance: 999,
data: Data::default(), data: Data::default(),
nonce: Nonce::default(), nonce: Nonce::default(),

View File

@ -7,12 +7,11 @@
use std::time::Duration; use std::time::Duration;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use ata_core::{compute_ata_seed, get_associated_token_account_id}; use associated_token_account_core::{compute_ata_seed, get_associated_token_account_id};
use integration_tests::{ use integration_tests::{
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention,
verify_commitment_is_in_state, verify_commitment_is_in_state,
}; };
use lee::program::Program;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use token_core::{TokenDefinition, TokenHolding}; use token_core::{TokenDefinition, TokenHolding};
@ -93,7 +92,7 @@ async fn create_ata_initializes_holding_account() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Derive expected ATA address and check on-chain state // Derive expected ATA address and check on-chain state
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let ata_id = get_associated_token_account_id( let ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(owner_account_id, definition_account_id), &compute_ata_seed(owner_account_id, definition_account_id),
@ -105,7 +104,7 @@ async fn create_ata_initializes_holding_account() -> Result<()> {
.await .await
.context("ATA account not found")?; .context("ATA account not found")?;
assert_eq!(ata_acc.program_owner, Program::token().id()); assert_eq!(ata_acc.program_owner, programs::token().id());
let holding = TokenHolding::try_from(&ata_acc.data)?; let holding = TokenHolding::try_from(&ata_acc.data)?;
assert_eq!( assert_eq!(
holding, holding,
@ -168,7 +167,7 @@ async fn create_ata_is_idempotent() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// State must be unchanged // State must be unchanged
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let ata_id = get_associated_token_account_id( let ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(owner_account_id, definition_account_id), &compute_ata_seed(owner_account_id, definition_account_id),
@ -180,7 +179,7 @@ async fn create_ata_is_idempotent() -> Result<()> {
.await .await
.context("ATA account not found")?; .context("ATA account not found")?;
assert_eq!(ata_acc.program_owner, Program::token().id()); assert_eq!(ata_acc.program_owner, programs::token().id());
let holding = TokenHolding::try_from(&ata_acc.data)?; let holding = TokenHolding::try_from(&ata_acc.data)?;
assert_eq!( assert_eq!(
holding, holding,
@ -220,7 +219,7 @@ async fn transfer_and_burn_via_ata() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Derive ATA addresses // Derive ATA addresses
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let sender_ata_id = get_associated_token_account_id( let sender_ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(sender_account_id, definition_account_id), &compute_ata_seed(sender_account_id, definition_account_id),
@ -389,7 +388,7 @@ async fn create_ata_with_private_owner() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Derive expected ATA address and check on-chain state // Derive expected ATA address and check on-chain state
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let ata_id = get_associated_token_account_id( let ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(owner_account_id, definition_account_id), &compute_ata_seed(owner_account_id, definition_account_id),
@ -401,7 +400,7 @@ async fn create_ata_with_private_owner() -> Result<()> {
.await .await
.context("ATA account not found")?; .context("ATA account not found")?;
assert_eq!(ata_acc.program_owner, Program::token().id()); assert_eq!(ata_acc.program_owner, programs::token().id());
let holding = TokenHolding::try_from(&ata_acc.data)?; let holding = TokenHolding::try_from(&ata_acc.data)?;
assert_eq!( assert_eq!(
holding, holding,
@ -448,7 +447,7 @@ async fn transfer_via_ata_private_owner() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Derive ATA addresses // Derive ATA addresses
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let sender_ata_id = get_associated_token_account_id( let sender_ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(sender_account_id, definition_account_id), &compute_ata_seed(sender_account_id, definition_account_id),
@ -572,7 +571,7 @@ async fn burn_via_ata_private_owner() -> Result<()> {
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// Derive holder's ATA address // Derive holder's ATA address
let ata_program_id = Program::ata().id(); let ata_program_id = programs::ata().id();
let holder_ata_id = get_associated_token_account_id( let holder_ata_id = get_associated_token_account_id(
&ata_program_id, &ata_program_id,
&compute_ata_seed(holder_account_id, definition_account_id), &compute_ata_seed(holder_account_id, definition_account_id),

View File

@ -429,7 +429,7 @@ async fn initialize_private_account() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(account.balance, 0); assert_eq!(account.balance, 0);
assert!(account.data.is_empty()); assert!(account.data.is_empty());
@ -526,7 +526,7 @@ async fn initialize_private_account_using_label() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
info!("Successfully initialized private account using label"); info!("Successfully initialized private account using label");
@ -646,23 +646,20 @@ async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> {
async fn ppt_cant_chain_call_faucet() -> Result<()> { async fn ppt_cant_chain_call_faucet() -> Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let binary = std::fs::read( let faucet_chain_caller = test_programs::faucet_chain_caller();
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../artifacts/test_program_methods/faucet_chain_caller.bin"),
)?;
let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(binary.clone()), lee::program_deployment_transaction::Message::new(faucet_chain_caller.elf().to_owned()),
)); ));
ctx.sequencer_client().send_transaction(deploy_tx).await?; ctx.sequencer_client().send_transaction(deploy_tx).await?;
info!("Waiting for deploy block creation"); info!("Waiting for deploy block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let faucet_account_id = lee::system_faucet_account_id(); let faucet_account_id = system_accounts::faucet_account_id();
let attacker_id = ctx.existing_public_accounts()[0]; let attacker_id = ctx.existing_public_accounts()[0];
let faucet_program_id = Program::faucet().id(); let faucet_program_id = programs::faucet().id();
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let auth_transfer_program_id = Program::authenticated_transfer_program().id(); let auth_transfer_program_id = programs::authenticated_transfer().id();
let nsk: lee_core::NullifierSecretKey = [3; 32]; let nsk: lee_core::NullifierSecretKey = [3; 32];
let npk = NullifierPublicKey::from(&nsk); let npk = NullifierPublicKey::from(&nsk);
let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap(); let vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap();
@ -689,16 +686,12 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> {
attacker_vault_id, attacker_vault_id,
); );
let faucet_chain_caller = Program::new(binary)?;
let program_with_deps = ProgramWithDependencies::new( let program_with_deps = ProgramWithDependencies::new(
faucet_chain_caller, faucet_chain_caller,
[ [
(faucet_program_id, Program::faucet()), (faucet_program_id, programs::faucet()),
(vault_program_id, Program::vault()), (vault_program_id, programs::vault()),
( (auth_transfer_program_id, programs::authenticated_transfer()),
auth_transfer_program_id,
Program::authenticated_transfer_program(),
),
] ]
.into(), .into(),
); );

View File

@ -1,9 +1,9 @@
use std::{path::PathBuf, time::Duration}; use std::time::Duration;
use anyhow::Result; use anyhow::Result;
use common::transaction::LeeTransaction; use common::transaction::LeeTransaction;
use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, public_mention}; use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, public_mention};
use lee::{program::Program, public_transaction, system_faucet_account_id}; use lee::public_transaction;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use tokio::test; use tokio::test;
@ -250,7 +250,7 @@ async fn initialize_public_account() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(account.balance, 0); assert_eq!(account.balance, 0);
assert_eq!(account.nonce.0, 1); assert_eq!(account.nonce.0, 1);
@ -356,7 +356,7 @@ async fn successful_transfer_using_to_label() -> Result<()> {
#[test] #[test]
async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let faucet_account_id = system_faucet_account_id(); let faucet_account_id = system_accounts::faucet_account_id();
let recipient = ctx.existing_public_accounts()[0]; let recipient = ctx.existing_public_accounts()[0];
let recipient_balance_before = ctx let recipient_balance_before = ctx
@ -370,7 +370,7 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> {
let amount = 1_u128; let amount = 1_u128;
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
Program::authenticated_transfer_program().id(), programs::authenticated_transfer().id(),
vec![faucet_account_id, recipient], vec![faucet_account_id, recipient],
vec![], vec![],
authenticated_transfer_core::Instruction::Transfer { amount }, authenticated_transfer_core::Instruction::Transfer { amount },
@ -407,10 +407,10 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> {
#[test] #[test]
async fn cannot_execute_faucet_program() -> Result<()> { async fn cannot_execute_faucet_program() -> Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let faucet_account_id = system_faucet_account_id(); let faucet_account_id = system_accounts::faucet_account_id();
let recipient = ctx.existing_public_accounts()[0]; let recipient = ctx.existing_public_accounts()[0];
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient);
let recipient_balance_before = ctx let recipient_balance_before = ctx
@ -424,7 +424,7 @@ async fn cannot_execute_faucet_program() -> Result<()> {
let amount = 1_u128; let amount = 1_u128;
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
Program::faucet().id(), programs::faucet().id(),
vec![faucet_account_id, recipient_vault_id], vec![faucet_account_id, recipient_vault_id],
vec![], vec![],
faucet_core::Instruction::GenesisTransferVault { faucet_core::Instruction::GenesisTransferVault {
@ -466,28 +466,24 @@ async fn cannot_execute_faucet_program() -> Result<()> {
async fn user_tx_that_chain_calls_faucet_is_dropped() -> Result<()> { async fn user_tx_that_chain_calls_faucet_is_dropped() -> Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let binary = std::fs::read( let faucet_chain_caller = test_programs::faucet_chain_caller();
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../artifacts/test_program_methods/faucet_chain_caller.bin"),
)?;
let faucet_chain_caller_id = Program::new(binary.clone())?.id();
let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(binary), lee::program_deployment_transaction::Message::new(faucet_chain_caller.elf().to_owned()),
)); ));
ctx.sequencer_client().send_transaction(deploy_tx).await?; ctx.sequencer_client().send_transaction(deploy_tx).await?;
info!("Waiting for deploy block creation"); info!("Waiting for deploy block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let faucet_account_id = system_faucet_account_id(); let faucet_account_id = system_accounts::faucet_account_id();
let attacker = ctx.existing_public_accounts()[0]; let attacker = ctx.existing_public_accounts()[0];
let faucet_program_id = Program::faucet().id(); let faucet_program_id = programs::faucet().id();
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let attacker_vault_id = vault_core::compute_vault_account_id(vault_program_id, attacker); let attacker_vault_id = vault_core::compute_vault_account_id(vault_program_id, attacker);
let amount: u128 = 1; let amount: u128 = 1;
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
faucet_chain_caller_id, faucet_chain_caller.id(),
vec![faucet_account_id, attacker_vault_id], vec![faucet_account_id, attacker_vault_id],
vec![], vec![],
(faucet_program_id, vault_program_id, attacker, amount), (faucet_program_id, vault_program_id, attacker, amount),

View File

@ -94,16 +94,12 @@ async fn accept_transaction_within_limit() -> Result<()> {
#[test] #[test]
async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
let manifest_dir = env!("CARGO_MANIFEST_DIR"); let claimer = test_programs::claimer();
let artifacts_dir = let chain_caller = test_programs::chain_caller();
std::path::PathBuf::from(manifest_dir).join("../artifacts/test_program_methods");
let burner_bytecode = std::fs::read(artifacts_dir.join("burner.bin"))?;
let chain_caller_bytecode = std::fs::read(artifacts_dir.join("chain_caller.bin"))?;
// Calculate block size to fit only one of the two transactions, leaving some room for headers // Calculate block size to fit only one of the two transactions, leaving some room for headers
// (e.g., 10 KiB) // (e.g., 10 KiB)
let max_program_size = burner_bytecode.len().max(chain_caller_bytecode.len()); let max_program_size = claimer.elf().len().max(chain_caller.elf().len());
let block_size = ByteSize::b((max_program_size + 10 * 1024) as u64); let block_size = ByteSize::b((max_program_size + 10 * 1024) as u64);
let ctx = TestContext::builder() let ctx = TestContext::builder()
@ -116,16 +112,13 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
.build() .build()
.await?; .await?;
let burner_id = Program::new(burner_bytecode.clone())?.id();
let chain_caller_id = Program::new(chain_caller_bytecode.clone())?.id();
let initial_block_height = ctx.sequencer_client().get_last_block_id().await?; let initial_block_height = ctx.sequencer_client().get_last_block_id().await?;
// Submit both program deployments // Submit both program deployments
ctx.sequencer_client() ctx.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment( .send_transaction(LeeTransaction::ProgramDeployment(
lee::ProgramDeploymentTransaction::new( lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(burner_bytecode), lee::program_deployment_transaction::Message::new(claimer.elf().to_owned()),
), ),
)) ))
.await?; .await?;
@ -133,7 +126,7 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
ctx.sequencer_client() ctx.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment( .send_transaction(LeeTransaction::ProgramDeployment(
lee::ProgramDeploymentTransaction::new( lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(chain_caller_bytecode), lee::program_deployment_transaction::Message::new(chain_caller.elf().to_owned()),
), ),
)) ))
.await?; .await?;
@ -156,7 +149,7 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
.filter_map(|tx| { .filter_map(|tx| {
if let LeeTransaction::ProgramDeployment(deployment) = tx { if let LeeTransaction::ProgramDeployment(deployment) = tx {
let bytecode = deployment.message.clone().into_bytecode(); let bytecode = deployment.message.clone().into_bytecode();
Program::new(bytecode).ok().map(|p| p.id()) Program::new(bytecode.into()).ok().map(|p| p.id())
} else { } else {
None None
} }
@ -173,8 +166,9 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
"Expected exactly one program deployment in block 1" "Expected exactly one program deployment in block 1"
); );
assert_eq!( assert_eq!(
block1_program_ids[0], burner_id, block1_program_ids[0],
"Expected burner program to be deployed in block 1" claimer.id(),
"Expected claimer program to be deployed in block 1"
); );
// Wait for second block // Wait for second block
@ -194,7 +188,8 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
"Expected exactly one program deployment in block 2" "Expected exactly one program deployment in block 2"
); );
assert_eq!( assert_eq!(
block2_program_ids[0], chain_caller_id, block2_program_ids[0],
chain_caller.id(),
"Expected chain_caller program to be deployed in block 2" "Expected chain_caller program to be deployed in block 2"
); );

View File

@ -43,12 +43,12 @@ async fn public_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let recipient_id = ctx.existing_public_accounts()[0]; let recipient_id = ctx.existing_public_accounts()[0];
let bridge_account_id = lee::system_bridge_account_id(); let bridge_account_id = system_accounts::bridge_account_id();
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id);
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
Program::bridge().id(), programs::bridge().id(),
vec![bridge_account_id, recipient_vault_id], vec![bridge_account_id, recipient_vault_id],
vec![], vec![],
bridge_core::Instruction::Deposit { bridge_core::Instruction::Deposit {
@ -103,8 +103,8 @@ async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> {
let ctx = TestContext::new().await?; let ctx = TestContext::new().await?;
let recipient_id = ctx.existing_public_accounts()[0]; let recipient_id = ctx.existing_public_accounts()[0];
let bridge_account_id = lee::system_bridge_account_id(); let bridge_account_id = system_accounts::bridge_account_id();
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id);
// Get pre-state of bridge and vault accounts // Get pre-state of bridge and vault accounts
@ -126,12 +126,12 @@ async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> {
// Create program with dependencies // Create program with dependencies
let program_with_deps = let program_with_deps =
lee::privacy_preserving_transaction::circuit::ProgramWithDependencies::new( lee::privacy_preserving_transaction::circuit::ProgramWithDependencies::new(
Program::bridge(), programs::bridge(),
[ [
(vault_program_id, Program::vault()), (vault_program_id, programs::vault()),
( (
Program::authenticated_transfer_program().id(), programs::authenticated_transfer().id(),
Program::authenticated_transfer_program(), programs::authenticated_transfer(),
), ),
] ]
.into(), .into(),
@ -386,7 +386,7 @@ async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Res
let bedrock_account_pk = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"; let bedrock_account_pk = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26";
let recipient_id = ctx.existing_public_accounts()[0]; let recipient_id = ctx.existing_public_accounts()[0];
let amount = 1_u64; let amount = 1_u64;
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id);
let vault_balance_before = ctx let vault_balance_before = ctx
@ -474,7 +474,7 @@ async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Res
// state as the sequencer — including the bridge system account the deposit // state as the sequencer — including the bridge system account the deposit
// modifies, which is the case the hot fix unblocks. // modifies, which is the case the hot fix unblocks.
wait_for_indexer_to_catch_up(&ctx).await?; wait_for_indexer_to_catch_up(&ctx).await?;
let bridge_account_id = lee::system_bridge_account_id(); let bridge_account_id = system_accounts::bridge_account_id();
for account_id in [recipient_id, recipient_vault_id, bridge_account_id] { for account_id in [recipient_id, recipient_vault_id, bridge_account_id] {
let indexer_account = indexer_service_rpc::RpcClient::get_account( let indexer_account = indexer_service_rpc::RpcClient::get_account(
// `deref` is needed for correct trait resolution // `deref` is needed for correct trait resolution

View File

@ -12,7 +12,7 @@ use integration_tests::{
public_mention, verify_commitment_is_in_state, public_mention, verify_commitment_is_in_state,
}; };
use key_protocol::key_management::key_tree::chain_index::ChainIndex; use key_protocol::key_management::key_tree::chain_index::ChainIndex;
use lee::{AccountId, program::Program}; use lee::AccountId;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use tokio::test; use tokio::test;
@ -257,11 +257,11 @@ async fn restore_keys_from_seed() -> Result<()> {
assert_eq!( assert_eq!(
acc1.account.program_owner, acc1.account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!( assert_eq!(
acc2.account.program_owner, acc2.account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(acc1.account.balance, 100); assert_eq!(acc1.account.balance, 100);

View File

@ -7,7 +7,6 @@
use std::time::Duration; use std::time::Duration;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use common::PINATA_BASE58;
use integration_tests::{ use integration_tests::{
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention,
verify_commitment_is_in_state, verify_commitment_is_in_state,
@ -44,7 +43,7 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()>
let pinata_balance_pre = ctx let pinata_balance_pre = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
let claim_result = wallet::cli::execute_subcommand( let claim_result = wallet::cli::execute_subcommand(
@ -67,7 +66,7 @@ async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()>
let pinata_balance_post = ctx let pinata_balance_post = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
assert_eq!(pinata_balance_post, pinata_balance_pre); assert_eq!(pinata_balance_post, pinata_balance_pre);
@ -96,7 +95,7 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<()
let pinata_balance_pre = ctx let pinata_balance_pre = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
let claim_result = wallet::cli::execute_subcommand( let claim_result = wallet::cli::execute_subcommand(
@ -119,7 +118,7 @@ async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<()
let pinata_balance_post = ctx let pinata_balance_post = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
assert_eq!(pinata_balance_post, pinata_balance_pre); assert_eq!(pinata_balance_post, pinata_balance_pre);
@ -138,7 +137,7 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> {
let pinata_balance_pre = ctx let pinata_balance_pre = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -149,7 +148,7 @@ async fn claim_pinata_to_existing_public_account() -> Result<()> {
info!("Checking correct balance move"); info!("Checking correct balance move");
let pinata_balance_post = ctx let pinata_balance_post = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
let winner_balance_post = ctx let winner_balance_post = ctx
@ -176,7 +175,7 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> {
let pinata_balance_pre = ctx let pinata_balance_pre = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -199,7 +198,7 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> {
let pinata_balance_post = ctx let pinata_balance_post = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);
@ -253,7 +252,7 @@ async fn claim_pinata_to_new_private_account() -> Result<()> {
let pinata_balance_pre = ctx let pinata_balance_pre = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -269,7 +268,7 @@ async fn claim_pinata_to_new_private_account() -> Result<()> {
let pinata_balance_post = ctx let pinata_balance_post = ctx
.sequencer_client() .sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap()) .get_account_balance(system_accounts::pinata_account_id())
.await?; .await?;
assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize);

View File

@ -3,14 +3,13 @@
reason = "We don't care about these in tests" reason = "We don't care about these in tests"
)] )]
use std::{path::PathBuf, time::Duration}; use std::time::Duration;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use authenticated_transfer_core::Instruction as AuthTransferInstruction; use authenticated_transfer_core::Instruction as AuthTransferInstruction;
use common::transaction::LeeTransaction; use common::transaction::LeeTransaction;
use integration_tests::{ use integration_tests::{
LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, verify_commitment_is_in_state,
verify_commitment_is_in_state,
}; };
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
use lee::{ use lee::{
@ -165,14 +164,8 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> {
(kc.nullifier_public_key, kc.viewing_public_key.clone()) (kc.nullifier_public_key, kc.viewing_public_key.clone())
}; };
let proxy = { let proxy = test_programs::pda_spend_proxy();
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) let auth_transfer = programs::authenticated_transfer();
.join("../artifacts/test_program_methods")
.join(LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY);
Program::new(std::fs::read(&path).with_context(|| format!("reading {path:?}"))?)
.context("invalid pda_spend_proxy binary")?
};
let auth_transfer = Program::authenticated_transfer_program();
let proxy_id = proxy.id(); let proxy_id = proxy.id();
let auth_transfer_id = auth_transfer.id(); let auth_transfer_id = auth_transfer.id();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);

View File

@ -3,14 +3,11 @@
reason = "We don't care about these in tests" reason = "We don't care about these in tests"
)] )]
use std::{path::PathBuf, time::Duration}; use std::{io::Write as _, time::Duration};
use anyhow::Result; use anyhow::Result;
use common::transaction::LeeTransaction; use common::transaction::LeeTransaction;
use integration_tests::{ use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext};
LEE_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext,
};
use lee::program::Program;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use tokio::test; use tokio::test;
@ -23,10 +20,11 @@ use wallet::cli::{
async fn deploy_and_execute_program() -> Result<()> { async fn deploy_and_execute_program() -> Result<()> {
let mut ctx = TestContext::new().await?; let mut ctx = TestContext::new().await?;
let manifest_dir = env!("CARGO_MANIFEST_DIR"); let claimer = test_programs::claimer();
let binary_filepath: PathBuf = PathBuf::from(manifest_dir) let mut tempfile = tempfile::NamedTempFile::new()?;
.join("../artifacts/test_program_methods") tempfile.write_all(claimer.elf())?;
.join(LEE_PROGRAM_FOR_TEST_DATA_CHANGER);
let binary_filepath = tempfile.path().to_owned();
let command = Command::DeployProgram { let command = Command::DeployProgram {
binary_filepath: binary_filepath.clone(), binary_filepath: binary_filepath.clone(),
@ -37,13 +35,6 @@ async fn deploy_and_execute_program() -> Result<()> {
info!("Waiting for next block creation"); info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// The program is the data changer and takes one account as input.
// We pass an uninitialized account and we expect after execution to be owned by the data
// changer program (LEE account claiming mechanism) with data equal to [0] (due to program
// logic)
let bytecode = std::fs::read(binary_filepath)?;
let data_changer = Program::new(bytecode)?;
let SubcommandReturnValue::RegisterAccount { account_id } = wallet::cli::execute_subcommand( let SubcommandReturnValue::RegisterAccount { account_id } = wallet::cli::execute_subcommand(
ctx.wallet_mut(), ctx.wallet_mut(),
Command::Account(AccountSubcommand::New(NewSubcommand::Public { Command::Account(AccountSubcommand::New(NewSubcommand::Public {
@ -61,12 +52,8 @@ async fn deploy_and_execute_program() -> Result<()> {
.wallet() .wallet()
.get_account_public_signing_key(account_id) .get_account_public_signing_key(account_id)
.unwrap(); .unwrap();
let message = lee::public_transaction::Message::try_new( let message =
data_changer.id(), lee::public_transaction::Message::try_new(claimer.id(), vec![account_id], nonces, ())?;
vec![account_id],
nonces,
vec![0],
)?;
let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[private_key]); let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[private_key]);
let transaction = lee::PublicTransaction::new(message, witness_set); let transaction = lee::PublicTransaction::new(message, witness_set);
let _response = ctx let _response = ctx
@ -81,9 +68,10 @@ async fn deploy_and_execute_program() -> Result<()> {
let post_state_account = ctx.sequencer_client().get_account(account_id).await?; let post_state_account = ctx.sequencer_client().get_account(account_id).await?;
assert_eq!(post_state_account.program_owner, data_changer.id()); let expected_data: &[u8] = &[];
assert_eq!(post_state_account.program_owner, claimer.id());
assert_eq!(post_state_account.balance, 0); assert_eq!(post_state_account.balance, 0);
assert_eq!(post_state_account.data.as_ref(), &[0]); assert_eq!(post_state_account.data.as_ref(), expected_data);
assert_eq!(post_state_account.nonce.0, 1); assert_eq!(post_state_account.nonce.0, 1);
info!("Successfully deployed and executed program"); info!("Successfully deployed and executed program");

View File

@ -12,7 +12,6 @@ use integration_tests::{
verify_commitment_is_in_state, verify_commitment_is_in_state,
}; };
use key_protocol::key_management::key_tree::chain_index::ChainIndex; use key_protocol::key_management::key_tree::chain_index::ChainIndex;
use lee::program::Program;
use log::info; use log::info;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use token_core::{TokenDefinition, TokenHolding}; use token_core::{TokenDefinition, TokenHolding};
@ -99,7 +98,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
.await?; .await?;
let token_definition = TokenDefinition::try_from(&definition_acc.data)?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
assert_eq!(definition_acc.program_owner, Program::token().id()); assert_eq!(definition_acc.program_owner, programs::token().id());
assert_eq!( assert_eq!(
token_definition, token_definition,
TokenDefinition::Fungible { TokenDefinition::Fungible {
@ -116,7 +115,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
.await?; .await?;
// The account must be owned by the token program // The account must be owned by the token program
assert_eq!(supply_acc.program_owner, Program::token().id()); assert_eq!(supply_acc.program_owner, programs::token().id());
let token_holding = TokenHolding::try_from(&supply_acc.data)?; let token_holding = TokenHolding::try_from(&supply_acc.data)?;
assert_eq!( assert_eq!(
token_holding, token_holding,
@ -148,7 +147,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
.sequencer_client() .sequencer_client()
.get_account(supply_account_id) .get_account(supply_account_id)
.await?; .await?;
assert_eq!(supply_acc.program_owner, Program::token().id()); assert_eq!(supply_acc.program_owner, programs::token().id());
let token_holding = TokenHolding::try_from(&supply_acc.data)?; let token_holding = TokenHolding::try_from(&supply_acc.data)?;
assert_eq!( assert_eq!(
token_holding, token_holding,
@ -163,7 +162,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
.sequencer_client() .sequencer_client()
.get_account(recipient_account_id) .get_account(recipient_account_id)
.await?; .await?;
assert_eq!(recipient_acc.program_owner, Program::token().id()); assert_eq!(recipient_acc.program_owner, programs::token().id());
let token_holding = TokenHolding::try_from(&recipient_acc.data)?; let token_holding = TokenHolding::try_from(&recipient_acc.data)?;
assert_eq!( assert_eq!(
token_holding, token_holding,
@ -344,7 +343,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> {
.await?; .await?;
let token_definition = TokenDefinition::try_from(&definition_acc.data)?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
assert_eq!(definition_acc.program_owner, Program::token().id()); assert_eq!(definition_acc.program_owner, programs::token().id());
assert_eq!( assert_eq!(
token_definition, token_definition,
TokenDefinition::Fungible { TokenDefinition::Fungible {
@ -508,7 +507,7 @@ async fn create_token_with_private_definition() -> Result<()> {
.get_account(supply_account_id) .get_account(supply_account_id)
.await?; .await?;
assert_eq!(supply_acc.program_owner, Program::token().id()); assert_eq!(supply_acc.program_owner, programs::token().id());
let token_holding = TokenHolding::try_from(&supply_acc.data)?; let token_holding = TokenHolding::try_from(&supply_acc.data)?;
assert_eq!( assert_eq!(
token_holding, token_holding,
@ -1231,7 +1230,7 @@ async fn create_token_using_labels() -> Result<()> {
.await?; .await?;
let token_definition = TokenDefinition::try_from(&definition_acc.data)?; let token_definition = TokenDefinition::try_from(&definition_acc.data)?;
assert_eq!(definition_acc.program_owner, Program::token().id()); assert_eq!(definition_acc.program_owner, programs::token().id());
assert_eq!( assert_eq!(
token_definition, token_definition,
TokenDefinition::Fungible { TokenDefinition::Fungible {

View File

@ -76,7 +76,7 @@ impl TpsTestManager {
&self, &self,
sequencer_client: &sequencer_service_rpc::SequencerClient, sequencer_client: &sequencer_service_rpc::SequencerClient,
) -> Result<()> { ) -> Result<()> {
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let mut tx_hashes = Vec::with_capacity(self.public_keypairs.len()); let mut tx_hashes = Vec::with_capacity(self.public_keypairs.len());
for (private_key, account_id) in &self.public_keypairs { for (private_key, account_id) in &self.public_keypairs {
@ -126,7 +126,7 @@ impl TpsTestManager {
/// Must be called after `claim_vault_funds`, which sets each account's nonce to 1. /// Must be called after `claim_vault_funds`, which sets each account's nonce to 1.
pub fn build_public_txs(&self) -> Vec<PublicTransaction> { pub fn build_public_txs(&self) -> Vec<PublicTransaction> {
// Create valid public transactions // Create valid public transactions
let program = Program::authenticated_transfer_program(); let program = programs::authenticated_transfer();
let public_txs: Vec<PublicTransaction> = self let public_txs: Vec<PublicTransaction> = self
.public_keypairs .public_keypairs
.windows(2) .windows(2)
@ -254,7 +254,7 @@ pub async fn tps_test() -> Result<()> {
/// multiple times with the purpose of testing the node's processing performance. /// multiple times with the purpose of testing the node's processing performance.
#[expect(dead_code, reason = "No idea if we need this, should we remove it?")] #[expect(dead_code, reason = "No idea if we need this, should we remove it?")]
fn build_privacy_transaction() -> PrivacyPreservingTransaction { fn build_privacy_transaction() -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program(); let program = programs::authenticated_transfer();
let sender_nsk = [1; 32]; let sender_nsk = [1; 32];
let sender_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]); let sender_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]);
let sender_npk = NullifierPublicKey::from(&sender_nsk); let sender_npk = NullifierPublicKey::from(&sender_nsk);

View File

@ -5,7 +5,6 @@
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use integration_tests::{TestContext, private_mention, public_mention}; use integration_tests::{TestContext, private_mention, public_mention};
use lee::program::Program;
use sequencer_service_rpc::RpcClient as _; use sequencer_service_rpc::RpcClient as _;
use tokio::test; use tokio::test;
use wallet::cli::{Command, SubcommandReturnValue, programs::vault::VaultSubcommand}; use wallet::cli::{Command, SubcommandReturnValue, programs::vault::VaultSubcommand};
@ -18,7 +17,7 @@ async fn public_transfer_and_public_claim() -> Result<()> {
let sender = ctx.existing_public_accounts()[0]; let sender = ctx.existing_public_accounts()[0];
let recipient = ctx.existing_public_accounts()[1]; let recipient = ctx.existing_public_accounts()[1];
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient);
let sender_balance_before = ctx.sequencer_client().get_account_balance(sender).await?; let sender_balance_before = ctx.sequencer_client().get_account_balance(sender).await?;
@ -109,7 +108,7 @@ async fn private_transfer_and_private_claim() -> Result<()> {
let sender = ctx.existing_private_accounts()[0]; let sender = ctx.existing_private_accounts()[0];
let owner = ctx.existing_private_accounts()[1]; let owner = ctx.existing_private_accounts()[1];
let vault_program_id = Program::vault().id(); let vault_program_id = programs::vault().id();
let owner_vault_id = vault_core::compute_vault_account_id(vault_program_id, owner); let owner_vault_id = vault_core::compute_vault_account_id(vault_program_id, owner);
let sender_balance_before = ctx let sender_balance_before = ctx

View File

@ -31,7 +31,7 @@ use tempfile::tempdir;
use wallet::{account::HumanReadableAccount, program_facades::vault::Vault}; use wallet::{account::HumanReadableAccount, program_facades::vault::Vault};
use wallet_ffi::{ use wallet_ffi::{
FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys,
FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error, FfiProgramId, FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error,
generic_transaction::{FfiProgramWithDependencies, FfiTransactionResult}, generic_transaction::{FfiProgramWithDependencies, FfiTransactionResult},
wallet::FfiCreateWalletOutput, wallet::FfiCreateWalletOutput,
}; };
@ -234,7 +234,7 @@ unsafe extern "C" {
account_identities_size: usize, account_identities_size: usize,
instruction_words: *const u32, instruction_words: *const u32,
instruction_words_size: usize, instruction_words_size: usize,
program_with_dependencies: *const FfiProgramWithDependencies, program_id: FfiProgramId,
out_result: *mut FfiTransactionResult, out_result: *mut FfiTransactionResult,
) -> error::WalletFfiError; ) -> error::WalletFfiError;
@ -608,7 +608,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(account.balance, 10000); assert_eq!(account.balance, 10000);
assert!(account.data.is_empty()); assert!(account.data.is_empty());
@ -648,7 +648,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> {
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
assert_eq!(account.balance, 10000); assert_eq!(account.balance, 10000);
assert!(account.data.is_empty()); assert!(account.data.is_empty());
@ -846,7 +846,7 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
}; };
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
unsafe { unsafe {
@ -906,7 +906,7 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
}; };
assert_eq!( assert_eq!(
account.program_owner, account.program_owner,
Program::authenticated_transfer_program().id() programs::authenticated_transfer().id()
); );
unsafe { unsafe {
@ -1493,7 +1493,7 @@ fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
mnemonic: _, mnemonic: _,
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
let bridge_account: FfiBytes32 = lee::system_bridge_account_id().into(); let bridge_account: FfiBytes32 = system_accounts::bridge_account_id().into();
let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]); let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
let amount = 100_u64; let amount = 100_u64;
@ -1585,8 +1585,7 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
let instruction_words_size = instruction_data.len(); let instruction_words_size = instruction_data.len();
let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32;
let program: ProgramWithDependencies = Program::authenticated_transfer_program().into(); let program_id = programs::authenticated_transfer().id();
let program_with_dependencies: FfiProgramWithDependencies = program.into();
unsafe { unsafe {
wallet_ffi_send_generic_public_transaction( wallet_ffi_send_generic_public_transaction(
@ -1595,7 +1594,7 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
account_identities_size, account_identities_size,
instruction_words, instruction_words,
instruction_words_size, instruction_words_size,
&raw const program_with_dependencies, program_id.into(),
&raw mut transaction_result, &raw mut transaction_result,
) )
.unwrap(); .unwrap();
@ -1682,7 +1681,7 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
let instruction_words_size = instruction_data.len(); let instruction_words_size = instruction_data.len();
let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32;
let program: ProgramWithDependencies = Program::authenticated_transfer_program().into(); let program: ProgramWithDependencies = programs::authenticated_transfer().into();
let program_with_dependencies: FfiProgramWithDependencies = program.into(); let program_with_dependencies: FfiProgramWithDependencies = program.into();
unsafe { unsafe {

View File

@ -0,0 +1,17 @@
[package]
name = "privacy_preserving_circuit_program"
version = "0.1.0"
edition = "2024"
license = { workspace = true }
# Renaming binary to privacy_preserving_circuit for better looking.
[[bin]]
name = "privacy_preserving_circuit"
path = "src/main.rs"
[lints]
workspace = true
[dependencies]
lee_core.workspace = true
risc0-zkvm.workspace = true

View File

@ -9,9 +9,6 @@ workspace = true
[dependencies] [dependencies]
lee_core = { workspace = true, features = ["host"] } lee_core = { workspace = true, features = ["host"] }
clock_core.workspace = true
faucet_core.workspace = true
bridge_core.workspace = true
anyhow.workspace = true anyhow.workspace = true
thiserror.workspace = true thiserror.workspace = true
@ -27,14 +24,12 @@ risc0-binfmt = "3.0.2"
log.workspace = true log.workspace = true
[build-dependencies] [build-dependencies]
risc0-build = "3.0.3" build_utils.workspace = true
risc0-binfmt = "3.0.2"
[dev-dependencies] [dev-dependencies]
lee_core = { workspace = true, features = ["test_utils"] } lee_core = { workspace = true, features = ["test_utils"] }
token_core.workspace = true token_core.workspace = true
authenticated_transfer_core.workspace = true test_methods = { path = "test_methods" }
test_program_methods.workspace = true
env_logger.workspace = true env_logger.workspace = true
hex-literal = "1.0.0" hex-literal = "1.0.0"

View File

@ -1,43 +1,5 @@
use std::{env, fmt::Write as _, fs, path::PathBuf};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); build_utils::include_artifacts("lee/privacy_preserving_circuit")?;
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
let mod_dir = out_dir.join("program_methods");
let mod_file = mod_dir.join("mod.rs");
let program_methods_dir = manifest_dir.join("../../artifacts/program_methods/");
println!("cargo:rerun-if-changed={}", program_methods_dir.display());
let bins = fs::read_dir(&program_methods_dir)?
.filter_map(Result::ok)
.filter(|e| e.path().extension().is_some_and(|ext| ext == "bin"))
.collect::<Vec<_>>();
if bins.is_empty() {
return Err(format!("No .bin files found in {}", program_methods_dir.display()).into());
}
fs::create_dir_all(&mod_dir)?;
let mut src = String::new();
for entry in bins {
let path = entry.path();
let name = path.file_stem().unwrap().to_string_lossy();
let bytecode = fs::read(&path)?;
let image_id: [u32; 8] = risc0_binfmt::compute_image_id(&bytecode)?.into();
write!(
src,
"pub const {}_ELF: &[u8] = include_bytes!(r#\"{}\"#);\n\
#[expect(clippy::unreadable_literal, reason = \"Generated image IDs from risc0 are cryptographic hashes represented as u32 arrays\")]\n\
pub const {}_ID: [u32; 8] = {:?};\n",
name.to_uppercase(),
path.display(),
name.to_uppercase(),
image_id
)?;
}
fs::write(&mod_file, src)?;
println!("cargo:warning=Generated module at {}", mod_file.display());
Ok(()) Ok(())
} }

View File

@ -9,17 +9,16 @@ pub use lee_core::{
encryption::EphemeralPublicKey, encryption::EphemeralPublicKey,
program::ProgramId, program::ProgramId,
}; };
pub use privacy_preserving_circuit::{
PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID,
};
pub use privacy_preserving_transaction::{ pub use privacy_preserving_transaction::{
PrivacyPreservingTransaction, circuit::execute_and_prove, PrivacyPreservingTransaction, circuit::execute_and_prove,
}; };
pub use program_deployment_transaction::ProgramDeploymentTransaction; pub use program_deployment_transaction::ProgramDeploymentTransaction;
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
pub use public_transaction::PublicTransaction; pub use public_transaction::PublicTransaction;
pub use signature::{PrivateKey, PublicKey, Signature}; pub use signature::{PrivateKey, PublicKey, Signature};
pub use state::{ pub use state::V03State;
CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID,
CLOCK_PROGRAM_ACCOUNT_IDS, V03State, system_bridge_account_id, system_faucet_account_id,
};
pub use validated_state_diff::ValidatedStateDiff; pub use validated_state_diff::ValidatedStateDiff;
pub mod encoding; pub mod encoding;
@ -33,6 +32,238 @@ mod signature;
mod state; mod state;
mod validated_state_diff; mod validated_state_diff;
pub mod program_methods { mod privacy_preserving_circuit {
include!(concat!(env!("OUT_DIR"), "/program_methods/mod.rs")); include!(concat!(
env!("OUT_DIR"),
"/lee/privacy_preserving_circuit/mod.rs"
));
}
#[cfg(test)]
mod test_methods {
use std::borrow::Cow;
use crate::program::Program;
#[must_use]
pub const fn simple_balance_transfer() -> Program {
Program::new_unchecked(
test_methods::SIMPLE_BALANCE_TRANSFER_ID,
Cow::Borrowed(test_methods::SIMPLE_BALANCE_TRANSFER_ELF),
)
}
#[must_use]
pub const fn nonce_changer() -> Program {
Program::new_unchecked(
test_methods::NONCE_CHANGER_ID,
Cow::Borrowed(test_methods::NONCE_CHANGER_ELF),
)
}
#[must_use]
pub const fn extra_output() -> Program {
Program::new_unchecked(
test_methods::EXTRA_OUTPUT_ID,
Cow::Borrowed(test_methods::EXTRA_OUTPUT_ELF),
)
}
#[must_use]
pub const fn missing_output() -> Program {
Program::new_unchecked(
test_methods::MISSING_OUTPUT_ID,
Cow::Borrowed(test_methods::MISSING_OUTPUT_ELF),
)
}
#[must_use]
pub const fn program_owner_changer() -> Program {
Program::new_unchecked(
test_methods::PROGRAM_OWNER_CHANGER_ID,
Cow::Borrowed(test_methods::PROGRAM_OWNER_CHANGER_ELF),
)
}
#[must_use]
pub const fn data_changer() -> Program {
Program::new_unchecked(
test_methods::DATA_CHANGER_ID,
Cow::Borrowed(test_methods::DATA_CHANGER_ELF),
)
}
#[must_use]
pub const fn minter() -> Program {
Program::new_unchecked(
test_methods::MINTER_ID,
Cow::Borrowed(test_methods::MINTER_ELF),
)
}
#[must_use]
pub const fn burner() -> Program {
Program::new_unchecked(
test_methods::BURNER_ID,
Cow::Borrowed(test_methods::BURNER_ELF),
)
}
#[must_use]
pub const fn auth_asserting_noop() -> Program {
Program::new_unchecked(
test_methods::AUTH_ASSERTING_NOOP_ID,
Cow::Borrowed(test_methods::AUTH_ASSERTING_NOOP_ELF),
)
}
#[must_use]
pub const fn private_pda_delegator() -> Program {
Program::new_unchecked(
test_methods::PRIVATE_PDA_DELEGATOR_ID,
Cow::Borrowed(test_methods::PRIVATE_PDA_DELEGATOR_ELF),
)
}
#[must_use]
pub const fn pda_claimer() -> Program {
Program::new_unchecked(
test_methods::PDA_CLAIMER_ID,
Cow::Borrowed(test_methods::PDA_CLAIMER_ELF),
)
}
#[must_use]
pub const fn two_pda_claimer() -> Program {
Program::new_unchecked(
test_methods::TWO_PDA_CLAIMER_ID,
Cow::Borrowed(test_methods::TWO_PDA_CLAIMER_ELF),
)
}
#[must_use]
pub const fn noop() -> Program {
Program::new_unchecked(test_methods::NOOP_ID, Cow::Borrowed(test_methods::NOOP_ELF))
}
#[must_use]
pub const fn chain_caller() -> Program {
Program::new_unchecked(
test_methods::CHAIN_CALLER_ID,
Cow::Borrowed(test_methods::CHAIN_CALLER_ELF),
)
}
#[must_use]
pub const fn modified_transfer_program() -> Program {
Program::new_unchecked(
test_methods::MODIFIED_TRANSFER_ID,
Cow::Borrowed(test_methods::MODIFIED_TRANSFER_ELF),
)
}
#[must_use]
pub const fn malicious_authorization_changer() -> Program {
Program::new_unchecked(
test_methods::MALICIOUS_AUTHORIZATION_CHANGER_ID,
Cow::Borrowed(test_methods::MALICIOUS_AUTHORIZATION_CHANGER_ELF),
)
}
#[must_use]
pub const fn validity_window() -> Program {
Program::new_unchecked(
test_methods::VALIDITY_WINDOW_ID,
Cow::Borrowed(test_methods::VALIDITY_WINDOW_ELF),
)
}
#[must_use]
pub const fn flash_swap_initiator() -> Program {
Program::new_unchecked(
test_methods::FLASH_SWAP_INITIATOR_ID,
Cow::Borrowed(test_methods::FLASH_SWAP_INITIATOR_ELF),
)
}
#[must_use]
pub const fn flash_swap_callback() -> Program {
Program::new_unchecked(
test_methods::FLASH_SWAP_CALLBACK_ID,
Cow::Borrowed(test_methods::FLASH_SWAP_CALLBACK_ELF),
)
}
#[must_use]
pub const fn malicious_self_program_id() -> Program {
Program::new_unchecked(
test_methods::MALICIOUS_SELF_PROGRAM_ID_ID,
Cow::Borrowed(test_methods::MALICIOUS_SELF_PROGRAM_ID_ELF),
)
}
#[must_use]
pub const fn malicious_caller_program_id() -> Program {
Program::new_unchecked(
test_methods::MALICIOUS_CALLER_PROGRAM_ID_ID,
Cow::Borrowed(test_methods::MALICIOUS_CALLER_PROGRAM_ID_ELF),
)
}
#[must_use]
pub const fn pda_spend_proxy() -> Program {
Program::new_unchecked(
test_methods::PDA_SPEND_PROXY_ID,
Cow::Borrowed(test_methods::PDA_SPEND_PROXY_ELF),
)
}
#[must_use]
pub const fn claimer() -> Program {
Program::new_unchecked(
test_methods::CLAIMER_ID,
Cow::Borrowed(test_methods::CLAIMER_ELF),
)
}
#[must_use]
pub const fn changer_claimer() -> Program {
Program::new_unchecked(
test_methods::CHANGER_CLAIMER_ID,
Cow::Borrowed(test_methods::CHANGER_CLAIMER_ELF),
)
}
#[must_use]
pub const fn validity_window_chain_caller() -> Program {
Program::new_unchecked(
test_methods::VALIDITY_WINDOW_CHAIN_CALLER_ID,
Cow::Borrowed(test_methods::VALIDITY_WINDOW_CHAIN_CALLER_ELF),
)
}
#[must_use]
#[inline]
pub const fn simple_transfer_proxy() -> Program {
Program::new_unchecked(
test_methods::SIMPLE_TRANSFER_PROXY_ID,
Cow::Borrowed(test_methods::SIMPLE_TRANSFER_PROXY_ELF),
)
}
#[must_use]
pub const fn malicious_injector() -> Program {
Program::new_unchecked(
test_methods::MALICIOUS_INJECTOR_ID,
Cow::Borrowed(test_methods::MALICIOUS_INJECTOR_ELF),
)
}
#[must_use]
pub const fn malicious_launderer() -> Program {
Program::new_unchecked(
test_methods::MALICIOUS_LAUNDERER_ID,
Cow::Borrowed(test_methods::MALICIOUS_LAUNDERER_ELF),
)
}
} }

View File

@ -9,9 +9,9 @@ use lee_core::{
use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover};
use crate::{ use crate::{
PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID,
error::{InvalidProgramBehaviorError, LeeError}, error::{InvalidProgramBehaviorError, LeeError},
program::Program, program::Program,
program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID},
state::MAX_NUMBER_CHAINED_CALLS, state::MAX_NUMBER_CHAINED_CALLS,
}; };
@ -224,7 +224,7 @@ mod tests {
#[test] #[test]
fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() {
let recipient_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_1();
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::simple_balance_transfer();
let sender = AccountWithMetadata::new( let sender = AccountWithMetadata::new(
Account { Account {
program_owner: program.id(), program_owner: program.id(),
@ -261,10 +261,7 @@ mod tests {
let (output, proof) = execute_and_prove( let (output, proof) = execute_and_prove(
vec![sender, recipient], vec![sender, recipient],
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { Program::serialize_instruction(balance_to_move).unwrap(),
amount: balance_to_move,
})
.unwrap(),
vec![ vec![
InputAccountIdentity::Public, InputAccountIdentity::Public,
InputAccountIdentity::PrivateUnauthorized { InputAccountIdentity::PrivateUnauthorized {
@ -278,7 +275,7 @@ mod tests {
identifier: 0, identifier: 0,
}, },
], ],
&Program::authenticated_transfer_program().into(), &crate::test_methods::simple_balance_transfer().into(),
) )
.unwrap(); .unwrap();
@ -304,7 +301,7 @@ mod tests {
#[test] #[test]
fn prove_privacy_preserving_execution_circuit_fully_private() { fn prove_privacy_preserving_execution_circuit_fully_private() {
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::simple_balance_transfer();
let sender_keys = test_private_account_keys_1(); let sender_keys = test_private_account_keys_1();
let recipient_keys = test_private_account_keys_2(); let recipient_keys = test_private_account_keys_2();
@ -339,7 +336,7 @@ mod tests {
), ),
]; ];
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::simple_balance_transfer();
let expected_private_account_1 = Account { let expected_private_account_1 = Account {
program_owner: program.id(), program_owner: program.id(),
@ -366,10 +363,7 @@ mod tests {
let (output, proof) = execute_and_prove( let (output, proof) = execute_and_prove(
vec![sender_pre, recipient], vec![sender_pre, recipient],
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { Program::serialize_instruction(balance_to_move).unwrap(),
amount: balance_to_move,
})
.unwrap(),
vec![ vec![
InputAccountIdentity::PrivateAuthorizedUpdate { InputAccountIdentity::PrivateAuthorizedUpdate {
epk: EphemeralPublicKey(Vec::new()), epk: EphemeralPublicKey(Vec::new()),
@ -434,8 +428,8 @@ mod tests {
AccountId::for_regular_private_account(&account_keys.npk(), 0), AccountId::for_regular_private_account(&account_keys.npk(), 0),
); );
let validity_window_chain_caller = Program::validity_window_chain_caller(); let validity_window_chain_caller = crate::test_methods::validity_window_chain_caller();
let validity_window = Program::validity_window(); let validity_window = crate::test_methods::validity_window();
let instruction = Program::serialize_instruction(( let instruction = Program::serialize_instruction((
Some(1_u64), Some(1_u64),
@ -477,7 +471,7 @@ mod tests {
/// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`. /// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`.
#[test] #[test]
fn private_pda_claim_with_custom_identifier_encrypts_correct_kind() { fn private_pda_claim_with_custom_identifier_encrypts_correct_kind() {
let program = Program::pda_claimer(); let program = crate::test_methods::pda_claimer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
@ -513,13 +507,13 @@ mod tests {
); );
} }
/// PDA init: initializes a new PDA under `authenticated_transfer`'s ownership. /// PDA init: initializes a new PDA under `simple_balance_transfer`'s ownership.
/// The `auth_transfer_proxy` program chains to `authenticated_transfer` with `pda_seeds` /// The `simple_transfer_proxy` program chains to `simple_balance_transfer` with `pda_seeds`
/// to establish authorization and the private PDA binding. /// to establish authorization and the private PDA binding.
#[test] #[test]
fn private_pda_init() { fn private_pda_init() {
let program = Program::auth_transfer_proxy(); let program = crate::test_methods::simple_transfer_proxy();
let auth_transfer = Program::authenticated_transfer_program(); let simple_transfer = crate::test_methods::simple_balance_transfer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
@ -530,9 +524,9 @@ mod tests {
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0); let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0);
let pda_pre = AccountWithMetadata::new(Account::default(), false, pda_id); let pda_pre = AccountWithMetadata::new(Account::default(), false, pda_id);
let auth_id = auth_transfer.id(); let auth_id = simple_transfer.id();
let program_with_deps = let program_with_deps =
ProgramWithDependencies::new(program, [(auth_id, auth_transfer)].into()); ProgramWithDependencies::new(program, [(auth_id, simple_transfer)].into());
// is_withdraw=false triggers init path (1 pre-state) // is_withdraw=false triggers init path (1 pre-state)
let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, false)).unwrap(); let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, false)).unwrap();
@ -555,13 +549,13 @@ mod tests {
assert_eq!(output.new_commitments.len(), 1); assert_eq!(output.new_commitments.len(), 1);
} }
/// PDA withdraw: chains to `authenticated_transfer` to move balance from PDA to recipient. /// PDA withdraw: chains to `simple_balance_transfer` to move balance from PDA to recipient.
/// Uses a default PDA (amount=0) because testing with a pre-funded PDA requires a /// Uses a default PDA (amount=0) because testing with a pre-funded PDA requires a
/// two-tx sequence with membership proofs. /// two-tx sequence with membership proofs.
#[test] #[test]
fn private_pda_withdraw() { fn private_pda_withdraw() {
let program = Program::auth_transfer_proxy(); let program = crate::test_methods::simple_transfer_proxy();
let auth_transfer = Program::authenticated_transfer_program(); let simple_transfer = crate::test_methods::simple_balance_transfer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
@ -576,7 +570,7 @@ mod tests {
let recipient_id = AccountId::new([88; 32]); let recipient_id = AccountId::new([88; 32]);
let recipient_pre = AccountWithMetadata::new( let recipient_pre = AccountWithMetadata::new(
Account { Account {
program_owner: auth_transfer.id(), program_owner: simple_transfer.id(),
balance: 10000, balance: 10000,
..Account::default() ..Account::default()
}, },
@ -584,9 +578,9 @@ mod tests {
recipient_id, recipient_id,
); );
let auth_id = auth_transfer.id(); let auth_id = simple_transfer.id();
let program_with_deps = let program_with_deps =
ProgramWithDependencies::new(program, [(auth_id, auth_transfer)].into()); ProgramWithDependencies::new(program, [(auth_id, simple_transfer)].into());
// is_withdraw=true, amount=0 (PDA has no balance yet) // is_withdraw=true, amount=0 (PDA has no balance yet)
let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, true)).unwrap(); let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, true)).unwrap();
@ -618,8 +612,8 @@ mod tests {
/// uses the standard unauthorized private account path and works with auth-transfer's /// uses the standard unauthorized private account path and works with auth-transfer's
/// transfer path like any other private account. /// transfer path like any other private account.
#[test] #[test]
fn shared_account_receives_via_auth_transfer() { fn shared_account_receives_via_simple_transfer() {
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::simple_balance_transfer();
let shared_keys = test_private_account_keys_1(); let shared_keys = test_private_account_keys_1();
let shared_npk = shared_keys.npk(); let shared_npk = shared_keys.npk();
let shared_identifier: u128 = 42; let shared_identifier: u128 = 42;
@ -643,11 +637,7 @@ mod tests {
let recipient = AccountWithMetadata::new(Account::default(), false, shared_account_id); let recipient = AccountWithMetadata::new(Account::default(), false, shared_account_id);
let balance_to_move: u128 = 100; let balance_to_move: u128 = 100;
let instruction = let instruction = Program::serialize_instruction(balance_to_move).unwrap();
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer {
amount: balance_to_move,
})
.unwrap();
let result = execute_and_prove( let result = execute_and_prove(
vec![sender, recipient], vec![sender, recipient],
@ -677,7 +667,7 @@ mod tests {
/// to `PrivateAccountKind::Regular` carrying the correct identifier. /// to `PrivateAccountKind::Regular` carrying the correct identifier.
#[test] #[test]
fn private_authorized_init_encrypts_regular_kind_with_identifier() { fn private_authorized_init_encrypts_regular_kind_with_identifier() {
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::claimer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let identifier: u128 = 99; let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
@ -686,8 +676,7 @@ mod tests {
let (output, _) = execute_and_prove( let (output, _) = execute_and_prove(
vec![pre], vec![pre],
Program::serialize_instruction(authenticated_transfer_core::Instruction::Initialize) Program::serialize_instruction(()).unwrap(),
.unwrap(),
vec![InputAccountIdentity::PrivateAuthorizedInit { vec![InputAccountIdentity::PrivateAuthorizedInit {
epk: EphemeralPublicKey(Vec::new()), epk: EphemeralPublicKey(Vec::new()),
view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()),
@ -709,39 +698,23 @@ mod tests {
/// to `PrivateAccountKind::Regular` carrying the correct identifier. /// to `PrivateAccountKind::Regular` carrying the correct identifier.
#[test] #[test]
fn private_unauthorized_init_encrypts_regular_kind_with_identifier() { fn private_unauthorized_init_encrypts_regular_kind_with_identifier() {
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::claimer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let identifier: u128 = 99; let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let sender = AccountWithMetadata::new(
Account {
program_owner: program.id(),
balance: 1,
..Account::default()
},
true,
AccountId::new([0; 32]),
);
let recipient_id = AccountId::for_regular_private_account(&keys.npk(), identifier); let recipient_id = AccountId::for_regular_private_account(&keys.npk(), identifier);
let recipient = AccountWithMetadata::new(Account::default(), false, recipient_id); let recipient = AccountWithMetadata::new(Account::default(), false, recipient_id);
let (output, _) = execute_and_prove( let (output, _) = execute_and_prove(
vec![sender, recipient], vec![recipient],
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { Program::serialize_instruction(()).unwrap(),
amount: 1, vec![InputAccountIdentity::PrivateUnauthorized {
}) epk: EphemeralPublicKey(Vec::new()),
.unwrap(), view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()),
vec![ npk: keys.npk(),
InputAccountIdentity::Public, ssk,
InputAccountIdentity::PrivateUnauthorized { identifier,
epk: EphemeralPublicKey(Vec::new()), }],
view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()),
npk: keys.npk(),
ssk,
identifier,
},
],
&program.into(), &program.into(),
) )
.unwrap(); .unwrap();
@ -756,7 +729,7 @@ mod tests {
/// to `PrivateAccountKind::Regular` carrying the correct identifier. /// to `PrivateAccountKind::Regular` carrying the correct identifier.
#[test] #[test]
fn private_authorized_update_encrypts_regular_kind_with_identifier() { fn private_authorized_update_encrypts_regular_kind_with_identifier() {
let program = Program::authenticated_transfer_program(); let program = crate::test_methods::noop();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let identifier: u128 = 99; let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
@ -771,25 +744,18 @@ mod tests {
commitment_set.extend(std::slice::from_ref(&commitment)); commitment_set.extend(std::slice::from_ref(&commitment));
let sender = AccountWithMetadata::new(account, true, account_id); let sender = AccountWithMetadata::new(account, true, account_id);
let recipient = AccountWithMetadata::new(Account::default(), true, AccountId::new([0; 32]));
let (output, _) = execute_and_prove( let (output, _) = execute_and_prove(
vec![sender, recipient], vec![sender],
Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { Program::serialize_instruction(()).unwrap(),
amount: 1, vec![InputAccountIdentity::PrivateAuthorizedUpdate {
}) epk: EphemeralPublicKey(Vec::new()),
.unwrap(), view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()),
vec![ ssk,
InputAccountIdentity::PrivateAuthorizedUpdate { nsk: keys.nsk,
epk: EphemeralPublicKey(Vec::new()), membership_proof: commitment_set.get_proof_for(&commitment).unwrap(),
view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), identifier,
ssk, }],
nsk: keys.nsk,
membership_proof: commitment_set.get_proof_for(&commitment).unwrap(),
identifier,
},
InputAccountIdentity::Public,
],
&program.into(), &program.into(),
) )
.unwrap(); .unwrap();
@ -804,18 +770,18 @@ mod tests {
/// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`. /// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`.
#[test] #[test]
fn private_pda_update_encrypts_pda_kind_with_identifier() { fn private_pda_update_encrypts_pda_kind_with_identifier() {
let program = Program::pda_spend_proxy(); let program = crate::test_methods::pda_spend_proxy();
let auth_transfer = Program::authenticated_transfer_program(); let simple_transfer = crate::test_methods::simple_balance_transfer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
let identifier: u128 = 99; let identifier: u128 = 99;
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let auth_transfer_id = auth_transfer.id(); let simple_transfer_id = simple_transfer.id();
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier); let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier);
let pda_account = Account { let pda_account = Account {
program_owner: auth_transfer_id, program_owner: simple_transfer_id,
balance: 1, balance: 1,
..Account::default() ..Account::default()
}; };
@ -829,12 +795,12 @@ mod tests {
let program_with_deps = ProgramWithDependencies::new( let program_with_deps = ProgramWithDependencies::new(
program.clone(), program.clone(),
[(auth_transfer_id, auth_transfer)].into(), [(simple_transfer_id, simple_transfer)].into(),
); );
let (output, _) = execute_and_prove( let (output, _) = execute_and_prove(
vec![pda_pre, recipient_pre], vec![pda_pre, recipient_pre],
Program::serialize_instruction((seed, 1_u128, auth_transfer_id, false)).unwrap(), Program::serialize_instruction((seed, 1_u128, simple_transfer_id, false)).unwrap(),
vec![ vec![
InputAccountIdentity::PrivatePdaUpdate { InputAccountIdentity::PrivatePdaUpdate {
epk: EphemeralPublicKey(Vec::new()), epk: EphemeralPublicKey(Vec::new()),
@ -863,7 +829,7 @@ mod tests {
#[test] #[test]
fn private_pda_init_identifier_mismatch_fails() { fn private_pda_init_identifier_mismatch_fails() {
let program = Program::pda_claimer(); let program = crate::test_methods::pda_claimer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
@ -892,17 +858,17 @@ mod tests {
#[test] #[test]
fn private_pda_update_identifier_mismatch_fails() { fn private_pda_update_identifier_mismatch_fails() {
let program = Program::pda_spend_proxy(); let program = crate::test_methods::pda_spend_proxy();
let auth_transfer = Program::authenticated_transfer_program(); let simple_transfer = crate::test_methods::simple_balance_transfer();
let keys = test_private_account_keys_1(); let keys = test_private_account_keys_1();
let npk = keys.npk(); let npk = keys.npk();
let seed = PdaSeed::new([42; 32]); let seed = PdaSeed::new([42; 32]);
let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0;
let auth_transfer_id = auth_transfer.id(); let simple_transfer_id = simple_transfer.id();
let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5); let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5);
let pda_account = Account { let pda_account = Account {
program_owner: auth_transfer_id, program_owner: simple_transfer_id,
balance: 1, balance: 1,
..Account::default() ..Account::default()
}; };
@ -915,11 +881,11 @@ mod tests {
AccountWithMetadata::new(Account::default(), true, AccountId::new([0; 32])); AccountWithMetadata::new(Account::default(), true, AccountId::new([0; 32]));
let program_with_deps = let program_with_deps =
ProgramWithDependencies::new(program, [(auth_transfer_id, auth_transfer)].into()); ProgramWithDependencies::new(program, [(simple_transfer_id, simple_transfer)].into());
let result = execute_and_prove( let result = execute_and_prove(
vec![pda_pre, recipient_pre], vec![pda_pre, recipient_pre],
Program::serialize_instruction((seed, 1_u128, auth_transfer_id, false)).unwrap(), Program::serialize_instruction((seed, 1_u128, simple_transfer_id, false)).unwrap(),
vec![ vec![
InputAccountIdentity::PrivatePdaUpdate { InputAccountIdentity::PrivatePdaUpdate {
epk: EphemeralPublicKey(Vec::new()), epk: EphemeralPublicKey(Vec::new()),

View File

@ -1,3 +1,5 @@
use std::borrow::Cow;
use borsh::{BorshDeserialize, BorshSerialize}; use borsh::{BorshDeserialize, BorshSerialize};
use lee_core::{ use lee_core::{
account::AccountWithMetadata, account::AccountWithMetadata,
@ -6,15 +8,7 @@ use lee_core::{
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
use serde::Serialize; use serde::Serialize;
use crate::{ use crate::error::LeeError;
error::LeeError,
program_methods::{
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, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF,
VAULT_ID,
},
};
/// Maximum number of cycles for a public execution. /// Maximum number of cycles for a public execution.
/// TODO: Make this variable when fees are implemented. /// TODO: Make this variable when fees are implemented.
@ -23,18 +17,23 @@ const MAX_NUM_CYCLES_PUBLIC_EXECUTION: u64 = 1024 * 1024 * 32; // 32M cycles
#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)] #[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
pub struct Program { pub struct Program {
id: ProgramId, id: ProgramId,
elf: Vec<u8>, elf: Cow<'static, [u8]>,
} }
impl Program { impl Program {
pub fn new(bytecode: Vec<u8>) -> Result<Self, LeeError> { pub fn new(elf: Cow<'static, [u8]>) -> Result<Self, LeeError> {
let binary = risc0_binfmt::ProgramBinary::decode(&bytecode) let binary = risc0_binfmt::ProgramBinary::decode(elf.as_ref())
.map_err(LeeError::InvalidProgramBytecode)?; .map_err(LeeError::InvalidProgramBytecode)?;
let id = binary let id = binary
.compute_image_id() .compute_image_id()
.map_err(LeeError::InvalidProgramBytecode)? .map_err(LeeError::InvalidProgramBytecode)?
.into(); .into();
Ok(Self { elf: bytecode, id }) Ok(Self { id, elf })
}
#[must_use]
pub const fn new_unchecked(id: ProgramId, elf: Cow<'static, [u8]>) -> Self {
Self { id, elf }
} }
#[must_use] #[must_use]
@ -109,412 +108,17 @@ impl Program {
.map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?;
Ok(()) Ok(())
} }
#[must_use]
pub fn authenticated_transfer_program() -> Self {
Self {
id: AUTHENTICATED_TRANSFER_ID,
elf: AUTHENTICATED_TRANSFER_ELF.to_vec(),
}
}
#[must_use]
pub fn token() -> Self {
Self {
id: TOKEN_ID,
elf: TOKEN_ELF.to_vec(),
}
}
#[must_use]
pub fn amm() -> Self {
Self {
id: AMM_ID,
elf: AMM_ELF.to_vec(),
}
}
#[must_use]
pub fn clock() -> Self {
Self {
id: CLOCK_ID,
elf: CLOCK_ELF.to_vec(),
}
}
#[must_use]
pub fn ata() -> Self {
Self {
id: ASSOCIATED_TOKEN_ACCOUNT_ID,
elf: ASSOCIATED_TOKEN_ACCOUNT_ELF.to_vec(),
}
}
#[must_use]
pub fn vault() -> Self {
Self {
id: VAULT_ID,
elf: VAULT_ELF.to_vec(),
}
}
#[must_use]
pub fn faucet() -> Self {
Self {
id: FAUCET_ID,
elf: FAUCET_ELF.to_vec(),
}
}
#[must_use]
pub fn bridge() -> Self {
Self {
id: BRIDGE_ID,
elf: BRIDGE_ELF.to_vec(),
}
}
}
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
impl Program {
#[must_use]
pub fn pinata() -> Self {
Self {
id: PINATA_ID,
elf: PINATA_ELF.to_vec(),
}
}
#[must_use]
pub fn pinata_token() -> Self {
use crate::program_methods::{PINATA_TOKEN_ELF, PINATA_TOKEN_ID};
Self {
id: PINATA_TOKEN_ID,
elf: PINATA_TOKEN_ELF.to_vec(),
}
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use lee_core::account::{Account, AccountId, AccountWithMetadata}; use lee_core::account::{Account, AccountId, AccountWithMetadata};
use crate::{ use crate::program::Program;
program::Program,
program_methods::{
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, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, PINATA_TOKEN_ELF,
PINATA_TOKEN_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID,
},
};
impl Program {
/// A program that changes the nonce of an account.
#[must_use]
pub fn nonce_changer_program() -> Self {
use test_program_methods::{NONCE_CHANGER_ELF, NONCE_CHANGER_ID};
Self {
id: NONCE_CHANGER_ID,
elf: NONCE_CHANGER_ELF.to_vec(),
}
}
/// A program that produces more output accounts than the inputs it received.
#[must_use]
pub fn extra_output_program() -> Self {
use test_program_methods::{EXTRA_OUTPUT_ELF, EXTRA_OUTPUT_ID};
Self {
id: EXTRA_OUTPUT_ID,
elf: EXTRA_OUTPUT_ELF.to_vec(),
}
}
/// A program that produces less output accounts than the inputs it received.
#[must_use]
pub fn missing_output_program() -> Self {
use test_program_methods::{MISSING_OUTPUT_ELF, MISSING_OUTPUT_ID};
Self {
id: MISSING_OUTPUT_ID,
elf: MISSING_OUTPUT_ELF.to_vec(),
}
}
/// A program that changes the program owner of an account to [0, 1, 2, 3, 4, 5, 6, 7].
#[must_use]
pub fn program_owner_changer() -> Self {
use test_program_methods::{PROGRAM_OWNER_CHANGER_ELF, PROGRAM_OWNER_CHANGER_ID};
Self {
id: PROGRAM_OWNER_CHANGER_ID,
elf: PROGRAM_OWNER_CHANGER_ELF.to_vec(),
}
}
/// A program that transfers balance without caring about authorizations.
#[must_use]
pub fn simple_balance_transfer() -> Self {
use test_program_methods::{SIMPLE_BALANCE_TRANSFER_ELF, SIMPLE_BALANCE_TRANSFER_ID};
Self {
id: SIMPLE_BALANCE_TRANSFER_ID,
elf: SIMPLE_BALANCE_TRANSFER_ELF.to_vec(),
}
}
/// A program that modifies the data of an account.
#[must_use]
pub fn data_changer() -> Self {
use test_program_methods::{DATA_CHANGER_ELF, DATA_CHANGER_ID};
Self {
id: DATA_CHANGER_ID,
elf: DATA_CHANGER_ELF.to_vec(),
}
}
/// A program that mints balance.
#[must_use]
pub fn minter() -> Self {
use test_program_methods::{MINTER_ELF, MINTER_ID};
Self {
id: MINTER_ID,
elf: MINTER_ELF.to_vec(),
}
}
/// A program that burns balance.
#[must_use]
pub fn burner() -> Self {
use test_program_methods::{BURNER_ELF, BURNER_ID};
Self {
id: BURNER_ID,
elf: BURNER_ELF.to_vec(),
}
}
#[must_use]
pub fn chain_caller() -> Self {
use test_program_methods::{CHAIN_CALLER_ELF, CHAIN_CALLER_ID};
Self {
id: CHAIN_CALLER_ID,
elf: CHAIN_CALLER_ELF.to_vec(),
}
}
#[must_use]
pub fn claimer() -> Self {
use test_program_methods::{CLAIMER_ELF, CLAIMER_ID};
Self {
id: CLAIMER_ID,
elf: CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn pda_claimer() -> Self {
use test_program_methods::{PDA_CLAIMER_ELF, PDA_CLAIMER_ID};
Self {
id: PDA_CLAIMER_ID,
elf: PDA_CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn private_pda_delegator() -> Self {
use test_program_methods::{PRIVATE_PDA_DELEGATOR_ELF, PRIVATE_PDA_DELEGATOR_ID};
Self {
id: PRIVATE_PDA_DELEGATOR_ID,
elf: PRIVATE_PDA_DELEGATOR_ELF.to_vec(),
}
}
#[must_use]
pub fn auth_transfer_proxy() -> Self {
use test_program_methods::{AUTH_TRANSFER_PROXY_ELF, AUTH_TRANSFER_PROXY_ID};
Self {
id: AUTH_TRANSFER_PROXY_ID,
elf: AUTH_TRANSFER_PROXY_ELF.to_vec(),
}
}
#[must_use]
pub fn two_pda_claimer() -> Self {
use test_program_methods::{TWO_PDA_CLAIMER_ELF, TWO_PDA_CLAIMER_ID};
Self {
id: TWO_PDA_CLAIMER_ID,
elf: TWO_PDA_CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn pda_spend_proxy() -> Self {
use test_program_methods::{PDA_SPEND_PROXY_ELF, PDA_SPEND_PROXY_ID};
Self {
id: PDA_SPEND_PROXY_ID,
elf: PDA_SPEND_PROXY_ELF.to_vec(),
}
}
#[must_use]
pub fn changer_claimer() -> Self {
use test_program_methods::{CHANGER_CLAIMER_ELF, CHANGER_CLAIMER_ID};
Self {
id: CHANGER_CLAIMER_ID,
elf: CHANGER_CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn noop() -> Self {
use test_program_methods::{NOOP_ELF, NOOP_ID};
Self {
id: NOOP_ID,
elf: NOOP_ELF.to_vec(),
}
}
#[must_use]
pub fn auth_asserting_noop() -> Self {
use test_program_methods::{AUTH_ASSERTING_NOOP_ELF, AUTH_ASSERTING_NOOP_ID};
Self {
id: AUTH_ASSERTING_NOOP_ID,
elf: AUTH_ASSERTING_NOOP_ELF.to_vec(),
}
}
#[must_use]
pub fn malicious_authorization_changer() -> Self {
use test_program_methods::{
MALICIOUS_AUTHORIZATION_CHANGER_ELF, MALICIOUS_AUTHORIZATION_CHANGER_ID,
};
Self {
id: MALICIOUS_AUTHORIZATION_CHANGER_ID,
elf: MALICIOUS_AUTHORIZATION_CHANGER_ELF.to_vec(),
}
}
#[must_use]
pub fn modified_transfer_program() -> Self {
use test_program_methods::{MODIFIED_TRANSFER_ELF, MODIFIED_TRANSFER_ID};
Self {
id: MODIFIED_TRANSFER_ID,
elf: MODIFIED_TRANSFER_ELF.to_vec(),
}
}
#[must_use]
pub fn validity_window() -> Self {
use test_program_methods::{VALIDITY_WINDOW_ELF, VALIDITY_WINDOW_ID};
Self {
id: VALIDITY_WINDOW_ID,
elf: VALIDITY_WINDOW_ELF.to_vec(),
}
}
#[must_use]
pub fn validity_window_chain_caller() -> Self {
use test_program_methods::{
VALIDITY_WINDOW_CHAIN_CALLER_ELF, VALIDITY_WINDOW_CHAIN_CALLER_ID,
};
Self {
id: VALIDITY_WINDOW_CHAIN_CALLER_ID,
elf: VALIDITY_WINDOW_CHAIN_CALLER_ELF.to_vec(),
}
}
#[must_use]
pub fn flash_swap_initiator() -> Self {
use test_program_methods::FLASH_SWAP_INITIATOR_ELF;
Self::new(FLASH_SWAP_INITIATOR_ELF.to_vec())
.expect("flash_swap_initiator must be a valid Risc0 program")
}
#[must_use]
pub fn flash_swap_callback() -> Self {
use test_program_methods::FLASH_SWAP_CALLBACK_ELF;
Self::new(FLASH_SWAP_CALLBACK_ELF.to_vec())
.expect("flash_swap_callback must be a valid Risc0 program")
}
#[must_use]
pub fn malicious_self_program_id() -> Self {
use test_program_methods::MALICIOUS_SELF_PROGRAM_ID_ELF;
Self::new(MALICIOUS_SELF_PROGRAM_ID_ELF.to_vec())
.expect("malicious_self_program_id must be a valid Risc0 program")
}
#[must_use]
pub fn malicious_caller_program_id() -> Self {
use test_program_methods::MALICIOUS_CALLER_PROGRAM_ID_ELF;
Self::new(MALICIOUS_CALLER_PROGRAM_ID_ELF.to_vec())
.expect("malicious_caller_program_id must be a valid Risc0 program")
}
#[must_use]
pub fn time_locked_transfer() -> Self {
use test_program_methods::TIME_LOCKED_TRANSFER_ELF;
Self::new(TIME_LOCKED_TRANSFER_ELF.to_vec()).unwrap()
}
#[must_use]
pub fn pinata_cooldown() -> Self {
use test_program_methods::PINATA_COOLDOWN_ELF;
Self::new(PINATA_COOLDOWN_ELF.to_vec()).unwrap()
}
#[must_use]
pub fn malicious_injector() -> Self {
use test_program_methods::{MALICIOUS_INJECTOR_ELF, MALICIOUS_INJECTOR_ID};
Self {
id: MALICIOUS_INJECTOR_ID,
elf: MALICIOUS_INJECTOR_ELF.to_vec(),
}
}
#[must_use]
pub fn malicious_launderer() -> Self {
use test_program_methods::{MALICIOUS_LAUNDERER_ELF, MALICIOUS_LAUNDERER_ID};
Self {
id: MALICIOUS_LAUNDERER_ID,
elf: MALICIOUS_LAUNDERER_ELF.to_vec(),
}
}
}
#[test]
fn elf_returns_the_program_bytecode_constant() {
// `Program::elf` must return exactly the compile-time ELF, never an empty
// or placeholder slice. Catches mutations returning `Vec::leak(Vec::new())`,
// `Vec::leak(vec![0])`, or `Vec::leak(vec![1])`.
let at = Program::authenticated_transfer_program();
assert!(!at.elf().is_empty());
assert_eq!(at.elf(), AUTHENTICATED_TRANSFER_ELF);
let token = Program::token();
assert!(!token.elf().is_empty());
assert_eq!(token.elf(), TOKEN_ELF);
}
#[test] #[test]
fn program_execution() { fn program_execution() {
let program = Program::simple_balance_transfer(); let program = crate::test_methods::simple_balance_transfer();
let balance_to_move: u128 = 11_223_344_556_677; let balance_to_move: u128 = 11_223_344_556_677;
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
let sender = AccountWithMetadata::new( let sender = AccountWithMetadata::new(
@ -545,47 +149,4 @@ mod tests {
assert_eq!(sender_post.account(), &expected_sender_post); assert_eq!(sender_post.account(), &expected_sender_post);
assert_eq!(recipient_post.account(), &expected_recipient_post); assert_eq!(recipient_post.account(), &expected_recipient_post);
} }
#[test]
fn builtin_programs() {
let auth_transfer_program = Program::authenticated_transfer_program();
let token_program = Program::token();
let vault_program = Program::vault();
let faucet_program = Program::faucet();
let bridge_program = Program::bridge();
let pinata_program = Program::pinata();
assert_eq!(auth_transfer_program.id, AUTHENTICATED_TRANSFER_ID);
assert_eq!(auth_transfer_program.elf, AUTHENTICATED_TRANSFER_ELF);
assert_eq!(token_program.id, TOKEN_ID);
assert_eq!(token_program.elf, TOKEN_ELF);
assert_eq!(vault_program.id, VAULT_ID);
assert_eq!(vault_program.elf, VAULT_ELF);
assert_eq!(faucet_program.id, FAUCET_ID);
assert_eq!(faucet_program.elf, FAUCET_ELF);
assert_eq!(bridge_program.id, BRIDGE_ID);
assert_eq!(bridge_program.elf, BRIDGE_ELF);
assert_eq!(pinata_program.id, PINATA_ID);
assert_eq!(pinata_program.elf, PINATA_ELF);
}
#[test]
fn builtin_program_ids_match_elfs() {
let cases: &[(&[u8], [u32; 8])] = &[
(AMM_ELF, AMM_ID),
(AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID),
(ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID),
(CLOCK_ELF, CLOCK_ID),
(FAUCET_ELF, FAUCET_ID),
(BRIDGE_ELF, BRIDGE_ID),
(PINATA_ELF, PINATA_ID),
(PINATA_TOKEN_ELF, PINATA_TOKEN_ID),
(TOKEN_ELF, TOKEN_ID),
(VAULT_ELF, VAULT_ID),
];
for (elf, expected_id) in cases {
let program = Program::new(elf.to_vec()).unwrap();
assert_eq!(program.id(), *expected_id);
}
}
} }

View File

@ -66,7 +66,6 @@ pub mod tests {
use crate::{ use crate::{
AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V03State, AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V03State,
error::LeeError, error::LeeError,
program::Program,
public_transaction::{Message, WitnessSet}, public_transaction::{Message, WitnessSet},
validated_state_diff::ValidatedStateDiff, validated_state_diff::ValidatedStateDiff,
}; };
@ -82,7 +81,9 @@ pub mod tests {
fn state_for_tests() -> V03State { fn state_for_tests() -> V03State {
let (_, _, addr1, addr2) = keys_for_tests(); let (_, _, addr1, addr2) = keys_for_tests();
let initial_data = [(addr1, 10000), (addr2, 20000)]; let initial_data = [(addr1, 10000), (addr2, 20000)];
V03State::new_with_genesis_accounts(&initial_data, vec![], 0) V03State::new()
.with_public_account_balances(initial_data)
.with_programs([crate::test_methods::simple_balance_transfer()])
} }
fn transaction_for_tests() -> PublicTransaction { fn transaction_for_tests() -> PublicTransaction {
@ -90,7 +91,7 @@ pub mod tests {
let nonces = vec![0_u128.into(), 0_u128.into()]; let nonces = vec![0_u128.into(), 0_u128.into()];
let instruction = 1337; let instruction = 1337;
let message = Message::try_new( let message = Message::try_new(
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
vec![addr1, addr2], vec![addr1, addr2],
nonces, nonces,
instruction, instruction,
@ -168,7 +169,7 @@ pub mod tests {
let nonces = vec![0_u128.into(), 0_u128.into()]; let nonces = vec![0_u128.into(), 0_u128.into()];
let instruction = 1337; let instruction = 1337;
let message = Message::try_new( let message = Message::try_new(
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
vec![addr1, addr1], vec![addr1, addr1],
nonces, nonces,
instruction, instruction,
@ -188,7 +189,7 @@ pub mod tests {
let nonces = vec![0_u128.into()]; let nonces = vec![0_u128.into()];
let instruction = 1337; let instruction = 1337;
let message = Message::try_new( let message = Message::try_new(
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
vec![addr1, addr2], vec![addr1, addr2],
nonces, nonces,
instruction, instruction,
@ -208,7 +209,7 @@ pub mod tests {
let nonces = vec![0_u128.into(), 0_u128.into()]; let nonces = vec![0_u128.into(), 0_u128.into()];
let instruction = 1337; let instruction = 1337;
let message = Message::try_new( let message = Message::try_new(
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
vec![addr1, addr2], vec![addr1, addr2],
nonces, nonces,
instruction, instruction,
@ -229,7 +230,7 @@ pub mod tests {
let nonces = vec![0_u128.into(), 1_u128.into()]; let nonces = vec![0_u128.into(), 1_u128.into()];
let instruction = 1337; let instruction = 1337;
let message = Message::try_new( let message = Message::try_new(
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
vec![addr1, addr2], vec![addr1, addr2],
nonces, nonces,
instruction, instruction,

File diff suppressed because it is too large Load Diff

View File

@ -462,7 +462,7 @@ impl ValidatedStateDiff {
state: &V03State, state: &V03State,
) -> Result<Self, LeeError> { ) -> Result<Self, LeeError> {
// TODO: remove clone // TODO: remove clone
let program = Program::new(tx.message.bytecode.clone())?; let program = Program::new(tx.message.bytecode.clone().into())?;
if state.programs().contains_key(&program.id()) { if state.programs().contains_key(&program.id()) {
return Err(LeeError::ProgramAlreadyExists); return Err(LeeError::ProgramAlreadyExists);
} }
@ -516,7 +516,9 @@ fn n_unique<T: Eq + Hash>(data: &[T]) -> usize {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use lee_core::account::{AccountId, Nonce}; use std::collections::HashMap;
use lee_core::account::{Account, AccountId, Nonce};
use crate::{ use crate::{
PrivateKey, PublicKey, V03State, PrivateKey, PublicKey, V03State,
@ -526,27 +528,43 @@ mod tests {
validated_state_diff::ValidatedStateDiff, validated_state_diff::ValidatedStateDiff,
}; };
fn public_state_from_balances(
initial_data: &[(AccountId, u128)],
) -> HashMap<AccountId, Account> {
initial_data
.iter()
.copied()
.map(|(account_id, balance)| {
(
account_id,
Account {
program_owner: crate::test_methods::simple_balance_transfer().id(),
balance,
..Account::default()
},
)
})
.collect()
}
#[test] #[test]
fn public_diff_reflects_a_successful_transfer() { fn public_diff_reflects_a_successful_transfer() {
// A successful native transfer must record the debited sender in // A successful native transfer must record the debited sender in
// `public_diff()`. Catches the mutation that replaces `public_diff` with // `public_diff()`. Catches the mutation that replaces `public_diff` with
// `HashMap::new()` (which would hide every account change). // `HashMap::new()` (which would hide every account change).
use authenticated_transfer_core::Instruction as AtInstruction;
let from_key = PrivateKey::try_new([1_u8; 32]).unwrap(); let from_key = PrivateKey::try_new([1_u8; 32]).unwrap();
let from = AccountId::from(&PublicKey::new_from_private_key(&from_key)); let from = AccountId::from(&PublicKey::new_from_private_key(&from_key));
let to_key = PrivateKey::try_new([2_u8; 32]).unwrap(); let to_key = PrivateKey::try_new([2_u8; 32]).unwrap();
let to = AccountId::from(&PublicKey::new_from_private_key(&to_key)); let to = AccountId::from(&PublicKey::new_from_private_key(&to_key));
let state = V03State::new_with_genesis_accounts(&[(from, 100)], vec![], 0); let state = V03State::new()
let program_id = Program::authenticated_transfer_program().id(); .with_public_accounts(public_state_from_balances(&[(from, 100)]))
let message = Message::try_new( .with_programs(std::iter::once(
program_id, crate::test_methods::simple_balance_transfer(),
vec![from, to], ));
vec![Nonce(0), Nonce(0)], let program_id = crate::test_methods::simple_balance_transfer().id();
AtInstruction::Transfer { amount: 5 }, let message =
) Message::try_new(program_id, vec![from, to], vec![Nonce(0), Nonce(0)], 5_u128).unwrap();
.unwrap();
let witness_set = WitnessSet::for_message(&message, &[&from_key, &to_key]); let witness_set = WitnessSet::for_message(&message, &[&from_key, &to_key]);
let tx = crate::PublicTransaction::new(message, witness_set); let tx = crate::PublicTransaction::new(message, witness_set);
@ -596,7 +614,7 @@ mod tests {
type InjectorInstruction = ( type InjectorInstruction = (
lee_core::program::ProgramId, // p2_id lee_core::program::ProgramId, // p2_id
lee_core::program::ProgramId, // auth_transfer_id lee_core::program::ProgramId, // simple_balance_transfer_id
[u8; 32], // victim_id_raw [u8; 32], // victim_id_raw
u128, // victim_balance u128, // victim_balance
u128, // victim_nonce u128, // victim_nonce
@ -614,18 +632,21 @@ mod tests {
let recipient_id = AccountId::new([42_u8; 32]); let recipient_id = AccountId::new([42_u8; 32]);
let victim_balance = 5_000_u128; let victim_balance = 5_000_u128;
// genesis sets program_owner = authenticated_transfer_program.id() on all accounts. // genesis sets program_owner = simple_balance_transfer_program.id() on all accounts.
let mut state = V03State::new_with_genesis_accounts( let state = V03State::new()
&[(victim_id, victim_balance), (recipient_id, 0)], .with_public_accounts(public_state_from_balances(&[
vec![], (victim_id, victim_balance),
0, (recipient_id, 0),
); ]))
state.insert_program(Program::malicious_injector()); .with_programs([
state.insert_program(Program::malicious_launderer()); crate::test_methods::simple_balance_transfer(),
crate::test_methods::malicious_injector(),
crate::test_methods::malicious_launderer(),
]);
// Build attacker's private account and its local commitment tree. // Build attacker's private account and its local commitment tree.
let attacker_account = Account { let attacker_account = Account {
program_owner: Program::authenticated_transfer_program().id(), program_owner: crate::test_methods::simple_balance_transfer().id(),
balance: 100, balance: 100,
..Account::default() ..Account::default()
}; };
@ -640,8 +661,8 @@ mod tests {
let victim_account = state.get_account_by_id(victim_id); let victim_account = state.get_account_by_id(victim_id);
let instruction: InjectorInstruction = ( let instruction: InjectorInstruction = (
Program::malicious_launderer().id(), crate::test_methods::malicious_launderer().id(),
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
*victim_id.value(), *victim_id.value(),
victim_account.balance, victim_account.balance,
victim_account.nonce.0, victim_account.nonce.0,
@ -651,17 +672,17 @@ mod tests {
); );
let instruction_data = Program::serialize_instruction(instruction).unwrap(); let instruction_data = Program::serialize_instruction(instruction).unwrap();
let p2 = Program::malicious_launderer(); let p2 = crate::test_methods::malicious_launderer();
let at = Program::authenticated_transfer_program(); let at = crate::test_methods::simple_balance_transfer();
let program_with_deps = ProgramWithDependencies::new( let program_with_deps = ProgramWithDependencies::new(
Program::malicious_injector(), crate::test_methods::malicious_injector(),
[(p2.id(), p2), (at.id(), at)].into(), [(p2.id(), p2), (at.id(), at)].into(),
); );
// account_identities order must match self.pre_states as built by the circuit: // account_identities order must match self.pre_states as built by the circuit:
// [0] attacker — first seen in P1's program_output.pre_states // [0] attacker — first seen in P1's program_output.pre_states
// [1] victim — first seen in authenticated_transfer's program_output.pre_states // [1] victim — first seen in simple_balance_transfer's program_output.pre_states
// [2] recipient — first seen in authenticated_transfer's program_output.pre_states // [2] recipient — first seen in simple_balance_transfer's program_output.pre_states
let account_identities = vec![ let account_identities = vec![
InputAccountIdentity::PrivateAuthorizedUpdate { InputAccountIdentity::PrivateAuthorizedUpdate {
epk: attacker_epk, epk: attacker_epk,
@ -751,7 +772,7 @@ mod tests {
type InjectorInstruction = ( type InjectorInstruction = (
lee_core::program::ProgramId, // p2_id lee_core::program::ProgramId, // p2_id
lee_core::program::ProgramId, // auth_transfer_id lee_core::program::ProgramId, // simple_balance_transfer_id
[u8; 32], // victim_id_raw [u8; 32], // victim_id_raw
u128, // victim_balance u128, // victim_balance
u128, // victim_nonce u128, // victim_nonce
@ -773,13 +794,17 @@ mod tests {
let recipient_id = AccountId::new([42_u8; 32]); let recipient_id = AccountId::new([42_u8; 32]);
// Victim has no public state entry; only recipient is registered at genesis. // Victim has no public state entry; only recipient is registered at genesis.
let mut state = V03State::new_with_genesis_accounts(&[(recipient_id, 0)], vec![], 0); let state = V03State::new()
state.insert_program(Program::malicious_injector()); .with_public_accounts(public_state_from_balances(&[(recipient_id, 0)]))
state.insert_program(Program::malicious_launderer()); .with_programs([
crate::test_methods::simple_balance_transfer(),
crate::test_methods::malicious_injector(),
crate::test_methods::malicious_launderer(),
]);
// Build attacker's private account and its local commitment tree. // Build attacker's private account and its local commitment tree.
let attacker_account = Account { let attacker_account = Account {
program_owner: Program::authenticated_transfer_program().id(), program_owner: crate::test_methods::simple_balance_transfer().id(),
balance: 100, balance: 100,
..Account::default() ..Account::default()
}; };
@ -793,32 +818,32 @@ mod tests {
let attacker_pre = AccountWithMetadata::new(attacker_account, true, attacker_id); let attacker_pre = AccountWithMetadata::new(attacker_account, true, attacker_id);
// The attacker supplies the victim's account data directly — it cannot be read from // The attacker supplies the victim's account data directly — it cannot be read from
// public state. The injected balance and program_owner allow authenticated_transfer // public state. The injected balance and program_owner allow simple_balance_transfer
// to succeed inside the circuit, which has no access to chain state and cannot detect // to succeed inside the circuit, which has no access to chain state and cannot detect
// that these values are fabricated. // that these values are fabricated.
let instruction: InjectorInstruction = ( let instruction: InjectorInstruction = (
Program::malicious_launderer().id(), crate::test_methods::malicious_launderer().id(),
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
*victim_id.value(), *victim_id.value(),
victim_balance, victim_balance,
0_u128, // nonce 0_u128, // nonce
Program::authenticated_transfer_program().id(), // program_owner crate::test_methods::simple_balance_transfer().id(), // program_owner
*recipient_id.value(), *recipient_id.value(),
victim_balance, victim_balance,
); );
let instruction_data = Program::serialize_instruction(instruction).unwrap(); let instruction_data = Program::serialize_instruction(instruction).unwrap();
let p2 = Program::malicious_launderer(); let p2 = crate::test_methods::malicious_launderer();
let at = Program::authenticated_transfer_program(); let at = crate::test_methods::simple_balance_transfer();
let program_with_deps = ProgramWithDependencies::new( let program_with_deps = ProgramWithDependencies::new(
Program::malicious_injector(), crate::test_methods::malicious_injector(),
[(p2.id(), p2), (at.id(), at)].into(), [(p2.id(), p2), (at.id(), at)].into(),
); );
// account_identities order must match self.pre_states as built by the circuit: // account_identities order must match self.pre_states as built by the circuit:
// [0] attacker — first seen in P1's program_output.pre_states // [0] attacker — first seen in P1's program_output.pre_states
// [1] victim — first seen in authenticated_transfer's program_output.pre_states // [1] victim — first seen in simple_balance_transfer's program_output.pre_states
// [2] recipient — first seen in authenticated_transfer's program_output.pre_states // [2] recipient — first seen in simple_balance_transfer's program_output.pre_states
// //
// Victim is marked Public: the attacker has no nsk for the victim's private account, // Victim is marked Public: the attacker has no nsk for the victim's private account,
// so PrivateAuthorizedUpdate is not an option. // so PrivateAuthorizedUpdate is not an option.
@ -838,7 +863,7 @@ mod tests {
InputAccountIdentity::Public, // recipient InputAccountIdentity::Public, // recipient
]; ];
// execute_and_prove succeeds: authenticated_transfer runs against the injected // execute_and_prove succeeds: simple_balance_transfer runs against the injected
// victim(balance=5000, is_authorized=true) and produces valid inner receipts. // victim(balance=5000, is_authorized=true) and produces valid inner receipts.
// The outer circuit commits victim(is_authorized=true) to public_pre_states. // The outer circuit commits victim(is_authorized=true) to public_pre_states.
let (circuit_output, proof) = execute_and_prove( let (circuit_output, proof) = execute_and_prove(
@ -880,7 +905,7 @@ mod tests {
/// Transaction (attacker signs) → P1 (`malicious_injector`) /// Transaction (attacker signs) → P1 (`malicious_injector`)
/// → injects `victim(is_authorized=true)` into chained-call `pre_states` for P2 /// → injects `victim(is_authorized=true)` into chained-call `pre_states` for P2
/// P2 (`malicious_launderer`) /// P2 (`malicious_launderer`)
/// → outputs empty pre/post states, forwarding the forged flag to `authenticated_transfer` /// → outputs empty pre/post states, forwarding the forged flag to `simple_balance_transfer`
/// → if `authorized_accounts` were built from the injected `pre_states`, /// → if `authorized_accounts` were built from the injected `pre_states`,
/// `{victim}.contains(victim)` would pass and the transfer would execute. /// `{victim}.contains(victim)` would pass and the transfer would execute.
/// ///
@ -889,13 +914,13 @@ mod tests {
/// input, so a forged `is_authorized=true` flag is never trusted. /// input, so a forged `is_authorized=true` flag is never trusted.
#[test] #[test]
fn malicious_programs_cannot_drain_victim_without_signature() { fn malicious_programs_cannot_drain_victim_without_signature() {
// p2_id, auth_transfer_id, victim_id_raw, victim_balance, victim_nonce, // p2_id, simple_balance_transfer_id, victim_id_raw, victim_balance, victim_nonce,
// victim_program_owner, recipient_id_raw, amount. // victim_program_owner, recipient_id_raw, amount.
// Primitives only — AccountId/Account cannot round-trip through instruction_data // Primitives only — AccountId/Account cannot round-trip through instruction_data
// via risc0_zkvm::serde (SerializeDisplay issue). // via risc0_zkvm::serde (SerializeDisplay issue).
type InjectorInstruction = ( type InjectorInstruction = (
lee_core::program::ProgramId, // p2_id lee_core::program::ProgramId, // p2_id
lee_core::program::ProgramId, // auth_transfer_id lee_core::program::ProgramId, // simple_balance_transfer_id
[u8; 32], // victim_id_raw [u8; 32], // victim_id_raw
u128, // victim_balance u128, // victim_balance
u128, // victim_nonce u128, // victim_nonce
@ -913,25 +938,24 @@ mod tests {
let recipient_id = AccountId::new([42; 32]); let recipient_id = AccountId::new([42; 32]);
let victim_balance = 5_000_u128; let victim_balance = 5_000_u128;
let mut state = V03State::new_with_genesis_accounts( let state = V03State::new()
&[ .with_public_accounts(public_state_from_balances(&[
(attacker_id, 100), (attacker_id, 100),
(victim_id, victim_balance), (victim_id, victim_balance),
(recipient_id, 0), (recipient_id, 0),
], ]))
vec![], .with_programs([
0, crate::test_methods::simple_balance_transfer(),
); crate::test_methods::malicious_injector(),
crate::test_methods::malicious_launderer(),
state.insert_program(Program::malicious_injector()); ]);
state.insert_program(Program::malicious_launderer());
// Read victim state from chain, exactly as the attacker would. // Read victim state from chain, exactly as the attacker would.
let victim_account = state.get_account_by_id(victim_id); let victim_account = state.get_account_by_id(victim_id);
let instruction: InjectorInstruction = ( let instruction: InjectorInstruction = (
Program::malicious_launderer().id(), crate::test_methods::malicious_launderer().id(),
Program::authenticated_transfer_program().id(), crate::test_methods::simple_balance_transfer().id(),
*victim_id.value(), *victim_id.value(),
victim_account.balance, victim_account.balance,
victim_account.nonce.0, victim_account.nonce.0,
@ -941,7 +965,7 @@ mod tests {
); );
let message = Message::try_new( let message = Message::try_new(
Program::malicious_injector().id(), crate::test_methods::malicious_injector().id(),
vec![attacker_id], vec![attacker_id],
vec![Nonce(0)], vec![Nonce(0)],
instruction, instruction,
@ -994,7 +1018,7 @@ mod tests {
}, },
}; };
let state = V03State::new_with_genesis_accounts(&[], vec![], 0); let state = V03State::new();
// Minimal message that passes every check up to proof verification: a single // Minimal message that passes every check up to proof verification: a single
// commitment satisfies the non-empty requirement, no signers makes the // commitment satisfies the non-empty requirement, no signers makes the

View File

@ -1,5 +1,5 @@
[package] [package]
name = "program_methods" name = "test_methods"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
license = { workspace = true } license = { workspace = true }

View File

@ -0,0 +1,14 @@
[package]
name = "test_methods_guests"
version = "0.1.0"
edition = "2024"
license = { workspace = true }
[lints]
workspace = true
[dependencies]
lee_core.workspace = true
risc0-zkvm.workspace = true
serde.workspace = true

Some files were not shown because too many files have changed in this diff Show More