Merge origin/main

Integrates origin/main (per-program-crate refactor) and re-homes the cross-zone messaging feature onto it.

BREAKING CHANGE: Genesis state root changes. This registers six builtin programs
(cross_zone_outbox, cross_zone_inbox, ping_sender, ping_receiver, bridge_lock,
wrapped_token) and seeds their genesis accounts (the wrapped_token authorized
minter config, the per-zone inbox config, and optional bridge-lock holdings).
Building the new cores alongside the existing builtins also enables serde/alloc
for the shared programs build, regenerating every builtin program image id. All
nodes must upgrade together.
This commit is contained in:
moudyellaz 2026-07-04 00:47:20 +02:00
commit 4f75e29a3c
344 changed files with 8888 additions and 4312 deletions

View File

@ -60,7 +60,7 @@ allow-git = [
"https://github.com/logos-blockchain/logos-blockchain.git",
"https://github.com/logos-blockchain/logos-blockchain-circuits.git",
"https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git",
"https://github.com/arkworks-rs/spongefish.git"
"https://github.com/arkworks-rs/spongefish.git",
]
unknown-git = "deny"
unknown-registry = "deny"

View File

@ -1,19 +0,0 @@
name: Setup Logos Blockchain Circuits
description: Set up Logos Blockchain Circom Circuits, Rapidsnark prover and Rapidsnark verifier using the setup-logos-blockchain-circuits.sh script.
inputs:
github-token:
description: GitHub token for downloading releases
required: true
runs:
using: "composite"
steps:
- name: Setup logos-blockchain-circuits
shell: bash
working-directory: ${{ github.workspace }}
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
run: |
curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/6ac348bea4160ca708b70a86b3964e9f1ce82fff/scripts/setup-logos-blockchain-circuits.sh | bash

View File

@ -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

118
.github/workflows/pr-review-board.yml vendored Normal file
View File

