diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40a0a84c..a8c588b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: - name: Lint programs env: RISC0_SKIP_BUILD: "1" - run: cargo clippy -p "*programs" -- -D warnings + run: cargo clippy -p "*program" -- -D warnings unit-tests: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 86295b9d..3f973541 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,7 @@ dependencies = [ "amm_core", "lee", "lee_core", + "programs", "token_core", ] @@ -513,6 +514,24 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "astral-tokio-tar" version = "0.6.2" @@ -665,24 +684,6 @@ dependencies = [ "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]] name = "atomic-polyfill" version = "1.0.3" @@ -758,6 +759,14 @@ dependencies = [ "serde", ] +[[package]] +name = "authenticated_transfer_program" +version = "0.1.0" +dependencies = [ + "authenticated_transfer_core", + "lee_core", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -1145,6 +1154,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bridge_program" +version = "0.1.0" +dependencies = [ + "authenticated_transfer_core", + "bridge_core", + "lee_core", + "vault_core", +] + [[package]] name = "bs58" version = "0.5.1" @@ -1154,6 +1173,14 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "build_utils" +version = "0.1.0" +dependencies = [ + "anyhow", + "risc0-binfmt", +] + [[package]] name = "bumpalo" version = "3.20.3" @@ -1452,6 +1479,14 @@ dependencies = [ "lee_core", ] +[[package]] +name = "clock_program" +version = "0.1.0" +dependencies = [ + "clock_core", + "lee_core", +] + [[package]] name = "cmov" version = "0.5.4" @@ -1514,9 +1549,11 @@ dependencies = [ "lee_core", "log", "logos-blockchain-common-http-client", + "programs", "serde", "serde_with", "sha2", + "system_accounts", "thiserror 2.0.18", ] @@ -1932,7 +1969,7 @@ version = "0.1.0" dependencies = [ "amm_core", "anyhow", - "ata_core", + "associated_token_account_core", "authenticated_transfer_core", "borsh", "clap", @@ -1940,9 +1977,11 @@ dependencies = [ "criterion", "lee", "lee_core", + "programs", "risc0-zkvm", "serde", "serde_json", + "test_programs", "token_core", ] @@ -2640,6 +2679,16 @@ dependencies = [ "serde", ] +[[package]] +name = "faucet_program" +version = "0.1.0" +dependencies = [ + "authenticated_transfer_core", + "faucet_core", + "lee_core", + "vault_core", +] + [[package]] name = "fd-lock" version = "4.0.4" @@ -3959,7 +4008,7 @@ name = "integration_tests" version = "0.1.0" dependencies = [ "anyhow", - "ata_core", + "associated_token_account_core", "authenticated_transfer_core", "borsh", "bridge_core", @@ -3980,12 +4029,15 @@ dependencies = [ "logos-blockchain-key-management-system-service", "logos-blockchain-zone-sdk", "num-bigint 0.4.6", + "programs", "reqwest", "sequencer_core", "sequencer_service_rpc", "serde_json", + "system_accounts", "tempfile", "test_fixtures", + "test_programs", "token_core", "tokio", "vault_core", @@ -4499,12 +4551,9 @@ name = "lee" version = "0.1.0" dependencies = [ "anyhow", - "authenticated_transfer_core", "borsh", - "bridge_core", - "clock_core", + "build_utils", "env_logger", - "faucet_core", "hex", "hex-literal 1.1.0", "k256", @@ -4512,13 +4561,12 @@ dependencies = [ "log", "rand 0.8.6", "risc0-binfmt", - "risc0-build", "risc0-zkvm", "serde", "serde_with", "sha2", "test-case", - "test_program_methods", + "test_methods", "thiserror 2.0.18", "token_core", ] @@ -7112,6 +7160,23 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "pkcs1" version = "0.7.5" @@ -7265,6 +7330,14 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "privacy_preserving_circuit_program" +version = "0.1.0" +dependencies = [ + "lee_core", + "risc0-zkvm", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -7366,28 +7439,22 @@ dependencies = [ "wallet", ] -[[package]] -name = "program_methods" -version = "0.1.0" -dependencies = [ - "risc0-build", -] - [[package]] name = "programs" version = "0.1.0" dependencies = [ "amm_core", "amm_program", - "ata_core", - "ata_program", + "associated_token_account_core", + "associated_token_account_program", "authenticated_transfer_core", "bridge_core", + "build_utils", "clock_core", "faucet_core", + "lee", "lee_core", "risc0-zkvm", - "serde", "token_core", "token_program", "vault_core", @@ -8842,14 +8909,17 @@ dependencies = [ "logos-blockchain-zone-sdk", "mempool", "num-bigint 0.4.6", + "programs", "rand 0.8.6", "risc0-zkvm", "serde", "serde_json", "storage", + "system_accounts", "tempfile", - "test_program_methods", + "test_programs", "testnet_initial_state", + "token_core", "tokio", "url", "vault_core", @@ -8870,6 +8940,7 @@ dependencies = [ "lee", "log", "mempool", + "programs", "sequencer_core", "sequencer_service_protocol", "sequencer_service_rpc", @@ -9388,7 +9459,9 @@ dependencies = [ "borsh", "common", "lee", + "programs", "rocksdb", + "system_accounts", "tempfile", "thiserror 2.0.18", ] @@ -9541,6 +9614,17 @@ dependencies = [ "libc", ] +[[package]] +name = "system_accounts" +version = "0.1.0" +dependencies = [ + "bridge_core", + "clock_core", + "faucet_core", + "lee_core", + "programs", +] + [[package]] name = "tachys" version = "0.2.15" @@ -9663,6 +9747,7 @@ dependencies = [ "lee", "lee_core", "log", + "programs", "sequencer_core", "sequencer_service", "sequencer_service_rpc", @@ -9676,14 +9761,23 @@ dependencies = [ ] [[package]] -name = "test_program_methods" +name = "test_methods" version = "0.1.0" dependencies = [ "risc0-build", ] [[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" dependencies = [ "authenticated_transfer_core", @@ -9691,7 +9785,14 @@ dependencies = [ "faucet_core", "lee_core", "risc0-zkvm", - "serde", +] + +[[package]] +name = "test_programs" +version = "0.1.0" +dependencies = [ + "lee", + "risc0-build", ] [[package]] @@ -9731,11 +9832,12 @@ dependencies = [ name = "testnet_initial_state" version = "0.1.0" dependencies = [ - "common", "key_protocol", "lee", "lee_core", + "programs", "serde", + "system_accounts", ] [[package]] @@ -10693,6 +10795,15 @@ dependencies = [ "serde", ] +[[package]] +name = "vault_program" +version = "0.1.0" +dependencies = [ + "authenticated_transfer_core", + "lee_core", + "vault_core", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -10721,8 +10832,8 @@ version = "0.1.0" dependencies = [ "amm_core", "anyhow", + "associated_token_account_core", "async-stream", - "ata_core", "authenticated_transfer_core", "base58", "bincode", @@ -10744,6 +10855,7 @@ dependencies = [ "lee_core", "log", "optfield", + "programs", "pyo3", "rand 0.8.6", "rpassword", @@ -10751,6 +10863,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "system_accounts", "tempfile", "testnet_initial_state", "thiserror 2.0.18", @@ -10771,6 +10884,7 @@ dependencies = [ "key_protocol", "lee", "lee_core", + "programs", "risc0-zkvm", "sequencer_service_rpc", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 4c64aaba..3e71f293 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,25 +5,17 @@ license = "MIT or Apache-2.0" resolver = "3" members = [ "integration_tests", + "lez/storage", "lee/key_protocol", "lee/state_machine", "lee/state_machine/core", - "lez/mempool", - "lez/wallet", - "lez/wallet-ffi", - "lez/common", - "programs/amm/core", - "programs/amm", - "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", + "lee/privacy_preserving_circuit", + "lee/state_machine/test_methods", + "lee/state_machine/test_methods/guest", + + "lez", + "lez/system_accounts", "lez/sequencer/core", "lez/sequencer/service", "lez/sequencer/service/protocol", @@ -33,18 +25,36 @@ members = [ "lez/indexer/service/protocol", "lez/indexer/service/rpc", "lez/explorer_service", - "program_methods", - "program_methods/guest", - "test_program_methods", - "test_program_methods/guest", + "lez/testnet_initial_state", + "lez/indexer/ffi", + "lez/keycard_wallet", + "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/methods", "examples/program_deployment/methods/guest", - "lez/testnet_initial_state", - "lez/indexer/ffi", - "lez", - "lez/keycard_wallet", + + "build_utils", + "test_fixtures", + "tools/cycle_bench", "tools/crypto_primitives_bench", "tools/integration_bench", @@ -69,18 +79,23 @@ wallet = { path = "lez/wallet" } wallet-ffi = { path = "lez/wallet-ffi", default-features = false } indexer_ffi = { path = "lez/indexer/ffi" } lez = { path = "lez" } -clock_core = { path = "programs/clock/core" } -token_core = { path = "programs/token/core" } -token_program = { path = "programs/token" } -amm_core = { path = "programs/amm/core" } -amm_program = { path = "programs/amm" } -ata_core = { path = "programs/associated_token_account/core" } -ata_program = { path = "programs/associated_token_account" } -authenticated_transfer_core = { path = "programs/authenticated_transfer/core" } -faucet_core = { path = "programs/faucet/core" } -bridge_core = { path = "programs/bridge/core" } -vault_core = { path = "programs/vault/core" } -test_program_methods = { path = "test_program_methods" } +programs = { path = "lez/programs", default-features = false, features = [ + "artifacts", +] } +system_accounts = { path = "lez/system_accounts" } +clock_core = { path = "lez/programs/clock/core" } +token_core = { path = "lez/programs/token/core" } +token_program = { path = "lez/programs/token" } +amm_core = { path = "lez/programs/amm/core" } +amm_program = { path = "lez/programs/amm" } +associated_token_account_core = { path = "lez/programs/associated_token_account/core" } +ata_program = { path = "lez/programs/associated_token_account" } +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" } keycard_wallet = { path = "lez/keycard_wallet" } test_fixtures = { path = "test_fixtures" } diff --git a/Justfile b/Justfile index 690bdc1d..afd3d9b7 100644 --- a/Justfile +++ b/Justfile @@ -4,19 +4,25 @@ default: @just --list # ---- Configuration ---- -METHODS_PATH := "program_methods" -TEST_METHODS_PATH := "test_program_methods" ARTIFACTS := "artifacts" # Build risc0 program artifacts. build-artifacts: @echo "🔨 Building artifacts" - @for methods_path in {{METHODS_PATH}} {{TEST_METHODS_PATH}}; do \ - echo "Building artifacts for $methods_path"; \ - CARGO_TARGET_DIR=target/$methods_path cargo risczero build --manifest-path $methods_path/guest/Cargo.toml; \ - mkdir -p {{ARTIFACTS}}/$methods_path; \ - cp target/$methods_path/riscv32im-risc0-zkvm-elf/docker/*.bin {{ARTIFACTS}}/$methods_path; \ - done + @rm -rf {{ARTIFACTS}} + @just build-artifact lee/privacy_preserving_circuit + @just build-artifact lez/programs programs + +build-artifact methods_path features="": + @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. fmt: diff --git a/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin new file mode 100644 index 00000000..e0a383b5 Binary files /dev/null and b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin differ diff --git a/artifacts/lez/programs/amm.bin b/artifacts/lez/programs/amm.bin new file mode 100644 index 00000000..1cd07ff0 Binary files /dev/null and b/artifacts/lez/programs/amm.bin differ diff --git a/artifacts/lez/programs/associated_token_account.bin b/artifacts/lez/programs/associated_token_account.bin new file mode 100644 index 00000000..0a5310b4 Binary files /dev/null and b/artifacts/lez/programs/associated_token_account.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/lez/programs/authenticated_transfer.bin similarity index 58% rename from artifacts/program_methods/authenticated_transfer.bin rename to artifacts/lez/programs/authenticated_transfer.bin index 481baa83..5e2cf804 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/lez/programs/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/bridge.bin b/artifacts/lez/programs/bridge.bin similarity index 59% rename from artifacts/program_methods/bridge.bin rename to artifacts/lez/programs/bridge.bin index c55b6f94..2c45ef05 100644 Binary files a/artifacts/program_methods/bridge.bin and b/artifacts/lez/programs/bridge.bin differ diff --git a/artifacts/program_methods/clock.bin b/artifacts/lez/programs/clock.bin similarity index 88% rename from artifacts/program_methods/clock.bin rename to artifacts/lez/programs/clock.bin index 151a72d7..2141c3bc 100644 Binary files a/artifacts/program_methods/clock.bin and b/artifacts/lez/programs/clock.bin differ diff --git a/artifacts/program_methods/faucet.bin b/artifacts/lez/programs/faucet.bin similarity index 70% rename from artifacts/program_methods/faucet.bin rename to artifacts/lez/programs/faucet.bin index 1385c2e1..8f79b4a5 100644 Binary files a/artifacts/program_methods/faucet.bin and b/artifacts/lez/programs/faucet.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/lez/programs/pinata.bin similarity index 69% rename from artifacts/program_methods/pinata.bin rename to artifacts/lez/programs/pinata.bin index 7ae7c005..47aedc8d 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/lez/programs/pinata.bin differ diff --git a/artifacts/lez/programs/pinata_token.bin b/artifacts/lez/programs/pinata_token.bin new file mode 100644 index 00000000..51b744e1 Binary files /dev/null and b/artifacts/lez/programs/pinata_token.bin differ diff --git a/artifacts/lez/programs/token.bin b/artifacts/lez/programs/token.bin new file mode 100644 index 00000000..8285ab49 Binary files /dev/null and b/artifacts/lez/programs/token.bin differ diff --git a/artifacts/program_methods/vault.bin b/artifacts/lez/programs/vault.bin similarity index 69% rename from artifacts/program_methods/vault.bin rename to artifacts/lez/programs/vault.bin index 57bba45e..77250083 100644 Binary files a/artifacts/program_methods/vault.bin and b/artifacts/lez/programs/vault.bin differ diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin deleted file mode 100644 index e8eab0e7..00000000 Binary files a/artifacts/program_methods/amm.bin and /dev/null differ diff --git a/artifacts/program_methods/associated_token_account.bin b/artifacts/program_methods/associated_token_account.bin deleted file mode 100644 index ed23efb4..00000000 Binary files a/artifacts/program_methods/associated_token_account.bin and /dev/null differ diff --git a/artifacts/program_methods/genesis_supply_account.bin b/artifacts/program_methods/genesis_supply_account.bin deleted file mode 100644 index c377a1e6..00000000 Binary files a/artifacts/program_methods/genesis_supply_account.bin and /dev/null differ diff --git a/artifacts/program_methods/genesis_supply_private_account.bin b/artifacts/program_methods/genesis_supply_private_account.bin deleted file mode 100644 index 9d6aa313..00000000 Binary files a/artifacts/program_methods/genesis_supply_private_account.bin and /dev/null differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin deleted file mode 100644 index a2581702..00000000 Binary files a/artifacts/program_methods/pinata_token.bin and /dev/null differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin deleted file mode 100644 index ebd4c38f..00000000 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and /dev/null differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin deleted file mode 100644 index 430122b1..00000000 Binary files a/artifacts/program_methods/token.bin and /dev/null differ diff --git a/artifacts/test_program_methods/auth_asserting_noop.bin b/artifacts/test_program_methods/auth_asserting_noop.bin deleted file mode 100644 index 2507eacb..00000000 Binary files a/artifacts/test_program_methods/auth_asserting_noop.bin and /dev/null differ diff --git a/artifacts/test_program_methods/auth_transfer_proxy.bin b/artifacts/test_program_methods/auth_transfer_proxy.bin deleted file mode 100644 index 2672cd29..00000000 Binary files a/artifacts/test_program_methods/auth_transfer_proxy.bin and /dev/null differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin deleted file mode 100644 index d0d9893a..00000000 Binary files a/artifacts/test_program_methods/burner.bin and /dev/null differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin deleted file mode 100644 index 4511b516..00000000 Binary files a/artifacts/test_program_methods/chain_caller.bin and /dev/null differ diff --git a/artifacts/test_program_methods/chain_caller_pda_drop.bin b/artifacts/test_program_methods/chain_caller_pda_drop.bin deleted file mode 100644 index 91b42aa2..00000000 Binary files a/artifacts/test_program_methods/chain_caller_pda_drop.bin and /dev/null differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin deleted file mode 100644 index c657a86d..00000000 Binary files a/artifacts/test_program_methods/changer_claimer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin deleted file mode 100644 index 47b451ec..00000000 Binary files a/artifacts/test_program_methods/claimer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/clock_chain_caller.bin b/artifacts/test_program_methods/clock_chain_caller.bin deleted file mode 100644 index b6e5b7f6..00000000 Binary files a/artifacts/test_program_methods/clock_chain_caller.bin and /dev/null differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin deleted file mode 100644 index 4cae9b77..00000000 Binary files a/artifacts/test_program_methods/data_changer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin deleted file mode 100644 index d93baede..00000000 Binary files a/artifacts/test_program_methods/extra_output.bin and /dev/null differ diff --git a/artifacts/test_program_methods/faucet_chain_caller.bin b/artifacts/test_program_methods/faucet_chain_caller.bin deleted file mode 100644 index 01e32aa1..00000000 Binary files a/artifacts/test_program_methods/faucet_chain_caller.bin and /dev/null differ diff --git a/artifacts/test_program_methods/flash_swap_callback.bin b/artifacts/test_program_methods/flash_swap_callback.bin deleted file mode 100644 index 028b64df..00000000 Binary files a/artifacts/test_program_methods/flash_swap_callback.bin and /dev/null differ diff --git a/artifacts/test_program_methods/flash_swap_initiator.bin b/artifacts/test_program_methods/flash_swap_initiator.bin deleted file mode 100644 index f18afc5f..00000000 Binary files a/artifacts/test_program_methods/flash_swap_initiator.bin and /dev/null differ diff --git a/artifacts/test_program_methods/group_pda_spender.bin b/artifacts/test_program_methods/group_pda_spender.bin deleted file mode 100644 index 16efb8a4..00000000 Binary files a/artifacts/test_program_methods/group_pda_spender.bin and /dev/null differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin deleted file mode 100644 index 99359e22..00000000 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/malicious_caller_program_id.bin b/artifacts/test_program_methods/malicious_caller_program_id.bin deleted file mode 100644 index fe8f5511..00000000 Binary files a/artifacts/test_program_methods/malicious_caller_program_id.bin and /dev/null differ diff --git a/artifacts/test_program_methods/malicious_injector.bin b/artifacts/test_program_methods/malicious_injector.bin deleted file mode 100644 index 9cadd3b3..00000000 Binary files a/artifacts/test_program_methods/malicious_injector.bin and /dev/null differ diff --git a/artifacts/test_program_methods/malicious_launderer.bin b/artifacts/test_program_methods/malicious_launderer.bin deleted file mode 100644 index 9686a8f4..00000000 Binary files a/artifacts/test_program_methods/malicious_launderer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/malicious_self_program_id.bin b/artifacts/test_program_methods/malicious_self_program_id.bin deleted file mode 100644 index 853740ba..00000000 Binary files a/artifacts/test_program_methods/malicious_self_program_id.bin and /dev/null differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin deleted file mode 100644 index a012dd94..00000000 Binary files a/artifacts/test_program_methods/minter.bin and /dev/null differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin deleted file mode 100644 index 4a056f6d..00000000 Binary files a/artifacts/test_program_methods/missing_output.bin and /dev/null differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin deleted file mode 100644 index 65f77b77..00000000 Binary files a/artifacts/test_program_methods/modified_transfer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin deleted file mode 100644 index e1cb3175..00000000 Binary files a/artifacts/test_program_methods/nonce_changer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin deleted file mode 100644 index 7575a2c3..00000000 Binary files a/artifacts/test_program_methods/noop.bin and /dev/null differ diff --git a/artifacts/test_program_methods/pda_claimer.bin b/artifacts/test_program_methods/pda_claimer.bin deleted file mode 100644 index 55a934b1..00000000 Binary files a/artifacts/test_program_methods/pda_claimer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/pda_fund_spend_proxy.bin b/artifacts/test_program_methods/pda_fund_spend_proxy.bin deleted file mode 100644 index 9a04a29c..00000000 Binary files a/artifacts/test_program_methods/pda_fund_spend_proxy.bin and /dev/null differ diff --git a/artifacts/test_program_methods/pda_spend_proxy.bin b/artifacts/test_program_methods/pda_spend_proxy.bin deleted file mode 100644 index 8f7e8977..00000000 Binary files a/artifacts/test_program_methods/pda_spend_proxy.bin and /dev/null differ diff --git a/artifacts/test_program_methods/pinata_cooldown.bin b/artifacts/test_program_methods/pinata_cooldown.bin deleted file mode 100644 index 5655e958..00000000 Binary files a/artifacts/test_program_methods/pinata_cooldown.bin and /dev/null differ diff --git a/artifacts/test_program_methods/private_pda_claimer.bin b/artifacts/test_program_methods/private_pda_claimer.bin deleted file mode 100644 index 5a64c66d..00000000 Binary files a/artifacts/test_program_methods/private_pda_claimer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/private_pda_delegator.bin b/artifacts/test_program_methods/private_pda_delegator.bin deleted file mode 100644 index 163135b6..00000000 Binary files a/artifacts/test_program_methods/private_pda_delegator.bin and /dev/null differ diff --git a/artifacts/test_program_methods/private_pda_spender.bin b/artifacts/test_program_methods/private_pda_spender.bin deleted file mode 100644 index b9848210..00000000 Binary files a/artifacts/test_program_methods/private_pda_spender.bin and /dev/null differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin deleted file mode 100644 index 185e521e..00000000 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin deleted file mode 100644 index 57510322..00000000 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/time_locked_transfer.bin b/artifacts/test_program_methods/time_locked_transfer.bin deleted file mode 100644 index f762398b..00000000 Binary files a/artifacts/test_program_methods/time_locked_transfer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/two_pda_claimer.bin b/artifacts/test_program_methods/two_pda_claimer.bin deleted file mode 100644 index 33995cb7..00000000 Binary files a/artifacts/test_program_methods/two_pda_claimer.bin and /dev/null differ diff --git a/artifacts/test_program_methods/validity_window.bin b/artifacts/test_program_methods/validity_window.bin deleted file mode 100644 index 88cbf9c3..00000000 Binary files a/artifacts/test_program_methods/validity_window.bin and /dev/null differ diff --git a/artifacts/test_program_methods/validity_window_chain_caller.bin b/artifacts/test_program_methods/validity_window_chain_caller.bin deleted file mode 100644 index a8cb5663..00000000 Binary files a/artifacts/test_program_methods/validity_window_chain_caller.bin and /dev/null differ diff --git a/build_utils/Cargo.toml b/build_utils/Cargo.toml new file mode 100644 index 00000000..63ba15bf --- /dev/null +++ b/build_utils/Cargo.toml @@ -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" diff --git a/build_utils/src/lib.rs b/build_utils/src/lib.rs new file mode 100644 index 00000000..1323d830 --- /dev/null +++ b/build_utils/src/lib.rs @@ -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::>(); + + 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(()) +} diff --git a/examples/program_deployment/README.md b/examples/program_deployment/README.md index 6d1bde25..240079a5 100644 --- a/examples/program_deployment/README.md +++ b/examples/program_deployment/README.md @@ -46,7 +46,7 @@ export EXAMPLE_PROGRAMS_BUILD_DIR=$(pwd)/target/riscv32im-risc0-zkvm-elf/docker > [!IMPORTANT] > **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. 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 ```rust let bytecode: Vec = 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. @@ -266,7 +266,7 @@ The relevant part for this tutorial is the account id `7EDHyxejuynBpmbLuiEym9HMU > [!NOTE] > 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 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. > 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 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 ``` -Let's execute the write function +Let's execute the write function ```bash cargo run --bin run_hello_world_with_move_function \ diff --git a/examples/program_deployment/src/bin/run_hello_world.rs b/examples/program_deployment/src/bin/run_hello_world.rs index ef5545f7..3f2223a1 100644 --- a/examples/program_deployment/src/bin/run_hello_world.rs +++ b/examples/program_deployment/src/bin/run_hello_world.rs @@ -43,7 +43,7 @@ async fn main() { // Load the program let bytecode: Vec = 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 let greeting: Vec = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; diff --git a/examples/program_deployment/src/bin/run_hello_world_private.rs b/examples/program_deployment/src/bin/run_hello_world_private.rs index 088eb19a..f6202433 100644 --- a/examples/program_deployment/src/bin/run_hello_world_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_private.rs @@ -39,7 +39,7 @@ async fn main() { // Load the program let bytecode: Vec = 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 let greeting: Vec = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs index a5f449e1..6ebba70f 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs @@ -43,7 +43,7 @@ async fn main() { // Load the program let bytecode: Vec = std::fs::read(program_path).unwrap(); - let program = Program::new(bytecode).unwrap(); + let program = Program::new(bytecode.into()).unwrap(); let instruction_data = (); let nonces = vec![]; diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs index 4983afdb..d35e6521 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs @@ -44,9 +44,9 @@ async fn main() { // Load the program and its dependencies (the hellow world program) let simple_tail_call_bytecode: Vec = 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 = 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 = std::iter::once((hello_world.id(), hello_world)).collect(); let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs index 15fc028a..0d257db2 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs @@ -45,7 +45,7 @@ async fn main() { // Load the program let bytecode: Vec = 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 let signing_key = wallet_core diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs index 2b0e05ed..70688cfd 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs @@ -43,7 +43,7 @@ async fn main() { // Load the program let bytecode: Vec = 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 let pda = AccountId::for_public_pda(&program.id(), &PDA_SEED); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index 3b175bda..a77fe2e6 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -63,7 +63,7 @@ async fn main() { // Load the program let bytecode: Vec = std::fs::read(cli.program_path).unwrap(); - let program = Program::new(bytecode).unwrap(); + let program = Program::new(bytecode.into()).unwrap(); // Initialize wallet let wallet_core = WalletCore::from_env().unwrap(); diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 3b1731d8..bba06ec0 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -9,7 +9,6 @@ workspace = true [dependencies] test_fixtures.workspace = true - lee_core = { workspace = true, features = ["host"] } lee.workspace = true authenticated_transfer_core.workspace = true @@ -19,7 +18,7 @@ common.workspace = true key_protocol.workspace = true serde_json.workspace = true token_core.workspace = true -ata_core.workspace = true +associated_token_account_core.workspace = true vault_core.workspace = true faucet_core.workspace = true bridge_core.workspace = true @@ -28,6 +27,9 @@ sequencer_service_rpc = { workspace = true, features = ["client"] } wallet-ffi.workspace = true indexer_ffi.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-core.workspace = true diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 48f69559..07212251 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -10,7 +10,7 @@ use log::info; pub use test_fixtures::*; /// 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 /// current last block id or until [`L2_TO_L1_TIMEOUT`] elapses. diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index 3d5854cf..0de8a9e2 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -6,7 +6,7 @@ use anyhow::{Context as _, Result}; use integration_tests::{TestContext, private_mention}; use key_protocol::key_management::KeyChain; -use lee::{Data, program::Program}; +use lee::Data; use lee_core::account::Nonce; use log::info; use sequencer_service_rpc::RpcClient as _; @@ -31,7 +31,7 @@ async fn get_existing_account() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -158,7 +158,7 @@ async fn import_private_account() -> Result<()> { let key_chain = KeyChain::new_os_random(); let account_id = lee::AccountId::from((&key_chain.nullifier_public_key, 0)); let account = lee::Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: programs::authenticated_transfer().id(), balance: 777, data: Data::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")?; let initial_account = lee::Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: programs::authenticated_transfer().id(), balance: 100, data: Data::default(), nonce: Nonce::default(), @@ -237,7 +237,7 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<( .await?; let updated_account = lee::Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: programs::authenticated_transfer().id(), balance: 999, data: Data::default(), nonce: Nonce::default(), diff --git a/integration_tests/tests/ata.rs b/integration_tests/tests/ata.rs index 9e37061b..7faac67e 100644 --- a/integration_tests/tests/ata.rs +++ b/integration_tests/tests/ata.rs @@ -7,12 +7,11 @@ use std::time::Duration; 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::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, verify_commitment_is_in_state, }; -use lee::program::Program; use log::info; use sequencer_service_rpc::RpcClient as _; 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; // 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( &ata_program_id, &compute_ata_seed(owner_account_id, definition_account_id), @@ -105,7 +104,7 @@ async fn create_ata_initializes_holding_account() -> Result<()> { .await .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)?; assert_eq!( 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; // 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( &ata_program_id, &compute_ata_seed(owner_account_id, definition_account_id), @@ -180,7 +179,7 @@ async fn create_ata_is_idempotent() -> Result<()> { .await .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)?; assert_eq!( 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; // 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( &ata_program_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; // 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( &ata_program_id, &compute_ata_seed(owner_account_id, definition_account_id), @@ -401,7 +400,7 @@ async fn create_ata_with_private_owner() -> Result<()> { .await .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)?; assert_eq!( 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; // 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( &ata_program_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; // 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( &ata_program_id, &compute_ata_seed(holder_account_id, definition_account_id), diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 45a1b085..30f0cfdd 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -429,7 +429,7 @@ async fn initialize_private_account() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(account.balance, 0); assert!(account.data.is_empty()); @@ -526,7 +526,7 @@ async fn initialize_private_account_using_label() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); 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<()> { let ctx = TestContext::new().await?; - let binary = std::fs::read( - std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../artifacts/test_program_methods/faucet_chain_caller.bin"), - )?; + let faucet_chain_caller = test_programs::faucet_chain_caller(); 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?; info!("Waiting for deploy block creation"); 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 faucet_program_id = Program::faucet().id(); - let vault_program_id = Program::vault().id(); - let auth_transfer_program_id = Program::authenticated_transfer_program().id(); + let faucet_program_id = programs::faucet().id(); + let vault_program_id = programs::vault().id(); + let auth_transfer_program_id = programs::authenticated_transfer().id(); let nsk: lee_core::NullifierSecretKey = [3; 32]; let npk = NullifierPublicKey::from(&nsk); 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, ); - let faucet_chain_caller = Program::new(binary)?; let program_with_deps = ProgramWithDependencies::new( faucet_chain_caller, [ - (faucet_program_id, Program::faucet()), - (vault_program_id, Program::vault()), - ( - auth_transfer_program_id, - Program::authenticated_transfer_program(), - ), + (faucet_program_id, programs::faucet()), + (vault_program_id, programs::vault()), + (auth_transfer_program_id, programs::authenticated_transfer()), ] .into(), ); diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index d00b7964..5bbf0954 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -1,9 +1,9 @@ -use std::{path::PathBuf, time::Duration}; +use std::time::Duration; use anyhow::Result; use common::transaction::LeeTransaction; 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 sequencer_service_rpc::RpcClient as _; use tokio::test; @@ -250,7 +250,7 @@ async fn initialize_public_account() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(account.balance, 0); assert_eq!(account.nonce.0, 1); @@ -356,7 +356,7 @@ async fn successful_transfer_using_to_label() -> Result<()> { #[test] async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { 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_balance_before = ctx @@ -370,7 +370,7 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { let amount = 1_u128; let message = public_transaction::Message::try_new( - Program::authenticated_transfer_program().id(), + programs::authenticated_transfer().id(), vec![faucet_account_id, recipient], vec![], authenticated_transfer_core::Instruction::Transfer { amount }, @@ -407,10 +407,10 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { #[test] async fn cannot_execute_faucet_program() -> Result<()> { 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 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_balance_before = ctx @@ -424,7 +424,7 @@ async fn cannot_execute_faucet_program() -> Result<()> { let amount = 1_u128; let message = public_transaction::Message::try_new( - Program::faucet().id(), + programs::faucet().id(), vec![faucet_account_id, recipient_vault_id], vec![], 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<()> { let ctx = TestContext::new().await?; - let binary = std::fs::read( - 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 faucet_chain_caller = test_programs::faucet_chain_caller(); 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?; info!("Waiting for deploy block creation"); 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 faucet_program_id = Program::faucet().id(); - let vault_program_id = Program::vault().id(); + let faucet_program_id = programs::faucet().id(); + let vault_program_id = programs::vault().id(); let attacker_vault_id = vault_core::compute_vault_account_id(vault_program_id, attacker); let amount: u128 = 1; let message = public_transaction::Message::try_new( - faucet_chain_caller_id, + faucet_chain_caller.id(), vec![faucet_account_id, attacker_vault_id], vec![], (faucet_program_id, vault_program_id, attacker, amount), diff --git a/integration_tests/tests/block_size_limit.rs b/integration_tests/tests/block_size_limit.rs index d95150f5..d97b695d 100644 --- a/integration_tests/tests/block_size_limit.rs +++ b/integration_tests/tests/block_size_limit.rs @@ -94,16 +94,12 @@ async fn accept_transaction_within_limit() -> Result<()> { #[test] async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { - let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let artifacts_dir = - 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"))?; + let claimer = test_programs::claimer(); + let chain_caller = test_programs::chain_caller(); // Calculate block size to fit only one of the two transactions, leaving some room for headers // (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 ctx = TestContext::builder() @@ -116,16 +112,13 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { .build() .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?; // Submit both program deployments ctx.sequencer_client() .send_transaction(LeeTransaction::ProgramDeployment( lee::ProgramDeploymentTransaction::new( - lee::program_deployment_transaction::Message::new(burner_bytecode), + lee::program_deployment_transaction::Message::new(claimer.elf().to_owned()), ), )) .await?; @@ -133,7 +126,7 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { ctx.sequencer_client() .send_transaction(LeeTransaction::ProgramDeployment( lee::ProgramDeploymentTransaction::new( - lee::program_deployment_transaction::Message::new(chain_caller_bytecode), + lee::program_deployment_transaction::Message::new(chain_caller.elf().to_owned()), ), )) .await?; @@ -156,7 +149,7 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { .filter_map(|tx| { if let LeeTransaction::ProgramDeployment(deployment) = tx { 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 { None } @@ -173,8 +166,9 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { "Expected exactly one program deployment in block 1" ); assert_eq!( - block1_program_ids[0], burner_id, - "Expected burner program to be deployed in block 1" + block1_program_ids[0], + claimer.id(), + "Expected claimer program to be deployed in block 1" ); // 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" ); 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" ); diff --git a/integration_tests/tests/bridge.rs b/integration_tests/tests/bridge.rs index 41781a68..9c2fa8c5 100644 --- a/integration_tests/tests/bridge.rs +++ b/integration_tests/tests/bridge.rs @@ -43,12 +43,12 @@ async fn public_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { let ctx = TestContext::new().await?; let recipient_id = ctx.existing_public_accounts()[0]; - let bridge_account_id = lee::system_bridge_account_id(); - let vault_program_id = Program::vault().id(); + let bridge_account_id = system_accounts::bridge_account_id(); + let vault_program_id = programs::vault().id(); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); let message = public_transaction::Message::try_new( - Program::bridge().id(), + programs::bridge().id(), vec![bridge_account_id, recipient_vault_id], vec![], bridge_core::Instruction::Deposit { @@ -103,8 +103,8 @@ async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { let ctx = TestContext::new().await?; let recipient_id = ctx.existing_public_accounts()[0]; - let bridge_account_id = lee::system_bridge_account_id(); - let vault_program_id = Program::vault().id(); + let bridge_account_id = system_accounts::bridge_account_id(); + let vault_program_id = programs::vault().id(); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); // 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 let program_with_deps = 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(), - Program::authenticated_transfer_program(), + programs::authenticated_transfer().id(), + programs::authenticated_transfer(), ), ] .into(), @@ -386,7 +386,7 @@ async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Res let bedrock_account_pk = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"; let recipient_id = ctx.existing_public_accounts()[0]; 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 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 // modifies, which is the case the hot fix unblocks. 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] { let indexer_account = indexer_service_rpc::RpcClient::get_account( // `deref` is needed for correct trait resolution diff --git a/integration_tests/tests/keys.rs b/integration_tests/tests/keys.rs index 01af23cd..9fd3b3f1 100644 --- a/integration_tests/tests/keys.rs +++ b/integration_tests/tests/keys.rs @@ -12,7 +12,7 @@ use integration_tests::{ public_mention, verify_commitment_is_in_state, }; use key_protocol::key_management::key_tree::chain_index::ChainIndex; -use lee::{AccountId, program::Program}; +use lee::AccountId; use log::info; use sequencer_service_rpc::RpcClient as _; use tokio::test; @@ -257,11 +257,11 @@ async fn restore_keys_from_seed() -> Result<()> { assert_eq!( acc1.account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!( acc2.account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(acc1.account.balance, 100); diff --git a/integration_tests/tests/pinata.rs b/integration_tests/tests/pinata.rs index 9beb5b1f..fa4c3d98 100644 --- a/integration_tests/tests/pinata.rs +++ b/integration_tests/tests/pinata.rs @@ -7,7 +7,6 @@ use std::time::Duration; use anyhow::{Context as _, Result}; -use common::PINATA_BASE58; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .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"); let pinata_balance_post = ctx .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; let winner_balance_post = ctx @@ -176,7 +175,7 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> { let pinata_balance_pre = ctx .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; 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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .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 .sequencer_client() - .get_account_balance(PINATA_BASE58.parse().unwrap()) + .get_account_balance(system_accounts::pinata_account_id()) .await?; assert_eq!(pinata_balance_post, pinata_balance_pre - pinata_prize); diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index f96faa52..f3136717 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -3,14 +3,13 @@ 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 authenticated_transfer_core::Instruction as AuthTransferInstruction; use common::transaction::LeeTransaction; use integration_tests::{ - LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, - verify_commitment_is_in_state, + TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, verify_commitment_is_in_state, }; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; 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()) }; - let proxy = { - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .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 = test_programs::pda_spend_proxy(); + let auth_transfer = programs::authenticated_transfer(); let proxy_id = proxy.id(); let auth_transfer_id = auth_transfer.id(); let seed = PdaSeed::new([42; 32]); diff --git a/integration_tests/tests/program_deployment.rs b/integration_tests/tests/program_deployment.rs index 77ac1fb9..ec01c3c8 100644 --- a/integration_tests/tests/program_deployment.rs +++ b/integration_tests/tests/program_deployment.rs @@ -3,14 +3,11 @@ 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 common::transaction::LeeTransaction; -use integration_tests::{ - LEE_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, -}; -use lee::program::Program; +use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext}; use log::info; use sequencer_service_rpc::RpcClient as _; use tokio::test; @@ -23,10 +20,11 @@ use wallet::cli::{ async fn deploy_and_execute_program() -> Result<()> { let mut ctx = TestContext::new().await?; - let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let binary_filepath: PathBuf = PathBuf::from(manifest_dir) - .join("../artifacts/test_program_methods") - .join(LEE_PROGRAM_FOR_TEST_DATA_CHANGER); + let claimer = test_programs::claimer(); + let mut tempfile = tempfile::NamedTempFile::new()?; + tempfile.write_all(claimer.elf())?; + + let binary_filepath = tempfile.path().to_owned(); let command = Command::DeployProgram { binary_filepath: binary_filepath.clone(), @@ -37,13 +35,6 @@ async fn deploy_and_execute_program() -> Result<()> { info!("Waiting for next block creation"); 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( ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Public { @@ -61,12 +52,8 @@ async fn deploy_and_execute_program() -> Result<()> { .wallet() .get_account_public_signing_key(account_id) .unwrap(); - let message = lee::public_transaction::Message::try_new( - data_changer.id(), - vec![account_id], - nonces, - vec![0], - )?; + let message = + lee::public_transaction::Message::try_new(claimer.id(), vec![account_id], nonces, ())?; let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[private_key]); let transaction = lee::PublicTransaction::new(message, witness_set); 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?; - 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.data.as_ref(), &[0]); + assert_eq!(post_state_account.data.as_ref(), expected_data); assert_eq!(post_state_account.nonce.0, 1); info!("Successfully deployed and executed program"); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index b0c569e8..60bd3de8 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -12,7 +12,6 @@ use integration_tests::{ verify_commitment_is_in_state, }; use key_protocol::key_management::key_tree::chain_index::ChainIndex; -use lee::program::Program; use log::info; use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; @@ -99,7 +98,7 @@ async fn create_and_transfer_public_token() -> Result<()> { .await?; 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!( token_definition, TokenDefinition::Fungible { @@ -116,7 +115,7 @@ async fn create_and_transfer_public_token() -> Result<()> { .await?; // 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)?; assert_eq!( token_holding, @@ -148,7 +147,7 @@ async fn create_and_transfer_public_token() -> Result<()> { .sequencer_client() .get_account(supply_account_id) .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)?; assert_eq!( token_holding, @@ -163,7 +162,7 @@ async fn create_and_transfer_public_token() -> Result<()> { .sequencer_client() .get_account(recipient_account_id) .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)?; assert_eq!( token_holding, @@ -344,7 +343,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { .await?; 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!( token_definition, TokenDefinition::Fungible { @@ -508,7 +507,7 @@ async fn create_token_with_private_definition() -> Result<()> { .get_account(supply_account_id) .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)?; assert_eq!( token_holding, @@ -1231,7 +1230,7 @@ async fn create_token_using_labels() -> Result<()> { .await?; 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!( token_definition, TokenDefinition::Fungible { diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index 459f3d61..a11668a8 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -76,7 +76,7 @@ impl TpsTestManager { &self, sequencer_client: &sequencer_service_rpc::SequencerClient, ) -> 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()); 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. pub fn build_public_txs(&self) -> Vec { // Create valid public transactions - let program = Program::authenticated_transfer_program(); + let program = programs::authenticated_transfer(); let public_txs: Vec = self .public_keypairs .windows(2) @@ -254,7 +254,7 @@ pub async fn tps_test() -> Result<()> { /// 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?")] fn build_privacy_transaction() -> PrivacyPreservingTransaction { - let program = Program::authenticated_transfer_program(); + let program = programs::authenticated_transfer(); let sender_nsk = [1; 32]; let sender_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]); let sender_npk = NullifierPublicKey::from(&sender_nsk); diff --git a/integration_tests/tests/vault.rs b/integration_tests/tests/vault.rs index 33d2e9a9..e9ea2075 100644 --- a/integration_tests/tests/vault.rs +++ b/integration_tests/tests/vault.rs @@ -5,7 +5,6 @@ use anyhow::{Context as _, Result}; use integration_tests::{TestContext, private_mention, public_mention}; -use lee::program::Program; use sequencer_service_rpc::RpcClient as _; use tokio::test; 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 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 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 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 sender_balance_before = ctx diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 295d3917..0ef53592 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -31,7 +31,7 @@ use tempfile::tempdir; use wallet::{account::HumanReadableAccount, program_facades::vault::Vault}; use wallet_ffi::{ FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, - FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error, + FfiProgramId, FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error, generic_transaction::{FfiProgramWithDependencies, FfiTransactionResult}, wallet::FfiCreateWalletOutput, }; @@ -234,7 +234,7 @@ unsafe extern "C" { account_identities_size: usize, instruction_words: *const u32, instruction_words_size: usize, - program_with_dependencies: *const FfiProgramWithDependencies, + program_id: FfiProgramId, out_result: *mut FfiTransactionResult, ) -> error::WalletFfiError; @@ -608,7 +608,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -648,7 +648,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -846,7 +846,7 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> { }; assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); unsafe { @@ -906,7 +906,7 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> { }; assert_eq!( account.program_owner, - Program::authenticated_transfer_program().id() + programs::authenticated_transfer().id() ); unsafe { @@ -1493,7 +1493,7 @@ fn test_wallet_ffi_bridge_withdraw() -> Result<()> { mnemonic: _, } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; 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 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 = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; - let program: ProgramWithDependencies = Program::authenticated_transfer_program().into(); - let program_with_dependencies: FfiProgramWithDependencies = program.into(); + let program_id = programs::authenticated_transfer().id(); unsafe { wallet_ffi_send_generic_public_transaction( @@ -1595,7 +1594,7 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> { account_identities_size, instruction_words, instruction_words_size, - &raw const program_with_dependencies, + program_id.into(), &raw mut transaction_result, ) .unwrap(); @@ -1682,7 +1681,7 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> { let instruction_words_size = instruction_data.len(); 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(); unsafe { diff --git a/lee/privacy_preserving_circuit/Cargo.toml b/lee/privacy_preserving_circuit/Cargo.toml new file mode 100644 index 00000000..26dfa132 --- /dev/null +++ b/lee/privacy_preserving_circuit/Cargo.toml @@ -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 diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs b/lee/privacy_preserving_circuit/src/execution_state.rs similarity index 100% rename from program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs rename to lee/privacy_preserving_circuit/src/execution_state.rs diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/main.rs b/lee/privacy_preserving_circuit/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/privacy_preserving_circuit/main.rs rename to lee/privacy_preserving_circuit/src/main.rs diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs b/lee/privacy_preserving_circuit/src/output.rs similarity index 100% rename from program_methods/guest/src/bin/privacy_preserving_circuit/output.rs rename to lee/privacy_preserving_circuit/src/output.rs diff --git a/lee/state_machine/Cargo.toml b/lee/state_machine/Cargo.toml index 8777db09..d4014465 100644 --- a/lee/state_machine/Cargo.toml +++ b/lee/state_machine/Cargo.toml @@ -9,9 +9,6 @@ workspace = true [dependencies] lee_core = { workspace = true, features = ["host"] } -clock_core.workspace = true -faucet_core.workspace = true -bridge_core.workspace = true anyhow.workspace = true thiserror.workspace = true @@ -27,14 +24,12 @@ risc0-binfmt = "3.0.2" log.workspace = true [build-dependencies] -risc0-build = "3.0.3" -risc0-binfmt = "3.0.2" +build_utils.workspace = true [dev-dependencies] lee_core = { workspace = true, features = ["test_utils"] } token_core.workspace = true -authenticated_transfer_core.workspace = true -test_program_methods.workspace = true +test_methods = { path = "test_methods" } env_logger.workspace = true hex-literal = "1.0.0" diff --git a/lee/state_machine/build.rs b/lee/state_machine/build.rs index 5e8ac989..de7c6095 100644 --- a/lee/state_machine/build.rs +++ b/lee/state_machine/build.rs @@ -1,43 +1,5 @@ -use std::{env, fmt::Write as _, fs, path::PathBuf}; - fn main() -> Result<(), Box> { - let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); - 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::>(); - - 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()); + build_utils::include_artifacts("lee/privacy_preserving_circuit")?; Ok(()) } diff --git a/lee/state_machine/src/lib.rs b/lee/state_machine/src/lib.rs index 129821b5..f8cc034a 100644 --- a/lee/state_machine/src/lib.rs +++ b/lee/state_machine/src/lib.rs @@ -9,17 +9,16 @@ pub use lee_core::{ encryption::EphemeralPublicKey, program::ProgramId, }; +pub use privacy_preserving_circuit::{ + PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID, +}; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, }; pub use program_deployment_transaction::ProgramDeploymentTransaction; -pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; pub use public_transaction::PublicTransaction; pub use signature::{PrivateKey, PublicKey, Signature}; -pub use state::{ - 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 state::V03State; pub use validated_state_diff::ValidatedStateDiff; pub mod encoding; @@ -33,6 +32,238 @@ mod signature; mod state; mod validated_state_diff; -pub mod program_methods { - include!(concat!(env!("OUT_DIR"), "/program_methods/mod.rs")); +mod privacy_preserving_circuit { + 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), + ) + } } diff --git a/lee/state_machine/src/privacy_preserving_transaction/circuit.rs b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs index 87c7c5bb..489ee373 100644 --- a/lee/state_machine/src/privacy_preserving_transaction/circuit.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs @@ -9,9 +9,9 @@ use lee_core::{ use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; use crate::{ + PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID, error::{InvalidProgramBehaviorError, LeeError}, program::Program, - program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}, state::MAX_NUMBER_CHAINED_CALLS, }; @@ -224,7 +224,7 @@ mod tests { #[test] fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { 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( Account { program_owner: program.id(), @@ -261,10 +261,7 @@ mod tests { let (output, proof) = execute_and_prove( vec![sender, recipient], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: balance_to_move, - }) - .unwrap(), + Program::serialize_instruction(balance_to_move).unwrap(), vec![ InputAccountIdentity::Public, InputAccountIdentity::PrivateUnauthorized { @@ -278,7 +275,7 @@ mod tests { identifier: 0, }, ], - &Program::authenticated_transfer_program().into(), + &crate::test_methods::simple_balance_transfer().into(), ) .unwrap(); @@ -304,7 +301,7 @@ mod tests { #[test] 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 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 { program_owner: program.id(), @@ -366,10 +363,7 @@ mod tests { let (output, proof) = execute_and_prove( vec![sender_pre, recipient], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: balance_to_move, - }) - .unwrap(), + Program::serialize_instruction(balance_to_move).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { epk: EphemeralPublicKey(Vec::new()), @@ -434,8 +428,8 @@ mod tests { AccountId::for_regular_private_account(&account_keys.npk(), 0), ); - let validity_window_chain_caller = Program::validity_window_chain_caller(); - let validity_window = Program::validity_window(); + let validity_window_chain_caller = crate::test_methods::validity_window_chain_caller(); + let validity_window = crate::test_methods::validity_window(); let instruction = Program::serialize_instruction(( Some(1_u64), @@ -477,7 +471,7 @@ mod tests { /// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`. #[test] 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 npk = keys.npk(); let seed = PdaSeed::new([42; 32]); @@ -513,13 +507,13 @@ mod tests { ); } - /// PDA init: initializes a new PDA under `authenticated_transfer`'s ownership. - /// The `auth_transfer_proxy` program chains to `authenticated_transfer` with `pda_seeds` + /// PDA init: initializes a new PDA under `simple_balance_transfer`'s ownership. + /// The `simple_transfer_proxy` program chains to `simple_balance_transfer` with `pda_seeds` /// to establish authorization and the private PDA binding. #[test] fn private_pda_init() { - let program = Program::auth_transfer_proxy(); - let auth_transfer = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_transfer_proxy(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); 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_pre = AccountWithMetadata::new(Account::default(), false, pda_id); - let auth_id = auth_transfer.id(); + let auth_id = simple_transfer.id(); 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) 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); } - /// 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 /// two-tx sequence with membership proofs. #[test] fn private_pda_withdraw() { - let program = Program::auth_transfer_proxy(); - let auth_transfer = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_transfer_proxy(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); @@ -576,7 +570,7 @@ mod tests { let recipient_id = AccountId::new([88; 32]); let recipient_pre = AccountWithMetadata::new( Account { - program_owner: auth_transfer.id(), + program_owner: simple_transfer.id(), balance: 10000, ..Account::default() }, @@ -584,9 +578,9 @@ mod tests { recipient_id, ); - let auth_id = auth_transfer.id(); + let auth_id = simple_transfer.id(); 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) 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 /// transfer path like any other private account. #[test] - fn shared_account_receives_via_auth_transfer() { - let program = Program::authenticated_transfer_program(); + fn shared_account_receives_via_simple_transfer() { + let program = crate::test_methods::simple_balance_transfer(); let shared_keys = test_private_account_keys_1(); let shared_npk = shared_keys.npk(); let shared_identifier: u128 = 42; @@ -643,11 +637,7 @@ mod tests { let recipient = AccountWithMetadata::new(Account::default(), false, shared_account_id); let balance_to_move: u128 = 100; - let instruction = - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: balance_to_move, - }) - .unwrap(); + let instruction = Program::serialize_instruction(balance_to_move).unwrap(); let result = execute_and_prove( vec![sender, recipient], @@ -677,7 +667,7 @@ mod tests { /// to `PrivateAccountKind::Regular` carrying the correct identifier. #[test] 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 identifier: u128 = 99; let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; @@ -686,8 +676,7 @@ mod tests { let (output, _) = execute_and_prove( vec![pre], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Initialize) - .unwrap(), + Program::serialize_instruction(()).unwrap(), vec![InputAccountIdentity::PrivateAuthorizedInit { epk: EphemeralPublicKey(Vec::new()), view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), @@ -709,39 +698,23 @@ mod tests { /// to `PrivateAccountKind::Regular` carrying the correct identifier. #[test] 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 identifier: u128 = 99; 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 = AccountWithMetadata::new(Account::default(), false, recipient_id); let (output, _) = execute_and_prove( - vec![sender, recipient], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: 1, - }) - .unwrap(), - vec![ - InputAccountIdentity::Public, - InputAccountIdentity::PrivateUnauthorized { - epk: EphemeralPublicKey(Vec::new()), - view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), - npk: keys.npk(), - ssk, - identifier, - }, - ], + vec![recipient], + Program::serialize_instruction(()).unwrap(), + vec![InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), + npk: keys.npk(), + ssk, + identifier, + }], &program.into(), ) .unwrap(); @@ -756,7 +729,7 @@ mod tests { /// to `PrivateAccountKind::Regular` carrying the correct identifier. #[test] 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 identifier: u128 = 99; 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)); let sender = AccountWithMetadata::new(account, true, account_id); - let recipient = AccountWithMetadata::new(Account::default(), true, AccountId::new([0; 32])); let (output, _) = execute_and_prove( - vec![sender, recipient], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: 1, - }) - .unwrap(), - vec![ - InputAccountIdentity::PrivateAuthorizedUpdate { - epk: EphemeralPublicKey(Vec::new()), - view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), - ssk, - nsk: keys.nsk, - membership_proof: commitment_set.get_proof_for(&commitment).unwrap(), - identifier, - }, - InputAccountIdentity::Public, - ], + vec![sender], + Program::serialize_instruction(()).unwrap(), + vec![InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&keys.npk(), &keys.vpk()), + ssk, + nsk: keys.nsk, + membership_proof: commitment_set.get_proof_for(&commitment).unwrap(), + identifier, + }], &program.into(), ) .unwrap(); @@ -804,18 +770,18 @@ mod tests { /// to `PrivateAccountKind::Pda` carrying the correct `(program_id, seed, identifier)`. #[test] fn private_pda_update_encrypts_pda_kind_with_identifier() { - let program = Program::pda_spend_proxy(); - let auth_transfer = Program::authenticated_transfer_program(); + let program = crate::test_methods::pda_spend_proxy(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); let identifier: u128 = 99; 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_account = Account { - program_owner: auth_transfer_id, + program_owner: simple_transfer_id, balance: 1, ..Account::default() }; @@ -829,12 +795,12 @@ mod tests { let program_with_deps = ProgramWithDependencies::new( program.clone(), - [(auth_transfer_id, auth_transfer)].into(), + [(simple_transfer_id, simple_transfer)].into(), ); let (output, _) = execute_and_prove( 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![ InputAccountIdentity::PrivatePdaUpdate { epk: EphemeralPublicKey(Vec::new()), @@ -863,7 +829,7 @@ mod tests { #[test] 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 npk = keys.npk(); let seed = PdaSeed::new([42; 32]); @@ -892,17 +858,17 @@ mod tests { #[test] fn private_pda_update_identifier_mismatch_fails() { - let program = Program::pda_spend_proxy(); - let auth_transfer = Program::authenticated_transfer_program(); + let program = crate::test_methods::pda_spend_proxy(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); 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_account = Account { - program_owner: auth_transfer_id, + program_owner: simple_transfer_id, balance: 1, ..Account::default() }; @@ -915,11 +881,11 @@ mod tests { AccountWithMetadata::new(Account::default(), true, AccountId::new([0; 32])); 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( 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![ InputAccountIdentity::PrivatePdaUpdate { epk: EphemeralPublicKey(Vec::new()), diff --git a/lee/state_machine/src/program.rs b/lee/state_machine/src/program.rs index c4223810..65d60a42 100644 --- a/lee/state_machine/src/program.rs +++ b/lee/state_machine/src/program.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use borsh::{BorshDeserialize, BorshSerialize}; use lee_core::{ account::AccountWithMetadata, @@ -6,15 +8,7 @@ use lee_core::{ use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use serde::Serialize; -use crate::{ - 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, - }, -}; +use crate::error::LeeError; /// Maximum number of cycles for a public execution. /// 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)] pub struct Program { id: ProgramId, - elf: Vec, + elf: Cow<'static, [u8]>, } impl Program { - pub fn new(bytecode: Vec) -> Result { - let binary = risc0_binfmt::ProgramBinary::decode(&bytecode) + pub fn new(elf: Cow<'static, [u8]>) -> Result { + let binary = risc0_binfmt::ProgramBinary::decode(elf.as_ref()) .map_err(LeeError::InvalidProgramBytecode)?; let id = binary .compute_image_id() .map_err(LeeError::InvalidProgramBytecode)? .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] @@ -109,412 +108,17 @@ impl Program { .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; 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)] mod tests { use lee_core::account::{Account, AccountId, AccountWithMetadata}; - use crate::{ - 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); - } + use crate::program::Program; #[test] 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 instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); let sender = AccountWithMetadata::new( @@ -545,47 +149,4 @@ mod tests { assert_eq!(sender_post.account(), &expected_sender_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); - } - } } diff --git a/lee/state_machine/src/public_transaction/transaction.rs b/lee/state_machine/src/public_transaction/transaction.rs index d382d458..e068133a 100644 --- a/lee/state_machine/src/public_transaction/transaction.rs +++ b/lee/state_machine/src/public_transaction/transaction.rs @@ -66,7 +66,6 @@ pub mod tests { use crate::{ AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V03State, error::LeeError, - program::Program, public_transaction::{Message, WitnessSet}, validated_state_diff::ValidatedStateDiff, }; @@ -82,7 +81,9 @@ pub mod tests { fn state_for_tests() -> V03State { let (_, _, addr1, addr2) = keys_for_tests(); 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 { @@ -90,7 +91,7 @@ pub mod tests { let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), vec![addr1, addr2], nonces, instruction, @@ -168,7 +169,7 @@ pub mod tests { let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), vec![addr1, addr1], nonces, instruction, @@ -188,7 +189,7 @@ pub mod tests { let nonces = vec![0_u128.into()]; let instruction = 1337; let message = Message::try_new( - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), vec![addr1, addr2], nonces, instruction, @@ -208,7 +209,7 @@ pub mod tests { let nonces = vec![0_u128.into(), 0_u128.into()]; let instruction = 1337; let message = Message::try_new( - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), vec![addr1, addr2], nonces, instruction, @@ -229,7 +230,7 @@ pub mod tests { let nonces = vec![0_u128.into(), 1_u128.into()]; let instruction = 1337; let message = Message::try_new( - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), vec![addr1, addr2], nonces, instruction, diff --git a/lee/state_machine/src/state.rs b/lee/state_machine/src/state.rs index c7152917..c399cea1 100644 --- a/lee/state_machine/src/state.rs +++ b/lee/state_machine/src/state.rs @@ -1,15 +1,10 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSerialize}; -use clock_core::ClockAccountData; -pub use clock_core::{ - CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, - CLOCK_PROGRAM_ACCOUNT_IDS, -}; use lee_core::{ BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, Timestamp, - account::{Account, AccountId, Nonce}, + account::{Account, AccountId}, program::ProgramId, }; @@ -124,18 +119,15 @@ pub struct V03State { impl Default for V03State { fn default() -> Self { - let faucet_account_id = system_faucet_account_id(); - let faucet_account = system_faucet_account(); - let bridge_account_id = system_bridge_account_id(); - let bridge_account = system_bridge_account(); - let mut public_state = HashMap::new(); - public_state.insert(faucet_account_id, faucet_account); - public_state.insert(bridge_account_id, bridge_account); + let mut commitment_set = CommitmentSet::with_capacity(32); + commitment_set.extend(&[DUMMY_COMMITMENT]); + let nullifier_set = NullifierSet::new(); + let private_state = (commitment_set, nullifier_set); Self { - public_state, - private_state: (CommitmentSet::with_capacity(32), NullifierSet::new()), - programs: HashMap::new(), + public_state: HashMap::default(), + private_state, + programs: HashMap::default(), } } } @@ -146,81 +138,56 @@ impl V03State { Self::default() } + /// Initializes state with given public account balances leaving other account fields at their + /// default values. #[must_use] - pub fn new_with_genesis_accounts( - initial_data: &[(AccountId, u128)], - initial_private_accounts: Vec<(Commitment, Nullifier)>, - genesis_timestamp: lee_core::Timestamp, + pub fn with_public_account_balances( + mut self, + balances: impl IntoIterator, ) -> Self { - let faucet_account_id = system_faucet_account_id(); - let bridge_account_id = system_bridge_account_id(); - let authenticated_transfer_program = Program::authenticated_transfer_program(); - let mut public_state: HashMap<_, _> = initial_data - .iter() - .copied() - .map(|(account_id, balance)| { - let account = Account { - balance, - program_owner: authenticated_transfer_program.id(), - ..Account::default() - }; - (account_id, account) - }) - .collect(); - let faucet_account = system_faucet_account(); - let bridge_account = system_bridge_account(); - public_state.insert(faucet_account_id, faucet_account); - public_state.insert(bridge_account_id, bridge_account); - - let mut commitment_set = CommitmentSet::with_capacity(32); - commitment_set.extend(&[DUMMY_COMMITMENT]); - let (commitments, nullifiers): (Vec, Vec) = - initial_private_accounts.into_iter().unzip(); - commitment_set.extend(&commitments); - let mut nullifier_set = NullifierSet::new(); - nullifier_set.extend(&nullifiers); - let private_state = (commitment_set, nullifier_set); - - let mut this = Self { - public_state, - private_state, - programs: HashMap::new(), - }; - - this.insert_program(Program::clock()); - this.insert_clock_accounts(genesis_timestamp); - - this.insert_program(Program::authenticated_transfer_program()); - this.insert_program(Program::token()); - this.insert_program(Program::amm()); - this.insert_program(Program::ata()); - this.insert_program(Program::vault()); - this.insert_program(Program::faucet()); - this.insert_program(Program::bridge()); - - this - } - - fn insert_clock_accounts(&mut self, genesis_timestamp: lee_core::Timestamp) { - let data = ClockAccountData { - block_id: 0, - timestamp: genesis_timestamp, - } - .to_bytes(); - let clock_program_id = Program::clock().id(); - for account_id in CLOCK_PROGRAM_ACCOUNT_IDS { - self.public_state.insert( + let public_accounts = balances.into_iter().map(|(account_id, balance)| { + ( account_id, Account { - program_owner: clock_program_id, - data: data - .clone() - .try_into() - .expect("Clock account data should fit within accounts data"), + balance, ..Account::default() }, - ); + ) + }); + self.public_state.extend(public_accounts); + self + } + + /// Initializes state with given public accounts. + #[must_use] + pub fn with_public_accounts( + mut self, + public_accounts: impl IntoIterator, + ) -> Self { + self.public_state.extend(public_accounts); + self + } + + /// Initializes state with given private accounts. + #[must_use] + pub fn with_private_accounts( + mut self, + private_accounts: impl IntoIterator, + ) -> Self { + let (commitments, nullifiers): (Vec, Vec) = + private_accounts.into_iter().unzip(); + self.private_state.0.extend(&commitments); + self.private_state.1.extend(&nullifiers); + self + } + + /// Initializes state with given builtin programs. + #[must_use] + pub fn with_programs(mut self, programs: impl IntoIterator) -> Self { + for program in programs { + self.insert_program(program); } + self } pub(crate) fn insert_program(&mut self, program: Program) { @@ -342,38 +309,6 @@ impl V03State { } } -// TODO: Testnet only. Refactor to prevent compilation on mainnet. -impl V03State { - pub fn add_pinata_program(&mut self, account_id: AccountId) { - self.insert_program(Program::pinata()); - - self.public_state.insert( - account_id, - Account { - program_owner: Program::pinata().id(), - balance: 1_500_000, - // Difficulty: 3 - data: vec![3; 33].try_into().expect("should fit"), - nonce: Nonce::default(), - }, - ); - } - - pub fn add_pinata_token_program(&mut self, account_id: AccountId) { - self.insert_program(Program::pinata_token()); - - self.public_state.insert( - account_id, - Account { - program_owner: Program::pinata_token().id(), - // Difficulty: 3 - data: vec![3; 33].try_into().expect("should fit"), - ..Account::default() - }, - ); - } -} - #[cfg(any(test, feature = "test-utils"))] impl V03State { pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) { @@ -381,31 +316,6 @@ impl V03State { } } -fn system_faucet_account() -> Account { - Account { - program_owner: Program::authenticated_transfer_program().id(), - balance: u128::MAX, - ..Account::default() - } -} - -fn system_bridge_account() -> Account { - Account { - program_owner: Program::authenticated_transfer_program().id(), - ..Account::default() - } -} - -#[must_use] -pub fn system_faucet_account_id() -> AccountId { - faucet_core::compute_faucet_account_id(Program::faucet().id()) -} - -#[must_use] -pub fn system_bridge_account_id() -> AccountId { - bridge_core::compute_bridge_account_id(Program::bridge().id()) -} - #[cfg(test)] pub mod tests { #![expect( @@ -416,15 +326,14 @@ pub mod tests { use std::collections::HashMap; - use authenticated_transfer_core::Instruction as AuthTransferInstruction; use lee_core::{ BlockId, Commitment, EncryptedAccountData, InputAccountIdentity, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, Timestamp, account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, encryption::{EphemeralPublicKey, ViewingPublicKey}, program::{ - BlockValidityWindow, ExecutionValidationError, PdaSeed, ProgramId, - TimestampValidityWindow, WrappedBalanceSum, + BlockValidityWindow, ExecutionValidationError, MAX_NUMBER_CHAINED_CALLS, PdaSeed, + ProgramId, TimestampValidityWindow, WrappedBalanceSum, }, }; @@ -441,37 +350,41 @@ pub mod tests { program::Program, public_transaction, signature::PrivateKey, - state::{ - CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, - CLOCK_PROGRAM_ACCOUNT_IDS, MAX_NUMBER_CHAINED_CALLS, system_bridge_account, - system_faucet_account, - }, - system_bridge_account_id, system_faucet_account_id, }; impl V03State { /// Include test programs in the builtin programs map. #[must_use] pub fn with_test_programs(mut self) -> Self { - self.insert_program(Program::nonce_changer_program()); - self.insert_program(Program::extra_output_program()); - self.insert_program(Program::missing_output_program()); - self.insert_program(Program::program_owner_changer()); - self.insert_program(Program::simple_balance_transfer()); - self.insert_program(Program::data_changer()); - self.insert_program(Program::minter()); - self.insert_program(Program::burner()); - self.insert_program(Program::chain_caller()); - self.insert_program(Program::amm()); - self.insert_program(Program::claimer()); - self.insert_program(Program::changer_claimer()); - self.insert_program(Program::validity_window()); - self.insert_program(Program::flash_swap_initiator()); - self.insert_program(Program::flash_swap_callback()); - self.insert_program(Program::malicious_self_program_id()); - self.insert_program(Program::malicious_caller_program_id()); - self.insert_program(Program::time_locked_transfer()); - self.insert_program(Program::pinata_cooldown()); + self.insert_program(crate::test_methods::simple_balance_transfer()); + self.insert_program(crate::test_methods::nonce_changer()); + self.insert_program(crate::test_methods::extra_output()); + self.insert_program(crate::test_methods::missing_output()); + self.insert_program(crate::test_methods::program_owner_changer()); + self.insert_program(crate::test_methods::data_changer()); + self.insert_program(crate::test_methods::minter()); + self.insert_program(crate::test_methods::burner()); + self.insert_program(crate::test_methods::auth_asserting_noop()); + self.insert_program(crate::test_methods::private_pda_delegator()); + self.insert_program(crate::test_methods::pda_claimer()); + self.insert_program(crate::test_methods::two_pda_claimer()); + self.insert_program(crate::test_methods::noop()); + self.insert_program(crate::test_methods::chain_caller()); + self.insert_program(crate::test_methods::modified_transfer_program()); + self.insert_program(crate::test_methods::malicious_authorization_changer()); + self.insert_program(crate::test_methods::validity_window()); + self.insert_program(crate::test_methods::flash_swap_initiator()); + self.insert_program(crate::test_methods::flash_swap_callback()); + self.insert_program(crate::test_methods::malicious_self_program_id()); + self.insert_program(crate::test_methods::malicious_caller_program_id()); + self.insert_program(crate::test_methods::pda_spend_proxy()); + self.insert_program(crate::test_methods::claimer()); + self.insert_program(crate::test_methods::changer_claimer()); + self.insert_program(crate::test_methods::validity_window_chain_caller()); + self.insert_program(crate::test_methods::simple_transfer_proxy()); + self.insert_program(crate::test_methods::malicious_injector()); + self.insert_program(crate::test_methods::malicious_launderer()); + self.insert_program(crate::test_methods::modified_transfer_program()); self } @@ -507,7 +420,7 @@ pub mod tests { #[must_use] pub fn with_account_owned_by_burner_program(mut self) -> Self { let account = Account { - program_owner: Program::burner().id(), + program_owner: crate::test_methods::burner().id(), balance: 100, ..Default::default() }; @@ -572,6 +485,25 @@ pub mod tests { }, } + fn public_state_from_balances( + initial_data: &[(AccountId, u128)], + ) -> HashMap { + initial_data + .iter() + .copied() + .map(|(account_id, balance)| { + ( + account_id, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance, + ..Account::default() + }, + ) + }) + .collect() + } + fn transfer_transaction( from: AccountId, from_key: &PrivateKey, @@ -583,14 +515,9 @@ pub mod tests { ) -> PublicTransaction { let account_ids = vec![from, to]; let nonces = vec![Nonce(from_nonce), Nonce(to_nonce)]; - let program_id = Program::authenticated_transfer_program().id(); - let message = public_transaction::Message::try_new( - program_id, - account_ids, - nonces, - AuthTransferInstruction::Transfer { amount: balance }, - ) - .unwrap(); + let program_id = crate::test_methods::simple_balance_transfer().id(); + let message = + public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[from_key, to_key]); PublicTransaction::new(message, witness_set) @@ -614,63 +541,17 @@ pub mod tests { } #[test] - fn genesis_system_accounts_have_expected_contents() { - // System-account IDs must be distinct and non-default, and the genesis - // faucet/bridge accounts must carry their expected field values. Catches - // mutations that replace `system_faucet_account`/`system_bridge_account` - // with `Default::default()`, delete their `balance`/`program_owner` - // fields, or replace `system_bridge_account_id` with `Default::default()`. - let faucet_id = system_faucet_account_id(); - let bridge_id = system_bridge_account_id(); - assert_ne!(bridge_id, AccountId::default()); - assert_ne!(faucet_id, bridge_id); - - let state = V03State::new_with_genesis_accounts(&[], vec![], 0); - let default_owner = Account::default().program_owner; - - let faucet = state.get_account_by_id(faucet_id); - assert_eq!(faucet.balance, u128::MAX, "faucet must hold u128::MAX"); - assert_ne!( - faucet.program_owner, default_owner, - "faucet must have a non-default program_owner" - ); - - let bridge = state.get_account_by_id(bridge_id); - assert_ne!( - bridge.program_owner, default_owner, - "bridge must have a non-default program_owner" - ); - } - - #[test] - fn genesis_commitment_set_digest_differs_from_empty_state() { - // The genesis state inserts DUMMY_COMMITMENT, so its commitment-set digest - // must differ from a freshly-created empty state's all-zero root. Catches - // the mutation that replaces `commitment_set_digest` with `Default::default()`. - let genesis = V03State::new_with_genesis_accounts(&[], vec![], 0); - let empty = V03State::new(); - assert_ne!( - genesis.commitment_set_digest(), - empty.commitment_set_digest() - ); - } - - #[test] - fn new_with_genesis() { + fn new_works() { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(addr1, 100_u128), (addr2, 151_u128)]; - let authenticated_transfers_program = Program::authenticated_transfer_program(); - let clock_program = Program::clock(); let expected_public_state = { let mut this = HashMap::new(); this.insert( addr1, Account { balance: 100, - program_owner: authenticated_transfers_program.id(), ..Account::default() }, ); @@ -678,54 +559,27 @@ pub mod tests { addr2, Account { balance: 151, - program_owner: authenticated_transfers_program.id(), ..Account::default() }, ); - this.insert(system_faucet_account_id(), system_faucet_account()); - this.insert(system_bridge_account_id(), system_bridge_account()); - for account_id in CLOCK_PROGRAM_ACCOUNT_IDS { - this.insert( - account_id, - Account { - program_owner: clock_program.id(), - data: [0_u8; 16].to_vec().try_into().unwrap(), - ..Account::default() - }, - ); - } - this - }; - let expected_builtin_programs = { - let mut this = HashMap::new(); - this.insert( - authenticated_transfers_program.id(), - authenticated_transfers_program, - ); - this.insert(clock_program.id(), clock_program); - this.insert(Program::token().id(), Program::token()); - this.insert(Program::amm().id(), Program::amm()); - this.insert(Program::ata().id(), Program::ata()); - this.insert(Program::vault().id(), Program::vault()); - this.insert(Program::faucet().id(), Program::faucet()); - this.insert(Program::bridge().id(), Program::bridge()); this }; + let expected_builtin_programs = HashMap::new(); - let state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let state = + V03State::new().with_public_account_balances([(addr1, 100_u128), (addr2, 151_u128)]); assert_eq!(state.public_state, expected_public_state); assert_eq!(state.programs, expected_builtin_programs); } #[test] - fn new_with_genesis_includes_nullifiers_for_private_accounts() { + fn new_includes_nullifiers_for_private_accounts() { let keys1 = test_private_account_keys_1(); let keys2 = test_private_account_keys_2(); let account = Account { balance: 100, - program_owner: Program::authenticated_transfer_program().id(), ..Account::default() }; @@ -742,7 +596,7 @@ pub mod tests { (init_commitment2, init_nullifier2), ]; - let state = V03State::new_with_genesis_accounts(&[], initial_private_accounts, 0); + let state = V03State::new().with_private_accounts(initial_private_accounts); assert!(state.private_state.1.contains(&init_nullifier1)); assert!(state.private_state.1.contains(&init_nullifier2)); @@ -750,8 +604,8 @@ pub mod tests { #[test] fn insert_program() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - let program_to_insert = Program::simple_balance_transfer(); + let mut state = V03State::new(); + let program_to_insert = crate::test_methods::simple_balance_transfer(); let program_id = program_to_insert.id(); assert!(!state.programs.contains_key(&program_id)); @@ -764,8 +618,15 @@ pub mod tests { fn get_account_by_account_id_non_default_account() { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(account_id, 100_u128)]; - let state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let initial_data = [( + account_id, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 100, + ..Account::default() + }, + )]; + let state = V03State::new().with_public_accounts(initial_data); let expected_account = &state.public_state[&account_id]; let account = state.get_account_by_id(account_id); @@ -776,7 +637,7 @@ pub mod tests { #[test] fn get_account_by_account_id_default_account() { let addr2 = AccountId::new([0; 32]); - let state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let state = V03State::new(); let expected_account = Account::default(); let account = state.get_account_by_id(addr2); @@ -786,7 +647,7 @@ pub mod tests { #[test] fn builtin_programs_getter() { - let state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let state = V03State::new(); let builtin_programs = state.programs(); @@ -797,8 +658,17 @@ pub mod tests { fn transition_from_authenticated_transfer_program_invocation_default_account_destination() { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(account_id, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let initial_data = [( + account_id, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 100, + ..Account::default() + }, + )]; + let mut state = V03State::new() + .with_public_accounts(initial_data) + .with_test_programs(); let from = account_id; let to_key = PrivateKey::try_new([2; 32]).unwrap(); let to = AccountId::from(&PublicKey::new_from_private_key(&to_key)); @@ -818,8 +688,9 @@ pub mod tests { fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() { let key = PrivateKey::try_new([1; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(account_id, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let mut state = V03State::new() + .with_public_account_balances([(account_id, 100)]) + .with_test_programs(); let from = account_id; let from_key = key; let to_key = PrivateKey::try_new([2; 32]).unwrap(); @@ -843,8 +714,27 @@ pub mod tests { let key2 = PrivateKey::try_new([2; 32]).unwrap(); let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(account_id1, 100), (account_id2, 200)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let initial_data = [ + ( + account_id1, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 100, + ..Account::default() + }, + ), + ( + account_id2, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 200, + ..Account::default() + }, + ), + ]; + let mut state = V03State::new() + .with_public_accounts(initial_data) + .with_test_programs(); let from = account_id2; let from_key = key2; let to = account_id1; @@ -867,8 +757,17 @@ pub mod tests { let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); let key2 = PrivateKey::try_new([2; 32]).unwrap(); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(account_id1, 100)]; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); + let initial_data = [( + account_id1, + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 100, + ..Account::default() + }, + )]; + let mut state = V03State::new() + .with_public_accounts(initial_data) + .with_test_programs(); let key3 = PrivateKey::try_new([3; 32]).unwrap(); let account_id3 = AccountId::from(&PublicKey::new_from_private_key(&key3)); let balance_to_move = 5; @@ -903,157 +802,14 @@ pub mod tests { assert_eq!(state.get_account_by_id(account_id3).nonce, Nonce(1)); } - fn clock_transaction(timestamp: lee_core::Timestamp) -> PublicTransaction { - let message = public_transaction::Message::try_new( - Program::clock().id(), - CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), - vec![], - timestamp, - ) - .unwrap(); - PublicTransaction::new( - message, - public_transaction::WitnessSet::from_raw_parts(vec![]), - ) - } - - fn clock_account_data(state: &V03State, account_id: AccountId) -> (u64, lee_core::Timestamp) { - let data = state.get_account_by_id(account_id).data.into_inner(); - let parsed = clock_core::ClockAccountData::from_bytes(&data); - (parsed.block_id, parsed.timestamp) - } - - #[test] - fn clock_genesis_state_has_zero_block_id_and_genesis_timestamp() { - let genesis_timestamp = 1_000_000_u64; - let state = V03State::new_with_genesis_accounts(&[], vec![], genesis_timestamp); - - let (block_id, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - - assert_eq!(block_id, 0); - assert_eq!(timestamp, genesis_timestamp); - } - - #[test] - fn clock_invocation_increments_block_id() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - - let tx = clock_transaction(1234); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - - let (block_id, _) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - assert_eq!(block_id, 1); - } - - #[test] - fn clock_invocation_stores_timestamp_from_instruction() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - let block_timestamp = 1_700_000_000_000_u64; - - let tx = clock_transaction(block_timestamp); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - - let (_, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - assert_eq!(timestamp, block_timestamp); - } - - #[test] - fn clock_invocation_sequence_correctly_increments_block_id() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - - for expected_block_id in 1_u64..=5 { - let tx = clock_transaction(expected_block_id * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - - let (block_id, timestamp) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - assert_eq!(block_id, expected_block_id); - assert_eq!(timestamp, expected_block_id * 1000); - } - } - - #[test] - fn clock_10_account_not_updated_when_block_id_not_multiple_of_10() { - let genesis_timestamp = 0_u64; - let mut state = V03State::new_with_genesis_accounts(&[], vec![], genesis_timestamp); - - // Run 9 clock ticks (block_ids 1..=9), none of which are multiples of 10. - for tick in 1_u64..=9 { - let tx = clock_transaction(tick * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - } - - let (block_id_10, timestamp_10) = clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID); - // The 10-block account should still reflect genesis state. - assert_eq!(block_id_10, 0); - assert_eq!(timestamp_10, genesis_timestamp); - } - - #[test] - fn clock_10_account_updated_when_block_id_is_multiple_of_10() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - - // Run 10 clock ticks so block_id reaches 10. - for tick in 1_u64..=10 { - let tx = clock_transaction(tick * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - } - - let (block_id_1, timestamp_1) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - let (block_id_10, timestamp_10) = clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID); - assert_eq!(block_id_1, 10); - assert_eq!(block_id_10, 10); - assert_eq!(timestamp_10, timestamp_1); - } - - #[test] - fn clock_50_account_only_updated_at_multiples_of_50() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - - // After 49 ticks the 50-block account should be unchanged. - for tick in 1_u64..=49 { - let tx = clock_transaction(tick * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - } - let (block_id_50, _) = clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID); - assert_eq!(block_id_50, 0); - - // Tick 50 — now the 50-block account should update. - let tx = clock_transaction(50 * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - let (block_id_50, timestamp_50) = clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID); - assert_eq!(block_id_50, 50); - assert_eq!(timestamp_50, 50 * 1000); - } - - #[test] - fn all_three_clock_accounts_updated_at_multiple_of_50() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - - // Advance to block 50 (a multiple of both 10 and 50). - for tick in 1_u64..=50 { - let tx = clock_transaction(tick * 1000); - state.transition_from_public_transaction(&tx, 0, 0).unwrap(); - } - - let (block_id_1, ts_1) = clock_account_data(&state, CLOCK_01_PROGRAM_ACCOUNT_ID); - let (block_id_10, ts_10) = clock_account_data(&state, CLOCK_10_PROGRAM_ACCOUNT_ID); - let (block_id_50, ts_50) = clock_account_data(&state, CLOCK_50_PROGRAM_ACCOUNT_ID); - - assert_eq!(block_id_1, 50); - assert_eq!(block_id_10, 50); - assert_eq!(block_id_50, 50); - assert_eq!(ts_1, ts_10); - assert_eq!(ts_1, ts_50); - } - #[test] fn program_should_fail_if_modifies_nonces() { let account_id = AccountId::new([1; 32]); - let initial_data = [(account_id, 100)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_account_balances([(account_id, 100)]) + .with_test_programs(); let account_ids = vec![account_id]; - let program_id = Program::nonce_changer_program().id(); + let program_id = crate::test_methods::nonce_changer().id(); let message = public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1073,11 +829,11 @@ pub mod tests { #[test] fn program_should_fail_if_output_accounts_exceed_inputs() { - let initial_data = [(AccountId::new([1; 32]), 100)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_account_balances([(AccountId::new([1; 32]), 0)]) + .with_test_programs(); let account_ids = vec![AccountId::new([1; 32])]; - let program_id = Program::extra_output_program().id(); + let program_id = crate::test_methods::extra_output().id(); let message = public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1100,11 +856,11 @@ pub mod tests { #[test] fn program_should_fail_with_missing_output_accounts() { - let initial_data = [(AccountId::new([1; 32]), 100)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_account_balances([(AccountId::new([1; 32]), 100)]) + .with_test_programs(); let account_ids = vec![AccountId::new([1; 32]), AccountId::new([2; 32])]; - let program_id = Program::missing_output_program().id(); + let program_id = crate::test_methods::missing_output().id(); let message = public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1127,9 +883,16 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() { - let initial_data = [(AccountId::new([1; 32]), 0)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let initial_data = [( + AccountId::new([1; 32]), + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + ..Account::default() + }, + )]; + let mut state = V03State::new() + .with_public_accounts(initial_data) + .with_test_programs(); let account_id = AccountId::new([1; 32]); let account = state.get_account_by_id(account_id); // Assert the target account only differs from the default account in the program owner @@ -1138,7 +901,7 @@ pub mod tests { assert_eq!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = Program::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().id(); let message = public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1156,8 +919,9 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_balance() { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0) + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([255; 32]); @@ -1167,7 +931,7 @@ pub mod tests { assert_ne!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = Program::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().id(); let message = public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1185,8 +949,9 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0) + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([254; 32]); @@ -1196,7 +961,7 @@ pub mod tests { assert_eq!(account.balance, Account::default().balance); assert_ne!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = Program::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().id(); let message = public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1214,8 +979,9 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_program_owner_with_only_non_default_data() { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0) + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([253; 32]); @@ -1225,7 +991,7 @@ pub mod tests { assert_eq!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_ne!(account.data, Account::default().data); - let program_id = Program::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().id(); let message = public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); @@ -1245,11 +1011,11 @@ pub mod tests { fn program_should_fail_if_transfers_balance_from_non_owned_account() { let sender_account_id = AccountId::new([1; 32]); let receiver_account_id = AccountId::new([2; 32]); - let initial_data = [(sender_account_id, 100)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_account_balances([(sender_account_id, 100)]) + .with_test_programs(); let balance_to_move: u128 = 1; - let program_id = Program::simple_balance_transfer().id(); + let program_id = crate::test_methods::simple_balance_transfer().id(); assert_ne!( state.get_account_by_id(sender_account_id).program_owner, program_id @@ -1276,12 +1042,13 @@ pub mod tests { #[test] fn program_should_fail_if_modifies_data_of_non_owned_account() { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0) + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([255; 32]); - let program_id = Program::data_changer().id(); + let program_id = crate::test_methods::data_changer().id(); assert_ne!(state.get_account_by_id(account_id), Account::default()); assert_ne!( @@ -1306,11 +1073,12 @@ pub mod tests { #[test] fn program_should_fail_if_does_not_preserve_total_balance_by_minting() { - let initial_data = []; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) + .with_test_programs(); let account_id = AccountId::new([1; 32]); - let program_id = Program::minter().id(); + let program_id = crate::test_methods::minter().id(); let message = public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); @@ -1329,11 +1097,12 @@ pub mod tests { #[test] fn program_should_fail_if_does_not_preserve_total_balance_by_burning() { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0) + let initial_data = HashMap::new(); + let mut state = V03State::new() + .with_public_accounts(initial_data) .with_test_programs() .with_account_owned_by_burner_program(); - let program_id = Program::burner().id(); + let program_id = crate::test_methods::burner().id(); let account_id = AccountId::new([252; 32]); assert_eq!( state.get_account_by_id(account_id).program_owner, @@ -1411,10 +1180,7 @@ pub mod tests { let (output, proof) = circuit::execute_and_prove( vec![sender, recipient], - Program::serialize_instruction(AuthTransferInstruction::Transfer { - amount: balance_to_move, - }) - .unwrap(), + Program::serialize_instruction(balance_to_move).unwrap(), vec![ InputAccountIdentity::Public, InputAccountIdentity::PrivateUnauthorized { @@ -1428,7 +1194,7 @@ pub mod tests { identifier: 0, }, ], - &Program::authenticated_transfer_program().into(), + &crate::test_methods::simple_balance_transfer().into(), ) .unwrap(); @@ -1450,7 +1216,7 @@ pub mod tests { balance_to_move: u128, state: &V03State, ) -> PrivacyPreservingTransaction { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let sender_account_id = AccountId::for_regular_private_account(&sender_keys.npk(), 0); let sender_commitment = Commitment::new(&sender_account_id, sender_private_account); let sender_pre = AccountWithMetadata::new( @@ -1469,10 +1235,7 @@ pub mod tests { let (output, proof) = circuit::execute_and_prove( vec![sender_pre, recipient_pre], - Program::serialize_instruction(AuthTransferInstruction::Transfer { - amount: balance_to_move, - }) - .unwrap(), + Program::serialize_instruction(balance_to_move).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { epk: epk_1, @@ -1516,7 +1279,7 @@ pub mod tests { balance_to_move: u128, state: &V03State, ) -> PrivacyPreservingTransaction { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let sender_account_id = AccountId::for_regular_private_account(&sender_keys.npk(), 0); let sender_commitment = Commitment::new(&sender_account_id, sender_private_account); let sender_pre = AccountWithMetadata::new( @@ -1535,10 +1298,7 @@ pub mod tests { let (output, proof) = circuit::execute_and_prove( vec![sender_pre, recipient_pre], - Program::serialize_instruction(AuthTransferInstruction::Transfer { - amount: balance_to_move, - }) - .unwrap(), + Program::serialize_instruction(balance_to_move).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { epk, @@ -1572,8 +1332,14 @@ pub mod tests { let sender_keys = test_public_account_keys_1(); let recipient_keys = test_private_account_keys_1(); - let mut state = - V03State::new_with_genesis_accounts(&[(sender_keys.account_id(), 200)], vec![], 0); + let mut state = V03State::new().with_public_accounts([( + sender_keys.account_id(), + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: 200, + ..Account::default() + }, + )]); let balance_to_move = 37; @@ -1614,15 +1380,14 @@ pub mod tests { let sender_nonce = Nonce(0xdead_beef); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0) - .with_private_account(&sender_keys, &sender_private_account); + let mut state = V03State::new().with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; @@ -1639,7 +1404,7 @@ pub mod tests { let expected_new_commitment_1 = Commitment::new( &sender_account_id, &Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), @@ -1653,7 +1418,7 @@ pub mod tests { let expected_new_commitment_2 = Commitment::new( &recipient_account_id, &Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), nonce: Nonce::private_account_nonce_init(&recipient_account_id), balance: balance_to_move, ..Account::default() @@ -1680,14 +1445,13 @@ pub mod tests { fn valid_private_transfer_tx_and_state() -> (V03State, PrivacyPreservingTransaction) { let sender_keys = test_private_account_keys_1(); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, nonce: Nonce(0xdead_beef), ..Account::default() }; let recipient_keys = test_private_account_keys_2(); - let state = V03State::new_with_genesis_accounts(&[], vec![], 0) - .with_private_account(&sender_keys, &sender_private_account); + let state = V03State::new().with_private_account(&sender_keys, &sender_private_account); let tx = private_balance_transfer_for_tests( &sender_keys, &sender_private_account, @@ -1756,19 +1520,23 @@ pub mod tests { let sender_nonce = Nonce(0xdead_beef); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_public_account_keys_1(); let recipient_initial_balance = 400; - let mut state = V03State::new_with_genesis_accounts( - &[(recipient_keys.account_id(), recipient_initial_balance)], - vec![], - 0, - ) - .with_private_account(&sender_keys, &sender_private_account); + let mut state = V03State::new() + .with_public_accounts([( + recipient_keys.account_id(), + Account { + program_owner: crate::test_methods::simple_balance_transfer().id(), + balance: recipient_initial_balance, + ..Account::default() + }, + )]) + .with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; @@ -1790,7 +1558,7 @@ pub mod tests { let expected_new_commitment = Commitment::new( &sender_account_id, &Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), nonce: sender_nonce.private_account_nonce_increment(&sender_keys.nsk), balance: sender_private_account.balance - balance_to_move, data: Data::default(), @@ -1822,7 +1590,7 @@ pub mod tests { #[test] fn burner_program_should_fail_in_privacy_preserving_circuit() { - let program = Program::burner(); + let program = crate::test_methods::burner(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -1845,7 +1613,7 @@ pub mod tests { #[test] fn minter_program_should_fail_in_privacy_preserving_circuit() { - let program = Program::minter(); + let program = crate::test_methods::minter(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -1868,7 +1636,7 @@ pub mod tests { #[test] fn nonce_changer_program_should_fail_in_privacy_preserving_circuit() { - let program = Program::nonce_changer_program(); + let program = crate::test_methods::nonce_changer(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -1891,7 +1659,7 @@ pub mod tests { #[test] fn data_changer_program_should_fail_for_non_owned_account_in_privacy_preserving_circuit() { - let program = Program::data_changer(); + let program = crate::test_methods::data_changer(); let public_account = AccountWithMetadata::new( Account { program_owner: [0, 1, 2, 3, 4, 5, 6, 7], @@ -1914,7 +1682,7 @@ pub mod tests { #[test] fn data_changer_program_should_fail_for_too_large_data_in_privacy_preserving_circuit() { - let program = Program::data_changer(); + let program = crate::test_methods::data_changer(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -1945,7 +1713,7 @@ pub mod tests { #[test] fn extra_output_program_should_fail_in_privacy_preserving_circuit() { - let program = Program::extra_output_program(); + let program = crate::test_methods::extra_output(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -1968,7 +1736,7 @@ pub mod tests { #[test] fn missing_output_program_should_fail_in_privacy_preserving_circuit() { - let program = Program::missing_output_program(); + let program = crate::test_methods::missing_output(); let public_account_1 = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -2000,7 +1768,7 @@ pub mod tests { #[test] fn program_owner_changer_should_fail_in_privacy_preserving_circuit() { - let program = Program::program_owner_changer(); + let program = crate::test_methods::program_owner_changer(); let public_account = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -2023,7 +1791,7 @@ pub mod tests { #[test] fn transfer_from_non_owned_account_should_fail_in_privacy_preserving_circuit() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let public_account_1 = AccountWithMetadata::new( Account { program_owner: [0, 1, 2, 3, 4, 5, 6, 7], @@ -2055,7 +1823,7 @@ pub mod tests { #[test] fn circuit_fails_if_visibility_masks_have_incorrect_lenght() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let public_account_1 = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -2088,7 +1856,7 @@ pub mod tests { #[test] fn circuit_fails_if_invalid_auth_keys_are_provided() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2151,7 +1919,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_new_private_account_with_non_default_balance_is_provided() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2217,7 +1985,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_new_private_account_with_non_default_program_owner_is_provided() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2283,7 +2051,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_new_private_account_with_non_default_data_is_provided() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2349,7 +2117,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_new_private_account_with_non_default_nonce_is_provided() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2416,7 +2184,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_new_private_account_is_provided_with_default_values_but_marked_as_authorized() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_2(); let private_account_1 = AccountWithMetadata::new( @@ -2483,7 +2251,7 @@ pub mod tests { /// second account, leaving position 1 unbound. #[test] fn private_pda_without_binding_fails() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let shared_secret = @@ -2527,7 +2295,7 @@ pub mod tests { /// and binds the supplied npk to the `account_id`. #[test] fn private_pda_claim_succeeds() { - let program = Program::pda_claimer(); + let program = crate::test_methods::pda_claimer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); @@ -2565,7 +2333,7 @@ pub mod tests { fn private_pda_npk_mismatch_fails() { // `keys_a` produces the `pre_state`'s `account_id` (the registered pair), `keys_b` is // the mismatched pair supplied in `private_account_keys` for that pre_state. - let program = Program::pda_claimer(); + let program = crate::test_methods::pda_claimer(); let keys_a = test_private_account_keys_1(); let keys_b = test_private_account_keys_2(); let npk_a = keys_a.npk(); @@ -2604,8 +2372,8 @@ pub mod tests { /// `AccountId::for_private_pda(delegator, seed, npk) == pre.account_id`. #[test] fn caller_pda_seeds_authorize_private_pda_for_callee() { - let delegator = Program::private_pda_delegator(); - let callee = Program::auth_asserting_noop(); + let delegator = crate::test_methods::private_pda_delegator(); + let callee = crate::test_methods::auth_asserting_noop(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([77; 32]); @@ -2645,8 +2413,8 @@ pub mod tests { /// assertion rejects. #[test] fn caller_pda_seeds_with_wrong_seed_rejects_private_pda_for_callee() { - let delegator = Program::private_pda_delegator(); - let callee = Program::auth_asserting_noop(); + let delegator = crate::test_methods::private_pda_delegator(); + let callee = crate::test_methods::auth_asserting_noop(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let claim_seed = PdaSeed::new([77; 32]); @@ -2688,7 +2456,7 @@ pub mod tests { /// tries to record `(program, seed) → PDA_bob` and panics. #[test] fn two_private_pda_claims_under_same_seed_are_rejected() { - let program = Program::two_pda_claimer(); + let program = crate::test_methods::two_pda_claimer(); let keys_a = test_private_account_keys_1(); let keys_b = test_private_account_keys_2(); let seed = PdaSeed::new([55; 32]); @@ -2735,7 +2503,7 @@ pub mod tests { /// the correct path for top-level reuse; this test pins the failure when no seed is provided. #[test] fn private_pda_top_level_reuse_rejected_by_binding_check() { - let program = Program::noop(); + let program = crate::test_methods::noop(); let keys = test_private_account_keys_1(); let npk = keys.npk(); let shared_secret = @@ -2777,15 +2545,14 @@ pub mod tests { let sender_nonce = Nonce(0xdead_beef); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, nonce: sender_nonce, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0) - .with_private_account(&sender_keys, &sender_private_account); + let mut state = V03State::new().with_private_account(&sender_keys, &sender_private_account); let balance_to_move = 37; let balance_to_move_2 = 30; @@ -2803,7 +2570,7 @@ pub mod tests { .unwrap(); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, nonce: sender_nonce, data: Data::default(), @@ -2829,7 +2596,7 @@ pub mod tests { #[test] fn circuit_should_fail_if_there_are_repeated_ids() { - let program = Program::simple_balance_transfer(); + let program = crate::test_methods::simple_balance_transfer(); let sender_keys = test_private_account_keys_1(); let private_account_1 = AccountWithMetadata::new( Account { @@ -2878,13 +2645,14 @@ pub mod tests { #[test] fn claiming_mechanism() { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let from_key = PrivateKey::try_new([1; 32]).unwrap(); let from = AccountId::from(&PublicKey::new_from_private_key(&from_key)); let initial_balance = 100; let initial_data = [(from, initial_balance)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let to_key = PrivateKey::try_new([2; 32]).unwrap(); let to = AccountId::from(&PublicKey::new_from_private_key(&to_key)); let amount: u128 = 37; @@ -2903,7 +2671,7 @@ pub mod tests { program.id(), vec![from, to], vec![Nonce(0), Nonce(0)], - AuthTransferInstruction::Transfer { amount }, + amount, ) .unwrap(); let witness_set = @@ -2919,20 +2687,16 @@ pub mod tests { #[test] fn unauthorized_public_account_claiming_fails() { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let account_key = PrivateKey::try_new([9; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&account_key)); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let mut state = V03State::new().with_test_programs(); assert_eq!(state.get_account_by_id(account_id), Account::default()); - let message = public_transaction::Message::try_new( - program.id(), - vec![account_id], - vec![], - AuthTransferInstruction::Initialize, - ) - .unwrap(); + let message = + public_transaction::Message::try_new(program.id(), vec![account_id], vec![], 0_u128) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -2944,10 +2708,10 @@ pub mod tests { #[test] fn authorized_public_account_claiming_succeeds() { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let account_key = PrivateKey::try_new([10; 32]).unwrap(); let account_id = AccountId::from(&PublicKey::new_from_private_key(&account_key)); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let mut state = V03State::new().with_test_programs(); assert_eq!(state.get_account_by_id(account_id), Account::default()); @@ -2955,7 +2719,7 @@ pub mod tests { program.id(), vec![account_id], vec![Nonce(0)], - AuthTransferInstruction::Initialize, + 0_u128, ) .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[&account_key]); @@ -2975,25 +2739,26 @@ pub mod tests { #[test] fn public_chained_call() { - let program = Program::chain_caller(); + let program = crate::test_methods::chain_caller(); let key = PrivateKey::try_new([1; 32]).unwrap(); let from = AccountId::from(&PublicKey::new_from_private_key(&key)); let to = AccountId::new([2; 32]); let initial_balance = 1000; let initial_data = [(from, initial_balance), (to, 0)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let from_key = key; let amount: u128 = 37; let instruction: (u128, ProgramId, u32, Option) = ( amount, - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), 2, None, ); let expected_to_post = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: amount * 2, // The `chain_caller` chains the program twice ..Account::default() }; @@ -3020,19 +2785,20 @@ pub mod tests { #[test] fn execution_fails_if_chained_calls_exceeds_depth() { - let program = Program::chain_caller(); + let program = crate::test_methods::chain_caller(); let key = PrivateKey::try_new([1; 32]).unwrap(); let from = AccountId::from(&PublicKey::new_from_private_key(&key)); let to = AccountId::new([2; 32]); let initial_balance = 100; let initial_data = [(from, initial_balance), (to, 0)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let from_key = key; let amount: u128 = 0; let instruction: (u128, ProgramId, u32, Option) = ( amount, - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), u32::try_from(MAX_NUMBER_CHAINED_CALLS).expect("MAX_NUMBER_CHAINED_CALLS fits in u32") + 1, None, @@ -3058,24 +2824,25 @@ pub mod tests { #[test] fn execution_that_requires_authentication_of_a_program_derived_account_id_succeeds() { - let chain_caller = Program::chain_caller(); + let chain_caller = crate::test_methods::chain_caller(); let pda_seed = PdaSeed::new([37; 32]); let from = AccountId::for_public_pda(&chain_caller.id(), &pda_seed); let to = AccountId::new([2; 32]); let initial_balance = 1000; let initial_data = [(from, initial_balance), (to, 0)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let amount: u128 = 58; let instruction: (u128, ProgramId, u32, Option) = ( amount, - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), 1, Some(pda_seed), ); let expected_to_post = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: amount, // The `chain_caller` chains the program twice ..Account::default() }; @@ -3104,14 +2871,15 @@ pub mod tests { // The transfer is made from an initialized sender to an uninitialized recipient. And // it is expected that the recipient account is claimed by the authenticated transfer // program and not the chained_caller program. - let chain_caller = Program::chain_caller(); - let auth_transfer = Program::authenticated_transfer_program(); + let chain_caller = crate::test_methods::chain_caller(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let from_key = PrivateKey::try_new([1; 32]).unwrap(); let from = AccountId::from(&PublicKey::new_from_private_key(&from_key)); let initial_balance = 100; let initial_data = [(from, initial_balance)]; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let to_key = PrivateKey::try_new([2; 32]).unwrap(); let to = AccountId::from(&PublicKey::new_from_private_key(&to_key)); let amount: u128 = 37; @@ -3121,7 +2889,7 @@ pub mod tests { let expected_to_post = Account { // The expected program owner is the authenticated transfer program - program_owner: auth_transfer.id(), + program_owner: simple_transfer.id(), balance: amount, nonce: Nonce(1), ..Account::default() @@ -3131,7 +2899,7 @@ pub mod tests { // authenticated_transfer program let instruction: (u128, ProgramId, u32, Option) = ( amount, - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), 1, None, ); @@ -3157,13 +2925,13 @@ pub mod tests { #[test] fn unauthorized_public_account_claiming_fails_when_executed_privately() { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let account_id = AccountId::new([11; 32]); let public_account = AccountWithMetadata::new(Account::default(), false, account_id); let result = execute_and_prove( vec![public_account], - Program::serialize_instruction(AuthTransferInstruction::Initialize).unwrap(), + Program::serialize_instruction(0_u128).unwrap(), vec![InputAccountIdentity::Public], &program.into(), ); @@ -3173,7 +2941,7 @@ pub mod tests { #[test] fn authorized_public_account_claiming_succeeds_when_executed_privately() { - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); let program_id = program.id(); let sender_keys = test_private_account_keys_1(); let sender_private_account = Account { @@ -3184,11 +2952,8 @@ pub mod tests { let sender_account_id = AccountId::for_regular_private_account(&sender_keys.npk(), 0); let sender_commitment = Commitment::new(&sender_account_id, &sender_private_account); let sender_init_nullifier = Nullifier::for_account_initialization(&sender_account_id); - let mut state = V03State::new_with_genesis_accounts( - &[], - vec![(sender_commitment.clone(), sender_init_nullifier)], - 0, - ); + let mut state = V03State::new() + .with_private_accounts([(sender_commitment.clone(), sender_init_nullifier)]); let sender_pre = AccountWithMetadata::new(sender_private_account, true, (&sender_keys.npk(), 0)); let recipient_private_key = PrivateKey::try_new([2; 32]).unwrap(); @@ -3203,10 +2968,7 @@ pub mod tests { let (output, proof) = execute_and_prove( vec![sender_pre, recipient_pre], - Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { - amount: balance, - }) - .unwrap(), + Program::serialize_instruction(balance).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { epk, @@ -3256,14 +3018,14 @@ pub mod tests { #[test_case::test_case(2; "two calls")] fn private_chained_call(number_of_calls: u32) { // Arrange - let chain_caller = Program::chain_caller(); - let auth_transfers = Program::authenticated_transfer_program(); + let chain_caller = crate::test_methods::chain_caller(); + let simple_transfers = crate::test_methods::simple_balance_transfer(); let from_keys = test_private_account_keys_1(); let to_keys = test_private_account_keys_2(); let initial_balance = 100; let from_account = AccountWithMetadata::new( Account { - program_owner: auth_transfers.id(), + program_owner: simple_transfers.id(), balance: initial_balance, ..Account::default() }, @@ -3272,7 +3034,7 @@ pub mod tests { ); let to_account = AccountWithMetadata::new( Account { - program_owner: auth_transfers.id(), + program_owner: simple_transfers.id(), ..Account::default() }, true, @@ -3285,19 +3047,16 @@ pub mod tests { let to_commitment = Commitment::new(&to_account_id, &to_account.account); let from_init_nullifier = Nullifier::for_account_initialization(&from_account_id); let to_init_nullifier = Nullifier::for_account_initialization(&to_account_id); - let mut state = V03State::new_with_genesis_accounts( - &[], - vec![ + let mut state = V03State::new() + .with_private_accounts([ (from_commitment.clone(), from_init_nullifier), (to_commitment.clone(), to_init_nullifier), - ], - 0, - ) - .with_test_programs(); + ]) + .with_test_programs(); let amount: u128 = 37; let instruction: (u128, ProgramId, u32, Option) = ( amount, - Program::authenticated_transfer_program().id(), + crate::test_methods::simple_balance_transfer().id(), number_of_calls, None, ); @@ -3310,7 +3069,7 @@ pub mod tests { let mut dependencies = HashMap::new(); - dependencies.insert(auth_transfers.id(), auth_transfers); + dependencies.insert(simple_transfers.id(), simple_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); let from_new_nonce = Nonce::default().private_account_nonce_increment(&from_keys.nsk); @@ -3387,101 +3146,10 @@ pub mod tests { ); } - #[test] - fn pda_mechanism_with_pinata_token_program() { - let pinata_token = Program::pinata_token(); - let token = Program::token(); - - let pinata_definition_id = AccountId::new([1; 32]); - let pinata_token_definition_id = AccountId::new([2; 32]); - // Total supply of pinata token will be in an account under a PDA. - let pinata_token_holding_id = - AccountId::for_public_pda(&pinata_token.id(), &PdaSeed::new([0; 32])); - let winner_token_holding_id = AccountId::new([3; 32]); - - let expected_winner_account_holding = token_core::TokenHolding::Fungible { - definition_id: pinata_token_definition_id, - balance: 150, - }; - let expected_winner_token_holding_post = Account { - program_owner: token.id(), - data: Data::from(&expected_winner_account_holding), - ..Account::default() - }; - - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); - state.add_pinata_token_program(pinata_definition_id); - - // Set up the token accounts directly (bypassing public transactions which - // would require signers for Claim::Authorized). The focus of this test is - // the PDA mechanism in the pinata program's chained call, not token creation. - let total_supply: u128 = 10_000_000; - let token_definition = token_core::TokenDefinition::Fungible { - name: String::from("PINATA"), - total_supply, - metadata_id: None, - }; - let token_holding = token_core::TokenHolding::Fungible { - definition_id: pinata_token_definition_id, - balance: total_supply, - }; - let winner_holding = token_core::TokenHolding::Fungible { - definition_id: pinata_token_definition_id, - balance: 0, - }; - state.force_insert_account( - pinata_token_definition_id, - Account { - program_owner: token.id(), - data: Data::from(&token_definition), - ..Account::default() - }, - ); - state.force_insert_account( - pinata_token_holding_id, - Account { - program_owner: token.id(), - data: Data::from(&token_holding), - ..Account::default() - }, - ); - state.force_insert_account( - winner_token_holding_id, - Account { - program_owner: token.id(), - data: Data::from(&winner_holding), - ..Account::default() - }, - ); - - // Submit a solution to the pinata program to claim the prize - let solution: u128 = 989_106; - let message = public_transaction::Message::try_new( - pinata_token.id(), - vec![ - pinata_definition_id, - pinata_token_holding_id, - winner_token_holding_id, - ], - vec![], - solution, - ) - .unwrap(); - let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); - let tx = PublicTransaction::new(message, witness_set); - state.transition_from_public_transaction(&tx, 1, 0).unwrap(); - - let winner_token_holding_post = state.get_account_by_id(winner_token_holding_id); - assert_eq!( - winner_token_holding_post, - expected_winner_token_holding_post - ); - } - #[test] fn claiming_mechanism_cannot_claim_initialied_accounts() { - let claimer = Program::claimer(); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let claimer = crate::test_methods::claimer(); + let mut state = V03State::new().with_test_programs(); let account_id = AccountId::new([2; 32]); // Insert an account with non-default program owner @@ -3521,16 +3189,28 @@ pub mod tests { let recipient_id = AccountId::from(&PublicKey::new_from_private_key(&recipient_key)); let recipient_init_balance: u128 = 10; - let mut state = V03State::new_with_genesis_accounts( - &[ - (sender_id, sender_init_balance), - (recipient_id, recipient_init_balance), - ], - vec![], - 0, - ); + let modified_transfer_id = crate::test_methods::modified_transfer_program().id(); - state.insert_program(Program::modified_transfer_program()); + let mut state = V03State::new() + .with_public_accounts([ + ( + sender_id, + Account { + program_owner: modified_transfer_id, + balance: sender_init_balance, + ..Account::default() + }, + ), + ( + recipient_id, + Account { + program_owner: modified_transfer_id, + balance: recipient_init_balance, + ..Account::default() + }, + ), + ]) + .with_test_programs(); let balance_to_move: u128 = 4; @@ -3542,7 +3222,7 @@ pub mod tests { AccountWithMetadata::new(state.get_account_by_id(recipient_id), false, sender_id); let message = public_transaction::Message::try_new( - Program::modified_transfer_program().id(), + modified_transfer_id, vec![sender_id, recipient_id], vec![sender_nonce], balance_to_move, @@ -3592,7 +3272,7 @@ pub mod tests { #[test] fn private_authorized_uninitialized_account() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let mut state = V03State::new().with_test_programs(); // Set up keys for the authorized private account let private_keys = test_private_account_keys_1(); @@ -3601,13 +3281,13 @@ pub mod tests { let authorized_account = AccountWithMetadata::new(Account::default(), true, (&private_keys.npk(), 0)); - let program = Program::authenticated_transfer_program(); + let program = crate::test_methods::simple_balance_transfer(); // Set up parameters for the new account let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); - let instruction = authenticated_transfer_core::Instruction::Initialize; + let instruction: u128 = 0; // Execute and prove the circuit with the authorized account but no commitment proof let (output, proof) = execute_and_prove( @@ -3643,7 +3323,7 @@ pub mod tests { #[test] fn private_unauthorized_uninitialized_account_can_still_be_claimed() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); let private_keys = test_private_account_keys_1(); // This is intentional: claim authorization was introduced to protect public accounts, @@ -3653,13 +3333,13 @@ pub mod tests { let unauthorized_account = AccountWithMetadata::new(Account::default(), false, (&private_keys.npk(), 0)); - let program = Program::claimer(); + let program = crate::test_methods::claimer(); let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); let (output, proof) = execute_and_prove( vec![unauthorized_account], - Program::serialize_instruction(0_u128).unwrap(), + Program::serialize_instruction(()).unwrap(), vec![InputAccountIdentity::PrivateUnauthorized { epk, view_tag: EncryptedAccountData::compute_view_tag( @@ -3690,7 +3370,7 @@ pub mod tests { #[test] fn private_account_claimed_then_used_without_init_flag_should_fail() { - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); // Set up keys for the private account let private_keys = test_private_account_keys_1(); @@ -3699,13 +3379,13 @@ pub mod tests { let authorized_account = AccountWithMetadata::new(Account::default(), true, (&private_keys.npk(), 0)); - let claimer_program = Program::claimer(); + let claimer_program = crate::test_methods::claimer(); // Set up parameters for claiming the new account let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); - let instruction = authenticated_transfer_core::Instruction::Initialize; + let instruction = (); // Step 2: Execute claimer program to claim the account with authentication let (output, proof) = execute_and_prove( @@ -3745,11 +3425,11 @@ pub mod tests { // Prepare new state of account let account_metadata = { let mut acc = authorized_account; - acc.account.program_owner = Program::claimer().id(); + acc.account.program_owner = crate::test_methods::claimer().id(); acc }; - let noop_program = Program::noop(); + let noop_program = crate::test_methods::noop(); let shared_secret2 = SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0).0; @@ -3776,10 +3456,11 @@ pub mod tests { #[test] fn public_changer_claimer_no_data_change_no_claim_succeeds() { let initial_data = []; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let account_id = AccountId::new([1; 32]); - let program_id = Program::changer_claimer().id(); + let program_id = crate::test_methods::changer_claimer().id(); // Don't change data (None) and don't claim (false) let instruction: (Option>, bool) = (None, false); @@ -3800,10 +3481,11 @@ pub mod tests { #[test] fn public_changer_claimer_data_change_no_claim_fails() { let initial_data = []; - let mut state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let account_id = AccountId::new([1; 32]); - let program_id = Program::changer_claimer().id(); + let program_id = crate::test_methods::changer_claimer().id(); // Change data but don't claim (false) - should fail let new_data = vec![1, 2, 3, 4, 5]; let instruction: (Option>, bool) = (Some(new_data), false); @@ -3829,7 +3511,7 @@ pub mod tests { #[test] fn private_changer_claimer_no_data_change_no_claim_succeeds() { - let program = Program::changer_claimer(); + let program = crate::test_methods::changer_claimer(); let sender_keys = test_private_account_keys_1(); let private_account = AccountWithMetadata::new(Account::default(), true, (&sender_keys.npk(), 0)); @@ -3860,7 +3542,7 @@ pub mod tests { #[test] fn private_changer_claimer_data_change_no_claim_fails() { - let program = Program::changer_claimer(); + let program = crate::test_methods::changer_claimer(); let sender_keys = test_private_account_keys_1(); let private_account = AccountWithMetadata::new(Account::default(), true, (&sender_keys.npk(), 0)); @@ -3893,14 +3575,14 @@ pub mod tests { #[test] fn malicious_authorization_changer_should_fail_in_privacy_preserving_circuit() { // Arrange - let malicious_program = Program::malicious_authorization_changer(); - let auth_transfers = Program::authenticated_transfer_program(); + let malicious_program = crate::test_methods::malicious_authorization_changer(); + let simple_transfers = crate::test_methods::simple_balance_transfer(); let sender_keys = test_public_account_keys_1(); let recipient_keys = test_private_account_keys_1(); let sender_account = AccountWithMetadata::new( Account { - program_owner: auth_transfers.id(), + program_owner: simple_transfers.id(), balance: 100, ..Default::default() }, @@ -3914,21 +3596,22 @@ pub mod tests { let recipient_commitment = Commitment::new(&recipient_account_id, &recipient_account.account); let recipient_init_nullifier = Nullifier::for_account_initialization(&recipient_account_id); - let state = V03State::new_with_genesis_accounts( - &[(sender_account.account_id, sender_account.account.balance)], - vec![(recipient_commitment.clone(), recipient_init_nullifier)], - 0, - ) - .with_test_programs(); + let state = V03State::new() + .with_public_accounts(public_state_from_balances(&[( + sender_account.account_id, + sender_account.account.balance, + )])) + .with_private_accounts([(recipient_commitment.clone(), recipient_init_nullifier)]) + .with_test_programs(); let balance_to_transfer = 10_u128; - let instruction = (balance_to_transfer, auth_transfers.id()); + let instruction = (balance_to_transfer, simple_transfers.id()); let recipient = SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0).0; let mut dependencies = HashMap::new(); - dependencies.insert(auth_transfers.id(), auth_transfers); + dependencies.insert(simple_transfers.id(), simple_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); // Act - execute the malicious program - this should fail during proving @@ -3976,10 +3659,10 @@ pub mod tests { block_id: BlockId, ) { let block_validity_window: BlockValidityWindow = validity_window.try_into().unwrap(); - let validity_window_program = Program::validity_window(); + let validity_window_program = crate::test_methods::validity_window(); let account_keys = test_public_account_keys_1(); let pre = AccountWithMetadata::new(Account::default(), false, account_keys.account_id()); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); let tx = { let account_ids = vec![pre.account_id]; let nonces = vec![]; @@ -4028,10 +3711,10 @@ pub mod tests { ) { let timestamp_validity_window: TimestampValidityWindow = validity_window.try_into().unwrap(); - let validity_window_program = Program::validity_window(); + let validity_window_program = crate::test_methods::validity_window(); let account_keys = test_public_account_keys_1(); let pre = AccountWithMetadata::new(Account::default(), false, account_keys.account_id()); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); let tx = { let account_ids = vec![pre.account_id]; let nonces = vec![]; @@ -4081,10 +3764,10 @@ pub mod tests { block_id: BlockId, ) { let block_validity_window: BlockValidityWindow = validity_window.try_into().unwrap(); - let validity_window_program = Program::validity_window(); + let validity_window_program = crate::test_methods::validity_window(); let account_keys = test_private_account_keys_1(); let pre = AccountWithMetadata::new(Account::default(), false, (&account_keys.npk(), 0)); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); let tx = { let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0); @@ -4149,10 +3832,10 @@ pub mod tests { ) { let timestamp_validity_window: TimestampValidityWindow = validity_window.try_into().unwrap(); - let validity_window_program = Program::validity_window(); + let validity_window_program = crate::test_methods::validity_window(); let account_keys = test_private_account_keys_1(); let pre = AccountWithMetadata::new(Account::default(), false, (&account_keys.npk(), 0)); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); let tx = { let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0); @@ -4200,234 +3883,14 @@ pub mod tests { } } - fn time_locked_transfer_transaction( - from: AccountId, - from_key: &PrivateKey, - from_nonce: u128, - to: AccountId, - clock_account_id: AccountId, - amount: u128, - deadline: u64, - ) -> PublicTransaction { - let program_id = Program::time_locked_transfer().id(); - let message = public_transaction::Message::try_new( - program_id, - vec![from, to, clock_account_id], - vec![Nonce(from_nonce)], - (amount, deadline), - ) - .unwrap(); - let witness_set = public_transaction::WitnessSet::for_message(&message, &[from_key]); - PublicTransaction::new(message, witness_set) - } - - #[test] - fn time_locked_transfer_succeeds_when_deadline_has_passed() { - let recipient_id = AccountId::new([42; 32]); - let genesis_timestamp = 500_u64; - let mut state = - V03State::new_with_genesis_accounts(&[(recipient_id, 0)], vec![], genesis_timestamp) - .with_test_programs(); - let key1 = PrivateKey::try_new([1; 32]).unwrap(); - let sender_id = AccountId::from(&PublicKey::new_from_private_key(&key1)); - state.force_insert_account( - sender_id, - Account { - program_owner: Program::time_locked_transfer().id(), - balance: 100, - ..Account::default() - }, - ); - - let amount = 100_u128; - // Deadline in the past: transfer should succeed. - let deadline = 0_u64; - - let tx = time_locked_transfer_transaction( - sender_id, - &key1, - 0, - recipient_id, - CLOCK_01_PROGRAM_ACCOUNT_ID, - amount, - deadline, - ); - - let block_id = 1; - let timestamp = genesis_timestamp + 100; - state - .transition_from_public_transaction(&tx, block_id, timestamp) - .unwrap(); - - // Balances changed. - assert_eq!(state.get_account_by_id(sender_id).balance, 0); - assert_eq!(state.get_account_by_id(recipient_id).balance, 100); - } - - #[test] - fn time_locked_transfer_fails_when_deadline_is_in_the_future() { - let recipient_id = AccountId::new([42; 32]); - let genesis_timestamp = 500_u64; - let mut state = - V03State::new_with_genesis_accounts(&[(recipient_id, 0)], vec![], genesis_timestamp) - .with_test_programs(); - let key1 = PrivateKey::try_new([1; 32]).unwrap(); - let sender_id = AccountId::from(&PublicKey::new_from_private_key(&key1)); - state.force_insert_account( - sender_id, - Account { - program_owner: Program::time_locked_transfer().id(), - balance: 100, - ..Account::default() - }, - ); - - let amount = 100_u128; - // Far-future deadline: program should panic. - let deadline = u64::MAX; - - let tx = time_locked_transfer_transaction( - sender_id, - &key1, - 0, - recipient_id, - CLOCK_01_PROGRAM_ACCOUNT_ID, - amount, - deadline, - ); - - let block_id = 1; - let timestamp = genesis_timestamp + 100; - let result = state.transition_from_public_transaction(&tx, block_id, timestamp); - - assert!( - result.is_err(), - "Transfer should fail when deadline is in the future" - ); - // Balances unchanged. - assert_eq!(state.get_account_by_id(sender_id).balance, 100); - assert_eq!(state.get_account_by_id(recipient_id).balance, 0); - } - - fn pinata_cooldown_data(prize: u128, cooldown_ms: u64, last_claim_timestamp: u64) -> Vec { - let mut buf = Vec::with_capacity(32); - buf.extend_from_slice(&prize.to_le_bytes()); - buf.extend_from_slice(&cooldown_ms.to_le_bytes()); - buf.extend_from_slice(&last_claim_timestamp.to_le_bytes()); - buf - } - - fn pinata_cooldown_transaction( - pinata_id: AccountId, - winner_id: AccountId, - clock_account_id: AccountId, - ) -> PublicTransaction { - let program_id = Program::pinata_cooldown().id(); - let message = public_transaction::Message::try_new( - program_id, - vec![pinata_id, winner_id, clock_account_id], - vec![], - (), - ) - .unwrap(); - let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); - PublicTransaction::new(message, witness_set) - } - - #[test] - fn pinata_cooldown_claim_succeeds_after_cooldown() { - let winner_id = AccountId::new([11; 32]); - let pinata_id = AccountId::new([99; 32]); - - let genesis_timestamp = 1000_u64; - let mut state = - V03State::new_with_genesis_accounts(&[(winner_id, 0)], vec![], genesis_timestamp) - .with_test_programs(); - - let prize = 50_u128; - let cooldown_ms = 500_u64; - // Last claim was at genesis, so any timestamp >= genesis + cooldown should work. - let last_claim_timestamp = genesis_timestamp; - - state.force_insert_account( - pinata_id, - Account { - program_owner: Program::pinata_cooldown().id(), - balance: 1000, - data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) - .try_into() - .unwrap(), - ..Account::default() - }, - ); - - let tx = pinata_cooldown_transaction(pinata_id, winner_id, CLOCK_01_PROGRAM_ACCOUNT_ID); - - let block_id = 1; - let block_timestamp = genesis_timestamp + cooldown_ms; - // Advance clock so the cooldown check reads an updated timestamp. - let clock_tx = clock_transaction(block_timestamp); - state - .transition_from_public_transaction(&clock_tx, block_id, block_timestamp) - .unwrap(); - - state - .transition_from_public_transaction(&tx, block_id, block_timestamp) - .unwrap(); - - assert_eq!(state.get_account_by_id(pinata_id).balance, 1000 - prize); - assert_eq!(state.get_account_by_id(winner_id).balance, prize); - } - - #[test] - fn pinata_cooldown_claim_fails_during_cooldown() { - let winner_id = AccountId::new([11; 32]); - let pinata_id = AccountId::new([99; 32]); - - let genesis_timestamp = 1000_u64; - let mut state = - V03State::new_with_genesis_accounts(&[(winner_id, 0)], vec![], genesis_timestamp) - .with_test_programs(); - - let prize = 50_u128; - let cooldown_ms = 500_u64; - let last_claim_timestamp = genesis_timestamp; - - state.force_insert_account( - pinata_id, - Account { - balance: 1000, - data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) - .try_into() - .unwrap(), - ..Account::default() - }, - ); - - let tx = pinata_cooldown_transaction(pinata_id, winner_id, CLOCK_01_PROGRAM_ACCOUNT_ID); - - let block_id = 1; - // Timestamp is only 100ms after last claim, well within the 500ms cooldown. - let block_timestamp = genesis_timestamp + 100; - let clock_tx = clock_transaction(block_timestamp); - state - .transition_from_public_transaction(&clock_tx, block_id, block_timestamp) - .unwrap(); - - let result = state.transition_from_public_transaction(&tx, block_id, block_timestamp); - - assert!(result.is_err(), "Claim should fail during cooldown period"); - assert_eq!(state.get_account_by_id(pinata_id).balance, 1000); - assert_eq!(state.get_account_by_id(winner_id).balance, 0); - } - #[test] fn state_serialization_roundtrip() { let account_id_1 = AccountId::new([1; 32]); let account_id_2 = AccountId::new([2; 32]); let initial_data = [(account_id_1, 100_u128), (account_id_2, 151_u128)]; - let state = - V03State::new_with_genesis_accounts(&initial_data, vec![], 0).with_test_programs(); + let state = V03State::new() + .with_public_accounts(public_state_from_balances(&initial_data)) + .with_test_programs(); let bytes = borsh::to_vec(&state).unwrap(); let state_from_bytes: V03State = borsh::from_slice(&bytes).unwrap(); assert_eq!(state, state_from_bytes); @@ -4435,9 +3898,9 @@ pub mod tests { #[test] fn flash_swap_successful() { - let initiator = Program::flash_swap_initiator(); - let callback = Program::flash_swap_callback(); - let token = Program::authenticated_transfer_program(); + let initiator = crate::test_methods::flash_swap_initiator(); + let callback = crate::test_methods::flash_swap_callback(); + let token = crate::test_methods::simple_balance_transfer(); let vault_id = AccountId::for_public_pda(&initiator.id(), &PdaSeed::new([0_u8; 32])); let receiver_id = AccountId::for_public_pda(&callback.id(), &PdaSeed::new([1_u8; 32])); @@ -4456,7 +3919,7 @@ pub mod tests { ..Account::default() }; - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(vault_id, vault_account); state.force_insert_account(receiver_id, receiver_account); @@ -4486,9 +3949,9 @@ pub mod tests { #[test] fn flash_swap_callback_keeps_funds_rollback() { - let initiator = Program::flash_swap_initiator(); - let callback = Program::flash_swap_callback(); - let token = Program::authenticated_transfer_program(); + let initiator = crate::test_methods::flash_swap_initiator(); + let callback = crate::test_methods::flash_swap_callback(); + let token = crate::test_methods::simple_balance_transfer(); let vault_id = AccountId::for_public_pda(&initiator.id(), &PdaSeed::new([0_u8; 32])); let receiver_id = AccountId::for_public_pda(&callback.id(), &PdaSeed::new([1_u8; 32])); @@ -4507,7 +3970,7 @@ pub mod tests { ..Account::default() }; - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(vault_id, vault_account); state.force_insert_account(receiver_id, receiver_account); @@ -4544,9 +4007,9 @@ pub mod tests { fn flash_swap_self_call_targets_correct_program() { // Zero-amount flash swap: the invariant self-call still runs and succeeds // because vault balance doesn't decrease. - let initiator = Program::flash_swap_initiator(); - let callback = Program::flash_swap_callback(); - let token = Program::authenticated_transfer_program(); + let initiator = crate::test_methods::flash_swap_initiator(); + let callback = crate::test_methods::flash_swap_callback(); + let token = crate::test_methods::simple_balance_transfer(); let vault_id = AccountId::for_public_pda(&initiator.id(), &PdaSeed::new([0_u8; 32])); let receiver_id = AccountId::for_public_pda(&callback.id(), &PdaSeed::new([1_u8; 32])); @@ -4564,7 +4027,7 @@ pub mod tests { ..Account::default() }; - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(vault_id, vault_account); state.force_insert_account(receiver_id, receiver_account); @@ -4594,8 +4057,8 @@ pub mod tests { fn flash_swap_standalone_invariant_check_rejected() { // Calling InvariantCheck directly (not as a chained self-call) should fail // because caller_program_id will be None. - let initiator = Program::flash_swap_initiator(); - let token = Program::authenticated_transfer_program(); + let initiator = crate::test_methods::flash_swap_initiator(); + let token = crate::test_methods::simple_balance_transfer(); let vault_id = AccountId::for_public_pda(&initiator.id(), &PdaSeed::new([0_u8; 32])); @@ -4605,7 +4068,7 @@ pub mod tests { ..Account::default() }; - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(vault_id, vault_account); let instruction = FlashSwapInstruction::InvariantCheck { @@ -4631,11 +4094,11 @@ pub mod tests { #[test] fn malicious_self_program_id_rejected_in_public_execution() { - let program = Program::malicious_self_program_id(); + let program = crate::test_methods::malicious_self_program_id(); let acc_id = AccountId::new([99; 32]); let account = Account::default(); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(acc_id, account); let message = @@ -4652,11 +4115,11 @@ pub mod tests { #[test] fn malicious_caller_program_id_rejected_in_public_execution() { - let program = Program::malicious_caller_program_id(); + let program = crate::test_methods::malicious_caller_program_id(); let acc_id = AccountId::new([99; 32]); let account = Account::default(); - let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); + let mut state = V03State::new().with_test_programs(); state.force_insert_account(acc_id, account); let message = @@ -4677,15 +4140,17 @@ pub mod tests { let alice_keys = test_private_account_keys_1(); let alice_npk = alice_keys.npk(); - let proxy = Program::pda_spend_proxy(); - let auth_transfer = Program::authenticated_transfer_program(); + let proxy = crate::test_methods::pda_spend_proxy(); + let simple_transfer = crate::test_methods::simple_balance_transfer(); let proxy_id = proxy.id(); - let auth_transfer_id = auth_transfer.id(); + let simple_transfer_id = simple_transfer.id(); let seed = PdaSeed::new([42; 32]); let amount: u128 = 100; - let spend_with_deps = - ProgramWithDependencies::new(proxy, [(auth_transfer_id, auth_transfer.clone())].into()); + let spend_with_deps = ProgramWithDependencies::new( + proxy, + [(simple_transfer_id, simple_transfer.clone())].into(), + ); let funder_id = funder_keys.account_id(); let alice_pda_0_id = AccountId::for_private_pda(&proxy_id, &seed, &alice_npk, 0); @@ -4693,16 +4158,17 @@ pub mod tests { let recipient_id = test_public_account_keys_2().account_id(); let recipient_signing_key = test_public_account_keys_2().signing_key; - let mut state = V03State::new_with_genesis_accounts(&[(funder_id, 500)], vec![], 0); + let mut state = + V03State::new().with_public_accounts(public_state_from_balances(&[(funder_id, 500)])); let alice_pda_0_account = Account { - program_owner: auth_transfer_id, + program_owner: simple_transfer_id, balance: amount, nonce: Nonce::private_account_nonce_init(&alice_pda_0_id), ..Account::default() }; let alice_pda_1_account = Account { - program_owner: auth_transfer_id, + program_owner: simple_transfer_id, balance: amount, nonce: Nonce::private_account_nonce_init(&alice_pda_1_id), ..Account::default() @@ -4722,8 +4188,7 @@ pub mod tests { AccountWithMetadata::new(funder_account, true, funder_id), AccountWithMetadata::new(Account::default(), false, alice_pda_0_id), ], - Program::serialize_instruction(AuthTransferInstruction::Transfer { amount }) - .unwrap(), + Program::serialize_instruction(amount).unwrap(), vec![ InputAccountIdentity::Public, InputAccountIdentity::PrivatePdaInit { @@ -4738,7 +4203,7 @@ pub mod tests { seed: Some((seed, proxy_id)), }, ], - &auth_transfer.clone().into(), + &simple_transfer.clone().into(), ) .unwrap(); let message = @@ -4763,8 +4228,7 @@ pub mod tests { AccountWithMetadata::new(funder_account, true, funder_id), AccountWithMetadata::new(Account::default(), false, alice_pda_1_id), ], - Program::serialize_instruction(AuthTransferInstruction::Transfer { amount }) - .unwrap(), + Program::serialize_instruction(amount).unwrap(), vec![ InputAccountIdentity::Public, InputAccountIdentity::PrivatePdaInit { @@ -4779,7 +4243,7 @@ pub mod tests { seed: Some((seed, proxy_id)), }, ], - &auth_transfer.into(), + &simple_transfer.into(), ) .unwrap(); let message = @@ -4809,7 +4273,7 @@ pub mod tests { AccountWithMetadata::new(alice_pda_0_account, true, alice_pda_0_id), AccountWithMetadata::new(recipient_account, true, recipient_id), ], - Program::serialize_instruction((seed, amount, auth_transfer_id)).unwrap(), + Program::serialize_instruction((seed, amount, simple_transfer_id)).unwrap(), vec![ InputAccountIdentity::PrivatePdaUpdate { epk: alice_epk_0, @@ -4851,7 +4315,7 @@ pub mod tests { AccountWithMetadata::new(alice_pda_1_account.clone(), true, alice_pda_1_id), AccountWithMetadata::new(recipient_account, false, recipient_id), ], - Program::serialize_instruction((seed, amount, auth_transfer_id)).unwrap(), + Program::serialize_instruction((seed, amount, simple_transfer_id)).unwrap(), vec![ InputAccountIdentity::PrivatePdaUpdate { epk: alice_epk_1, @@ -4886,10 +4350,10 @@ pub mod tests { assert_eq!(state.get_account_by_id(recipient_id).balance, 2 * amount); - // Re-fund alice_pda_1 top-level via auth_transfer using PrivatePdaUpdate with an + // Re-fund alice_pda_1 top-level via simple_transfer using PrivatePdaUpdate with an // external seed. let alice_pda_1_account_after_spend = Account { - program_owner: auth_transfer_id, + program_owner: simple_transfer_id, balance: 0, nonce: alice_pda_1_account .nonce @@ -4911,8 +4375,7 @@ pub mod tests { alice_pda_1_id, ), ], - Program::serialize_instruction(AuthTransferInstruction::Transfer { amount }) - .unwrap(), + Program::serialize_instruction(amount).unwrap(), vec![ InputAccountIdentity::Public, InputAccountIdentity::PrivatePdaUpdate { @@ -4930,7 +4393,7 @@ pub mod tests { seed: Some((seed, proxy_id)), }, ], - &Program::authenticated_transfer_program().into(), + &crate::test_methods::simple_balance_transfer().into(), ) .unwrap(); let message = diff --git a/lee/state_machine/src/validated_state_diff.rs b/lee/state_machine/src/validated_state_diff.rs index 3a3ff760..44a307af 100644 --- a/lee/state_machine/src/validated_state_diff.rs +++ b/lee/state_machine/src/validated_state_diff.rs @@ -462,7 +462,7 @@ impl ValidatedStateDiff { state: &V03State, ) -> Result { // 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()) { return Err(LeeError::ProgramAlreadyExists); } @@ -516,7 +516,9 @@ fn n_unique(data: &[T]) -> usize { #[cfg(test)] mod tests { - use lee_core::account::{AccountId, Nonce}; + use std::collections::HashMap; + + use lee_core::account::{Account, AccountId, Nonce}; use crate::{ PrivateKey, PublicKey, V03State, @@ -526,27 +528,43 @@ mod tests { validated_state_diff::ValidatedStateDiff, }; + fn public_state_from_balances( + initial_data: &[(AccountId, u128)], + ) -> HashMap { + 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] fn public_diff_reflects_a_successful_transfer() { // A successful native transfer must record the debited sender in // `public_diff()`. Catches the mutation that replaces `public_diff` with // `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 = AccountId::from(&PublicKey::new_from_private_key(&from_key)); let to_key = PrivateKey::try_new([2_u8; 32]).unwrap(); let to = AccountId::from(&PublicKey::new_from_private_key(&to_key)); - let state = V03State::new_with_genesis_accounts(&[(from, 100)], vec![], 0); - let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new( - program_id, - vec![from, to], - vec![Nonce(0), Nonce(0)], - AtInstruction::Transfer { amount: 5 }, - ) - .unwrap(); + let state = V03State::new() + .with_public_accounts(public_state_from_balances(&[(from, 100)])) + .with_programs(std::iter::once( + crate::test_methods::simple_balance_transfer(), + )); + let program_id = crate::test_methods::simple_balance_transfer().id(); + let message = + Message::try_new(program_id, vec![from, to], vec![Nonce(0), Nonce(0)], 5_u128).unwrap(); let witness_set = WitnessSet::for_message(&message, &[&from_key, &to_key]); let tx = crate::PublicTransaction::new(message, witness_set); @@ -596,7 +614,7 @@ mod tests { type InjectorInstruction = ( 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 u128, // victim_balance u128, // victim_nonce @@ -614,18 +632,21 @@ mod tests { let recipient_id = AccountId::new([42_u8; 32]); let victim_balance = 5_000_u128; - // genesis sets program_owner = authenticated_transfer_program.id() on all accounts. - let mut state = V03State::new_with_genesis_accounts( - &[(victim_id, victim_balance), (recipient_id, 0)], - vec![], - 0, - ); - state.insert_program(Program::malicious_injector()); - state.insert_program(Program::malicious_launderer()); + // genesis sets program_owner = simple_balance_transfer_program.id() on all accounts. + let state = V03State::new() + .with_public_accounts(public_state_from_balances(&[ + (victim_id, victim_balance), + (recipient_id, 0), + ])) + .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. let attacker_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, ..Account::default() }; @@ -640,8 +661,8 @@ mod tests { let victim_account = state.get_account_by_id(victim_id); let instruction: InjectorInstruction = ( - Program::malicious_launderer().id(), - Program::authenticated_transfer_program().id(), + crate::test_methods::malicious_launderer().id(), + crate::test_methods::simple_balance_transfer().id(), *victim_id.value(), victim_account.balance, victim_account.nonce.0, @@ -651,17 +672,17 @@ mod tests { ); let instruction_data = Program::serialize_instruction(instruction).unwrap(); - let p2 = Program::malicious_launderer(); - let at = Program::authenticated_transfer_program(); + let p2 = crate::test_methods::malicious_launderer(); + let at = crate::test_methods::simple_balance_transfer(); let program_with_deps = ProgramWithDependencies::new( - Program::malicious_injector(), + crate::test_methods::malicious_injector(), [(p2.id(), p2), (at.id(), at)].into(), ); // account_identities order must match self.pre_states as built by the circuit: // [0] attacker — first seen in P1's program_output.pre_states - // [1] victim — first seen in authenticated_transfer's program_output.pre_states - // [2] recipient — 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 simple_balance_transfer's program_output.pre_states let account_identities = vec![ InputAccountIdentity::PrivateAuthorizedUpdate { epk: attacker_epk, @@ -751,7 +772,7 @@ mod tests { type InjectorInstruction = ( 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 u128, // victim_balance u128, // victim_nonce @@ -773,13 +794,17 @@ mod tests { let recipient_id = AccountId::new([42_u8; 32]); // 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); - state.insert_program(Program::malicious_injector()); - state.insert_program(Program::malicious_launderer()); + let state = V03State::new() + .with_public_accounts(public_state_from_balances(&[(recipient_id, 0)])) + .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. let attacker_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: crate::test_methods::simple_balance_transfer().id(), balance: 100, ..Account::default() }; @@ -793,32 +818,32 @@ mod tests { let attacker_pre = AccountWithMetadata::new(attacker_account, true, attacker_id); // 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 // that these values are fabricated. let instruction: InjectorInstruction = ( - Program::malicious_launderer().id(), - Program::authenticated_transfer_program().id(), + crate::test_methods::malicious_launderer().id(), + crate::test_methods::simple_balance_transfer().id(), *victim_id.value(), victim_balance, - 0_u128, // nonce - Program::authenticated_transfer_program().id(), // program_owner + 0_u128, // nonce + crate::test_methods::simple_balance_transfer().id(), // program_owner *recipient_id.value(), victim_balance, ); let instruction_data = Program::serialize_instruction(instruction).unwrap(); - let p2 = Program::malicious_launderer(); - let at = Program::authenticated_transfer_program(); + let p2 = crate::test_methods::malicious_launderer(); + let at = crate::test_methods::simple_balance_transfer(); let program_with_deps = ProgramWithDependencies::new( - Program::malicious_injector(), + crate::test_methods::malicious_injector(), [(p2.id(), p2), (at.id(), at)].into(), ); // account_identities order must match self.pre_states as built by the circuit: // [0] attacker — first seen in P1's program_output.pre_states - // [1] victim — first seen in authenticated_transfer's program_output.pre_states - // [2] recipient — 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 simple_balance_transfer's program_output.pre_states // // Victim is marked Public: the attacker has no nsk for the victim's private account, // so PrivateAuthorizedUpdate is not an option. @@ -838,7 +863,7 @@ mod tests { 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. // The outer circuit commits victim(is_authorized=true) to public_pre_states. let (circuit_output, proof) = execute_and_prove( @@ -880,7 +905,7 @@ mod tests { /// Transaction (attacker signs) → P1 (`malicious_injector`) /// → injects `victim(is_authorized=true)` into chained-call `pre_states` for P2 /// 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`, /// `{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. #[test] 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. // Primitives only — AccountId/Account cannot round-trip through instruction_data // via risc0_zkvm::serde (SerializeDisplay issue). type InjectorInstruction = ( 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 u128, // victim_balance u128, // victim_nonce @@ -913,25 +938,24 @@ mod tests { let recipient_id = AccountId::new([42; 32]); 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), (victim_id, victim_balance), (recipient_id, 0), - ], - vec![], - 0, - ); - - state.insert_program(Program::malicious_injector()); - state.insert_program(Program::malicious_launderer()); + ])) + .with_programs([ + crate::test_methods::simple_balance_transfer(), + crate::test_methods::malicious_injector(), + crate::test_methods::malicious_launderer(), + ]); // Read victim state from chain, exactly as the attacker would. let victim_account = state.get_account_by_id(victim_id); let instruction: InjectorInstruction = ( - Program::malicious_launderer().id(), - Program::authenticated_transfer_program().id(), + crate::test_methods::malicious_launderer().id(), + crate::test_methods::simple_balance_transfer().id(), *victim_id.value(), victim_account.balance, victim_account.nonce.0, @@ -941,7 +965,7 @@ mod tests { ); let message = Message::try_new( - Program::malicious_injector().id(), + crate::test_methods::malicious_injector().id(), vec![attacker_id], vec![Nonce(0)], 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 // commitment satisfies the non-empty requirement, no signers makes the diff --git a/program_methods/Cargo.toml b/lee/state_machine/test_methods/Cargo.toml similarity index 88% rename from program_methods/Cargo.toml rename to lee/state_machine/test_methods/Cargo.toml index 573fd4e6..a2709e1f 100644 --- a/program_methods/Cargo.toml +++ b/lee/state_machine/test_methods/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "program_methods" +name = "test_methods" version = "0.1.0" edition = "2024" license = { workspace = true } diff --git a/program_methods/build.rs b/lee/state_machine/test_methods/build.rs similarity index 100% rename from program_methods/build.rs rename to lee/state_machine/test_methods/build.rs diff --git a/lee/state_machine/test_methods/guest/Cargo.toml b/lee/state_machine/test_methods/guest/Cargo.toml new file mode 100644 index 00000000..75d34081 --- /dev/null +++ b/lee/state_machine/test_methods/guest/Cargo.toml @@ -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 diff --git a/test_program_methods/guest/src/bin/auth_asserting_noop.rs b/lee/state_machine/test_methods/guest/src/bin/auth_asserting_noop.rs similarity index 100% rename from test_program_methods/guest/src/bin/auth_asserting_noop.rs rename to lee/state_machine/test_methods/guest/src/bin/auth_asserting_noop.rs diff --git a/test_program_methods/guest/src/bin/burner.rs b/lee/state_machine/test_methods/guest/src/bin/burner.rs similarity index 100% rename from test_program_methods/guest/src/bin/burner.rs rename to lee/state_machine/test_methods/guest/src/bin/burner.rs diff --git a/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs b/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs new file mode 100644 index 00000000..b812fc9e --- /dev/null +++ b/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs @@ -0,0 +1,70 @@ +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +}; +use risc0_zkvm::serde::to_vec; + +type Instruction = (u128, ProgramId, u32, Option); + +/// A program that calls another program `num_chain_calls` times. +/// It permutes the order of the input accounts on the subsequent call +/// The `ProgramId` in the instruction must be the `program_id` of the transfers +/// program. +fn main() { + let ( + ProgramInput { + self_program_id, + caller_program_id, + pre_states, + instruction: (balance, simple_transfer_id, num_chain_calls, pda_seed), + }, + instruction_words, + ) = read_lee_inputs::(); + + let Ok([recipient_pre, sender_pre]) = <[_; 2]>::try_from(pre_states) else { + return; + }; + + let instruction_data = to_vec(&balance).unwrap(); + + let mut running_recipient_pre = recipient_pre.clone(); + let mut running_sender_pre = sender_pre.clone(); + + if pda_seed.is_some() { + running_sender_pre.is_authorized = true; + } + + let mut chained_calls = Vec::new(); + for _i in 0..num_chain_calls { + let new_chained_call = ChainedCall { + program_id: simple_transfer_id, + instruction_data: instruction_data.clone(), + pre_states: vec![running_sender_pre.clone(), running_recipient_pre.clone()], /* <- Account order permutation here */ + pda_seeds: pda_seed.iter().copied().collect(), + }; + chained_calls.push(new_chained_call); + + running_sender_pre.account.balance = + match running_sender_pre.account.balance.checked_sub(balance) { + Some(new_balance) => new_balance, + None => return, + }; + running_recipient_pre.account.balance = + match running_recipient_pre.account.balance.checked_add(balance) { + Some(new_balance) => new_balance, + None => return, + }; + } + + ProgramOutput::new( + self_program_id, + caller_program_id, + instruction_words, + vec![sender_pre.clone(), recipient_pre.clone()], + vec![ + AccountPostState::new(sender_pre.account), + AccountPostState::new(recipient_pre.account), + ], + ) + .with_chained_calls(chained_calls) + .write(); +} diff --git a/test_program_methods/guest/src/bin/changer_claimer.rs b/lee/state_machine/test_methods/guest/src/bin/changer_claimer.rs similarity index 100% rename from test_program_methods/guest/src/bin/changer_claimer.rs rename to lee/state_machine/test_methods/guest/src/bin/changer_claimer.rs diff --git a/test_program_methods/guest/src/bin/claimer.rs b/lee/state_machine/test_methods/guest/src/bin/claimer.rs similarity index 100% rename from test_program_methods/guest/src/bin/claimer.rs rename to lee/state_machine/test_methods/guest/src/bin/claimer.rs diff --git a/test_program_methods/guest/src/bin/data_changer.rs b/lee/state_machine/test_methods/guest/src/bin/data_changer.rs similarity index 100% rename from test_program_methods/guest/src/bin/data_changer.rs rename to lee/state_machine/test_methods/guest/src/bin/data_changer.rs diff --git a/test_program_methods/guest/src/bin/extra_output.rs b/lee/state_machine/test_methods/guest/src/bin/extra_output.rs similarity index 100% rename from test_program_methods/guest/src/bin/extra_output.rs rename to lee/state_machine/test_methods/guest/src/bin/extra_output.rs diff --git a/test_program_methods/guest/src/bin/flash_swap_callback.rs b/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs similarity index 95% rename from test_program_methods/guest/src/bin/flash_swap_callback.rs rename to lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs index 5e1a30aa..28f6509f 100644 --- a/test_program_methods/guest/src/bin/flash_swap_callback.rs +++ b/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs @@ -62,10 +62,7 @@ fn main() { // Mark the receiver as authorized since it will be PDA-authorized in this chained call. let mut receiver_authorized = receiver_pre.clone(); receiver_authorized.is_authorized = true; - let transfer_instruction = - risc0_zkvm::serde::to_vec(&authenticated_transfer_core::Instruction::Transfer { - amount: instruction.amount, - }) + let transfer_instruction = risc0_zkvm::serde::to_vec(&instruction.amount) .expect("transfer instruction serialization"); chained_calls.push(ChainedCall { diff --git a/test_program_methods/guest/src/bin/flash_swap_initiator.rs b/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs similarity index 97% rename from test_program_methods/guest/src/bin/flash_swap_initiator.rs rename to lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs index 15706c1e..699d7c57 100644 --- a/test_program_methods/guest/src/bin/flash_swap_initiator.rs +++ b/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs @@ -122,10 +122,7 @@ fn main() { let mut vault_authorized = vault_pre.clone(); vault_authorized.is_authorized = true; let transfer_instruction = - risc0_zkvm::serde::to_vec(&authenticated_transfer_core::Instruction::Transfer { - amount: amount_out, - }) - .expect("transfer instruction serialization"); + risc0_zkvm::serde::to_vec(&amount_out).expect("transfer instruction serialization"); let call_1 = ChainedCall { program_id: token_program_id, pre_states: vec![vault_authorized, receiver_pre.clone()], diff --git a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs similarity index 92% rename from test_program_methods/guest/src/bin/malicious_authorization_changer.rs rename to lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs index f1e3be6b..80bd8aaa 100644 --- a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs +++ b/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs @@ -32,8 +32,7 @@ fn main() { ..sender.clone() }; - let instruction_data = - to_vec(&authenticated_transfer_core::Instruction::Transfer { amount: balance }).unwrap(); + let instruction_data = to_vec(&balance).unwrap(); let chained_call = ChainedCall { program_id: transfer_program_id, diff --git a/test_program_methods/guest/src/bin/malicious_caller_program_id.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_caller_program_id.rs similarity index 100% rename from test_program_methods/guest/src/bin/malicious_caller_program_id.rs rename to lee/state_machine/test_methods/guest/src/bin/malicious_caller_program_id.rs diff --git a/test_program_methods/guest/src/bin/malicious_injector.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs similarity index 100% rename from test_program_methods/guest/src/bin/malicious_injector.rs rename to lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs diff --git a/test_program_methods/guest/src/bin/malicious_launderer.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs similarity index 79% rename from test_program_methods/guest/src/bin/malicious_launderer.rs rename to lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs index 6794f0c0..5ec7989d 100644 --- a/test_program_methods/guest/src/bin/malicious_launderer.rs +++ b/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs @@ -9,7 +9,7 @@ fn main() { self_program_id, caller_program_id, pre_states, - instruction: (auth_transfer_id, amount), + instruction: (simple_transfer_id, amount), }, instruction_words, ) = read_lee_inputs::(); @@ -18,13 +18,12 @@ fn main() { // authorization check at validated_state_diff.rs:158-182 runs over nothing. // Victim is never compared against caller_data.authorized_accounts = {attacker}. // - // The bug: authorized_accounts for authenticated_transfer is built from + // The bug: authorized_accounts for simple_transfer is built from // chained_call.pre_states (this call's inputs, set by P1), which contains // victim(is_authorized=true). So authorized_accounts = {victim}, and the // subsequent check passes. let auth_transfer_instruction = - risc0_zkvm::serde::to_vec(&authenticated_transfer_core::Instruction::Transfer { amount }) - .expect("serialization is infallible"); + risc0_zkvm::serde::to_vec(&amount).expect("serialization is infallible"); ProgramOutput::new( self_program_id, @@ -34,7 +33,7 @@ fn main() { vec![], ) .with_chained_calls(vec![ChainedCall { - program_id: auth_transfer_id, + program_id: simple_transfer_id, pre_states, instruction_data: auth_transfer_instruction, pda_seeds: vec![], diff --git a/test_program_methods/guest/src/bin/malicious_self_program_id.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_self_program_id.rs similarity index 100% rename from test_program_methods/guest/src/bin/malicious_self_program_id.rs rename to lee/state_machine/test_methods/guest/src/bin/malicious_self_program_id.rs diff --git a/test_program_methods/guest/src/bin/minter.rs b/lee/state_machine/test_methods/guest/src/bin/minter.rs similarity index 100% rename from test_program_methods/guest/src/bin/minter.rs rename to lee/state_machine/test_methods/guest/src/bin/minter.rs diff --git a/test_program_methods/guest/src/bin/missing_output.rs b/lee/state_machine/test_methods/guest/src/bin/missing_output.rs similarity index 100% rename from test_program_methods/guest/src/bin/missing_output.rs rename to lee/state_machine/test_methods/guest/src/bin/missing_output.rs diff --git a/test_program_methods/guest/src/bin/modified_transfer.rs b/lee/state_machine/test_methods/guest/src/bin/modified_transfer.rs similarity index 100% rename from test_program_methods/guest/src/bin/modified_transfer.rs rename to lee/state_machine/test_methods/guest/src/bin/modified_transfer.rs diff --git a/test_program_methods/guest/src/bin/nonce_changer.rs b/lee/state_machine/test_methods/guest/src/bin/nonce_changer.rs similarity index 100% rename from test_program_methods/guest/src/bin/nonce_changer.rs rename to lee/state_machine/test_methods/guest/src/bin/nonce_changer.rs diff --git a/test_program_methods/guest/src/bin/noop.rs b/lee/state_machine/test_methods/guest/src/bin/noop.rs similarity index 100% rename from test_program_methods/guest/src/bin/noop.rs rename to lee/state_machine/test_methods/guest/src/bin/noop.rs diff --git a/test_program_methods/guest/src/bin/pda_claimer.rs b/lee/state_machine/test_methods/guest/src/bin/pda_claimer.rs similarity index 100% rename from test_program_methods/guest/src/bin/pda_claimer.rs rename to lee/state_machine/test_methods/guest/src/bin/pda_claimer.rs diff --git a/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs b/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs new file mode 100644 index 00000000..d8b9bb5c --- /dev/null +++ b/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs @@ -0,0 +1,48 @@ +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +}; +use risc0_zkvm::serde::to_vec; + +/// Proxy for spending from a private PDA via `simple_transfer`. +/// +/// `pre_states = [pda (authorized), recipient]`. Debits the PDA and credits the recipient. +/// The PDA-to-npk binding is established via `pda_seeds` in the chained call to `simple_transfer`. +type Instruction = (PdaSeed, u128, ProgramId); + +fn main() { + let ( + ProgramInput { + self_program_id, + caller_program_id, + pre_states, + instruction: (seed, amount, simple_transfer_id), + }, + instruction_words, + ) = read_lee_inputs::(); + + let Ok([first, second]) = <[_; 2]>::try_from(pre_states) else { + return; + }; + + assert!(first.is_authorized, "first pre_state must be authorized"); + + let first_post = AccountPostState::new(first.account.clone()); + let second_post = AccountPostState::new(second.account.clone()); + + let chained_call = ChainedCall { + program_id: simple_transfer_id, + instruction_data: to_vec(&amount).unwrap(), + pre_states: vec![first.clone(), second.clone()], + pda_seeds: vec![seed], + }; + + ProgramOutput::new( + self_program_id, + caller_program_id, + instruction_words, + vec![first, second], + vec![first_post, second_post], + ) + .with_chained_calls(vec![chained_call]) + .write(); +} diff --git a/test_program_methods/guest/src/bin/private_pda_delegator.rs b/lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs similarity index 100% rename from test_program_methods/guest/src/bin/private_pda_delegator.rs rename to lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs diff --git a/test_program_methods/guest/src/bin/program_owner_changer.rs b/lee/state_machine/test_methods/guest/src/bin/program_owner_changer.rs similarity index 100% rename from test_program_methods/guest/src/bin/program_owner_changer.rs rename to lee/state_machine/test_methods/guest/src/bin/program_owner_changer.rs diff --git a/test_program_methods/guest/src/bin/simple_balance_transfer.rs b/lee/state_machine/test_methods/guest/src/bin/simple_balance_transfer.rs similarity index 57% rename from test_program_methods/guest/src/bin/simple_balance_transfer.rs rename to lee/state_machine/test_methods/guest/src/bin/simple_balance_transfer.rs index 29149272..addc4a19 100644 --- a/test_program_methods/guest/src/bin/simple_balance_transfer.rs +++ b/lee/state_machine/test_methods/guest/src/bin/simple_balance_transfer.rs @@ -1,4 +1,4 @@ -use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = u128; @@ -13,6 +13,21 @@ fn main() { instruction_words, ) = read_lee_inputs::(); + if let Ok([account_pre]) = <[_; 1]>::try_from(pre_states.clone()) { + let account_post = + AccountPostState::new_claimed_if_default(account_pre.account, Claim::Authorized); + + ProgramOutput::new( + self_program_id, + caller_program_id, + instruction_words, + pre_states, + vec![account_post], + ) + .write(); + return; + } + let Ok([sender_pre, receiver_pre]) = <[_; 2]>::try_from(pre_states) else { return; }; @@ -34,8 +49,8 @@ fn main() { instruction_words, vec![sender_pre, receiver_pre], vec![ - AccountPostState::new(sender_post), - AccountPostState::new(receiver_post), + AccountPostState::new_claimed_if_default(sender_post, Claim::Authorized), + AccountPostState::new_claimed_if_default(receiver_post, Claim::Authorized), ], ) .write(); diff --git a/test_program_methods/guest/src/bin/auth_transfer_proxy.rs b/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs similarity index 65% rename from test_program_methods/guest/src/bin/auth_transfer_proxy.rs rename to lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs index a7e2f5be..ce7f1d8e 100644 --- a/test_program_methods/guest/src/bin/auth_transfer_proxy.rs +++ b/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs @@ -2,23 +2,23 @@ use lee_core::program::{ AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -/// PDA authorization program that delegates balance operations to `authenticated_transfer`. +/// PDA authorization program that delegates balance operations to `simple_transfer`. /// -/// The PDA is owned by `authenticated_transfer`, not by this program. This program's role +/// The PDA is owned by `simple_transfer`, not by this program. This program's role /// is solely to provide PDA authorization via `pda_seeds` in chained calls. /// -/// Instruction: `(pda_seed, auth_transfer_id, amount, is_withdraw)`. +/// Instruction: `(pda_seed, simple_transfer_id, amount, is_withdraw)`. /// /// **Init** (`is_withdraw = false`, 1 pre-state `[pda]`): -/// Chains to `authenticated_transfer` with `instruction=0` (init path) and `pda_seeds=[seed]` -/// to initialize the PDA under `authenticated_transfer`'s ownership. +/// Chains to `simple_transfer` with `instruction=0` (init path) and `pda_seeds=[seed]` +/// to initialize the PDA under `simple_transfer`'s ownership. /// /// **Withdraw** (`is_withdraw = true`, 2 pre-states `[pda, recipient]`): -/// Chains to `authenticated_transfer` with the amount and `pda_seeds=[seed]` to authorize +/// Chains to `simple_transfer` with the amount and `pda_seeds=[seed]` to authorize /// the PDA for a balance transfer. The actual balance modification happens in -/// `authenticated_transfer`, not here. +/// `simple_transfer`, not here. /// -/// **Deposit**: done directly via `authenticated_transfer` (no need for this program). +/// **Deposit**: done directly via `simple_transfer` (no need for this program). type Instruction = (PdaSeed, ProgramId, u128, bool); #[expect( @@ -35,7 +35,7 @@ fn main() { self_program_id, caller_program_id, pre_states, - instruction: (pda_seed, auth_transfer_id, amount, is_withdraw), + instruction: (pda_seed, simple_transfer_id, amount, is_withdraw), }, instruction_words, ) = read_lee_inputs::(); @@ -46,19 +46,19 @@ fn main() { }; // Post-states stay unchanged in this program. The actual balance transfer - // happens in the chained call to authenticated_transfer. + // happens in the chained call to simple_transfer. let pda_post = AccountPostState::new(pda_pre.account.clone()); let recipient_post = AccountPostState::new(recipient_pre.account.clone()); - // Chain to authenticated_transfer with pda_seeds to authorize the PDA. + // Chain to simple_transfer with pda_seeds to authorize the PDA. // The circuit's resolve_authorization_and_record_bindings establishes the // private PDA (seed, npk) binding when pda_seeds match the private PDA derivation. let mut auth_pda_pre = pda_pre; auth_pda_pre.is_authorized = true; let auth_call = ChainedCall::new( - auth_transfer_id, + simple_transfer_id, vec![auth_pda_pre, recipient_pre], - &authenticated_transfer_core::Instruction::Transfer { amount }, + &amount, ) .with_pda_seeds(vec![pda_seed]); @@ -72,23 +72,19 @@ fn main() { .with_chained_calls(vec![auth_call]) .write(); } else { - // Init: initialize the PDA under authenticated_transfer's ownership. + // Init: initialize the PDA under simple_transfer's ownership. let Ok([pda_pre]) = <[_; 1]>::try_from(pre_states.clone()) else { panic!("expected exactly 1 pre_state for init: [pda]"); }; let pda_post = AccountPostState::new(pda_pre.account.clone()); - // Chain to authenticated_transfer with instruction=0 (init path) and pda_seeds - // to authorize the PDA. authenticated_transfer will claim it with Claim::Authorized. + // Chain to simple_transfer with instruction=0 (init path) and pda_seeds + // to authorize the PDA. simple_transfer will claim it with Claim::Authorized. let mut auth_pda_pre = pda_pre; auth_pda_pre.is_authorized = true; - let auth_call = ChainedCall::new( - auth_transfer_id, - vec![auth_pda_pre], - &authenticated_transfer_core::Instruction::Initialize, - ) - .with_pda_seeds(vec![pda_seed]); + let auth_call = ChainedCall::new(simple_transfer_id, vec![auth_pda_pre], &amount) + .with_pda_seeds(vec![pda_seed]); ProgramOutput::new( self_program_id, diff --git a/test_program_methods/guest/src/bin/two_pda_claimer.rs b/lee/state_machine/test_methods/guest/src/bin/two_pda_claimer.rs similarity index 100% rename from test_program_methods/guest/src/bin/two_pda_claimer.rs rename to lee/state_machine/test_methods/guest/src/bin/two_pda_claimer.rs diff --git a/test_program_methods/guest/src/bin/validity_window.rs b/lee/state_machine/test_methods/guest/src/bin/validity_window.rs similarity index 100% rename from test_program_methods/guest/src/bin/validity_window.rs rename to lee/state_machine/test_methods/guest/src/bin/validity_window.rs diff --git a/test_program_methods/guest/src/bin/validity_window_chain_caller.rs b/lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs similarity index 100% rename from test_program_methods/guest/src/bin/validity_window_chain_caller.rs rename to lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs diff --git a/program_methods/src/lib.rs b/lee/state_machine/test_methods/src/lib.rs similarity index 100% rename from program_methods/src/lib.rs rename to lee/state_machine/test_methods/src/lib.rs diff --git a/lez/common/Cargo.toml b/lez/common/Cargo.toml index a559960d..8b2aa322 100644 --- a/lez/common/Cargo.toml +++ b/lez/common/Cargo.toml @@ -12,6 +12,8 @@ lee.workspace = true lee_core.workspace = true authenticated_transfer_core.workspace = true clock_core.workspace = true +programs.workspace = true +system_accounts.workspace = true anyhow.workspace = true thiserror.workspace = true diff --git a/lez/common/src/lib.rs b/lez/common/src/lib.rs index cfbbbd9b..3cca327b 100644 --- a/lez/common/src/lib.rs +++ b/lez/common/src/lib.rs @@ -12,8 +12,6 @@ pub mod transaction; // TODO: Compile only for tests pub mod test_utils; -pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7"; - #[derive( Default, Copy, diff --git a/lez/common/src/test_utils.rs b/lez/common/src/test_utils.rs index 179e9601..7afda3dd 100644 --- a/lez/common/src/test_utils.rs +++ b/lez/common/src/test_utils.rs @@ -44,7 +44,7 @@ pub fn produce_dummy_block( #[must_use] pub fn produce_dummy_empty_transaction() -> LeeTransaction { - let program_id = lee::program::Program::authenticated_transfer_program().id(); + let program_id = programs::authenticated_transfer().id(); let account_ids = vec![]; let nonces = vec![]; let message = lee::public_transaction::Message::try_new( @@ -72,7 +72,7 @@ pub fn create_transaction_native_token_transfer( ) -> LeeTransaction { let account_ids = vec![from, to]; let nonces = vec![nonce.into()]; - let program_id = lee::program::Program::authenticated_transfer_program().id(); + let program_id = programs::authenticated_transfer().id(); let message = lee::public_transaction::Message::try_new( program_id, account_ids, diff --git a/lez/common/src/transaction.rs b/lez/common/src/transaction.rs index 7fb32e39..eec01d4e 100644 --- a/lez/common/src/transaction.rs +++ b/lez/common/src/transaction.rs @@ -80,10 +80,9 @@ impl LeeTransaction { ) -> Result { let diff = self.compute_state_diff(state, block_id, timestamp)?; - let restricted_modification_accounts = lee::CLOCK_PROGRAM_ACCOUNT_IDS - .iter() - .copied() - .chain(std::iter::once(lee::system_faucet_account_id())); + let restricted_modification_accounts = system_accounts::clock_account_ids() + .into_iter() + .chain(std::iter::once(system_accounts::faucet_account_id())); for account_id in restricted_modification_accounts { validate_doesnt_modify_account(state, &diff, account_id)?; } @@ -157,7 +156,7 @@ impl LeeTransaction { state: &V03State, diff: &ValidatedStateDiff, ) -> Result<(), lee::error::LeeError> { - let bridge_account_id = lee::system_bridge_account_id(); + let bridge_account_id = system_accounts::bridge_account_id(); let pre = state.get_account_by_id(bridge_account_id); let Some(post) = diff.public_diff().get(&bridge_account_id).cloned() else { return Ok(()); @@ -229,7 +228,7 @@ pub enum TransactionMalformationError { #[must_use] pub fn clock_invocation(timestamp: clock_core::Instruction) -> lee::PublicTransaction { let message = lee::public_transaction::Message::try_new( - lee::program::Program::clock().id(), + programs::clock().id(), clock_core::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), vec![], timestamp, @@ -261,17 +260,14 @@ fn validate_doesnt_modify_account( #[cfg(test)] mod tests { - use lee::{ - AccountId, CLOCK_01_PROGRAM_ACCOUNT_ID, PrivateKey, PublicKey, V03State, - system_bridge_account_id, system_faucet_account_id, - }; + use lee::{AccountId, PrivateKey, PublicKey, V03State}; use crate::test_utils::create_transaction_native_token_transfer; #[test] fn system_account_ids_are_distinct_and_non_default() { - let faucet = system_faucet_account_id(); - let bridge = system_bridge_account_id(); + let faucet = system_accounts::faucet_account_id(); + let bridge = system_accounts::bridge_account_id(); assert_ne!(faucet, AccountId::default()); assert_ne!(bridge, AccountId::default()); assert_ne!(faucet, bridge); @@ -286,12 +282,12 @@ mod tests { // (an empty diff hides the modification). let sender_key = PrivateKey::try_new([5_u8; 32]).expect("valid key"); let sender_id = AccountId::from(&PublicKey::new_from_private_key(&sender_key)); - let state = V03State::new_with_genesis_accounts(&[(sender_id, 10_000)], vec![], 0); + let state = V03State::new().with_public_account_balances([(sender_id, 10_000)]); let tx = create_transaction_native_token_transfer( sender_id, 0, - CLOCK_01_PROGRAM_ACCOUNT_ID, + system_accounts::clock_account_ids()[0], 100, &sender_key, ); diff --git a/lez/programs/Cargo.toml b/lez/programs/Cargo.toml new file mode 100644 index 00000000..06038d7f --- /dev/null +++ b/lez/programs/Cargo.toml @@ -0,0 +1,101 @@ +[package] +name = "programs" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[[bin]] +name = "amm" +path = "amm/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "associated_token_account" +path = "associated_token_account/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "authenticated_transfer" +path = "authenticated_transfer/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "bridge" +path = "bridge/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "clock" +path = "clock/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "faucet" +path = "faucet/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "pinata" +path = "pinata/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "pinata_token" +path = "pinata_token/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "token" +path = "token/src/main.rs" +required-features = ["programs"] + +[[bin]] +name = "vault" +path = "vault/src/main.rs" +required-features = ["programs"] + +[features] +# TODO: Uncomment once https://github.com/risc0/risc0/issues/3772 is resolved. +# default = ["artifacts"] + +# This feature is only usable for library target. +# Activating this will cause library to include built binary artifacts and pack them into `Program` structs. +artifacts = ["dep:build_utils", "dep:lee"] + +# Import dependencies required for program binaries. +# You don't need this if you only want to use the library target. +programs = [ + "dep:lee_core", + "dep:risc0-zkvm", + "dep:amm_program", + "dep:associated_token_account_program", + "dep:token_program", + "dep:amm_core", + "dep:associated_token_account_core", + "dep:authenticated_transfer_core", + "dep:bridge_core", + "dep:clock_core", + "dep:faucet_core", + "dep:token_core", + "dep:vault_core", +] + +[dependencies] +lee = { workspace = true, optional = true } +lee_core = { workspace = true, optional = true } +risc0-zkvm = { workspace = true, optional = true } +amm_core = { workspace = true, optional = true } +associated_token_account_core = { workspace = true, optional = true } +authenticated_transfer_core = { workspace = true, optional = true } +bridge_core = { workspace = true, optional = true } +clock_core = { workspace = true, optional = true } +faucet_core = { workspace = true, optional = true } +token_core = { workspace = true, optional = true } +vault_core = { workspace = true, optional = true } + +amm_program = { path = "amm", optional = true } +associated_token_account_program = { path = "associated_token_account", optional = true } +token_program = { path = "token", optional = true } + +[build-dependencies] +build_utils = { workspace = true, optional = true } diff --git a/lez/programs/README.md b/lez/programs/README.md new file mode 100644 index 00000000..b52f6663 --- /dev/null +++ b/lez/programs/README.md @@ -0,0 +1,22 @@ +# Programs + +This crate serves two purposes at once: + +1. Provide one entrypoint for `cargo risczero build` to build guest binaries used in LEZ in one shot. +2. Provide access to the built binaries wrapped with `Program` type. + +## Binaries + +This crate contains binaries taken from sub-directories: one per each program. This binaries are meant to be compiled with `cargo risczero build`. No other use is intended for them. + +## Library + +You may import this crate as a library but it will only make sense if you enable `artifacts` feature flag. +Enabling this flag will make crate expect that [`binaries`](#binaries) where already built and put in the right place (use `just build-artifacts` for that). + +## Why not just `risc0_build::embed_methods()` ? + +Because this will either provide non-deterministic guest build or requires Docker. +And forcing to use Docker to build the project is not an option for us especially because we also build Docker images for our services, which would mean we would have to call docker from docker (and this is not really feasible). + +`risc0_build::embed_methods()` works well when you don't need deterministic build or Docker is not a problem. This is the case for our tests and we use it there. diff --git a/programs/amm/Cargo.toml b/lez/programs/amm/Cargo.toml similarity index 90% rename from programs/amm/Cargo.toml rename to lez/programs/amm/Cargo.toml index 5a4be879..171efbd9 100644 --- a/programs/amm/Cargo.toml +++ b/lez/programs/amm/Cargo.toml @@ -14,3 +14,4 @@ amm_core.workspace = true [dev-dependencies] lee = { workspace = true, features = ["test-utils"] } +programs = { workspace = true } diff --git a/programs/amm/core/Cargo.toml b/lez/programs/amm/core/Cargo.toml similarity index 100% rename from programs/amm/core/Cargo.toml rename to lez/programs/amm/core/Cargo.toml diff --git a/programs/amm/core/src/lib.rs b/lez/programs/amm/core/src/lib.rs similarity index 100% rename from programs/amm/core/src/lib.rs rename to lez/programs/amm/core/src/lib.rs diff --git a/programs/amm/src/add.rs b/lez/programs/amm/src/add.rs similarity index 100% rename from programs/amm/src/add.rs rename to lez/programs/amm/src/add.rs diff --git a/programs/amm/src/lib.rs b/lez/programs/amm/src/lib.rs similarity index 100% rename from programs/amm/src/lib.rs rename to lez/programs/amm/src/lib.rs diff --git a/program_methods/guest/src/bin/amm.rs b/lez/programs/amm/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/amm.rs rename to lez/programs/amm/src/main.rs diff --git a/programs/amm/src/new_definition.rs b/lez/programs/amm/src/new_definition.rs similarity index 100% rename from programs/amm/src/new_definition.rs rename to lez/programs/amm/src/new_definition.rs diff --git a/programs/amm/src/remove.rs b/lez/programs/amm/src/remove.rs similarity index 100% rename from programs/amm/src/remove.rs rename to lez/programs/amm/src/remove.rs diff --git a/programs/amm/src/swap.rs b/lez/programs/amm/src/swap.rs similarity index 100% rename from programs/amm/src/swap.rs rename to lez/programs/amm/src/swap.rs diff --git a/programs/amm/src/tests.rs b/lez/programs/amm/src/tests.rs similarity index 96% rename from programs/amm/src/tests.rs rename to lez/programs/amm/src/tests.rs index d93bedb2..e98c33a0 100644 --- a/programs/amm/src/tests.rs +++ b/lez/programs/amm/src/tests.rs @@ -4,9 +4,7 @@ use amm_core::{ PoolDefinition, compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_vault_pda, compute_vault_pda_seed, }; -use lee::{ - PrivateKey, PublicKey, PublicTransaction, V03State, program::Program, public_transaction, -}; +use lee::{PrivateKey, PublicKey, PublicTransaction, V03State, public_transaction}; use lee_core::{ account::{Account, AccountId, AccountWithMetadata, Data}, program::{ChainedCall, ProgramId}, @@ -1295,14 +1293,14 @@ impl BalanceForExeTests { impl IdForExeTests { fn pool_definition_id() -> AccountId { amm_core::compute_pool_pda( - Program::amm().id(), + programs::amm().id(), Self::token_a_definition_id(), Self::token_b_definition_id(), ) } fn token_lp_definition_id() -> AccountId { - amm_core::compute_liquidity_token_pda(Program::amm().id(), Self::pool_definition_id()) + amm_core::compute_liquidity_token_pda(programs::amm().id(), Self::pool_definition_id()) } fn token_a_definition_id() -> AccountId { @@ -1333,7 +1331,7 @@ impl IdForExeTests { fn vault_a_id() -> AccountId { amm_core::compute_vault_pda( - Program::amm().id(), + programs::amm().id(), Self::pool_definition_id(), Self::token_a_definition_id(), ) @@ -1341,7 +1339,7 @@ impl IdForExeTests { fn vault_b_id() -> AccountId { amm_core::compute_vault_pda( - Program::amm().id(), + programs::amm().id(), Self::pool_definition_id(), Self::token_b_definition_id(), ) @@ -1351,7 +1349,7 @@ impl IdForExeTests { impl AccountsForExeTests { fn user_token_a_holding() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1363,7 +1361,7 @@ impl AccountsForExeTests { fn user_token_b_holding() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1375,7 +1373,7 @@ impl AccountsForExeTests { fn pool_definition_init() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1395,7 +1393,7 @@ impl AccountsForExeTests { fn token_a_definition_account() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -1408,7 +1406,7 @@ impl AccountsForExeTests { fn token_b_definition_acc() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -1421,7 +1419,7 @@ impl AccountsForExeTests { fn token_lp_definition_acc() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1434,7 +1432,7 @@ impl AccountsForExeTests { fn vault_a_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1446,7 +1444,7 @@ impl AccountsForExeTests { fn vault_b_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1458,7 +1456,7 @@ impl AccountsForExeTests { fn user_token_lp_holding() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1470,7 +1468,7 @@ impl AccountsForExeTests { fn vault_a_swap_1() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1482,7 +1480,7 @@ impl AccountsForExeTests { fn vault_b_swap_1() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1494,7 +1492,7 @@ impl AccountsForExeTests { fn pool_definition_swap_1() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1514,7 +1512,7 @@ impl AccountsForExeTests { fn user_token_a_holding_swap_1() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1526,7 +1524,7 @@ impl AccountsForExeTests { fn user_token_b_holding_swap_1() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1538,7 +1536,7 @@ impl AccountsForExeTests { fn vault_a_swap_2() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1550,7 +1548,7 @@ impl AccountsForExeTests { fn vault_b_swap_2() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1562,7 +1560,7 @@ impl AccountsForExeTests { fn pool_definition_swap_2() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1582,7 +1580,7 @@ impl AccountsForExeTests { fn user_token_a_holding_swap_2() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1594,7 +1592,7 @@ impl AccountsForExeTests { fn user_token_b_holding_swap_2() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1606,7 +1604,7 @@ impl AccountsForExeTests { fn vault_a_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1618,7 +1616,7 @@ impl AccountsForExeTests { fn vault_b_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1630,7 +1628,7 @@ impl AccountsForExeTests { fn pool_definition_add() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1650,7 +1648,7 @@ impl AccountsForExeTests { fn user_token_a_holding_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1662,7 +1660,7 @@ impl AccountsForExeTests { fn user_token_b_holding_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1674,7 +1672,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1686,7 +1684,7 @@ impl AccountsForExeTests { fn token_lp_definition_add() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1699,7 +1697,7 @@ impl AccountsForExeTests { fn vault_a_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1711,7 +1709,7 @@ impl AccountsForExeTests { fn vault_b_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1723,7 +1721,7 @@ impl AccountsForExeTests { fn pool_definition_remove() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1743,7 +1741,7 @@ impl AccountsForExeTests { fn user_token_a_holding_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1755,7 +1753,7 @@ impl AccountsForExeTests { fn user_token_b_holding_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1767,7 +1765,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1779,7 +1777,7 @@ impl AccountsForExeTests { fn token_lp_definition_remove() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1792,7 +1790,7 @@ impl AccountsForExeTests { fn token_lp_definition_init_inactive() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1805,7 +1803,7 @@ impl AccountsForExeTests { fn vault_a_init_inactive() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1817,7 +1815,7 @@ impl AccountsForExeTests { fn vault_b_init_inactive() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1829,7 +1827,7 @@ impl AccountsForExeTests { fn pool_definition_inactive() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1849,7 +1847,7 @@ impl AccountsForExeTests { fn user_token_a_holding_new_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1861,7 +1859,7 @@ impl AccountsForExeTests { fn user_token_b_holding_new_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1873,7 +1871,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_new_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1885,7 +1883,7 @@ impl AccountsForExeTests { fn token_lp_definition_new_init() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1898,7 +1896,7 @@ impl AccountsForExeTests { fn pool_definition_new_init() -> Account { Account { - program_owner: Program::amm().id(), + program_owner: programs::amm().id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1918,7 +1916,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_init_zero() -> Account { Account { - program_owner: Program::token().id(), + program_owner: programs::token().id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -3035,68 +3033,73 @@ fn new_definition_lp_symmetric_amounts() { } fn state_for_amm_tests() -> V03State { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); - state.force_insert_account( - IdForExeTests::pool_definition_id(), - AccountsForExeTests::pool_definition_init(), - ); - state.force_insert_account( - IdForExeTests::token_a_definition_id(), - AccountsForExeTests::token_a_definition_account(), - ); - state.force_insert_account( - IdForExeTests::token_b_definition_id(), - AccountsForExeTests::token_b_definition_acc(), - ); - state.force_insert_account( - IdForExeTests::token_lp_definition_id(), - AccountsForExeTests::token_lp_definition_acc(), - ); - state.force_insert_account( - IdForExeTests::user_token_a_id(), - AccountsForExeTests::user_token_a_holding(), - ); - state.force_insert_account( - IdForExeTests::user_token_b_id(), - AccountsForExeTests::user_token_b_holding(), - ); - state.force_insert_account( - IdForExeTests::user_token_lp_id(), - AccountsForExeTests::user_token_lp_holding(), - ); - state.force_insert_account( - IdForExeTests::vault_a_id(), - AccountsForExeTests::vault_a_init(), - ); - state.force_insert_account( - IdForExeTests::vault_b_id(), - AccountsForExeTests::vault_b_init(), - ); + let public_state = [ + ( + IdForExeTests::pool_definition_id(), + AccountsForExeTests::pool_definition_init(), + ), + ( + IdForExeTests::token_a_definition_id(), + AccountsForExeTests::token_a_definition_account(), + ), + ( + IdForExeTests::token_b_definition_id(), + AccountsForExeTests::token_b_definition_acc(), + ), + ( + IdForExeTests::token_lp_definition_id(), + AccountsForExeTests::token_lp_definition_acc(), + ), + ( + IdForExeTests::user_token_a_id(), + AccountsForExeTests::user_token_a_holding(), + ), + ( + IdForExeTests::user_token_b_id(), + AccountsForExeTests::user_token_b_holding(), + ), + ( + IdForExeTests::user_token_lp_id(), + AccountsForExeTests::user_token_lp_holding(), + ), + ( + IdForExeTests::vault_a_id(), + AccountsForExeTests::vault_a_init(), + ), + ( + IdForExeTests::vault_b_id(), + AccountsForExeTests::vault_b_init(), + ), + ]; - state + V03State::new() + .with_public_accounts(public_state) + .with_programs([programs::amm(), programs::token()]) } fn state_for_amm_tests_with_new_def() -> V03State { - let initial_data = []; - let mut state = V03State::new_with_genesis_accounts(&initial_data, vec![], 0); - state.force_insert_account( - IdForExeTests::token_a_definition_id(), - AccountsForExeTests::token_a_definition_account(), - ); - state.force_insert_account( - IdForExeTests::token_b_definition_id(), - AccountsForExeTests::token_b_definition_acc(), - ); - state.force_insert_account( - IdForExeTests::user_token_a_id(), - AccountsForExeTests::user_token_a_holding(), - ); - state.force_insert_account( - IdForExeTests::user_token_b_id(), - AccountsForExeTests::user_token_b_holding(), - ); - state + let public_state = [ + ( + IdForExeTests::token_a_definition_id(), + AccountsForExeTests::token_a_definition_account(), + ), + ( + IdForExeTests::token_b_definition_id(), + AccountsForExeTests::token_b_definition_acc(), + ), + ( + IdForExeTests::user_token_a_id(), + AccountsForExeTests::user_token_a_holding(), + ), + ( + IdForExeTests::user_token_b_id(), + AccountsForExeTests::user_token_b_holding(), + ), + ]; + + V03State::new() + .with_public_accounts(public_state) + .with_programs([programs::amm(), programs::token()]) } #[test] @@ -3110,7 +3113,7 @@ fn simple_amm_remove() { }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3183,11 +3186,11 @@ fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { let instruction = amm_core::Instruction::NewDefinition { token_a_amount: BalanceForExeTests::vault_a_balance_init(), token_b_amount: BalanceForExeTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), + amm_program_id: programs::amm().id(), }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3268,11 +3271,11 @@ fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { let instruction = amm_core::Instruction::NewDefinition { token_a_amount: BalanceForExeTests::vault_a_balance_init(), token_b_amount: BalanceForExeTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), + amm_program_id: programs::amm().id(), }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3340,11 +3343,11 @@ fn simple_amm_new_definition_uninitialized_pool() { let instruction = amm_core::Instruction::NewDefinition { token_a_amount: BalanceForExeTests::vault_a_balance_init(), token_b_amount: BalanceForExeTests::vault_b_balance_init(), - amm_program_id: Program::amm().id(), + amm_program_id: programs::amm().id(), }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3407,7 +3410,7 @@ fn simple_amm_add() { }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3469,7 +3472,7 @@ fn simple_amm_swap_1() { }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3519,7 +3522,7 @@ fn simple_amm_swap_2() { token_definition_id_in: IdForExeTests::token_a_definition_id(), }; let message = public_transaction::Message::try_new( - Program::amm().id(), + programs::amm().id(), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), diff --git a/lez/programs/associated_token_account/Cargo.toml b/lez/programs/associated_token_account/Cargo.toml new file mode 100644 index 00000000..494b179f --- /dev/null +++ b/lez/programs/associated_token_account/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "associated_token_account_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +lee_core.workspace = true +token_core.workspace = true +associated_token_account_core.workspace = true diff --git a/programs/associated_token_account/core/Cargo.toml b/lez/programs/associated_token_account/core/Cargo.toml similarity index 81% rename from programs/associated_token_account/core/Cargo.toml rename to lez/programs/associated_token_account/core/Cargo.toml index 9c80e897..9b2ff668 100644 --- a/programs/associated_token_account/core/Cargo.toml +++ b/lez/programs/associated_token_account/core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ata_core" +name = "associated_token_account_core" version = "0.1.0" edition = "2024" license = { workspace = true } diff --git a/programs/associated_token_account/core/src/lib.rs b/lez/programs/associated_token_account/core/src/lib.rs similarity index 100% rename from programs/associated_token_account/core/src/lib.rs rename to lez/programs/associated_token_account/core/src/lib.rs diff --git a/programs/associated_token_account/src/burn.rs b/lez/programs/associated_token_account/src/burn.rs similarity index 88% rename from programs/associated_token_account/src/burn.rs rename to lez/programs/associated_token_account/src/burn.rs index 2aae0dd2..09d1645a 100644 --- a/programs/associated_token_account/src/burn.rs +++ b/lez/programs/associated_token_account/src/burn.rs @@ -16,8 +16,12 @@ pub fn burn_from_associated_token_account( let definition_id = TokenHolding::try_from(&holder_ata.account.data) .expect("Holder ATA must hold a valid token") .definition_id(); - let seed = - ata_core::verify_ata_and_get_seed(&holder_ata, &owner, definition_id, ata_program_id); + let seed = associated_token_account_core::verify_ata_and_get_seed( + &holder_ata, + &owner, + definition_id, + ata_program_id, + ); let post_states = vec![ AccountPostState::new(owner.account.clone()), diff --git a/programs/associated_token_account/src/create.rs b/lez/programs/associated_token_account/src/create.rs similarity index 95% rename from programs/associated_token_account/src/create.rs rename to lez/programs/associated_token_account/src/create.rs index c910ab5b..4e1b2074 100644 --- a/programs/associated_token_account/src/create.rs +++ b/lez/programs/associated_token_account/src/create.rs @@ -11,7 +11,7 @@ pub fn create_associated_token_account( ) -> (Vec, Vec) { // No authorization check needed: create is idempotent, so anyone can call it safely. let token_program_id = token_definition.account.program_owner; - let ata_seed = ata_core::verify_ata_and_get_seed( + let ata_seed = associated_token_account_core::verify_ata_and_get_seed( &ata_account, &owner, token_definition.account_id, diff --git a/programs/associated_token_account/src/lib.rs b/lez/programs/associated_token_account/src/lib.rs similarity index 73% rename from programs/associated_token_account/src/lib.rs rename to lez/programs/associated_token_account/src/lib.rs index 13740f0a..fc11902f 100644 --- a/programs/associated_token_account/src/lib.rs +++ b/lez/programs/associated_token_account/src/lib.rs @@ -1,6 +1,6 @@ //! The Associated Token Account Program implementation. -pub use ata_core as core; +pub use associated_token_account_core as core; pub mod burn; pub mod create; diff --git a/program_methods/guest/src/bin/associated_token_account.rs b/lez/programs/associated_token_account/src/main.rs similarity index 85% rename from program_methods/guest/src/bin/associated_token_account.rs rename to lez/programs/associated_token_account/src/main.rs index a32bbf9b..2eaa2f3c 100644 --- a/program_methods/guest/src/bin/associated_token_account.rs +++ b/lez/programs/associated_token_account/src/main.rs @@ -1,4 +1,4 @@ -use ata_core::Instruction; +use associated_token_account_core::Instruction; use lee_core::program::{ProgramInput, ProgramOutput, read_lee_inputs}; fn main() { @@ -19,7 +19,7 @@ fn main() { let [owner, token_definition, ata_account] = pre_states .try_into() .expect("Create instruction requires exactly three accounts"); - ata_program::create::create_associated_token_account( + associated_token_account_program::create::create_associated_token_account( owner, token_definition, ata_account, @@ -33,7 +33,7 @@ fn main() { let [owner, sender_ata, recipient] = pre_states .try_into() .expect("Transfer instruction requires exactly three accounts"); - ata_program::transfer::transfer_from_associated_token_account( + associated_token_account_program::transfer::transfer_from_associated_token_account( owner, sender_ata, recipient, @@ -48,7 +48,7 @@ fn main() { let [owner, holder_ata, token_definition] = pre_states .try_into() .expect("Burn instruction requires exactly three accounts"); - ata_program::burn::burn_from_associated_token_account( + associated_token_account_program::burn::burn_from_associated_token_account( owner, holder_ata, token_definition, diff --git a/programs/associated_token_account/src/tests.rs b/lez/programs/associated_token_account/src/tests.rs similarity index 97% rename from programs/associated_token_account/src/tests.rs rename to lez/programs/associated_token_account/src/tests.rs index 7717eae1..f244f6cd 100644 --- a/programs/associated_token_account/src/tests.rs +++ b/lez/programs/associated_token_account/src/tests.rs @@ -1,6 +1,6 @@ #![cfg(test)] -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 lee_core::account::{Account, AccountId, AccountWithMetadata, Data}; use token_core::{TokenDefinition, TokenHolding}; diff --git a/programs/associated_token_account/src/transfer.rs b/lez/programs/associated_token_account/src/transfer.rs similarity index 88% rename from programs/associated_token_account/src/transfer.rs rename to lez/programs/associated_token_account/src/transfer.rs index cd76292f..dbe38803 100644 --- a/programs/associated_token_account/src/transfer.rs +++ b/lez/programs/associated_token_account/src/transfer.rs @@ -16,8 +16,12 @@ pub fn transfer_from_associated_token_account( let definition_id = TokenHolding::try_from(&sender_ata.account.data) .expect("Sender ATA must hold a valid token") .definition_id(); - let seed = - ata_core::verify_ata_and_get_seed(&sender_ata, &owner, definition_id, ata_program_id); + let seed = associated_token_account_core::verify_ata_and_get_seed( + &sender_ata, + &owner, + definition_id, + ata_program_id, + ); let post_states = vec![ AccountPostState::new(owner.account.clone()), diff --git a/lez/programs/authenticated_transfer/Cargo.toml b/lez/programs/authenticated_transfer/Cargo.toml new file mode 100644 index 00000000..d586acdc --- /dev/null +++ b/lez/programs/authenticated_transfer/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "authenticated_transfer_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +authenticated_transfer_core.workspace = true +lee_core.workspace = true diff --git a/programs/authenticated_transfer/core/Cargo.toml b/lez/programs/authenticated_transfer/core/Cargo.toml similarity index 100% rename from programs/authenticated_transfer/core/Cargo.toml rename to lez/programs/authenticated_transfer/core/Cargo.toml diff --git a/programs/authenticated_transfer/core/src/lib.rs b/lez/programs/authenticated_transfer/core/src/lib.rs similarity index 100% rename from programs/authenticated_transfer/core/src/lib.rs rename to lez/programs/authenticated_transfer/core/src/lib.rs diff --git a/program_methods/guest/src/bin/authenticated_transfer.rs b/lez/programs/authenticated_transfer/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/authenticated_transfer.rs rename to lez/programs/authenticated_transfer/src/main.rs diff --git a/lez/programs/bridge/Cargo.toml b/lez/programs/bridge/Cargo.toml new file mode 100644 index 00000000..d7762f1f --- /dev/null +++ b/lez/programs/bridge/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bridge_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +bridge_core.workspace = true +vault_core.workspace = true +authenticated_transfer_core.workspace = true +lee_core.workspace = true diff --git a/programs/bridge/core/Cargo.toml b/lez/programs/bridge/core/Cargo.toml similarity index 100% rename from programs/bridge/core/Cargo.toml rename to lez/programs/bridge/core/Cargo.toml diff --git a/programs/bridge/core/src/lib.rs b/lez/programs/bridge/core/src/lib.rs similarity index 100% rename from programs/bridge/core/src/lib.rs rename to lez/programs/bridge/core/src/lib.rs diff --git a/program_methods/guest/src/bin/bridge.rs b/lez/programs/bridge/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/bridge.rs rename to lez/programs/bridge/src/main.rs diff --git a/lez/programs/build.rs b/lez/programs/build.rs new file mode 100644 index 00000000..b26b3bda --- /dev/null +++ b/lez/programs/build.rs @@ -0,0 +1,6 @@ +fn main() -> Result<(), Box> { + #[cfg(feature = "artifacts")] + build_utils::include_artifacts("lez/programs")?; + + Ok(()) +} diff --git a/lez/programs/clock/Cargo.toml b/lez/programs/clock/Cargo.toml new file mode 100644 index 00000000..0c51a69d --- /dev/null +++ b/lez/programs/clock/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "clock_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +clock_core.workspace = true +lee_core.workspace = true diff --git a/programs/clock/core/Cargo.toml b/lez/programs/clock/core/Cargo.toml similarity index 100% rename from programs/clock/core/Cargo.toml rename to lez/programs/clock/core/Cargo.toml diff --git a/programs/clock/core/src/lib.rs b/lez/programs/clock/core/src/lib.rs similarity index 100% rename from programs/clock/core/src/lib.rs rename to lez/programs/clock/core/src/lib.rs diff --git a/program_methods/guest/src/bin/clock.rs b/lez/programs/clock/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/clock.rs rename to lez/programs/clock/src/main.rs diff --git a/lez/programs/faucet/Cargo.toml b/lez/programs/faucet/Cargo.toml new file mode 100644 index 00000000..c1f4f426 --- /dev/null +++ b/lez/programs/faucet/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "faucet_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +lee_core.workspace = true +faucet_core.workspace = true +vault_core.workspace = true +authenticated_transfer_core.workspace = true diff --git a/programs/faucet/core/Cargo.toml b/lez/programs/faucet/core/Cargo.toml similarity index 100% rename from programs/faucet/core/Cargo.toml rename to lez/programs/faucet/core/Cargo.toml diff --git a/programs/faucet/core/src/lib.rs b/lez/programs/faucet/core/src/lib.rs similarity index 100% rename from programs/faucet/core/src/lib.rs rename to lez/programs/faucet/core/src/lib.rs diff --git a/program_methods/guest/src/bin/faucet.rs b/lez/programs/faucet/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/faucet.rs rename to lez/programs/faucet/src/main.rs diff --git a/lez/programs/pinata/Cargo.toml b/lez/programs/pinata/Cargo.toml new file mode 100644 index 00000000..7a6ad121 --- /dev/null +++ b/lez/programs/pinata/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "pinata_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +lee_core.workspace = true + +risc0-zkvm.workspace = true diff --git a/program_methods/guest/src/bin/pinata.rs b/lez/programs/pinata/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/pinata.rs rename to lez/programs/pinata/src/main.rs diff --git a/programs/associated_token_account/Cargo.toml b/lez/programs/pinata_token/Cargo.toml similarity index 63% rename from programs/associated_token_account/Cargo.toml rename to lez/programs/pinata_token/Cargo.toml index b6be7155..476409ec 100644 --- a/programs/associated_token_account/Cargo.toml +++ b/lez/programs/pinata_token/Cargo.toml @@ -1,10 +1,14 @@ [package] -name = "ata_program" +name = "pinata_token_program" version = "0.1.0" edition = "2024" license = { workspace = true } +[lints] +workspace = true + [dependencies] lee_core.workspace = true token_core.workspace = true -ata_core.workspace = true + +risc0-zkvm.workspace = true diff --git a/program_methods/guest/src/bin/pinata_token.rs b/lez/programs/pinata_token/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/pinata_token.rs rename to lez/programs/pinata_token/src/main.rs diff --git a/lez/programs/src/lib.rs b/lez/programs/src/lib.rs new file mode 100644 index 00000000..4acade0f --- /dev/null +++ b/lez/programs/src/lib.rs @@ -0,0 +1,137 @@ +//! This crate provides [`Program`]s and associated utilities used by LEZ. + +#[cfg(feature = "artifacts")] +pub use inner::*; + +#[cfg(feature = "artifacts")] +mod inner { + + use std::borrow::Cow; + + use guests::{ + 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, + }; + use lee::program::Program; + + mod guests { + include!(concat!(env!("OUT_DIR"), "/lez/programs/mod.rs")); + } + + #[must_use] + #[inline] + pub const fn authenticated_transfer() -> Program { + Program::new_unchecked( + AUTHENTICATED_TRANSFER_ID, + Cow::Borrowed(AUTHENTICATED_TRANSFER_ELF), + ) + } + + #[must_use] + #[inline] + pub const fn token() -> Program { + Program::new_unchecked(TOKEN_ID, Cow::Borrowed(TOKEN_ELF)) + } + + #[must_use] + #[inline] + pub const fn pinata() -> Program { + Program::new_unchecked(PINATA_ID, Cow::Borrowed(PINATA_ELF)) + } + + // TODO: Not used anywhere? + #[must_use] + #[inline] + pub const fn pinata_token() -> Program { + Program::new_unchecked(PINATA_TOKEN_ID, Cow::Borrowed(PINATA_TOKEN_ELF)) + } + + #[must_use] + #[inline] + pub const fn amm() -> Program { + Program::new_unchecked(AMM_ID, Cow::Borrowed(AMM_ELF)) + } + + #[must_use] + #[inline] + pub const fn clock() -> Program { + Program::new_unchecked(CLOCK_ID, Cow::Borrowed(CLOCK_ELF)) + } + + #[must_use] + #[inline] + pub const fn ata() -> Program { + Program::new_unchecked( + ASSOCIATED_TOKEN_ACCOUNT_ID, + Cow::Borrowed(ASSOCIATED_TOKEN_ACCOUNT_ELF), + ) + } + + #[must_use] + #[inline] + pub const fn vault() -> Program { + Program::new_unchecked(VAULT_ID, Cow::Borrowed(VAULT_ELF)) + } + + #[must_use] + #[inline] + pub const fn faucet() -> Program { + Program::new_unchecked(FAUCET_ID, Cow::Borrowed(FAUCET_ELF)) + } + + #[must_use] + #[inline] + pub const fn bridge() -> Program { + Program::new_unchecked(BRIDGE_ID, Cow::Borrowed(BRIDGE_ELF)) + } + + #[cfg(test)] + mod tests { + use super::*; + + #[test] + fn builtin_programs() { + let auth_transfer_program = authenticated_transfer(); + let token_program = token(); + let vault_program = vault(); + let faucet_program = faucet(); + let bridge_program = bridge(); + let pinata_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).into()).unwrap(); + assert_eq!(program.id(), *expected_id); + } + } + } +} diff --git a/programs/token/Cargo.toml b/lez/programs/token/Cargo.toml similarity index 100% rename from programs/token/Cargo.toml rename to lez/programs/token/Cargo.toml diff --git a/programs/token/core/Cargo.toml b/lez/programs/token/core/Cargo.toml similarity index 100% rename from programs/token/core/Cargo.toml rename to lez/programs/token/core/Cargo.toml diff --git a/programs/token/core/src/lib.rs b/lez/programs/token/core/src/lib.rs similarity index 100% rename from programs/token/core/src/lib.rs rename to lez/programs/token/core/src/lib.rs diff --git a/programs/token/src/burn.rs b/lez/programs/token/src/burn.rs similarity index 100% rename from programs/token/src/burn.rs rename to lez/programs/token/src/burn.rs diff --git a/programs/token/src/initialize.rs b/lez/programs/token/src/initialize.rs similarity index 100% rename from programs/token/src/initialize.rs rename to lez/programs/token/src/initialize.rs diff --git a/programs/token/src/lib.rs b/lez/programs/token/src/lib.rs similarity index 100% rename from programs/token/src/lib.rs rename to lez/programs/token/src/lib.rs diff --git a/program_methods/guest/src/bin/token.rs b/lez/programs/token/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/token.rs rename to lez/programs/token/src/main.rs diff --git a/programs/token/src/mint.rs b/lez/programs/token/src/mint.rs similarity index 100% rename from programs/token/src/mint.rs rename to lez/programs/token/src/mint.rs diff --git a/programs/token/src/new_definition.rs b/lez/programs/token/src/new_definition.rs similarity index 100% rename from programs/token/src/new_definition.rs rename to lez/programs/token/src/new_definition.rs diff --git a/programs/token/src/print_nft.rs b/lez/programs/token/src/print_nft.rs similarity index 100% rename from programs/token/src/print_nft.rs rename to lez/programs/token/src/print_nft.rs diff --git a/programs/token/src/tests.rs b/lez/programs/token/src/tests.rs similarity index 100% rename from programs/token/src/tests.rs rename to lez/programs/token/src/tests.rs diff --git a/programs/token/src/transfer.rs b/lez/programs/token/src/transfer.rs similarity index 100% rename from programs/token/src/transfer.rs rename to lez/programs/token/src/transfer.rs diff --git a/lez/programs/vault/Cargo.toml b/lez/programs/vault/Cargo.toml new file mode 100644 index 00000000..4faed055 --- /dev/null +++ b/lez/programs/vault/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "vault_program" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[dependencies] +lee_core.workspace = true +vault_core.workspace = true +authenticated_transfer_core.workspace = true diff --git a/programs/vault/core/Cargo.toml b/lez/programs/vault/core/Cargo.toml similarity index 100% rename from programs/vault/core/Cargo.toml rename to lez/programs/vault/core/Cargo.toml diff --git a/programs/vault/core/src/lib.rs b/lez/programs/vault/core/src/lib.rs similarity index 100% rename from programs/vault/core/src/lib.rs rename to lez/programs/vault/core/src/lib.rs diff --git a/program_methods/guest/src/bin/vault.rs b/lez/programs/vault/src/main.rs similarity index 100% rename from program_methods/guest/src/bin/vault.rs rename to lez/programs/vault/src/main.rs diff --git a/lez/sequencer/core/Cargo.toml b/lez/sequencer/core/Cargo.toml index 9201d8b3..2931c833 100644 --- a/lez/sequencer/core/Cargo.toml +++ b/lez/sequencer/core/Cargo.toml @@ -18,6 +18,8 @@ testnet_initial_state.workspace = true faucet_core.workspace = true bridge_core.workspace = true vault_core.workspace = true +programs.workspace = true +system_accounts.workspace = true logos-blockchain-key-management-system-service.workspace = true logos-blockchain-core.workspace = true @@ -46,6 +48,7 @@ mock = [] [dev-dependencies] futures.workspace = true -test_program_methods.workspace = true +test_programs.workspace = true lee = { workspace = true, features = ["test-utils"] } key_protocol.workspace = true +token_core.workspace = true diff --git a/lez/sequencer/core/src/block_store.rs b/lez/sequencer/core/src/block_store.rs index 4e5489ff..0db05d74 100644 --- a/lez/sequencer/core/src/block_store.rs +++ b/lez/sequencer/core/src/block_store.rs @@ -219,7 +219,7 @@ mod tests { let retrieved_tx = node_store.get_transaction_by_hash(tx.hash()); assert_eq!(None, retrieved_tx); // Add the block with the transaction - let dummy_state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let dummy_state = V03State::new(); node_store .update(&block, &[], vec![], &dummy_state) .unwrap(); @@ -286,7 +286,7 @@ mod tests { let block = common::test_utils::produce_dummy_block(1, None, vec![tx]); let block_hash = block.header.hash; - let dummy_state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let dummy_state = V03State::new(); node_store .update(&block, &[], vec![], &dummy_state) .unwrap(); @@ -324,7 +324,7 @@ mod tests { let block = common::test_utils::produce_dummy_block(1, None, vec![tx]); let block_id = block.header.block_id; - let dummy_state = V03State::new_with_genesis_accounts(&[], vec![], 0); + let dummy_state = V03State::new(); node_store .update(&block, &[], vec![], &dummy_state) .unwrap(); @@ -376,12 +376,7 @@ mod tests { // Add a new block let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()]); node_store - .update( - &block, - &[], - vec![], - &V03State::new_with_genesis_accounts(&[], vec![], 0), - ) + .update(&block, &[], vec![], &V03State::new()) .unwrap(); } diff --git a/lez/sequencer/core/src/lib.rs b/lez/sequencer/core/src/lib.rs index 651951d2..b140fda8 100644 --- a/lez/sequencer/core/src/lib.rs +++ b/lez/sequencer/core/src/lib.rs @@ -8,7 +8,7 @@ use common::{ transaction::{LeeTransaction, clock_invocation}, }; use config::{GenesisAction, SequencerConfig}; -use lee::{AccountId, PublicTransaction, program::Program, public_transaction::Message}; +use lee::{AccountId, PublicTransaction, public_transaction::Message}; use lee_core::GENESIS_BLOCK_ID; use log::{error, info, warn}; use logos_blockchain_key_management_system_service::keys::{ED25519_SECRET_KEY_SIZE, Ed25519Key}; @@ -616,13 +616,13 @@ fn build_supply_account_genesis_transaction( account_id: &AccountId, balance: u128, ) -> PublicTransaction { - let faucet_program_id = Program::faucet().id(); - let vault_program_id = Program::vault().id(); + let faucet_program_id = programs::faucet().id(); + let vault_program_id = programs::vault().id(); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, *account_id); let message = Message::try_new( faucet_program_id, - vec![lee::system_faucet_account_id(), recipient_vault_id], + vec![system_accounts::faucet_account_id(), recipient_vault_id], vec![], faucet_core::Instruction::GenesisTransferVault { vault_program_id, @@ -637,12 +637,12 @@ fn build_supply_account_genesis_transaction( } fn build_supply_bridge_account_genesis_transaction(balance: u128) -> PublicTransaction { - let faucet_program_id = Program::faucet().id(); - let bridge_account_id = lee::system_bridge_account_id(); + let faucet_program_id = programs::faucet().id(); + let bridge_account_id = system_accounts::bridge_account_id(); let message = Message::try_new( faucet_program_id, - vec![lee::system_faucet_account_id(), bridge_account_id], + vec![system_accounts::faucet_account_id(), bridge_account_id], vec![], faucet_core::Instruction::GenesisTransferDirect { amount: balance }, ) @@ -666,14 +666,14 @@ fn build_bridge_deposit_tx_from_event(event: &PendingDepositEventRecord) -> Resu let metadata = DepositMetadata::decode(&event.metadata) .context("Failed to decode finalized Bedrock deposit metadata")?; - let bridge_program_id = Program::bridge().id(); - let vault_program_id = Program::vault().id(); + let bridge_program_id = programs::bridge().id(); + let vault_program_id = programs::vault().id(); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, metadata.recipient_id); let message = Message::try_new( bridge_program_id, - vec![lee::system_bridge_account_id(), recipient_vault_id], + vec![system_accounts::bridge_account_id(), recipient_vault_id], vec![], bridge_core::Instruction::Deposit { l1_deposit_op_id: event.deposit_op_id.0, @@ -698,7 +698,7 @@ fn extract_bridge_deposit_id(tx: &LeeTransaction) -> Option { }; let message = tx.message(); - if message.program_id != lee::program::Program::bridge().id() { + if message.program_id != programs::bridge().id() { return None; } @@ -721,7 +721,7 @@ fn extract_bridge_withdraw_data(tx: &LeeTransaction) -> Option { }; let message = tx.message(); - if message.program_id != lee::program::Program::bridge().id() { + if message.program_id != programs::bridge().id() { return None; } @@ -819,23 +819,23 @@ mod tests { }; use key_protocol::key_management::KeyChain; use lee::{ - Account, AccountId, Data, EphemeralPublicKey, PrivacyPreservingTransaction, - SharedSecretKey, V03State, + Account, AccountId, Data, EphemeralPublicKey, PrivacyPreservingTransaction, PrivateKey, + PublicKey, PublicTransaction, SharedSecretKey, V03State, error::LeeError, execute_and_prove, privacy_preserving_transaction::{Message, circuit::ProgramWithDependencies}, program::Program, - system_bridge_account_id, }; use lee_core::{ Commitment, EncryptedAccountData, InputAccountIdentity, Nullifier, account::{AccountWithMetadata, Nonce}, + program::PdaSeed, }; use logos_blockchain_core::mantle::ops::channel::ChannelId; use mempool::MemPoolHandle; use storage::sequencer::sequencer_cells::PendingDepositEventRecord; use tempfile::tempdir; - use testnet_initial_state::{initial_accounts, initial_pub_accounts_private_keys}; + use testnet_initial_state::{initial_pub_accounts_private_keys, initial_public_user_accounts}; use crate::{ TransactionOrigin, @@ -916,7 +916,7 @@ mod tests { return false; }; - if public_tx.message.program_id != lee::program::Program::bridge().id() { + if public_tx.message.program_id != programs::bridge().id() { return false; } @@ -945,8 +945,8 @@ mod tests { assert_eq!(sequencer.chain_height, 1); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); - let acc1_account_id = initial_accounts()[0].account_id; - let acc2_account_id = initial_accounts()[1].account_id; + let acc1_account_id = initial_public_user_accounts()[0].account_id; + let acc2_account_id = initial_public_user_accounts()[1].account_id; let balance_acc_1 = sequencer.state.get_account_by_id(acc1_account_id).balance; let balance_acc_2 = sequencer.state.get_account_by_id(acc2_account_id).balance; @@ -1007,7 +1007,7 @@ mod tests { let config = setup_sequencer_config(); let deposit_op_id = [13_u8; 32]; let expected_amount = 1_u64; - let recipient_id = initial_accounts()[0].account_id; + let recipient_id = initial_public_user_accounts()[0].account_id; { let (_sequencer, _mempool_handle) = @@ -1077,8 +1077,8 @@ mod tests { async fn transaction_pre_check_native_transfer_valid() { let (_sequencer, _mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key1 = create_signing_key_for_account1(); @@ -1094,8 +1094,8 @@ mod tests { async fn transaction_pre_check_native_transfer_other_signature() { let (mut sequencer, _mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key2 = create_signing_key_for_account2(); @@ -1119,8 +1119,8 @@ mod tests { async fn transaction_pre_check_native_transfer_sent_too_much() { let (mut sequencer, _mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key1 = create_signing_key_for_account1(); @@ -1148,8 +1148,8 @@ mod tests { async fn transaction_execute_native_transfer() { let (mut sequencer, _mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key1 = create_signing_key_for_account1(); @@ -1215,8 +1215,8 @@ mod tests { async fn replay_transactions_are_rejected_in_the_same_block() { let (mut sequencer, mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key1 = create_signing_key_for_account1(); @@ -1258,8 +1258,8 @@ mod tests { async fn replay_transactions_are_rejected_in_different_blocks() { let (mut sequencer, mempool_handle) = common_setup().await; - let acc1 = initial_accounts()[0].account_id; - let acc2 = initial_accounts()[1].account_id; + let acc1 = initial_public_user_accounts()[0].account_id; + let acc2 = initial_public_user_accounts()[1].account_id; let sign_key1 = create_signing_key_for_account1(); @@ -1309,8 +1309,8 @@ mod tests { #[tokio::test] async fn restart_from_storage() { let config = setup_sequencer_config(); - let acc1_account_id = initial_accounts()[0].account_id; - let acc2_account_id = initial_accounts()[1].account_id; + let acc1_account_id = initial_public_user_accounts()[0].account_id; + let acc2_account_id = initial_public_user_accounts()[1].account_id; let balance_to_move = 13; // In the following code block a transaction will be processed that moves `balance_to_move` @@ -1358,11 +1358,11 @@ mod tests { // Balances should be consistent with the stored block assert_eq!( balance_acc_1, - initial_accounts()[0].balance - balance_to_move + initial_public_user_accounts()[0].balance - balance_to_move ); assert_eq!( balance_acc_2, - initial_accounts()[1].balance + balance_to_move + initial_public_user_accounts()[1].balance + balance_to_move ); } @@ -1397,8 +1397,8 @@ mod tests { #[tokio::test] async fn produce_block_with_correct_prev_meta_after_restart() { let config = setup_sequencer_config(); - let acc1_account_id = initial_accounts()[0].account_id; - let acc2_account_id = initial_accounts()[1].account_id; + let acc1_account_id = initial_public_user_accounts()[0].account_id; + let acc2_account_id = initial_public_user_accounts()[1].account_id; // Step 1: Create initial database with some block metadata let expected_prev_meta = { @@ -1477,8 +1477,8 @@ mod tests { // be dropped because their diffs touch the clock accounts. let crafted_clock_tx = { let message = lee::public_transaction::Message::try_new( - lee::program::Program::clock().id(), - lee::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), + programs::clock().id(), + system_accounts::clock_account_ids().to_vec(), vec![], 42_u64, ) @@ -1520,11 +1520,10 @@ mod tests { async fn user_tx_that_chain_calls_clock_is_dropped() { let (mut sequencer, mempool_handle) = common_setup().await; + let clock_chain_caller = test_programs::clock_chain_caller(); // Deploy the clock_chain_caller test program. let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( - lee::program_deployment_transaction::Message::new( - test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec(), - ), + lee::program_deployment_transaction::Message::new(clock_chain_caller.elf().to_owned()), )); mempool_handle .push((TransactionOrigin::User, deploy_tx)) @@ -1535,16 +1534,13 @@ mod tests { // Build a user transaction that invokes clock_chain_caller, which in turn chain-calls the // clock program with the clock accounts. The sequencer should detect that the resulting // state diff modifies clock accounts and drop the transaction. - let clock_chain_caller_id = - lee::program::Program::new(test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec()) - .unwrap() - .id(); - let clock_program_id = lee::program::Program::clock().id(); + let clock_chain_caller_id = test_programs::clock_chain_caller().id(); + let clock_program_id = programs::clock().id(); let timestamp: u64 = 0; let message = lee::public_transaction::Message::try_new( clock_chain_caller_id, - lee::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), + system_accounts::clock_account_ids().to_vec(), vec![], // no signers (clock_program_id, timestamp), ) @@ -1580,7 +1576,7 @@ mod tests { let (mut sequencer, mempool_handle) = common_setup().await; // Corrupt the clock 01 account data so the clock program panics on deserialization. - let clock_account_id = lee::CLOCK_01_PROGRAM_ACCOUNT_ID; + let clock_account_id = system_accounts::clock_account_ids()[0]; let mut corrupted = sequencer.state.get_account_by_id(clock_account_id); corrupted.data = vec![0xff; 3].try_into().unwrap(); sequencer @@ -1608,23 +1604,21 @@ mod tests { let sender_account_id = AccountId::for_regular_private_account(&sender_keys.nullifier_public_key, 0); let sender_private_account = Account { - program_owner: Program::authenticated_transfer_program().id(), + program_owner: programs::authenticated_transfer().id(), balance: 100, nonce: Nonce(0xdead_beef), data: Data::default(), }; + let bridge_account_id = system_accounts::bridge_account_id(); - let mut state = V03State::new_with_genesis_accounts( - &[], - vec![( + let mut state = V03State::new() + .with_public_accounts([(bridge_account_id, system_accounts::bridge_account())]) + .with_private_accounts([( Commitment::new(&sender_account_id, &sender_private_account), Nullifier::for_account_initialization(&sender_account_id), - )], - 0, - ); + )]); let sender_commitment = Commitment::new(&sender_account_id, &sender_private_account); - let bridge_account_id = system_bridge_account_id(); let sender_pre = AccountWithMetadata::new( sender_private_account, @@ -1646,10 +1640,10 @@ mod tests { .unwrap(); let program_with_deps = ProgramWithDependencies::new( - Program::bridge(), + programs::bridge(), [( - Program::authenticated_transfer_program().id(), - Program::authenticated_transfer_program(), + programs::authenticated_transfer().id(), + programs::authenticated_transfer(), )] .into(), ); @@ -1692,4 +1686,368 @@ mod tests { "Bridge withdraw invocation should be rejected in private execution" ); } + + /// Builds a [`V03State`] with the clock program and `program` registered, the three clock + /// accounts initialized, and the clock advanced to `clock_timestamp` so that reads of the + /// `CLOCK_01` account observe it. + fn state_with_clock_and_program(program: Program, clock_timestamp: u64) -> V03State { + let mut state = V03State::new().with_programs([programs::clock(), program]); + for clock_id in system_accounts::clock_account_ids() { + state.force_insert_account(clock_id, system_accounts::clock_account()); + } + state + .transition_from_public_transaction( + &clock_invocation(clock_timestamp), + 1, + clock_timestamp, + ) + .expect("Clock invocation should advance the clock"); + state + } + + fn time_locked_transfer_transaction( + from: AccountId, + from_key: &PrivateKey, + from_nonce: u128, + to: AccountId, + clock_account_id: AccountId, + amount: u128, + deadline: u64, + ) -> PublicTransaction { + let program_id = test_programs::time_locked_transfer().id(); + let message = lee::public_transaction::Message::try_new( + program_id, + vec![from, to, clock_account_id], + vec![Nonce(from_nonce)], + (amount, deadline), + ) + .unwrap(); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[from_key]); + PublicTransaction::new(message, witness_set) + } + + #[test] + fn time_locked_transfer_succeeds_when_deadline_has_passed() { + let clock_timestamp = 600; + let mut state = + state_with_clock_and_program(test_programs::time_locked_transfer(), clock_timestamp); + + // The recipient must be a non-default account so the program may credit it without + // claiming it. + let recipient_id = AccountId::new([42; 32]); + state.force_insert_account( + recipient_id, + Account { + program_owner: programs::authenticated_transfer().id(), + ..Account::default() + }, + ); + + let key1 = PrivateKey::try_new([1; 32]).unwrap(); + let sender_id = AccountId::from(&PublicKey::new_from_private_key(&key1)); + state.force_insert_account( + sender_id, + Account { + program_owner: test_programs::time_locked_transfer().id(), + balance: 100, + ..Account::default() + }, + ); + + let amount = 100; + // Deadline is in the past relative to the clock, so the transfer is unlocked. + let deadline = 0; + + let tx = time_locked_transfer_transaction( + sender_id, + &key1, + 0, + recipient_id, + system_accounts::clock_account_ids()[0], + amount, + deadline, + ); + + state + .transition_from_public_transaction(&tx, 2, clock_timestamp) + .unwrap(); + + // Balances changed. + assert_eq!(state.get_account_by_id(sender_id).balance, 0); + assert_eq!(state.get_account_by_id(recipient_id).balance, 100); + } + + #[test] + fn time_locked_transfer_fails_when_deadline_is_in_the_future() { + let clock_timestamp = 600; + let mut state = + state_with_clock_and_program(test_programs::time_locked_transfer(), clock_timestamp); + + let recipient_id = AccountId::new([42; 32]); + state.force_insert_account( + recipient_id, + Account { + program_owner: programs::authenticated_transfer().id(), + ..Account::default() + }, + ); + + let key1 = PrivateKey::try_new([1; 32]).unwrap(); + let sender_id = AccountId::from(&PublicKey::new_from_private_key(&key1)); + state.force_insert_account( + sender_id, + Account { + program_owner: test_programs::time_locked_transfer().id(), + balance: 100, + ..Account::default() + }, + ); + + let amount = 100; + // Far-future deadline: the program panics because the clock has not reached it. + let deadline = u64::MAX; + + let tx = time_locked_transfer_transaction( + sender_id, + &key1, + 0, + recipient_id, + system_accounts::clock_account_ids()[0], + amount, + deadline, + ); + + let result = state.transition_from_public_transaction(&tx, 2, clock_timestamp); + + assert!( + result.is_err(), + "Transfer should fail when deadline is in the future" + ); + // Balances unchanged. + assert_eq!(state.get_account_by_id(sender_id).balance, 100); + assert_eq!(state.get_account_by_id(recipient_id).balance, 0); + } + + fn pinata_cooldown_data(prize: u128, cooldown_ms: u64, last_claim_timestamp: u64) -> Vec { + let mut buf = Vec::with_capacity(32); + buf.extend_from_slice(&prize.to_le_bytes()); + buf.extend_from_slice(&cooldown_ms.to_le_bytes()); + buf.extend_from_slice(&last_claim_timestamp.to_le_bytes()); + buf + } + + fn pinata_cooldown_transaction( + pinata_id: AccountId, + winner_id: AccountId, + clock_account_id: AccountId, + ) -> PublicTransaction { + let program_id = test_programs::pinata_cooldown().id(); + let message = lee::public_transaction::Message::try_new( + program_id, + vec![pinata_id, winner_id, clock_account_id], + vec![], + (), + ) + .unwrap(); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[]); + PublicTransaction::new(message, witness_set) + } + + #[test] + fn pinata_cooldown_claim_succeeds_after_cooldown() { + let winner_id = AccountId::new([11; 32]); + let pinata_id = AccountId::new([99; 32]); + + let genesis_timestamp = 1000; + let prize = 50; + let cooldown_ms = 500; + // Last claim was at genesis, so any timestamp >= genesis + cooldown should work. + let last_claim_timestamp = genesis_timestamp; + + // Advance the clock so the cooldown check reads an updated timestamp. + let block_timestamp = genesis_timestamp + cooldown_ms; + let mut state = + state_with_clock_and_program(test_programs::pinata_cooldown(), block_timestamp); + + // The winner must be a non-default account so the program may credit it without claiming. + state.force_insert_account( + winner_id, + Account { + program_owner: programs::authenticated_transfer().id(), + ..Account::default() + }, + ); + state.force_insert_account( + pinata_id, + Account { + program_owner: test_programs::pinata_cooldown().id(), + balance: 1000, + data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) + .try_into() + .unwrap(), + ..Account::default() + }, + ); + + let tx = pinata_cooldown_transaction( + pinata_id, + winner_id, + system_accounts::clock_account_ids()[0], + ); + + state + .transition_from_public_transaction(&tx, 2, block_timestamp) + .unwrap(); + + assert_eq!(state.get_account_by_id(pinata_id).balance, 1000 - prize); + assert_eq!(state.get_account_by_id(winner_id).balance, prize); + } + + #[test] + fn pinata_cooldown_claim_fails_during_cooldown() { + let winner_id = AccountId::new([11; 32]); + let pinata_id = AccountId::new([99; 32]); + + let genesis_timestamp = 1000; + let prize = 50; + let cooldown_ms = 500; + let last_claim_timestamp = genesis_timestamp; + + // Timestamp is only 100ms after the last claim, well within the 500ms cooldown. + let block_timestamp = genesis_timestamp + 100; + let mut state = + state_with_clock_and_program(test_programs::pinata_cooldown(), block_timestamp); + + state.force_insert_account( + winner_id, + Account { + program_owner: programs::authenticated_transfer().id(), + ..Account::default() + }, + ); + state.force_insert_account( + pinata_id, + Account { + program_owner: test_programs::pinata_cooldown().id(), + balance: 1000, + data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) + .try_into() + .unwrap(), + ..Account::default() + }, + ); + + let tx = pinata_cooldown_transaction( + pinata_id, + winner_id, + system_accounts::clock_account_ids()[0], + ); + + let result = state.transition_from_public_transaction(&tx, 2, block_timestamp); + + assert!(result.is_err(), "Claim should fail during cooldown period"); + assert_eq!(state.get_account_by_id(pinata_id).balance, 1000); + assert_eq!(state.get_account_by_id(winner_id).balance, 0); + } + + #[test] + fn pda_mechanism_with_pinata_token_program() { + let pinata_token = programs::pinata_token(); + let token = programs::token(); + + let pinata_definition_id = AccountId::new([1; 32]); + let pinata_token_definition_id = AccountId::new([2; 32]); + // Total supply of pinata token will be in an account under a PDA. + let pinata_token_holding_id = + AccountId::for_public_pda(&pinata_token.id(), &PdaSeed::new([0; 32])); + let winner_token_holding_id = AccountId::new([3; 32]); + + let expected_winner_account_holding = token_core::TokenHolding::Fungible { + definition_id: pinata_token_definition_id, + balance: 150, + }; + let expected_winner_token_holding_post = Account { + program_owner: token.id(), + data: Data::from(&expected_winner_account_holding), + ..Account::default() + }; + + // Register the pinata-token and token programs and create the pinata definition account. + // This replaces the removed `add_pinata_token_program` helper. + let mut state = V03State::new().with_programs([pinata_token.clone(), token.clone()]); + state.force_insert_account( + pinata_definition_id, + Account { + program_owner: pinata_token.id(), + // Difficulty: 3 + data: vec![3; 33].try_into().unwrap(), + ..Account::default() + }, + ); + + // Set up the token accounts directly (bypassing public transactions which + // would require signers for Claim::Authorized). The focus of this test is + // the PDA mechanism in the pinata program's chained call, not token creation. + let total_supply: u128 = 10_000_000; + let token_definition = token_core::TokenDefinition::Fungible { + name: String::from("PINATA"), + total_supply, + metadata_id: None, + }; + let token_holding = token_core::TokenHolding::Fungible { + definition_id: pinata_token_definition_id, + balance: total_supply, + }; + let winner_holding = token_core::TokenHolding::Fungible { + definition_id: pinata_token_definition_id, + balance: 0, + }; + state.force_insert_account( + pinata_token_definition_id, + Account { + program_owner: token.id(), + data: Data::from(&token_definition), + ..Account::default() + }, + ); + state.force_insert_account( + pinata_token_holding_id, + Account { + program_owner: token.id(), + data: Data::from(&token_holding), + ..Account::default() + }, + ); + state.force_insert_account( + winner_token_holding_id, + Account { + program_owner: token.id(), + data: Data::from(&winner_holding), + ..Account::default() + }, + ); + + // Submit a solution to the pinata program to claim the prize + let solution: u128 = 989_106; + let message = lee::public_transaction::Message::try_new( + pinata_token.id(), + vec![ + pinata_definition_id, + pinata_token_holding_id, + winner_token_holding_id, + ], + vec![], + solution, + ) + .unwrap(); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[]); + let tx = PublicTransaction::new(message, witness_set); + state.transition_from_public_transaction(&tx, 1, 0).unwrap(); + + let winner_token_holding_post = state.get_account_by_id(winner_token_holding_id); + assert_eq!( + winner_token_holding_post, + expected_winner_token_holding_post + ); + } } diff --git a/lez/sequencer/service/Cargo.toml b/lez/sequencer/service/Cargo.toml index 4390f0d8..3427dc22 100644 --- a/lez/sequencer/service/Cargo.toml +++ b/lez/sequencer/service/Cargo.toml @@ -14,6 +14,7 @@ mempool.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } sequencer_service_protocol.workspace = true sequencer_service_rpc = { workspace = true, features = ["server"] } +programs.workspace = true clap = { workspace = true, features = ["derive", "env"] } anyhow.workspace = true diff --git a/lez/sequencer/service/src/service.rs b/lez/sequencer/service/src/service.rs index 1a781024..f3d791dc 100644 --- a/lez/sequencer/service/src/service.rs +++ b/lez/sequencer/service/src/service.rs @@ -5,7 +5,7 @@ use jsonrpsee::{ core::async_trait, types::{ErrorCode, ErrorObjectOwned}, }; -use lee::{self, program::Program}; +use lee; use log::warn; use mempool::MemPoolHandle; use sequencer_core::{ @@ -161,14 +161,15 @@ impl sequencer_service_rpc::RpcServer } async fn get_program_ids(&self) -> Result, ErrorObjectOwned> { + // TODO: Get programs from state let mut program_ids = BTreeMap::new(); program_ids.insert( "authenticated_transfer".to_owned(), - Program::authenticated_transfer_program().id(), + programs::authenticated_transfer().id(), ); - program_ids.insert("token".to_owned(), Program::token().id()); - program_ids.insert("pinata".to_owned(), Program::pinata().id()); - program_ids.insert("amm".to_owned(), Program::amm().id()); + program_ids.insert("token".to_owned(), programs::token().id()); + program_ids.insert("pinata".to_owned(), programs::pinata().id()); + program_ids.insert("amm".to_owned(), programs::amm().id()); program_ids.insert( "privacy_preserving_circuit".to_owned(), lee::PRIVACY_PRESERVING_CIRCUIT_ID, diff --git a/lez/storage/Cargo.toml b/lez/storage/Cargo.toml index 4588aab3..8767b525 100644 --- a/lez/storage/Cargo.toml +++ b/lez/storage/Cargo.toml @@ -15,3 +15,7 @@ thiserror.workspace = true borsh.workspace = true rocksdb.workspace = true tempfile.workspace = true + +[dev-dependencies] +programs.workspace = true +system_accounts.workspace = true diff --git a/lez/storage/src/indexer/mod.rs b/lez/storage/src/indexer/mod.rs index b682a4d7..a753a71a 100644 --- a/lez/storage/src/indexer/mod.rs +++ b/lez/storage/src/indexer/mod.rs @@ -263,7 +263,7 @@ fn closest_breakpoint_id(block_id: u64) -> u64 { #[cfg(test)] mod tests { use common::test_utils::produce_dummy_block; - use lee::{AccountId, PublicKey}; + use lee::{Account, AccountId, PublicKey}; use tempfile::tempdir; use super::*; @@ -288,20 +288,35 @@ mod tests { AccountId::from(&PublicKey::new_from_private_key(&acc2_sign_key())) } + fn initial_state() -> lee::V03State { + let mut public_accounts = [(acc1(), 10000), (acc2(), 20000)] + .into_iter() + .map(|(id, balance)| { + ( + id, + Account { + program_owner: programs::authenticated_transfer().id(), + balance, + ..Account::default() + }, + ) + }) + .collect::>(); + for clock_id in system_accounts::clock_account_ids() { + public_accounts.push((clock_id, system_accounts::clock_account())); + } + + lee::V03State::new() + .with_public_accounts(public_accounts) + .with_programs([programs::authenticated_transfer(), programs::clock()]) + } + #[test] fn start_db() { let temp_dir = tempdir().unwrap(); let temdir_path = temp_dir.path(); - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let last_id = dbio.get_meta_last_block_id_in_db().unwrap(); let first_id = dbio.get_meta_first_block_id_in_db().unwrap(); @@ -333,15 +348,7 @@ mod tests { let temp_dir = tempdir().unwrap(); let temdir_path = temp_dir.path(); - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let genesis_block = genesis_block(); dbio.put_block(&genesis_block, [0; 32]).unwrap(); @@ -392,15 +399,7 @@ mod tests { let temp_dir = tempdir().unwrap(); let temdir_path = temp_dir.path(); - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let from = acc1(); let to = acc2(); @@ -464,15 +463,7 @@ mod tests { let temp_dir = tempdir().unwrap(); let temdir_path = temp_dir.path(); - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let from = acc1(); let to = acc2(); @@ -546,15 +537,7 @@ mod tests { let mut block_res = vec![]; - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let from = acc1(); let to = acc2(); @@ -641,15 +624,7 @@ mod tests { let temp_dir = tempdir().unwrap(); let temdir_path = temp_dir.path(); - let dbio = RocksDBIO::open_or_create( - temdir_path, - &lee::V03State::new_with_genesis_accounts( - &[(acc1(), 10000), (acc2(), 20000)], - vec![], - 0, - ), - ) - .unwrap(); + let dbio = RocksDBIO::open_or_create(temdir_path, &initial_state()).unwrap(); let from = acc1(); let to = acc2(); diff --git a/lez/system_accounts/Cargo.toml b/lez/system_accounts/Cargo.toml new file mode 100644 index 00000000..093e6455 --- /dev/null +++ b/lez/system_accounts/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "system_accounts" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +lee_core.workspace = true +faucet_core.workspace = true +bridge_core.workspace = true +clock_core.workspace = true +programs.workspace = true diff --git a/lez/system_accounts/src/lib.rs b/lez/system_accounts/src/lib.rs new file mode 100644 index 00000000..3b6dd5af --- /dev/null +++ b/lez/system_accounts/src/lib.rs @@ -0,0 +1,71 @@ +//! This crate provides system accounts used by LEZ. + +use std::str::FromStr as _; + +use clock_core::ClockAccountData; +use lee_core::account::{Account, AccountId, Nonce}; + +#[must_use] +pub fn pinata_account_id() -> AccountId { + // TODO: Use derivation from a public key? + AccountId::from_str("EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7") + .expect("Pinata program id should be valid") +} + +#[must_use] +pub fn pinata_account() -> Account { + Account { + program_owner: programs::pinata().id(), + balance: 1_500_000, + // Difficulty: 3 + data: vec![3; 33].try_into().expect("Should fit"), + nonce: Nonce::default(), + } +} + +#[must_use] +pub fn faucet_account_id() -> AccountId { + faucet_core::compute_faucet_account_id(programs::faucet().id()) +} + +#[must_use] +pub fn faucet_account() -> Account { + Account { + program_owner: programs::authenticated_transfer().id(), + balance: u128::MAX, + ..Account::default() + } +} + +#[must_use] +pub fn bridge_account_id() -> AccountId { + bridge_core::compute_bridge_account_id(programs::bridge().id()) +} + +#[must_use] +pub fn bridge_account() -> Account { + Account { + program_owner: programs::authenticated_transfer().id(), + ..Account::default() + } +} + +#[must_use] +pub const fn clock_account_ids() -> [AccountId; 3] { + clock_core::CLOCK_PROGRAM_ACCOUNT_IDS +} + +#[must_use] +pub fn clock_account() -> Account { + Account { + program_owner: programs::clock().id(), + data: ClockAccountData { + block_id: 0, + timestamp: 0, + } + .to_bytes() + .try_into() + .expect("Clock account data should fit"), + ..Account::default() + } +} diff --git a/lez/testnet_initial_state/Cargo.toml b/lez/testnet_initial_state/Cargo.toml index c2e694b4..f06d5f51 100644 --- a/lez/testnet_initial_state/Cargo.toml +++ b/lez/testnet_initial_state/Cargo.toml @@ -8,7 +8,8 @@ license.workspace = true key_protocol.workspace = true lee.workspace = true lee_core.workspace = true -common.workspace = true +system_accounts.workspace = true +programs.workspace = true serde.workspace = true diff --git a/lez/testnet_initial_state/src/lib.rs b/lez/testnet_initial_state/src/lib.rs index 5bb6e1b4..423d6eda 100644 --- a/lez/testnet_initial_state/src/lib.rs +++ b/lez/testnet_initial_state/src/lib.rs @@ -1,10 +1,11 @@ -use common::PINATA_BASE58; +use std::collections::HashMap; + use key_protocol::key_management::{ KeyChain, key_tree::chain_index::ChainIndex, secret_holders::{PrivateKeyHolder, SecretSpendingKey, ViewingSecretKey}, }; -use lee::{Account, AccountId, Data, PrivateKey, PublicKey, V03State}; +use lee::{Account, AccountId, Data, PrivateKey, PublicKey, V03State, program::Program}; use lee_core::{NullifierPublicKey, encryption::ViewingPublicKey}; use serde::{Deserialize, Serialize}; @@ -130,8 +131,7 @@ pub fn initial_pub_accounts_private_keys() -> Vec Vec { +fn initial_priv_accounts_private_keys() -> Vec { let key_chain_1 = KeyChain { secret_spending_key: SecretSpendingKey(SSK_PRIV_ACC_A), private_key_holder: PrivateKeyHolder { @@ -178,8 +178,7 @@ pub fn initial_priv_accounts_private_keys() -> Vec Vec { +fn initial_commitments() -> Vec { initial_priv_accounts_private_keys() .into_iter() .map(|data| PrivateAccountPublicInitialData { @@ -189,8 +188,27 @@ pub fn initial_commitments() -> Vec { .collect() } +fn initial_private_accounts() -> Vec<(lee_core::Commitment, lee_core::Nullifier)> { + initial_commitments() + .iter() + .map(|init_comm_data| { + let npk = &init_comm_data.npk; + let account_id = lee::AccountId::for_regular_private_account(npk, 0); + + let mut acc = init_comm_data.account.clone(); + + acc.program_owner = programs::authenticated_transfer().id(); + + ( + lee_core::Commitment::new(&account_id, &acc), + lee_core::Nullifier::for_account_initialization(&account_id), + ) + }) + .collect() +} + #[must_use] -pub fn initial_accounts() -> Vec { +pub fn initial_public_user_accounts() -> Vec { let initial_account_ids = initial_pub_accounts_private_keys() .into_iter() .map(|data| data.account_id) @@ -208,41 +226,73 @@ pub fn initial_accounts() -> Vec { ] } +fn initial_public_accounts() -> HashMap { + initial_public_user_accounts() + .iter() + .map(|acc_data| { + ( + acc_data.account_id, + Account { + program_owner: programs::authenticated_transfer().id(), + balance: acc_data.balance, + ..Default::default() + }, + ) + }) + .chain([ + ( + system_accounts::faucet_account_id(), + system_accounts::faucet_account(), + ), + ( + system_accounts::bridge_account_id(), + system_accounts::bridge_account(), + ), + ]) + .chain( + system_accounts::clock_account_ids() + .into_iter() + .map(|clock_id| (clock_id, system_accounts::clock_account())), + ) + .collect() +} + +fn initial_programs() -> Vec { + vec![ + programs::authenticated_transfer(), + programs::token(), + programs::amm(), + programs::clock(), + programs::ata(), + programs::vault(), + programs::faucet(), + programs::bridge(), + ] +} + #[must_use] pub fn initial_state() -> V03State { - let initial_private_accounts: Vec<(lee_core::Commitment, lee_core::Nullifier)> = - initial_commitments() - .iter() - .map(|init_comm_data| { - let npk = &init_comm_data.npk; - let account_id = lee::AccountId::for_regular_private_account(npk, 0); - - let mut acc = init_comm_data.account.clone(); - - acc.program_owner = lee::program::Program::authenticated_transfer_program().id(); - - ( - lee_core::Commitment::new(&account_id, &acc), - lee_core::Nullifier::for_account_initialization(&account_id), - ) - }) - .collect(); - - let init_accs: Vec<(lee::AccountId, u128)> = initial_accounts() - .iter() - .map(|acc_data| (acc_data.account_id, acc_data.balance)) - .collect(); - - lee::V03State::new_with_genesis_accounts(&init_accs, initial_private_accounts, 0) + lee::V03State::new() + .with_public_accounts(initial_public_accounts()) + .with_private_accounts(initial_private_accounts()) + .with_programs(initial_programs()) } #[must_use] pub fn initial_state_testnet() -> V03State { - let mut state = initial_state(); + let mut initial_public_accounts = initial_public_accounts(); + initial_public_accounts.insert( + system_accounts::pinata_account_id(), + system_accounts::pinata_account(), + ); - state.add_pinata_program(PINATA_BASE58.parse().unwrap()); + let mut programs = initial_programs(); + programs.push(programs::pinata()); - state + V03State::new() + .with_public_accounts(initial_public_accounts) + .with_private_accounts(initial_private_accounts()) + .with_programs(programs) } #[cfg(test)] @@ -260,7 +310,7 @@ mod tests { #[test] fn pub_state_consistency() { let init_accs_private_data = initial_pub_accounts_private_keys(); - let init_accs_pub_data = initial_accounts(); + let init_accs_pub_data = initial_public_user_accounts(); assert_eq!( init_accs_private_data[0].account_id, @@ -412,4 +462,33 @@ mod tests { } ); } + + #[test] + fn genesis_system_accounts_have_expected_contents() { + // System-account IDs must be distinct and non-default, and the genesis + // faucet/bridge accounts must carry their expected field values. Catches + // mutations that replace `system_faucet_account`/`system_bridge_account` + // with `Default::default()`, delete their `balance`/`program_owner` + // fields, or replace `system_bridge_account_id` with `Default::default()`. + let faucet_id = system_accounts::faucet_account_id(); + let bridge_id = system_accounts::bridge_account_id(); + assert_ne!(bridge_id, AccountId::default()); + assert_ne!(faucet_id, bridge_id); + + let state = initial_state(); + let default_owner = Account::default().program_owner; + + let faucet = state.get_account_by_id(faucet_id); + assert_eq!(faucet.balance, u128::MAX, "faucet must hold u128::MAX"); + assert_ne!( + faucet.program_owner, default_owner, + "faucet must have a non-default program_owner" + ); + + let bridge = state.get_account_by_id(bridge_id); + assert_ne!( + bridge.program_owner, default_owner, + "bridge must have a non-default program_owner" + ); + } } diff --git a/lez/wallet-ffi/Cargo.toml b/lez/wallet-ffi/Cargo.toml index 5d56fb95..47d18c53 100644 --- a/lez/wallet-ffi/Cargo.toml +++ b/lez/wallet-ffi/Cargo.toml @@ -16,6 +16,7 @@ lee.workspace = true lee_core.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } common.workspace = true +programs.workspace = true tokio.workspace = true key_protocol.workspace = true diff --git a/lez/wallet-ffi/src/generic_transaction.rs b/lez/wallet-ffi/src/generic_transaction.rs index f8f344ad..7be6ddaf 100644 --- a/lez/wallet-ffi/src/generic_transaction.rs +++ b/lez/wallet-ffi/src/generic_transaction.rs @@ -10,7 +10,7 @@ use crate::{ error::{print_error, WalletFfiError}, map_execution_error, wallet::get_wallet, - FfiAccountIdentity, FfiBytes32, WalletHandle, + FfiAccountIdentity, FfiBytes32, FfiProgramId, WalletHandle, }; #[repr(C)] @@ -48,7 +48,7 @@ impl TryFrom<&FfiProgram> for Program { elf.push(unsafe { *value.elf_data.add(i) }); } - Self::new(elf).map_err(|err| { + Self::new(elf.into()).map_err(|err| { print_error(format!("Invalid program bytecode, err: {err}")); WalletFfiError::InvalidBytecode }) @@ -214,7 +214,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( account_identities_size: usize, instruction_words: *const u32, instruction_words_size: usize, - program_with_dependencies: *const FfiProgramWithDependencies, + program_id: FfiProgramId, out_result: *mut FfiTransactionResult, ) -> WalletFfiError { let wrapper = match get_wallet(handle) { @@ -260,12 +260,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( } } - let program = match unsafe { &*program_with_dependencies }.try_into() { - Ok(v) => v, - Err(err) => return err, - }; - - match block_on(wallet.send_pub_tx(accounts, instruction_data.to_vec(), &program)) { + match block_on(wallet.send_pub_tx(accounts, instruction_data.to_vec(), program_id.into())) { Ok(tx_hash) => { let tx_hash = CString::new(tx_hash.to_string()) .map_or(std::ptr::null_mut(), std::ffi::CString::into_raw); @@ -445,13 +440,11 @@ pub unsafe extern "C" fn wallet_ffi_free_instruction_words(words: *mut FfiInstru #[cfg(test)] mod tests { - use lee::program::Program; - use crate::generic_transaction::FfiProgram; #[test] fn program_cast_consistency() { - let prog = Program::amm(); + let prog = programs::amm(); let first_5_bytes = prog.elf()[..5].to_vec(); diff --git a/lez/wallet-ffi/src/program_deployment.rs b/lez/wallet-ffi/src/program_deployment.rs index 8820a935..2086fa5c 100644 --- a/lez/wallet-ffi/src/program_deployment.rs +++ b/lez/wallet-ffi/src/program_deployment.rs @@ -1,7 +1,7 @@ use std::{ffi::CString, ptr, slice}; use common::transaction::LeeTransaction; -use lee::{program::Program, ProgramDeploymentTransaction}; +use lee::ProgramDeploymentTransaction; use sequencer_service_rpc::RpcClient as _; use crate::{ @@ -112,7 +112,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_elf(ffi_program: *mut FfiProgram) - return WalletFfiError::NullPointer; } - let elf = Program::authenticated_transfer_program().elf().to_vec(); + let elf = programs::authenticated_transfer().elf().to_vec(); let (raw_elf_data, raw_elf_size, _) = elf.into_raw_parts(); @@ -147,7 +147,7 @@ pub unsafe extern "C" fn wallet_ffi_token_elf(ffi_program: *mut FfiProgram) -> W return WalletFfiError::NullPointer; } - let elf = Program::token().elf().to_vec(); + let elf = programs::token().elf().to_vec(); let (raw_elf_data, raw_elf_size, _) = elf.into_raw_parts(); @@ -182,7 +182,7 @@ pub unsafe extern "C" fn wallet_ffi_amm_elf(ffi_program: *mut FfiProgram) -> Wal return WalletFfiError::NullPointer; } - let elf = Program::amm().elf().to_vec(); + let elf = programs::amm().elf().to_vec(); let (raw_elf_data, raw_elf_size, _) = elf.into_raw_parts(); @@ -217,7 +217,7 @@ pub unsafe extern "C" fn wallet_ffi_ata_elf(ffi_program: *mut FfiProgram) -> Wal return WalletFfiError::NullPointer; } - let elf = Program::ata().elf().to_vec(); + let elf = programs::ata().elf().to_vec(); let (raw_elf_data, raw_elf_size, _) = elf.into_raw_parts(); diff --git a/lez/wallet-ffi/src/types.rs b/lez/wallet-ffi/src/types.rs index ad366b91..cbe9fab7 100644 --- a/lez/wallet-ffi/src/types.rs +++ b/lez/wallet-ffi/src/types.rs @@ -7,7 +7,7 @@ use std::{ str::FromStr as _, }; -use lee::{Data, SharedSecretKey}; +use lee::{Data, ProgramId, SharedSecretKey}; use lee_core::{encryption::MlKem768EncapsulationKey, NullifierPublicKey}; use wallet::AccountIdentity; @@ -581,6 +581,18 @@ impl TryFrom<&FfiAccountIdentity> for AccountIdentity { } } +impl From for FfiProgramId { + fn from(value: ProgramId) -> Self { + Self { data: value } + } +} + +impl From for ProgramId { + fn from(value: FfiProgramId) -> Self { + value.data + } +} + #[cfg(test)] mod tests { use lee::{AccountId, PrivateKey, PublicKey}; diff --git a/lez/wallet-ffi/src/vault.rs b/lez/wallet-ffi/src/vault.rs index e0575e3d..6db1fa66 100644 --- a/lez/wallet-ffi/src/vault.rs +++ b/lez/wallet-ffi/src/vault.rs @@ -6,7 +6,7 @@ use std::{ffi::CString, ptr}; -use lee::{program::Program, AccountId}; +use lee::AccountId; use wallet::program_facades::vault::Vault; use crate::{ @@ -57,7 +57,7 @@ pub unsafe extern "C" fn wallet_ffi_get_vault_balance( }; let owner_id = AccountId::new(unsafe { (*owner).data }); - let vault_id = vault_core::compute_vault_account_id(Program::vault().id(), owner_id); + let vault_id = vault_core::compute_vault_account_id(programs::vault().id(), owner_id); let balance = match block_on(wallet.get_account_balance(vault_id)) { Ok(b) => b, diff --git a/lez/wallet-ffi/wallet_ffi.h b/lez/wallet-ffi/wallet_ffi.h index a6ce6b72..d83c520e 100644 --- a/lez/wallet-ffi/wallet_ffi.h +++ b/lez/wallet-ffi/wallet_ffi.h @@ -256,23 +256,6 @@ typedef struct FfiAccountIdentity { struct FfiU128 identifier; } FfiAccountIdentity; -/** - * Intended to be created manually. - */ -typedef struct FfiProgram { - const uint8_t *elf_data; - uintptr_t elf_size; -} FfiProgram; - -/** - * Intended to be created manually. - */ -typedef struct FfiProgramWithDependencies { - struct FfiProgram program; - const struct FfiProgram *deps; - uintptr_t deps_size; -} FfiProgramWithDependencies; - /** * Result of a generic transaction operation. */ @@ -292,6 +275,23 @@ typedef struct FfiTransactionResult { uintptr_t secrets_size; } FfiTransactionResult; +/** + * Intended to be created manually. + */ +typedef struct FfiProgram { + const uint8_t *elf_data; + uintptr_t elf_size; +} FfiProgram; + +/** + * Intended to be created manually. + */ +typedef struct FfiProgramWithDependencies { + struct FfiProgram program; + const struct FfiProgram *deps; + uintptr_t deps_size; +} FfiProgramWithDependencies; + /** * Public key info for a public account. */ @@ -613,7 +613,7 @@ enum WalletFfiError wallet_ffi_send_generic_public_transaction(struct WalletHand uintptr_t account_identities_size, const uint32_t *instruction_words, uintptr_t instruction_words_size, - const struct FfiProgramWithDependencies *program_with_dependencies, + struct FfiProgramId program_id, struct FfiTransactionResult *out_result); /** diff --git a/lez/wallet/Cargo.toml b/lez/wallet/Cargo.toml index e04b0d91..974d6a71 100644 --- a/lez/wallet/Cargo.toml +++ b/lez/wallet/Cargo.toml @@ -17,10 +17,12 @@ sequencer_service_rpc = { workspace = true, features = ["client"] } amm_core.workspace = true testnet_initial_state.workspace = true token_core.workspace = true -ata_core.workspace = true vault_core.workspace = true bridge_core.workspace = true keycard_wallet.workspace = true +programs.workspace = true +system_accounts.workspace = true +associated_token_account_core.workspace = true bip39.workspace = true pyo3.workspace = true diff --git a/lez/wallet/src/cli/account.rs b/lez/wallet/src/cli/account.rs index e0ec2d0f..fb0db2cb 100644 --- a/lez/wallet/src/cli/account.rs +++ b/lez/wallet/src/cli/account.rs @@ -2,7 +2,7 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::{KeyChain, key_tree::chain_index::ChainIndex}; -use lee::{Account, PublicKey, program::Program}; +use lee::{Account, PublicKey}; use lee_core::Identifier; use token_core::{TokenDefinition, TokenHolding}; @@ -545,8 +545,8 @@ impl WalletSubcommand for ImportSubcommand { /// Formats account details for display, returning (description, `json_view`). fn format_account_details(account: &Account) -> (String, String) { - let auth_tr_prog_id = Program::authenticated_transfer_program().id(); - let token_prog_id = Program::token().id(); + let auth_tr_prog_id = programs::authenticated_transfer().id(); + let token_prog_id = programs::token().id(); match &account.program_owner { o if *o == auth_tr_prog_id => { diff --git a/lez/wallet/src/cli/keycard.rs b/lez/wallet/src/cli/keycard.rs index a2eae73c..37a83948 100644 --- a/lez/wallet/src/cli/keycard.rs +++ b/lez/wallet/src/cli/keycard.rs @@ -1,3 +1,8 @@ +#![expect( + clippy::print_stderr, + reason = "This is a CLI application, printing to stderr is expected and convenient" +)] + use anyhow::Result; use clap::Subcommand; use keycard_wallet::{KeycardWallet, clear_pairing, python_path}; diff --git a/lez/wallet/src/cli/mod.rs b/lez/wallet/src/cli/mod.rs index 8a91d3ae..aeadf426 100644 --- a/lez/wallet/src/cli/mod.rs +++ b/lez/wallet/src/cli/mod.rs @@ -6,7 +6,7 @@ use clap::{Parser, Subcommand}; use common::{HashType, transaction::LeeTransaction}; use derive_more::Display; use futures::TryFutureExt as _; -use lee::{ProgramDeploymentTransaction, program::Program}; +use lee::ProgramDeploymentTransaction; use sequencer_service_rpc::RpcClient as _; pub use crate::helperfunctions::{read_mnemonic, read_pin}; @@ -228,14 +228,14 @@ pub async fn execute_subcommand( panic!("Missing authenticated transfer ID from remote"); }; assert!( - authenticated_transfer_id == &Program::authenticated_transfer_program().id(), + authenticated_transfer_id == &::programs::authenticated_transfer().id(), "Local ID for authenticated transfer program is different from remote" ); let Some(token_id) = remote_program_ids.get("token") else { panic!("Missing token program ID from remote"); }; assert!( - token_id == &Program::token().id(), + token_id == &::programs::token().id(), "Local ID for token program is different from remote" ); let Some(circuit_id) = remote_program_ids.get("privacy_preserving_circuit") else { @@ -249,7 +249,7 @@ pub async fn execute_subcommand( panic!("Missing AMM program ID from remote"); }; assert!( - amm_id == &Program::amm().id(), + amm_id == &::programs::amm().id(), "Local ID for AMM program is different from remote" ); diff --git a/lez/wallet/src/cli/programs/ata.rs b/lez/wallet/src/cli/programs/ata.rs index b77ff61f..7afda06f 100644 --- a/lez/wallet/src/cli/programs/ata.rs +++ b/lez/wallet/src/cli/programs/ata.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::Subcommand; use common::transaction::LeeTransaction; -use lee::{Account, AccountId, program::Program}; +use lee::{Account, AccountId}; use token_core::TokenHolding; use crate::{ @@ -79,10 +79,10 @@ impl WalletSubcommand for AtaSubcommand { owner, token_definition, } => { - let ata_program_id = Program::ata().id(); - let ata_id = ata_core::get_associated_token_account_id( + let ata_program_id = programs::ata().id(); + let ata_id = associated_token_account_core::get_associated_token_account_id( &ata_program_id, - &ata_core::compute_ata_seed(owner, token_definition), + &associated_token_account_core::compute_ata_seed(owner, token_definition), ); println!("{ata_id}"); Ok(SubcommandReturnValue::Empty) @@ -218,12 +218,12 @@ impl WalletSubcommand for AtaSubcommand { owner, token_definition, } => { - let ata_program_id = Program::ata().id(); + let ata_program_id = programs::ata().id(); for def in &token_definition { - let ata_id = ata_core::get_associated_token_account_id( + let ata_id = associated_token_account_core::get_associated_token_account_id( &ata_program_id, - &ata_core::compute_ata_seed(owner, *def), + &associated_token_account_core::compute_ata_seed(owner, *def), ); let account = wallet_core.get_account_public(ata_id).await?; diff --git a/lez/wallet/src/cli/programs/pinata.rs b/lez/wallet/src/cli/programs/pinata.rs index 7ef92270..c08a33b8 100644 --- a/lez/wallet/src/cli/programs/pinata.rs +++ b/lez/wallet/src/cli/programs/pinata.rs @@ -1,6 +1,6 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; -use common::{PINATA_BASE58, transaction::LeeTransaction}; +use common::transaction::LeeTransaction; use lee::{Account, AccountId}; use crate::{ @@ -33,13 +33,13 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand { match to { AccountIdWithPrivacy::Public(to) => { PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim { - pinata_account_id: PINATA_BASE58.parse()?, + pinata_account_id: system_accounts::pinata_account_id(), winner_account_id: to, }) } AccountIdWithPrivacy::Private(to) => PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_account_id: PINATA_BASE58.parse()?, + pinata_account_id: system_accounts::pinata_account_id(), winner_account_id: to, }, ), diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index d8679dc1..80b42e17 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -1,6 +1,5 @@ #![expect( clippy::print_stdout, - clippy::print_stderr, reason = "This is a CLI application, printing to stdout and stderr is expected and convenient" )] #![expect( @@ -17,7 +16,7 @@ use common::{HashType, transaction::LeeTransaction}; use config::WalletConfig; use key_protocol::key_management::key_tree::chain_index::ChainIndex; use lee::{ - Account, AccountId, PrivacyPreservingTransaction, + Account, AccountId, PrivacyPreservingTransaction, ProgramId, privacy_preserving_transaction::{ circuit::ProgramWithDependencies, message::EncryptedAccountData, }, @@ -620,9 +619,9 @@ impl WalletCore { &self, accounts: Vec, instruction_data: InstructionData, - program: &ProgramWithDependencies, + program_id: ProgramId, ) -> Result { - self.send_pub_tx_with_pre_check(accounts, instruction_data, program, |_| Ok(())) + self.send_pub_tx_with_pre_check(accounts, instruction_data, program_id, |_| Ok(())) .await } @@ -630,7 +629,7 @@ impl WalletCore { &self, accounts: Vec, instruction_data: InstructionData, - program: &ProgramWithDependencies, + program_id: ProgramId, tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>, ) -> Result { // Public transaction, all accounts must be public @@ -653,7 +652,6 @@ impl WalletCore { )?; let account_ids = acc_manager.public_account_ids(); - let program_id = program.program.id(); let nonces = acc_manager.public_account_nonces(); let message = lee::public_transaction::Message::new_preserialized( diff --git a/lez/wallet/src/program_facades/amm.rs b/lez/wallet/src/program_facades/amm.rs index e1261b26..bc5c5d62 100644 --- a/lez/wallet/src/program_facades/amm.rs +++ b/lez/wallet/src/program_facades/amm.rs @@ -22,8 +22,7 @@ impl Amm<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::amm(); - let amm_program_id = Program::amm().id(); + let amm_program_id = programs::amm().id(); let user_a_acc = self .0 .get_account_public(a_id) @@ -67,7 +66,7 @@ impl Amm<'_> { user_holding_lp, ], instruction_data, - &program.into(), + amm_program_id, ) .await } @@ -87,8 +86,7 @@ impl Amm<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::amm(); - let amm_program_id = Program::amm().id(); + let amm_program_id = programs::amm().id(); let user_a_acc = self .0 .get_account_public(a_id) @@ -149,7 +147,7 @@ impl Amm<'_> { user_b_signing_identity, ], instruction_data, - &program.into(), + amm_program_id, ) .await } @@ -169,8 +167,7 @@ impl Amm<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::amm(); - let amm_program_id = Program::amm().id(); + let amm_program_id = programs::amm().id(); let user_a_acc = self .0 .get_account_public(a_id) @@ -231,7 +228,7 @@ impl Amm<'_> { user_b_signing_identity, ], instruction_data, - &program.into(), + amm_program_id, ) .await } @@ -252,8 +249,7 @@ impl Amm<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::amm(); - let amm_program_id = Program::amm().id(); + let amm_program_id = programs::amm().id(); let user_a_acc = self .0 .get_account_public(a_id) @@ -297,7 +293,7 @@ impl Amm<'_> { user_holding_lp, ], instruction_data, - &program.into(), + amm_program_id, ) .await } @@ -311,8 +307,7 @@ impl Amm<'_> { min_amount_to_remove_token_a: u128, min_amount_to_remove_token_b: u128, ) -> Result { - let program = Program::amm(); - let amm_program_id = Program::amm().id(); + let amm_program_id = programs::amm().id(); let user_a_acc = self .0 .get_account_public(user_holding_a) @@ -356,7 +351,7 @@ impl Amm<'_> { user_holding_lp, ], instruction_data, - &program.into(), + amm_program_id, ) .await } diff --git a/lez/wallet/src/program_facades/ata.rs b/lez/wallet/src/program_facades/ata.rs index e6b8fc29..6c9ec568 100644 --- a/lez/wallet/src/program_facades/ata.rs +++ b/lez/wallet/src/program_facades/ata.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -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 common::HashType; use lee::{ AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, @@ -21,13 +21,12 @@ impl Ata<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::ata(); - let ata_program_id = program.id(); + let ata_program_id = programs::ata().id(); let ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Create { ata_program_id }; + let instruction = associated_token_account_core::Instruction::Create { ata_program_id }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -39,7 +38,7 @@ impl Ata<'_> { AccountIdentity::PublicNoSign(ata_id), ], instruction_data, - &program.into(), + ata_program_id, ) .await } @@ -55,13 +54,12 @@ impl Ata<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::ata(); - let ata_program_id = program.id(); + let ata_program_id = programs::ata().id(); let sender_ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Transfer { + let instruction = associated_token_account_core::Instruction::Transfer { ata_program_id, amount, }; @@ -76,7 +74,7 @@ impl Ata<'_> { AccountIdentity::PublicNoSign(recipient_id), ], instruction_data, - &program.into(), + ata_program_id, ) .await } @@ -91,13 +89,12 @@ impl Ata<'_> { .public_account_id() .ok_or(ExecutionFailureKind::KeyNotFoundError)?; - let program = Program::ata(); - let ata_program_id = program.id(); + let ata_program_id = programs::ata().id(); let holder_ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Burn { + let instruction = associated_token_account_core::Instruction::Burn { ata_program_id, amount, }; @@ -112,7 +109,7 @@ impl Ata<'_> { AccountIdentity::PublicNoSign(definition_id), ], instruction_data, - &program.into(), + ata_program_id, ) .await } @@ -122,13 +119,13 @@ impl Ata<'_> { owner_id: AccountId, definition_id: AccountId, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - let ata_program_id = Program::ata().id(); + let ata_program_id = programs::ata().id(); let ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Create { ata_program_id }; + let instruction = associated_token_account_core::Instruction::Create { ata_program_id }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -156,13 +153,13 @@ impl Ata<'_> { recipient_id: AccountId, amount: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - let ata_program_id = Program::ata().id(); + let ata_program_id = programs::ata().id(); let sender_ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Transfer { + let instruction = associated_token_account_core::Instruction::Transfer { ata_program_id, amount, }; @@ -192,13 +189,13 @@ impl Ata<'_> { definition_id: AccountId, amount: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - let ata_program_id = Program::ata().id(); + let ata_program_id = programs::ata().id(); let holder_ata_id = get_associated_token_account_id( &ata_program_id, &compute_ata_seed(owner_id, definition_id), ); - let instruction = ata_core::Instruction::Burn { + let instruction = associated_token_account_core::Instruction::Burn { ata_program_id, amount, }; @@ -224,8 +221,8 @@ impl Ata<'_> { } fn ata_with_token_dependency() -> ProgramWithDependencies { - let token = Program::token(); + let token = programs::token(); let mut deps = HashMap::new(); deps.insert(token.id(), token); - ProgramWithDependencies::new(Program::ata(), deps) + ProgramWithDependencies::new(programs::ata(), deps) } diff --git a/lez/wallet/src/program_facades/bridge.rs b/lez/wallet/src/program_facades/bridge.rs index 60ad9483..c9aa585e 100644 --- a/lez/wallet/src/program_facades/bridge.rs +++ b/lez/wallet/src/program_facades/bridge.rs @@ -12,8 +12,7 @@ impl Bridge<'_> { amount: u64, bedrock_account_pk: [u8; 32], ) -> Result { - let program = Program::bridge(); - let bridge_account_id = lee::system_bridge_account_id(); + let bridge_account_id = system_accounts::bridge_account_id(); let instruction = bridge_core::Instruction::Withdraw { amount, bedrock_account_pk, @@ -28,7 +27,7 @@ impl Bridge<'_> { AccountIdentity::PublicNoSign(bridge_account_id), ], instruction_data, - &program.into(), + programs::bridge().id(), ) .await } diff --git a/lez/wallet/src/program_facades/native_token_transfer/mod.rs b/lez/wallet/src/program_facades/native_token_transfer/mod.rs index 74f9d7b7..c4e673fa 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/mod.rs @@ -26,7 +26,6 @@ fn auth_transfer_preparation( amount: balance_to_move, }) .unwrap(); - let program = Program::authenticated_transfer_program(); // TODO: handle large Err-variant properly let tx_pre_check = move |accounts: &[&Account]| { @@ -38,5 +37,9 @@ fn auth_transfer_preparation( } }; - (instruction_data, program, tx_pre_check) + ( + instruction_data, + programs::authenticated_transfer(), + tx_pre_check, + ) } diff --git a/lez/wallet/src/program_facades/native_token_transfer/private.rs b/lez/wallet/src/program_facades/native_token_transfer/private.rs index 6937ee5a..712d6774 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/private.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/private.rs @@ -23,7 +23,7 @@ impl NativeTokenTransfer<'_> { .send_privacy_preserving_tx( vec![account], Program::serialize_instruction(instruction).unwrap(), - &Program::authenticated_transfer_program().into(), + &programs::authenticated_transfer().into(), ) .await .map(|(resp, secrets)| { diff --git a/lez/wallet/src/program_facades/native_token_transfer/public.rs b/lez/wallet/src/program_facades/native_token_transfer/public.rs index 47cbf2c0..ee01d9c8 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/public.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/public.rs @@ -21,7 +21,7 @@ impl NativeTokenTransfer<'_> { .send_pub_tx_with_pre_check( vec![from, to], instruction_data, - &program.into(), + program.id(), tx_pre_check, ) .await @@ -31,11 +31,14 @@ impl NativeTokenTransfer<'_> { &self, account: AccountIdentity, ) -> Result { - let program = Program::authenticated_transfer_program(); let instruction_data = Program::serialize_instruction(AuthTransferInstruction::Initialize)?; self.0 - .send_pub_tx(vec![account], instruction_data, &program.into()) + .send_pub_tx( + vec![account], + instruction_data, + programs::authenticated_transfer().id(), + ) .await } } diff --git a/lez/wallet/src/program_facades/pinata.rs b/lez/wallet/src/program_facades/pinata.rs index 8da5f1a5..3a1ff898 100644 --- a/lez/wallet/src/program_facades/pinata.rs +++ b/lez/wallet/src/program_facades/pinata.rs @@ -13,7 +13,6 @@ impl Pinata<'_> { winner_account_id: AccountId, solution: u128, ) -> Result { - let program = Program::pinata(); let instruction = solution; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); @@ -25,7 +24,7 @@ impl Pinata<'_> { AccountIdentity::PublicNoSign(winner_account_id), ], instruction_data, - &program.into(), + programs::pinata().id(), ) .await } @@ -61,7 +60,7 @@ impl Pinata<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], lee::program::Program::serialize_instruction(solution).unwrap(), - &lee::program::Program::pinata().into(), + &programs::pinata().into(), ) .await .map(|(resp, secrets)| { diff --git a/lez/wallet/src/program_facades/token.rs b/lez/wallet/src/program_facades/token.rs index 2170c046..d634976f 100644 --- a/lez/wallet/src/program_facades/token.rs +++ b/lez/wallet/src/program_facades/token.rs @@ -15,13 +15,16 @@ impl Token<'_> { name: String, total_supply: u128, ) -> Result { - let program = Program::token(); let instruction = Instruction::NewFungibleDefinition { name, total_supply }; let instruction_data = Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 - .send_pub_tx(vec![definition, supply], instruction_data, &program.into()) + .send_pub_tx( + vec![definition, supply], + instruction_data, + programs::token().id(), + ) .await } @@ -45,7 +48,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -77,7 +80,7 @@ impl Token<'_> { AccountIdentity::Public(supply_account_id), ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -111,7 +114,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -128,7 +131,6 @@ impl Token<'_> { recipient: AccountIdentity, amount: u128, ) -> Result { - let program = Program::token(); let instruction = Instruction::Transfer { amount_to_transfer: amount, }; @@ -136,7 +138,11 @@ impl Token<'_> { Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 - .send_pub_tx(vec![sender, recipient], instruction_data, &program.into()) + .send_pub_tx( + vec![sender, recipient], + instruction_data, + programs::token().id(), + ) .await } @@ -163,7 +169,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -201,7 +207,7 @@ impl Token<'_> { }, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -233,7 +239,7 @@ impl Token<'_> { AccountIdentity::Public(recipient_account_id), ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -265,7 +271,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -301,7 +307,7 @@ impl Token<'_> { }, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -319,7 +325,6 @@ impl Token<'_> { holder: AccountIdentity, amount: u128, ) -> Result { - let program = Program::token(); let instruction = Instruction::Burn { amount_to_burn: amount, }; @@ -330,7 +335,7 @@ impl Token<'_> { .send_pub_tx( vec![AccountIdentity::PublicNoSign(definition_account_id), holder], instruction_data, - &program.into(), + programs::token().id(), ) .await } @@ -358,7 +363,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -390,7 +395,7 @@ impl Token<'_> { AccountIdentity::Public(holder_account_id), ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -423,7 +428,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -441,7 +446,6 @@ impl Token<'_> { holder: AccountIdentity, amount: u128, ) -> Result { - let program = Program::token(); let instruction = Instruction::Mint { amount_to_mint: amount, }; @@ -449,7 +453,11 @@ impl Token<'_> { Program::serialize_instruction(instruction).expect("Instruction should serialize"); self.0 - .send_pub_tx(vec![definition, holder], instruction_data, &program.into()) + .send_pub_tx( + vec![definition, holder], + instruction_data, + programs::token().id(), + ) .await } @@ -476,7 +484,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -514,7 +522,7 @@ impl Token<'_> { }, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -546,7 +554,7 @@ impl Token<'_> { AccountIdentity::Public(holder_account_id), ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -579,7 +587,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { @@ -616,7 +624,7 @@ impl Token<'_> { }, ], instruction_data, - &Program::token().into(), + &programs::token().into(), ) .await .map(|(resp, secrets)| { diff --git a/lez/wallet/src/program_facades/vault.rs b/lez/wallet/src/program_facades/vault.rs index bccee4f2..dcb5c5e0 100644 --- a/lez/wallet/src/program_facades/vault.rs +++ b/lez/wallet/src/program_facades/vault.rs @@ -17,8 +17,7 @@ impl Vault<'_> { recipient_id: AccountId, amount: u128, ) -> Result { - let program = Program::vault(); - let vault_program_id = program.id(); + let vault_program_id = programs::vault().id(); let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); @@ -36,7 +35,7 @@ impl Vault<'_> { AccountIdentity::PublicNoSign(recipient_vault_id), ], instruction_data, - &program.into(), + vault_program_id, ) .await } @@ -47,7 +46,7 @@ impl Vault<'_> { recipient_id: AccountId, amount: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - 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 instruction = vault_core::Instruction::Transfer { @@ -80,8 +79,7 @@ impl Vault<'_> { owner_id: AccountId, amount: u128, ) -> Result { - let program = Program::vault(); - let vault_program_id = program.id(); + let vault_program_id = programs::vault().id(); let owner_vault_id = vault_core::compute_vault_account_id(vault_program_id, owner_id); let instruction = vault_core::Instruction::Claim { amount }; @@ -95,7 +93,7 @@ impl Vault<'_> { AccountIdentity::PublicNoSign(owner_vault_id), ], instruction_data, - &program.into(), + vault_program_id, ) .await } @@ -105,7 +103,7 @@ impl Vault<'_> { owner_id: AccountId, amount: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - 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_id); let instruction = vault_core::Instruction::Claim { amount }; @@ -132,8 +130,8 @@ impl Vault<'_> { } fn vault_with_auth_dependency() -> ProgramWithDependencies { - let auth_transfer = Program::authenticated_transfer_program(); + let auth_transfer = programs::authenticated_transfer(); let mut deps = HashMap::new(); deps.insert(auth_transfer.id(), auth_transfer); - ProgramWithDependencies::new(Program::vault(), deps) + ProgramWithDependencies::new(programs::vault(), deps) } diff --git a/program_methods/guest/Cargo.toml b/program_methods/guest/Cargo.toml deleted file mode 100644 index b7b37961..00000000 --- a/program_methods/guest/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "programs" -version = "0.1.0" -edition = "2024" -license = { workspace = true } - -[lints] -workspace = true - -[dependencies] -lee_core.workspace = true -authenticated_transfer_core.workspace = true -clock_core.workspace = true -token_core.workspace = true -token_program.workspace = true -amm_core.workspace = true -amm_program.workspace = true -ata_core.workspace = true -ata_program.workspace = true -faucet_core.workspace = true -bridge_core.workspace = true -vault_core.workspace = true -risc0-zkvm.workspace = true -serde = { workspace = true, default-features = false } diff --git a/test_fixtures/Cargo.toml b/test_fixtures/Cargo.toml index 54cb6733..71f887b6 100644 --- a/test_fixtures/Cargo.toml +++ b/test_fixtures/Cargo.toml @@ -18,6 +18,7 @@ sequencer_core = { workspace = true, features = ["default", "testnet"] } sequencer_service.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } wallet.workspace = true +programs.workspace = true anyhow.workspace = true bytesize.workspace = true diff --git a/test_fixtures/src/lib.rs b/test_fixtures/src/lib.rs index 75394662..43e2a9db 100644 --- a/test_fixtures/src/lib.rs +++ b/test_fixtures/src/lib.rs @@ -32,9 +32,6 @@ pub mod setup; // TODO: Remove this and control time from tests pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; -pub const LEE_PROGRAM_FOR_TEST_DATA_CHANGER: &str = "data_changer.bin"; -pub const LEE_PROGRAM_FOR_TEST_NOOP: &str = "noop.bin"; -pub const LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY: &str = "pda_spend_proxy.bin"; pub(crate) const BEDROCK_SERVICE_WITH_OPEN_PORT: &str = "logos-blockchain-node-0"; pub(crate) const BEDROCK_SERVICE_PORT: u16 = 18080; diff --git a/test_program_methods/src/lib.rs b/test_program_methods/src/lib.rs deleted file mode 100644 index 1bdb3085..00000000 --- a/test_program_methods/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -include!(concat!(env!("OUT_DIR"), "/methods.rs")); diff --git a/test_program_methods/Cargo.toml b/test_programs/Cargo.toml similarity index 76% rename from test_program_methods/Cargo.toml rename to test_programs/Cargo.toml index 9b4934e2..8499f5aa 100644 --- a/test_program_methods/Cargo.toml +++ b/test_programs/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "test_program_methods" +name = "test_programs" version = "0.1.0" edition = "2024" license = { workspace = true } @@ -7,6 +7,9 @@ license = { workspace = true } [lints] workspace = true +[dependencies] +lee.workspace = true + [build-dependencies] risc0-build.workspace = true diff --git a/test_program_methods/build.rs b/test_programs/build.rs similarity index 100% rename from test_program_methods/build.rs rename to test_programs/build.rs diff --git a/test_program_methods/guest/Cargo.toml b/test_programs/guest/Cargo.toml similarity index 77% rename from test_program_methods/guest/Cargo.toml rename to test_programs/guest/Cargo.toml index f08b520b..1d6f927d 100644 --- a/test_program_methods/guest/Cargo.toml +++ b/test_programs/guest/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "test_programs" +name = "test_program_guests" version = "0.1.0" edition = "2024" license = { workspace = true } @@ -14,4 +14,3 @@ clock_core.workspace = true faucet_core.workspace = true risc0-zkvm.workspace = true -serde = { workspace = true, default-features = false } diff --git a/test_program_methods/guest/src/bin/chain_caller.rs b/test_programs/guest/src/bin/chain_caller.rs similarity index 100% rename from test_program_methods/guest/src/bin/chain_caller.rs rename to test_programs/guest/src/bin/chain_caller.rs diff --git a/test_programs/guest/src/bin/claimer.rs b/test_programs/guest/src/bin/claimer.rs new file mode 100644 index 00000000..b0efe992 --- /dev/null +++ b/test_programs/guest/src/bin/claimer.rs @@ -0,0 +1,30 @@ +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; + +type Instruction = (); + +fn main() { + let ( + ProgramInput { + self_program_id, + caller_program_id, + pre_states, + instruction: (), + }, + instruction_words, + ) = read_lee_inputs::(); + + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; + }; + + let account_post = AccountPostState::new_claimed(pre.account.clone(), Claim::Authorized); + + ProgramOutput::new( + self_program_id, + caller_program_id, + instruction_words, + vec![pre], + vec![account_post], + ) + .write(); +} diff --git a/test_program_methods/guest/src/bin/clock_chain_caller.rs b/test_programs/guest/src/bin/clock_chain_caller.rs similarity index 100% rename from test_program_methods/guest/src/bin/clock_chain_caller.rs rename to test_programs/guest/src/bin/clock_chain_caller.rs diff --git a/test_program_methods/guest/src/bin/faucet_chain_caller.rs b/test_programs/guest/src/bin/faucet_chain_caller.rs similarity index 100% rename from test_program_methods/guest/src/bin/faucet_chain_caller.rs rename to test_programs/guest/src/bin/faucet_chain_caller.rs diff --git a/test_program_methods/guest/src/bin/pda_spend_proxy.rs b/test_programs/guest/src/bin/pda_spend_proxy.rs similarity index 100% rename from test_program_methods/guest/src/bin/pda_spend_proxy.rs rename to test_programs/guest/src/bin/pda_spend_proxy.rs diff --git a/test_program_methods/guest/src/bin/pinata_cooldown.rs b/test_programs/guest/src/bin/pinata_cooldown.rs similarity index 100% rename from test_program_methods/guest/src/bin/pinata_cooldown.rs rename to test_programs/guest/src/bin/pinata_cooldown.rs diff --git a/test_program_methods/guest/src/bin/time_locked_transfer.rs b/test_programs/guest/src/bin/time_locked_transfer.rs similarity index 100% rename from test_program_methods/guest/src/bin/time_locked_transfer.rs rename to test_programs/guest/src/bin/time_locked_transfer.rs diff --git a/test_programs/src/lib.rs b/test_programs/src/lib.rs new file mode 100644 index 00000000..c13a1028 --- /dev/null +++ b/test_programs/src/lib.rs @@ -0,0 +1,88 @@ +#![expect( + clippy::no_effect_underscore_binding, + reason = "This way we can remove warnings about unused path constants" +)] + +use std::borrow::Cow; + +use lee::program::Program; + +mod guests { + include!(concat!(env!("OUT_DIR"), "/methods.rs")); +} + +#[must_use] +#[inline] +pub const fn chain_caller() -> Program { + use guests::{CHAIN_CALLER_ELF, CHAIN_CALLER_ID, CHAIN_CALLER_PATH}; + + let _unused = CHAIN_CALLER_PATH; + + Program::new_unchecked(CHAIN_CALLER_ID, Cow::Borrowed(CHAIN_CALLER_ELF)) +} + +#[must_use] +#[inline] +pub const fn claimer() -> Program { + use guests::{CLAIMER_ELF, CLAIMER_ID, CLAIMER_PATH}; + + let _unused = CLAIMER_PATH; + + Program::new_unchecked(CLAIMER_ID, Cow::Borrowed(CLAIMER_ELF)) +} + +#[must_use] +#[inline] +pub const fn pda_spend_proxy() -> Program { + use guests::{PDA_SPEND_PROXY_ELF, PDA_SPEND_PROXY_ID, PDA_SPEND_PROXY_PATH}; + + let _unused = PDA_SPEND_PROXY_PATH; + + Program::new_unchecked(PDA_SPEND_PROXY_ID, Cow::Borrowed(PDA_SPEND_PROXY_ELF)) +} + +#[must_use] +#[inline] +pub const fn time_locked_transfer() -> Program { + use guests::{TIME_LOCKED_TRANSFER_ELF, TIME_LOCKED_TRANSFER_ID, TIME_LOCKED_TRANSFER_PATH}; + + let _unused = TIME_LOCKED_TRANSFER_PATH; + + Program::new_unchecked( + TIME_LOCKED_TRANSFER_ID, + Cow::Borrowed(TIME_LOCKED_TRANSFER_ELF), + ) +} + +#[must_use] +#[inline] +pub const fn pinata_cooldown() -> Program { + use guests::{PINATA_COOLDOWN_ELF, PINATA_COOLDOWN_ID, PINATA_COOLDOWN_PATH}; + + let _unused = PINATA_COOLDOWN_PATH; + + Program::new_unchecked(PINATA_COOLDOWN_ID, Cow::Borrowed(PINATA_COOLDOWN_ELF)) +} + +#[must_use] +#[inline] +pub const fn faucet_chain_caller() -> Program { + use guests::{FAUCET_CHAIN_CALLER_ELF, FAUCET_CHAIN_CALLER_ID, FAUCET_CHAIN_CALLER_PATH}; + + let _unused = FAUCET_CHAIN_CALLER_PATH; + + Program::new_unchecked( + FAUCET_CHAIN_CALLER_ID, + Cow::Borrowed(FAUCET_CHAIN_CALLER_ELF), + ) +} + +#[must_use] +#[inline] +pub const fn clock_chain_caller() -> Program { + use guests::{CLOCK_CHAIN_CALLER_ELF, CLOCK_CHAIN_CALLER_ID, CLOCK_CHAIN_CALLER_PATH}; + + let _unused = CLOCK_CHAIN_CALLER_PATH; + + Program::new_unchecked(CLOCK_CHAIN_CALLER_ID, Cow::Borrowed(CLOCK_CHAIN_CALLER_ELF)) +} diff --git a/tools/cycle_bench/Cargo.toml b/tools/cycle_bench/Cargo.toml index 03491c98..22d034df 100644 --- a/tools/cycle_bench/Cargo.toml +++ b/tools/cycle_bench/Cargo.toml @@ -20,7 +20,9 @@ authenticated_transfer_core.workspace = true clock_core.workspace = true token_core.workspace = true amm_core.workspace = true -ata_core.workspace = true +associated_token_account_core.workspace = true +programs.workspace = true +test_programs.workspace = true risc0-zkvm.workspace = true borsh.workspace = true diff --git a/tools/cycle_bench/benches/verify.rs b/tools/cycle_bench/benches/verify.rs index 648262f1..09d817f8 100644 --- a/tools/cycle_bench/benches/verify.rs +++ b/tools/cycle_bench/benches/verify.rs @@ -11,7 +11,7 @@ use std::{hint::black_box, time::Duration}; use anyhow::Context as _; use criterion::{Criterion, criterion_group, criterion_main}; use cycle_bench::ppe::prove_auth_transfer_in_ppe; -use lee::program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; +use lee::PRIVACY_PRESERVING_CIRCUIT_ID; use risc0_zkvm::{InnerReceipt, Receipt}; fn bench_verify(c: &mut Criterion) { diff --git a/tools/cycle_bench/src/main.rs b/tools/cycle_bench/src/main.rs index bed61f92..5be5f367 100644 --- a/tools/cycle_bench/src/main.rs +++ b/tools/cycle_bench/src/main.rs @@ -24,18 +24,14 @@ use std::{path::PathBuf, time::Instant}; use amm_core::{PoolDefinition, compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda}; use anyhow::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 clap::Parser; use clock_core::{ CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, ClockAccountData, }; use cycle_bench::{ppe, stats::Stats}; -use lee::program_methods::{ - AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID, - AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, TOKEN_ELF, - TOKEN_ID, -}; +use lee::program::Program; use lee_core::{ Timestamp, account::{Account, AccountId, AccountWithMetadata, Data}, @@ -66,7 +62,7 @@ struct Cli { #[derive(Debug, Serialize)] struct BenchResult { - program: &'static str, + program_name: &'static str, instruction: &'static str, user_cycles: u64, segments: usize, @@ -175,28 +171,25 @@ impl Calibration { } struct Case { - program: &'static str, + program_name: &'static str, instruction_label: &'static str, - elf: &'static [u8], - self_program_id: ProgramId, + program: Program, pre_states: Vec, instruction_words: InstructionData, } impl Case { fn new( - program: &'static str, + program_name: &'static str, instruction_label: &'static str, - elf: &'static [u8], - self_program_id: ProgramId, + program: Program, pre_states: Vec, instruction: &I, ) -> Result { Ok(Self { - program, + program_name, instruction_label, - elf, - self_program_id, + program, pre_states, instruction_words: risc0_zkvm::serde::to_vec(instruction)?, }) @@ -204,10 +197,9 @@ impl Case { fn run(self, prove: bool, exec_iters: usize) -> Result { let Self { - program, + program_name, instruction_label, - elf, - self_program_id, + program, pre_states, instruction_words, } = self; @@ -222,14 +214,14 @@ impl Case { for iter in 0..total { let mut env_builder = ExecutorEnv::builder(); env_builder - .write(&self_program_id)? + .write(&program.id())? .write(&caller_program_id)? .write(&pre_states)? .write(&instruction_words)?; let env = env_builder.build()?; let started = Instant::now(); - let info = default_executor().execute(env, elf)?; + let info = default_executor().execute(env, program.elf())?; let elapsed_ms = started.elapsed().as_secs_f64() * 1_000.0; if iter > 0 { @@ -248,7 +240,7 @@ impl Case { if prove { let mut env_builder = ExecutorEnv::builder(); env_builder - .write(&self_program_id)? + .write(&program.id())? .write(&caller_program_id)? .write(&pre_states)? .write(&instruction_words)?; @@ -256,7 +248,7 @@ impl Case { let started = Instant::now(); let prove_info = default_prover() - .prove(env, elf) + .prove(env, program.elf()) .map_err(|e| anyhow::anyhow!("prove failed: {e}"))?; let prove_ms = started.elapsed().as_secs_f64() * 1_000.0; prove_stats = Some(Stats::from_samples(&[prove_ms])); @@ -265,7 +257,7 @@ impl Case { prove_paging_cycles = Some(prove_info.stats.paging_cycles); prove_segments = Some(prove_info.stats.segments); eprintln!( - " prove({program}/{instruction_label}): {prove_ms:.1} ms ({:.1}s), total_cycles={}, segments={}", + " prove({program_name}/{instruction_label}): {prove_ms:.1} ms ({:.1}s), total_cycles={}, segments={}", prove_ms / 1_000.0, prove_info.stats.total_cycles, prove_info.stats.segments, @@ -273,7 +265,7 @@ impl Case { } Ok(BenchResult { - program, + program_name, instruction: instruction_label, user_cycles: info.cycles(), segments: info.segments.len(), @@ -322,7 +314,7 @@ fn token_holding( ) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: TOKEN_ID, + program_owner: programs::token().id(), balance: 0, data: Data::from(&TokenHolding::Fungible { definition_id, @@ -342,7 +334,7 @@ fn token_definition( ) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: TOKEN_ID, + program_owner: programs::token().id(), balance: 0, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -380,7 +372,7 @@ fn token_burn_pre_states() -> Vec { fn clock_account(account_id: AccountId, block_id: u64) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: CLOCK_ID, + program_owner: programs::clock().id(), balance: 0, data: ClockAccountData { block_id, @@ -411,16 +403,20 @@ fn amm_token_b_def_id() -> AccountId { AccountId::new([43; 32]) } fn amm_pool_id() -> AccountId { - compute_pool_pda(AMM_ID, amm_token_a_def_id(), amm_token_b_def_id()) + compute_pool_pda( + programs::amm().id(), + amm_token_a_def_id(), + amm_token_b_def_id(), + ) } fn amm_vault_a_id() -> AccountId { - compute_vault_pda(AMM_ID, amm_pool_id(), amm_token_a_def_id()) + compute_vault_pda(programs::amm().id(), amm_pool_id(), amm_token_a_def_id()) } fn amm_vault_b_id() -> AccountId { - compute_vault_pda(AMM_ID, amm_pool_id(), amm_token_b_def_id()) + compute_vault_pda(programs::amm().id(), amm_pool_id(), amm_token_b_def_id()) } fn amm_lp_def_id() -> AccountId { - compute_liquidity_token_pda(AMM_ID, amm_pool_id()) + compute_liquidity_token_pda(programs::amm().id(), amm_pool_id()) } /// Pool seeded with reserves `1_000` / `500`, lp supply `sqrt(1000*500) = 707`. @@ -430,7 +426,7 @@ fn amm_pool_account() -> AccountWithMetadata { let lp_supply = (reserve_a * reserve_b).isqrt(); AccountWithMetadata { account: Account { - program_owner: AMM_ID, + program_owner: programs::amm().id(), balance: 0, data: Data::from(&PoolDefinition { definition_token_a_id: amm_token_a_def_id(), @@ -482,7 +478,7 @@ fn ata_create_pre_states() -> Vec { }; let token_def = token_definition(definition_id, 100_000, false); let seed = compute_ata_seed(owner_id, definition_id); - let ata_id = get_associated_token_account_id(&ASSOCIATED_TOKEN_ACCOUNT_ID, &seed); + let ata_id = get_associated_token_account_id(&programs::ata().id(), &seed); let ata_account = AccountWithMetadata { account: Account::default(), is_authorized: false, @@ -503,24 +499,21 @@ fn main() -> Result<()> { Case::new( "authenticated_transfer", "Transfer", - AUTHENTICATED_TRANSFER_ELF, - AUTHENTICATED_TRANSFER_ID, + programs::authenticated_transfer(), authenticated_transfer_transfer(), &authenticated_transfer_core::Instruction::Transfer { amount: 5_000 }, )?, Case::new( "authenticated_transfer", "Initialize", - AUTHENTICATED_TRANSFER_ELF, - AUTHENTICATED_TRANSFER_ID, + programs::authenticated_transfer(), authenticated_transfer_init(), &authenticated_transfer_core::Instruction::Initialize, )?, Case::new( "token", "Transfer", - TOKEN_ELF, - TOKEN_ID, + programs::token(), token_transfer_pre_states(), &token_core::Instruction::Transfer { amount_to_transfer: 5_000, @@ -529,8 +522,7 @@ fn main() -> Result<()> { Case::new( "token", "Mint", - TOKEN_ELF, - TOKEN_ID, + programs::token(), token_mint_pre_states(), &token_core::Instruction::Mint { amount_to_mint: 5_000, @@ -539,8 +531,7 @@ fn main() -> Result<()> { Case::new( "token", "Burn", - TOKEN_ELF, - TOKEN_ID, + programs::token(), token_burn_pre_states(), &token_core::Instruction::Burn { amount_to_burn: 500, @@ -549,16 +540,14 @@ fn main() -> Result<()> { Case::new( "clock", "Tick (block_id+1, no multiples)", - CLOCK_ELF, - CLOCK_ID, + programs::clock(), clock_pre_states_tick_at(0), &Timestamp::from(1_700_000_000_u64), )?, Case::new( "amm", "SwapExactInput", - AMM_ELF, - AMM_ID, + programs::amm(), amm_swap_pre_states(), &amm_core::Instruction::SwapExactInput { swap_amount_in: 200, @@ -569,8 +558,7 @@ fn main() -> Result<()> { Case::new( "amm", "AddLiquidity", - AMM_ELF, - AMM_ID, + programs::amm(), amm_add_liquidity_pre_states(), &amm_core::Instruction::AddLiquidity { min_amount_liquidity: 1, @@ -581,11 +569,10 @@ fn main() -> Result<()> { Case::new( "ata", "Create", - ASSOCIATED_TOKEN_ACCOUNT_ELF, - ASSOCIATED_TOKEN_ACCOUNT_ID, + programs::ata(), ata_create_pre_states(), - &ata_core::Instruction::Create { - ata_program_id: ASSOCIATED_TOKEN_ACCOUNT_ID, + &associated_token_account_core::Instruction::Create { + ata_program_id: programs::ata().id(), }, )?, ]; @@ -661,7 +648,7 @@ fn print_calibration(cal: &Calibration) { fn print_table(results: &[BenchResult], prove: bool) { let pw = results .iter() - .map(|r| r.program.len()) + .map(|r| r.program_name.len()) .max() .unwrap_or(0) .max("program".len()); @@ -701,7 +688,7 @@ fn print_table(results: &[BenchResult], prove: bool) { .map_or_else(|| "-".to_owned(), |v| format!("{v:.2}")); println!( "{:cw$} {:>sw$} {:dw$} {:>dw$}", - r.program, r.instruction, r.user_cycles, r.segments, r.exec_stats, calib, net, + r.program_name, r.instruction, r.user_cycles, r.segments, r.exec_stats, calib, net, ); } @@ -728,7 +715,7 @@ fn print_table(results: &[BenchResult], prove: bool) { .map_or_else(|| "-".to_owned(), |s| s.to_string()); println!( "{:pcw$} {:>pwallw$} {:>psw$}", - r.program, r.instruction, total, pms, psegs, + r.program_name, r.instruction, total, pms, psegs, ); } } @@ -744,7 +731,7 @@ mod tests { /// `user_cycles` (x) and `exec_stats.best_ms` (y). fn point(user_cycles: u64, best_ms: f64) -> BenchResult { BenchResult { - program: "test", + program_name: "test", instruction: "test", user_cycles, segments: 1, diff --git a/tools/cycle_bench/src/ppe/ppe_impl.rs b/tools/cycle_bench/src/ppe/ppe_impl.rs index 4d47bebc..e85c95f2 100644 --- a/tools/cycle_bench/src/ppe/ppe_impl.rs +++ b/tools/cycle_bench/src/ppe/ppe_impl.rs @@ -8,25 +8,15 @@ use std::{collections::HashMap, time::Instant}; use lee::{ execute_and_prove, privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof}, - program::Program, }; use lee_core::{ InputAccountIdentity, PrivacyPreservingCircuitOutput, account::{Account, AccountId, AccountWithMetadata}, - program::ProgramId, }; use risc0_zkvm::serde::to_vec; use super::PpeBenchResult; -const AUTH_TRANSFER_ID: ProgramId = lee::program_methods::AUTHENTICATED_TRANSFER_ID; -const AUTH_TRANSFER_ELF: &[u8] = lee::program_methods::AUTHENTICATED_TRANSFER_ELF; - -/// `chain_caller` bytecode shipped at `artifacts/test_program_methods/chain_caller.bin`. -/// Loaded at compile time so we don't need a dev-dependency on `test_program_methods`. -const CHAIN_CALLER_ELF: &[u8] = - include_bytes!("../../../../artifacts/test_program_methods/chain_caller.bin"); - pub fn run_auth_transfer_in_ppe() -> PpeBenchResult { let label = "auth_transfer Transfer in PPE".to_owned(); let started = Instant::now(); @@ -52,15 +42,16 @@ pub fn run_auth_transfer_in_ppe() -> PpeBenchResult { } pub fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> { - let program = Program::new(AUTH_TRANSFER_ELF.to_vec())?; - let pwd = ProgramWithDependencies::from(program); + let auth_transfer = programs::authenticated_transfer(); + let auth_transfer_id = auth_transfer.id(); + let pwd = ProgramWithDependencies::from(auth_transfer); // For PPE to allow the sender's balance to be decremented by this // program, the sender must already be claimed by auth_transfer. // Recipient stays default-owned so the first call can claim it. let sender = AccountWithMetadata { account: Account { - program_owner: AUTH_TRANSFER_ID, + program_owner: auth_transfer_id, balance: 1_000_000, ..Account::default() }, @@ -114,10 +105,11 @@ pub fn run_chain_caller(depth: u32) -> PpeBenchResult { fn prove_chain_caller( num_chain_calls: u32, ) -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> { - let chain_caller = Program::new(CHAIN_CALLER_ELF.to_vec())?; - let auth_transfer = Program::new(AUTH_TRANSFER_ELF.to_vec())?; + let chain_caller = test_programs::chain_caller(); + let auth_transfer = programs::authenticated_transfer(); + let auth_transfer_id = auth_transfer.id(); let mut deps = HashMap::new(); - deps.insert(AUTH_TRANSFER_ID, auth_transfer); + deps.insert(auth_transfer.id(), auth_transfer); let pwd = ProgramWithDependencies::new(chain_caller, deps); // Both accounts pre-claimed by auth_transfer. chain_caller doesn't @@ -125,7 +117,7 @@ fn prove_chain_caller( // would cause a state mismatch on subsequent chained calls. let recipient_pre = AccountWithMetadata { account: Account { - program_owner: AUTH_TRANSFER_ID, + program_owner: auth_transfer_id, ..Account::default() }, is_authorized: true, @@ -133,7 +125,7 @@ fn prove_chain_caller( }; let sender_pre = AccountWithMetadata { account: Account { - program_owner: AUTH_TRANSFER_ID, + program_owner: auth_transfer_id, balance: 1_000_000, ..Account::default() }, @@ -145,7 +137,7 @@ fn prove_chain_caller( let balance: u128 = 1; let pda_seed: Option = None; - let instruction = (balance, AUTH_TRANSFER_ID, num_chain_calls, pda_seed); + let instruction = (balance, auth_transfer_id, num_chain_calls, pda_seed); let instruction_data = to_vec(&instruction)?; let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];