@ -0,0 +1,118 @@
name: PR review board
# Keeps the org "LEZ PR Review Queue" board in sync for this repo.
# Adds each PR to the board and sets its Status column, enforcing the
# team rule that Approved means 2+ approvals.
on:
pull_request:
types: [opened, reopened, ready_for_review, converted_to_draft, closed, labeled, unlabeled]
pull_request_review:
types: [submitted, dismissed]
permissions:
contents: read
pull-requests: read
concurrency:
group: pr-review-board-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.PROJECT_PAT }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
PROJECT_ID: PVT_kwDODrxXXM4BbXZ_
STATUS_FIELD: PVTSSF_lADODrxXXM4BbXZ_zhWIZnU
OPT_DRAFT: f735bdac
OPT_NEEDS: cbc7321d
OPT_CHANGES: 302bbbd6
OPT_APPROVED: c9e0743e
PRIORITY_FIELD: PVTSSF_lADODrxXXM4BbXZ_zhWIyPA
PRIO_URGENT: b72854fd
PRIO_HIGH: 5e87ebf9
PRIO_MEDIUM: 22367611
PRIO_LOW: 41f60140
steps:
- name: Sync PR status to board
run: |
set -euo pipefail
DATA=$(gh pr view "$PR" --repo "$REPO" --json id,isDraft,mergedAt,state,latestReviews,labels)
PR_NODE=$(echo "$DATA" | jq -r '.id')
IS_DRAFT=$(echo "$DATA" | jq -r '.isDraft')
MERGED=$(echo "$DATA" | jq -r '(.mergedAt != null)')
STATE=$(echo "$DATA" | jq -r '.state')
NAP=$(echo "$DATA" | jq '[.latestReviews[] | select(.state=="APPROVED")] | length')
NCH=$(echo "$DATA" | jq '[.latestReviews[] | select(.state=="CHANGES_REQUESTED")] | length')
if [ "$STATE" = "CLOSED" ] && [ "$MERGED" != "true" ]; then
echo "PR #$PR closed unmerged; leaving board entry untouched."
exit 0
fi
# Add to the project (idempotent: returns existing item if already present)
ITEM=$(gh api graphql -f query='
mutation($p:ID!, $c:ID!) {
addProjectV2ItemById(input:{projectId:$p, contentId:$c}) { item { id } }
}' -f p="$PROJECT_ID" -f c="$PR_NODE" --jq '.data.addProjectV2ItemById.item.id')
# Merged PRs are archived off the active board
if [ "$MERGED" = "true" ]; then
gh api graphql -f query='
mutation($p:ID!, $i:ID!) {
archiveProjectV2Item(input:{projectId:$p, itemId:$i}) { item { id } }
}' -f p="$PROJECT_ID" -f i="$ITEM"
echo "$REPO#$PR merged -> archived"
exit 0
fi
# Status
if [ "$IS_DRAFT" = "true" ]; then
OPT=$OPT_DRAFT; LABEL="Draft"
elif [ "$NCH" -gt 0 ]; then
OPT=$OPT_CHANGES; LABEL="Changes requested"
elif [ "$NAP" -ge 2 ]; then
OPT=$OPT_APPROVED; LABEL="Approved"
else
OPT=$OPT_NEEDS; LABEL="Needs review"
fi
gh api graphql -f query='
mutation($p:ID!, $i:ID!, $f:ID!, $o:String!) {
updateProjectV2ItemFieldValue(input:{
projectId:$p, itemId:$i, fieldId:$f,
value:{ singleSelectOptionId:$o }
}) { projectV2Item { id } }
}' -f p="$PROJECT_ID" -f i="$ITEM" -f f="$STATUS_FIELD" -f o="$OPT"
# Set Priority from a priority:* label (clear it when none is present)
LABELS=$(echo "$DATA" | jq -r '.labels[].name')
case "$LABELS" in
*priority:urgent*) POPT=$PRIO_URGENT ;;
*priority:high*) POPT=$PRIO_HIGH ;;
*priority:medium*) POPT=$PRIO_MEDIUM ;;
*priority:low*) POPT=$PRIO_LOW ;;
*) POPT="" ;;
esac
if [ -n "$POPT" ]; then
gh api graphql -f query='
mutation($p:ID!, $i:ID!, $f:ID!, $o:String!) {
updateProjectV2ItemFieldValue(input:{
projectId:$p, itemId:$i, fieldId:$f,
value:{ singleSelectOptionId:$o }
}) { projectV2Item { id } }
}' -f p="$PROJECT_ID" -f i="$ITEM" -f f="$PRIORITY_FIELD" -f o="$POPT"
else
gh api graphql -f query='
mutation($p:ID!, $i:ID!, $f:ID!) {
clearProjectV2ItemFieldValue(input:{
projectId:$p, itemId:$i, fieldId:$f
}) { projectV2Item { id } }
}' -f p="$PROJECT_ID" -f i="$ITEM" -f f="$PRIORITY_FIELD"
fi
echo "$REPO#$PR (approvals=$NAP changes=$NCH) -> $LABEL"

View File

@ -7,7 +7,38 @@ on:
- "v*"
jobs:
# Shared base (toolchain + r0vm), single source of truth in
# lez/docker/risc0-base.Dockerfile. Built and pushed once so the service
# builds below can pull it as the `risc0_base` named context. The
# docker-container builder resolves named contexts from the registry (not the
# host image store), so the base must be pushed, not just loaded.
risc0_base:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push risc0 base image
uses: docker/build-push-action@v5
with:
context: .
file: ./lez/docker/risc0-base.Dockerfile
push: true
tags: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository }}/risc0_base:sha-${{ github.sha }}
cache-from: type=gha,scope=risc0-base
cache-to: type=gha,mode=max,scope=risc0-base
publish:
needs: risc0_base
runs-on: ubuntu-latest
strategy:
matrix:
@ -62,5 +93,6 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: ${{ matrix.build_args }}
build-contexts: risc0_base=docker-image://${{ secrets.DOCKER_REGISTRY }}/${{ github.repository }}/risc0_base:sha-${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

10
.gitignore vendored
View File

@ -1,17 +1,25 @@
.gitconfig
res/
target/
deps/
data/
.idea/
.vscode/
rocksdb
rocksdb*
sequencer/service/data/
storage.json
result
wallet-ffi/wallet_ffi.h
bedrock_signing_key
integration_tests/configs/debug/
venv/
keycard_wallet/python/__pycache__/
keycard_wallet/python/keycard-py/
.DS_Store

299
Cargo.lock generated
View File

@ -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"
@ -975,9 +984,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
name = "bitcoin_hashes"
version = "0.14.100"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9901a56e133a1fc86eeb1113e2591f45f4682451ca893bff494d2f88918e3f"
checksum = "4ed83caece3afc59919481b33b472e1432d1abc4641ed9100be142ef5110b406"
dependencies = [
"hex-conservative",
]
@ -1149,11 +1158,31 @@ dependencies = [
name = "bridge_lock_core"
version = "0.1.0"
dependencies = [
"lee",
"lee_core",
"serde",
]
[[package]]
name = "bridge_lock_program"
version = "0.1.0"
dependencies = [
"bridge_lock_core",
"cross_zone_outbox_core",
"lee_core",
"risc0-zkvm",
"wrapped_token_core",
]
[[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"
@ -1163,6 +1192,14 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "build_utils"
version = "0.1.0"
dependencies = [
"anyhow",
"risc0-binfmt",
]
[[package]]
name = "bumpalo"
version = "3.20.3"
@ -1461,6 +1498,14 @@ dependencies = [
"lee_core",
]
[[package]]
name = "clock_program"
version = "0.1.0"
dependencies = [
"clock_core",
"lee_core",
]
[[package]]
name = "cmov"
version = "0.5.4"
@ -1523,9 +1568,11 @@ dependencies = [
"lee_core",
"log",
"logos-blockchain-common-http-client",
"programs",
"serde",
"serde_with",
"sha2",
"system_accounts",
"thiserror 2.0.18",
]
@ -1805,19 +1852,37 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "cross_zone"
version = "0.1.0"
dependencies = [
"bridge_lock_core",
"cross_zone_inbox_core",
"lee",
"lee_core",
"ping_core",
"programs",
"risc0-zkvm",
]
[[package]]
name = "cross_zone_inbox_core"
version = "0.1.0"
dependencies = [
"borsh",
"bridge_lock_core",
"lee",
"lee_core",
"ping_core",
"risc0-zkvm",
"serde",
]
[[package]]
name = "cross_zone_inbox_program"
version = "0.1.0"
dependencies = [
"cross_zone_inbox_core",
"lee_core",
]
[[package]]
name = "cross_zone_outbox_core"
version = "0.1.0"
@ -1828,6 +1893,14 @@ dependencies = [
"serde",
]
[[package]]
name = "cross_zone_outbox_program"
version = "0.1.0"
dependencies = [
"cross_zone_outbox_core",
"lee_core",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.15"
@ -1964,7 +2037,7 @@ version = "0.1.0"
dependencies = [
"amm_core",
"anyhow",
"ata_core",
"associated_token_account_core",
"authenticated_transfer_core",
"borsh",
"clap",
@ -1972,9 +2045,11 @@ dependencies = [
"criterion",
"lee",
"lee_core",
"programs",
"risc0-zkvm",
"serde",
"serde_json",
"test_programs",
"token_core",
]
@ -2070,7 +2145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
dependencies = [
"data-encoding",
"syn 2.0.117",
"syn 1.0.109",
]
[[package]]
@ -2672,6 +2747,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"
@ -3831,11 +3916,13 @@ name = "indexer_core"
version = "0.1.0"
dependencies = [
"anyhow",
"arc-swap",
"async-stream",
"authenticated_transfer_core",
"borsh",
"bridge_lock_core",
"common",
"cross_zone",
"cross_zone_inbox_core",
"futures",
"hex",
@ -3846,6 +3933,7 @@ dependencies = [
"logos-blockchain-core",
"logos-blockchain-zone-sdk",
"ping_core",
"programs",
"risc0-zkvm",
"serde",
"serde_json",
@ -3860,16 +3948,15 @@ dependencies = [
name = "indexer_ffi"
version = "0.1.0"
dependencies = [
"anyhow",
"cbindgen",
"indexer_service",
"env_logger",
"futures",
"indexer_core",
"indexer_service_protocol",
"indexer_service_rpc",
"jsonrpsee",
"lee",
"log",
"serde_json",
"tokio",
"url",
]
[[package]]
@ -3996,7 +4083,7 @@ name = "integration_tests"
version = "0.1.0"
dependencies = [
"anyhow",
"ata_core",
"associated_token_account_core",
"authenticated_transfer_core",
"borsh",
"bridge_core",
@ -4021,13 +4108,16 @@ dependencies = [
"logos-blockchain-zone-sdk",
"num-bigint 0.4.6",
"ping_core",
"programs",
"reqwest",
"risc0-zkvm",
"sequencer_core",
"sequencer_service_rpc",
"serde_json",
"system_accounts",
"tempfile",
"test_fixtures",
"test_programs",
"token_core",
"tokio",
"vault_core",
@ -4542,33 +4632,24 @@ name = "lee"
version = "0.1.0"
dependencies = [
"anyhow",
"authenticated_transfer_core",
"borsh",
"bridge_core",
"bridge_lock_core",
"clock_core",
"cross_zone_inbox_core",
"cross_zone_outbox_core",
"build_utils",
"env_logger",
"faucet_core",
"hex",
"hex-literal 1.1.0",
"k256",
"lee_core",
"log",
"ping_core",
"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",
"wrapped_token_core",
]
[[package]]
@ -7160,6 +7241,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 = "ping_core"
version = "0.1.0"
@ -7168,6 +7266,23 @@ dependencies = [
"serde",
]
[[package]]
name = "ping_receiver_program"
version = "0.1.0"
dependencies = [
"lee_core",
"ping_core",
]
[[package]]
name = "ping_sender_program"
version = "0.1.0"
dependencies = [
"cross_zone_outbox_core",
"lee_core",
"ping_core",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
@ -7321,6 +7436,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"
@ -7422,32 +7545,26 @@ 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",
"bridge_lock_core",
"build_utils",
"clock_core",
"cross_zone_inbox_core",
"cross_zone_outbox_core",
"faucet_core",
"lee",
"lee_core",
"ping_core",
"risc0-zkvm",
"serde",
"token_core",
"token_program",
"vault_core",
@ -7671,9 +7788,9 @@ dependencies = [
[[package]]
name = "quinn-proto"
version = "0.11.14"
version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
dependencies = [
"bytes",
"getrandom 0.3.4",
@ -8887,10 +9004,10 @@ dependencies = [
"anyhow",
"borsh",
"bridge_core",
"bridge_lock_core",
"bytesize",
"chrono",
"common",
"cross_zone",
"cross_zone_inbox_core",
"faucet_core",
"futures",
@ -8905,14 +9022,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",
@ -8933,6 +9053,7 @@ dependencies = [
"lee",
"log",
"mempool",
"programs",
"sequencer_core",
"sequencer_service_protocol",
"sequencer_service_rpc",
@ -9451,7 +9572,9 @@ dependencies = [
"borsh",
"common",
"lee",
"programs",
"rocksdb",
"system_accounts",
"tempfile",
"thiserror 2.0.18",
]
@ -9604,6 +9727,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"
@ -9726,6 +9860,7 @@ dependencies = [
"lee",
"lee_core",
"log",
"programs",
"sequencer_core",
"sequencer_service",
"sequencer_service_rpc",
@ -9739,14 +9874,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",
@ -9754,7 +9898,14 @@ dependencies = [
"faucet_core",
"lee_core",
"risc0-zkvm",
"serde",
]
[[package]]
name = "test_programs"
version = "0.1.0"
dependencies = [
"lee",
"risc0-build",
]
[[package]]
@ -9794,11 +9945,13 @@ dependencies = [
name = "testnet_initial_state"
version = "0.1.0"
dependencies = [
"common",
"key_protocol",
"lee",
"lee_core",
"programs",
"serde",
"system_accounts",
"wrapped_token_core",
]
[[package]]
@ -10756,6 +10909,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"
@ -10784,8 +10946,8 @@ version = "0.1.0"
dependencies = [
"amm_core",
"anyhow",
"associated_token_account_core",
"async-stream",
"ata_core",
"authenticated_transfer_core",
"base58",
"bincode",
@ -10807,6 +10969,7 @@ dependencies = [
"lee_core",
"log",
"optfield",
"programs",
"pyo3",
"rand 0.8.6",
"rpassword",
@ -10814,6 +10977,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"system_accounts",
"tempfile",
"testnet_initial_state",
"thiserror 2.0.18",
@ -10828,16 +10992,19 @@ dependencies = [
name = "wallet-ffi"
version = "0.1.0"
dependencies = [
"bip39",
"cbindgen",
"common",
"key_protocol",
"lee",
"lee_core",
"programs",
"risc0-zkvm",
"sequencer_service_rpc",
"serde_json",
"tempfile",
"tokio",
"vault_core",
"wallet",
]
@ -11504,6 +11671,14 @@ dependencies = [
"serde",
]
[[package]]
name = "wrapped_token_program"
version = "0.1.0"
dependencies = [
"lee_core",
"wrapped_token_core",
]
[[package]]
name = "writeable"
version = "0.6.3"

View File

@ -5,30 +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",
"programs/cross_zone_outbox/core",
"programs/cross_zone_inbox/core",
"programs/ping/core",
"programs/wrapped_token/core",
"programs/bridge_lock/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",
@ -38,18 +25,43 @@ 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",
"lez/programs/cross_zone_inbox",
"lez/programs/cross_zone_outbox",
"lez/programs/bridge_lock",
"lez/programs/wrapped_token",
"lez/programs/ping_sender",
"lez/programs/ping_receiver",
"lez/cross_zone",
"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",
@ -74,23 +86,29 @@ 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" }
cross_zone_outbox_core = { path = "programs/cross_zone_outbox/core" }
cross_zone_inbox_core = { path = "programs/cross_zone_inbox/core" }
ping_core = { path = "programs/ping/core" }
wrapped_token_core = { path = "programs/wrapped_token/core" }
bridge_lock_core = { path = "programs/bridge_lock/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" }
cross_zone_inbox_core = { path = "lez/programs/cross_zone_inbox/core" }
cross_zone_outbox_core = { path = "lez/programs/cross_zone_outbox/core" }
bridge_lock_core = { path = "lez/programs/bridge_lock/core" }
wrapped_token_core = { path = "lez/programs/wrapped_token/core" }
ping_core = { path = "lez/programs/ping_core" }
cross_zone = { path = "lez/cross_zone" }
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" }
@ -127,6 +145,7 @@ hex = "0.4.3"
bytemuck = "1.24.0"
bytesize = { version = "2.3.1", features = ["serde"] }
humantime-serde = "1.1"
arc-swap = "1.7"
humantime = "2.1"
aes-gcm = "0.10.3"
toml = "0.9.8"

View File

@ -4,8 +4,6 @@ default:
@just --list
# ---- Configuration ----
METHODS_PATH := "program_methods"
TEST_METHODS_PATH := "test_program_methods"
ARTIFACTS := "artifacts"
# On macOS the integration-test binary links pyo3 against the CommandLineTools
@ -16,12 +14,20 @@ DEMO_ENV := if os() == "macos" { "DYLD_FALLBACK_FRAMEWORK_PATH=/Library/Develope
# 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:
@ -64,10 +70,10 @@ run-indexer mock="":
@echo "🔍 Running indexer"
@if [ "{{mock}}" = "mock" ]; then \
echo "🧪 Using mock data"; \
RUST_LOG=info cargo run --release --features mock-responses -p indexer_service configs/indexer_config.json; \
RUST_LOG=info cargo run --release --features mock-responses -p indexer_service configs/debug/indexer_config.json; \
else \
echo "🚀 Using real data"; \
RUST_LOG=info cargo run --release -p indexer_service configs/indexer_config.json; \
RUST_LOG=info cargo run --release -p indexer_service configs/debug/indexer_config.json; \
fi
# Run Explorer.
@ -111,7 +117,7 @@ clean:
@echo "🧹 Cleaning run artifacts"
rm -rf lez/sequencer/service/bedrock_signing_key
rm -rf lez/sequencer/service/rocksdb
rm -rf lez/indexer/service/rocksdb
rm -rf lez/indexer/service/rocksdb*
rm -rf lez/wallet/configs/debug/storage.json
rm -rf rocksdb
rm -rf rocksdb*
cd bedrock && docker compose down -v

View File

@ -156,7 +156,7 @@ The sequencer and logos blockchain node can be run locally:
- `docker compose up`
2. On another terminal go to the `logos-blockchain/logos-execution-zone` repo and run indexer service:
- `RUST_LOG=info cargo run -p indexer_service lez/indexer/service/configs/indexer_config.json`
- `RUST_LOG=info cargo run -p indexer_service lez/indexer/service/configs/debug/indexer_config.json`
3. On another terminal go to the `logos-blockchain/logos-execution-zone` repo and run the sequencer:
- `RUST_LOG=info cargo run -p sequencer_service lez/sequencer/service/configs/debug/sequencer_config.json`

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,7 +3,7 @@ services:
logos-blockchain-node-0:
image: ghcr.io/logos-blockchain/logos-blockchain@sha256:91d6c5bf07e07fcfba5e7cf07d21ee686a6bc4b9f6210f2d28bffbcad9a3729f
ports:
- "${PORT:-8080}:18080/tcp"
- "${PORT:-18080}:18080/tcp"
volumes:
- ./scripts:/etc/logos-blockchain/scripts
- ./kzgrs_test_params:/kzgrs_test_params:z

11
build_utils/Cargo.toml Normal file
View File

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

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

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

View File

@ -2,8 +2,6 @@
services:
logos-blockchain-node-0:
ports: !override
- "18080:18080/tcp"
environment:
- RUST_LOG=error

View File

@ -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<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
let program = Program::new(bytecode.into()).unwrap();
```
The Risc0 ELF is read from disk and wrapped in a Program object, which can be used to compute the program ID. The ID is used by the node to identify which program is invoked by the transaction.
@ -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 \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

2222
flake.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -99,6 +99,28 @@
sha256 = recursionZkrHash;
};
# risc0 compiles its Metal (GPU) prover kernels by invoking
# `xcrun metal` / `xcrun metallib`. Under nix, the darwin stdenv sets
# DEVELOPER_DIR/SDKROOT to its own SDK, which makes `xcrun` look for
# the `metal` tool in the wrong place and fail with
# error: cannot execute tool 'metal' due to missing Metal Toolchain
# even when a working Metal Toolchain is installed. This wrapper, put
# first in PATH, clears those two vars for metal/metallib invocations
# only — so they resolve the real system Xcode Metal Toolchain — while
# every other xcrun call passes through with the nix environment
# intact. (On recent macOS the Metal Toolchain is a per-user component;
# `xcodebuild -downloadComponent MetalToolchain` must have been run.)
metalStub = pkgs.writeShellScriptBin "xcrun" ''
tool=
for a in "$@"; do
case "$a" in metal|metallib) tool=1 ;; esac
done
if [ -n "$tool" ]; then
unset DEVELOPER_DIR SDKROOT
fi
exec /usr/bin/xcrun "$@"
'';
commonArgs = {
inherit src;
buildInputs = [ pkgs.openssl ];
@ -118,13 +140,14 @@
RECURSION_SRC_PATH = "${recursionZkr}";
# Provide a writable HOME so risc0-build-kernel can use its cache directory
# (needed on macOS for Metal kernel compilation cache).
# On macOS, append /usr/bin to PATH so xcrun (Metal compiler) can be found,
# while keeping Nix tools (like gnutar) first in PATH.
# On macOS, put the metalStub xcrun wrapper first so `xcrun metal` /
# `metallib` resolve the system Metal Toolchain (see metalStub above),
# and append /usr/bin for the real xcrun it execs.
# This requires running with --option sandbox false for Metal GPU support.
preBuild = ''
export HOME=$(mktemp -d)
'' + pkgs.lib.optionalString pkgs.stdenv.isDarwin ''
export PATH="$PATH:/usr/bin"
export PATH="${metalStub}/bin:$PATH:/usr/bin"
'';
};

View File

@ -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
@ -34,6 +33,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

View File

@ -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.

View File

@ -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(),

View File

@ -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),

View File

@ -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(),
);

View File

@ -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),

View File

@ -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"
);

View File

@ -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

View File

@ -1,14 +1,13 @@
#![expect(
clippy::tests_outside_test_module,
clippy::arithmetic_side_effects,
reason = "We don't care about these in tests"
reason = "top-level test functions are conventional for integration tests"
)]
//! Demo 2: a wrapped-token bridge over the cross-zone spine. A holder locks part
//! of their bridgeable balance on zone A; the watcher carries the emitted mint to
//! zone B, where the indexer re-derives and verifies it (Option B) before the
//! wrapped token is minted to the recipient. Reuses the M3/M4 spine unchanged;
//! only the source caller (bridge_lock) and target (wrapped_token) are new.
//! only the source caller (`bridge_lock`) and target (`wrapped_token`) are new.
use std::{net::SocketAddr, time::Duration};
@ -22,7 +21,6 @@ use integration_tests::{
};
use lee::{
AccountId, PrivateKey, PublicKey, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use sequencer_core::config::{CrossZoneConfig, CrossZonePeer, GenesisAction};
@ -49,7 +47,7 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> {
let holder_key = PrivateKey::try_new([7; 32]).expect("valid key");
let holder_id = AccountId::from(&PublicKey::new_from_private_key(&holder_key));
let wrapped_token_id = Program::wrapped_token().id();
let wrapped_token_id = programs::wrapped_token().id();
let cross_zone = CrossZoneConfig {
peers: vec![CrossZonePeer {
channel_id: *channel_a.as_ref(),
@ -105,7 +103,7 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> {
// has already landed (it preceded delivery), so zone A reflects the debit and
// escrow now.
let seq_a_client = sequencer_client(seq_a.addr())?;
let escrow_id = bridge_lock_core::escrow_account_id(Program::bridge_lock().id());
let escrow_id = bridge_lock_core::escrow_account_id(programs::bridge_lock().id());
let escrowed = bridge_lock_core::read_balance(
&seq_a_client.get_account(escrow_id).await?.data.into_inner(),
);
@ -124,16 +122,16 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> {
Ok(())
}
/// Builds a signed bridge_lock Lock that forwards a wrapped-token Mint of the
/// Builds a signed `bridge_lock` Lock that forwards a wrapped-token Mint of the
/// locked amount to the recipient on the target zone.
fn build_lock_tx(
holder_key: &PrivateKey,
holder_id: AccountId,
target_zone: [u8; 32],
) -> LeeTransaction {
let bridge_lock_id = Program::bridge_lock().id();
let wrapped_token_id = Program::wrapped_token().id();
let outbox_id = Program::cross_zone_outbox().id();
let bridge_lock_id = programs::bridge_lock().id();
let wrapped_token_id = programs::wrapped_token().id();
let outbox_id = programs::cross_zone_outbox().id();
let ordinal = 0;
let mint = wrapped_token_core::Instruction::Mint {

View File

@ -22,7 +22,6 @@ use integration_tests::{
};
use lee::{
PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
@ -40,13 +39,13 @@ async fn user_origin_inbox_call_rejected() -> Result<()> {
.context("Failed to set up sequencer")?;
// A user hand-builds a top-level inbox Dispatch and submits it via RPC.
let inbox_id = Program::cross_zone_inbox().id();
let inbox_id = programs::cross_zone_inbox().id();
let msg = CrossZoneMessage {
src_zone: [2; 32],
src_block_id: 1,
src_tx_index: 0,
src_program_id: [9; 8],
target_program_id: Program::ping_receiver().id(),
target_program_id: programs::ping_receiver().id(),
payload: vec![],
l1_inclusion_witness: None,
};

View File

@ -1,7 +1,6 @@
#![expect(
clippy::tests_outside_test_module,
clippy::arithmetic_side_effects,
reason = "We don't care about these in tests"
reason = "top-level test functions are conventional for integration tests"
)]
//! End-to-end cross-zone round trip: a ping submitted on zone A is delivered by
@ -21,7 +20,7 @@ use integration_tests::{
config::{self, SequencerPartialConfig},
setup::{setup_bedrock_node, setup_sequencer},
};
use lee::{AccountId, PublicTransaction, program::Program, public_transaction::Message};
use lee::{AccountId, PublicTransaction, public_transaction::Message};
use lee_core::program::ProgramId;
use ping_core::{ReceiverInstruction, SenderInstruction, ping_record_pda};
use sequencer_core::config::{CrossZoneConfig, CrossZonePeer};
@ -44,7 +43,7 @@ async fn ping_crosses_from_zone_a_to_zone_b() -> Result<()> {
let zone_a: [u8; 32] = *channel_a.as_ref();
let zone_b: [u8; 32] = *channel_b.as_ref();
let receiver_id = Program::ping_receiver().id();
let receiver_id = programs::ping_receiver().id();
// Zone B watches zone A and allows delivery only to ping_receiver.
let cross_zone = CrossZoneConfig {
@ -81,10 +80,10 @@ async fn ping_crosses_from_zone_a_to_zone_b() -> Result<()> {
Ok(())
}
/// Builds a top-level ping_sender transaction that chains into the outbox to emit
/// Builds a top-level `ping_sender` transaction that chains into the outbox to emit
/// a message carrying a `ping_receiver::Record` instruction for the target zone.
fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransaction {
let outbox_id = Program::cross_zone_outbox().id();
let outbox_id = programs::cross_zone_outbox().id();
let ordinal = 0;
// The payload is the ping_receiver instruction, serialized as risc0 words in
@ -106,7 +105,7 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio
let outbox_account = outbox_pda(outbox_id, &target_zone, ordinal);
let message = Message::try_new(
Program::ping_sender().id(),
programs::ping_sender().id(),
vec![outbox_account],
vec![],
send,

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