Merge pull request #654 from logos-blockchain/arjentix/bump-bedrock-and-sdk

feat(zone_sdk): update to a new bedrock & zone sdk
This commit is contained in:
Daniil Polyakov 2026-07-31 21:09:56 +03:00 committed by GitHub
commit 7132a899ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 1321 additions and 1118 deletions

373
Cargo.lock generated
View File

@ -499,7 +499,7 @@ dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom 7.1.3",
"nom",
"num-traits",
"rusticata-macros",
"thiserror 2.0.18",
@ -1220,7 +1220,6 @@ dependencies = [
name = "bridge_program"
version = "0.1.0"
dependencies = [
"authenticated_transfer_core",
"bridge_core",
"lee_core",
"vault_core",
@ -1405,7 +1404,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom 7.1.3",
"nom",
]
[[package]]
@ -2315,7 +2314,7 @@ checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
dependencies = [
"asn1-rs",
"displaydoc",
"nom 7.1.3",
"nom",
"num-bigint 0.4.6",
"num-traits",
"rusticata-macros",
@ -3037,15 +3036,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared 0.1.1",
]
[[package]]
name = "foreign-types"
version = "0.5.0"
@ -3053,7 +3043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [
"foreign-types-macros",
"foreign-types-shared 0.3.1",
"foreign-types-shared",
]
[[package]]
@ -3067,12 +3057,6 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "foreign-types-shared"
version = "0.3.1"
@ -3852,22 +3836,6 @@ dependencies = [
"tower-service",
]
[[package]]
name = "hyper-tls"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
"hyper",
"hyper-util",
"native-tls",
"tokio",
"tokio-native-tls",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.20"
@ -3886,11 +3854,9 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"socket2 0.6.4",
"system-configuration 0.7.0",
"tokio",
"tower-service",
"tracing",
"windows-registry",
]
[[package]]
@ -4304,7 +4270,6 @@ dependencies = [
"anyhow",
"associated_token_account_core",
"authenticated_transfer_core",
"borsh",
"bridge_core",
"bridge_lock_core",
"bytesize",
@ -4312,7 +4277,6 @@ dependencies = [
"cross_zone_inbox_core",
"cross_zone_outbox_core",
"faucet_core",
"futures",
"hex",
"indexer_ffi",
"indexer_service_protocol",
@ -4322,13 +4286,9 @@ dependencies = [
"lee_core",
"log",
"logos-blockchain-core",
"logos-blockchain-http-api-common",
"logos-blockchain-key-management-system-service",
"logos-blockchain-zone-sdk",
"num-bigint 0.4.6",
"ping_core",
"programs",
"reqwest",
"risc0-zkvm",
"sequencer_core",
"sequencer_service_rpc",
@ -5671,10 +5631,20 @@ version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f"
[[package]]
name = "logos-blockchain-blake2btree"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"blake2",
"logos-blockchain-dynamic-merkle",
"logos-blockchain-merkle-tree",
]
[[package]]
name = "logos-blockchain-blend-crypto"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"blake2",
"logos-blockchain-groth16",
@ -5687,8 +5657,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-blend-message"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"blake2",
"derivative",
@ -5696,6 +5666,7 @@ dependencies = [
"itertools 0.14.0",
"logos-blockchain-blend-crypto",
"logos-blockchain-blend-proofs",
"logos-blockchain-codec",
"logos-blockchain-core",
"logos-blockchain-cryptarchia-engine",
"logos-blockchain-groth16",
@ -5711,13 +5682,14 @@ dependencies = [
[[package]]
name = "logos-blockchain-blend-proofs"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ed25519-dalek",
"generic-array 1.4.3",
"hex",
"logos-blockchain-blend-crypto",
"logos-blockchain-codec",
"logos-blockchain-groth16",
"logos-blockchain-pol",
"logos-blockchain-poq",
@ -5731,8 +5703,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-chain-broadcast-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"derivative",
@ -5745,8 +5717,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-chain-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"bytes",
@ -5826,8 +5798,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-circuits-prover"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"rust-rapidsnark",
]
@ -5851,10 +5823,33 @@ dependencies = [
"libc",
]
[[package]]
name = "logos-blockchain-codec"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"hex",
"logos-blockchain-codec-macros",
"logos-blockchain-groth16",
"logos-blockchain-utils",
"thiserror 2.0.18",
]
[[package]]
name = "logos-blockchain-codec-macros"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"hex",
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "logos-blockchain-common-http-client"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"futures",
"hex",
@ -5876,17 +5871,18 @@ dependencies = [
[[package]]
name = "logos-blockchain-core"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ark-ff",
"bincode",
"blake2",
"bytes",
"const-hex",
"futures",
"hex",
"logos-blockchain-blake2btree",
"logos-blockchain-blend-proofs",
"logos-blockchain-codec",
"logos-blockchain-cryptarchia-engine",
"logos-blockchain-groth16",
"logos-blockchain-key-management-system-keys",
@ -5898,9 +5894,7 @@ dependencies = [
"logos-blockchain-utils",
"logos-blockchain-utxotree",
"multiaddr",
"nom 8.0.0",
"num-bigint 0.4.6",
"rpds",
"serde",
"strum",
"thiserror 2.0.18",
@ -5910,11 +5904,13 @@ dependencies = [
[[package]]
name = "logos-blockchain-cryptarchia-engine"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-codec",
"logos-blockchain-pol",
"logos-blockchain-utils",
"rpds",
"serde",
"serde_with",
"thiserror 2.0.18",
@ -5925,8 +5921,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-cryptarchia-sync"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"bytes",
"futures",
@ -5942,10 +5938,19 @@ dependencies = [
"tracing",
]
[[package]]
name = "logos-blockchain-dynamic-merkle"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"rpds",
"serde",
]
[[package]]
name = "logos-blockchain-groth16"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ark-bn254",
"ark-ec",
@ -5955,6 +5960,7 @@ dependencies = [
"generic-array 1.4.3",
"hex",
"num-bigint 0.4.6",
"rand 0.8.6",
"serde",
"serde_json",
"thiserror 2.0.18",
@ -5962,8 +5968,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-http-api-common"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"axum 0.7.9",
"logos-blockchain-core",
@ -5983,14 +5989,15 @@ dependencies = [
[[package]]
name = "logos-blockchain-key-management-system-keys"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"bytes",
"ed25519-dalek",
"generic-array 1.4.3",
"hex",
"logos-blockchain-codec",
"logos-blockchain-groth16",
"logos-blockchain-key-management-system-macros",
"logos-blockchain-log-targets",
@ -6010,8 +6017,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-key-management-system-macros"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"proc-macro2",
"quote",
@ -6020,8 +6027,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-key-management-system-operators"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"logos-blockchain-blend-proofs",
@ -6030,6 +6037,7 @@ dependencies = [
"logos-blockchain-key-management-system-keys",
"logos-blockchain-log-targets",
"logos-blockchain-poseidon2",
"logos-blockchain-utils",
"logos-blockchain-utxotree",
"tokio",
"tracing",
@ -6037,8 +6045,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-key-management-system-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"logos-blockchain-key-management-system-keys",
@ -6054,8 +6062,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-ledger"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"derivative",
"logos-blockchain-blend-crypto",
@ -6080,8 +6088,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-libp2p"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"backon",
@ -6109,30 +6117,42 @@ dependencies = [
[[package]]
name = "logos-blockchain-log-targets"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-log-targets-macros",
]
[[package]]
name = "logos-blockchain-log-targets-macros"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "logos-blockchain-merkle-tree"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-dynamic-merkle",
"rpds",
"serde",
"thiserror 2.0.18",
]
[[package]]
name = "logos-blockchain-mmr"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ark-ff",
"logos-blockchain-groth16",
"logos-blockchain-poseidon2",
"logos-blockchain-utils",
"rpds",
"serde",
"thiserror 2.0.18",
@ -6140,8 +6160,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-network-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"futures",
@ -6150,6 +6170,7 @@ dependencies = [
"logos-blockchain-libp2p",
"logos-blockchain-log-targets",
"logos-blockchain-tracing",
"logos-blockchain-utils",
"overwatch",
"rand 0.8.6",
"rand_chacha 0.3.1",
@ -6161,8 +6182,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-poc"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-circuits-poc-sys",
"logos-blockchain-circuits-prover",
@ -6178,8 +6199,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-pol"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"astro-float",
"logos-blockchain-circuits-pol-sys",
@ -6198,8 +6219,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-poq"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-circuits-poq-sys",
"logos-blockchain-circuits-prover",
@ -6217,8 +6238,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-poseidon2"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ark-bn254",
"ark-ff",
@ -6228,8 +6249,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-proofs-error"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-circuits-types",
"logos-blockchain-groth16",
@ -6239,24 +6260,24 @@ dependencies = [
[[package]]
name = "logos-blockchain-services-utils"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"bytes",
"futures",
"log",
"logos-blockchain-log-targets",
"overwatch",
"serde",
"serde_json",
"thiserror 2.0.18",
"tracing",
]
[[package]]
name = "logos-blockchain-storage-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"bytes",
@ -6264,7 +6285,9 @@ dependencies = [
"logos-blockchain-core",
"logos-blockchain-cryptarchia-engine",
"logos-blockchain-log-targets",
"logos-blockchain-services-utils",
"logos-blockchain-tracing",
"logos-blockchain-utils",
"overwatch",
"serde",
"thiserror 2.0.18",
@ -6274,8 +6297,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-time-service"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"futures",
@ -6297,8 +6320,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-tracing"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"flate2",
"logos-blockchain-log-targets",
@ -6323,15 +6346,17 @@ dependencies = [
[[package]]
name = "logos-blockchain-utils"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"blake2",
"cipher 0.4.4",
"const-hex",
"futures",
"humantime",
"logos-blockchain-log-targets",
"multiaddr",
"overwatch",
"rand 0.8.6",
"serde",
@ -6340,27 +6365,27 @@ dependencies = [
"serde_yaml",
"thiserror 2.0.18",
"time",
"tokio",
"tracing",
]
[[package]]
name = "logos-blockchain-utxotree"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"ark-ff",
"logos-blockchain-groth16",
"logos-blockchain-dynamic-merkle",
"logos-blockchain-merkle-tree",
"logos-blockchain-poseidon2",
"num-bigint 0.4.6",
"rpds",
"serde",
"thiserror 2.0.18",
]
[[package]]
name = "logos-blockchain-zksign"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"logos-blockchain-circuits-prover",
"logos-blockchain-circuits-signature-sys",
@ -6371,6 +6396,7 @@ dependencies = [
"logos-blockchain-proofs-error",
"num-bigint 0.4.6",
"serde",
"serde-big-array",
"serde_json",
"thiserror 2.0.18",
"tracing",
@ -6378,8 +6404,8 @@ dependencies = [
[[package]]
name = "logos-blockchain-zone-sdk"
version = "0.1.2"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160"
version = "0.0.0"
source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=0dc34e2c5a6e2ff772140378659489a602ee06bc#0dc34e2c5a6e2ff772140378659489a602ee06bc"
dependencies = [
"async-trait",
"futures",
@ -6611,7 +6637,7 @@ dependencies = [
"bitflags 2.12.1",
"block",
"core-graphics-types",
"foreign-types 0.5.0",
"foreign-types",
"log",
"objc",
"paste",
@ -6774,23 +6800,6 @@ dependencies = [
"unsigned-varint 0.7.2",
]
[[package]]
name = "native-tls"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "natpmp"
version = "0.5.0"
@ -6955,15 +6964,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
@ -7184,49 +7184,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967"
dependencies = [
"bitflags 2.12.1",
"cfg-if",
"foreign-types 0.3.2",
"libc",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "openssl-probe"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "openssl-sys"
version = "0.9.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "opentelemetry"
version = "0.31.0"
@ -7345,7 +7308,7 @@ checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd"
[[package]]
name = "overwatch"
version = "0.1.0"
source = "git+https://github.com/logos-co/Overwatch?rev=448c192#448c192895b8311c742b1726a1bb12ee314ad95c"
source = "git+https://github.com/logos-co/Overwatch?rev=ae887f41f5a626c341179026ad7f03953ff2072e#ae887f41f5a626c341179026ad7f03953ff2072e"
dependencies = [
"async-trait",
"futures",
@ -7360,10 +7323,10 @@ dependencies = [
[[package]]
name = "overwatch-derive"
version = "0.1.0"
source = "git+https://github.com/logos-co/Overwatch?rev=448c192#448c192895b8311c742b1726a1bb12ee314ad95c"
source = "git+https://github.com/logos-co/Overwatch?rev=ae887f41f5a626c341179026ad7f03953ff2072e#ae887f41f5a626c341179026ad7f03953ff2072e"
dependencies = [
"convert_case 0.8.0",
"proc-macro-error2",
"manyhow",
"proc-macro2",
"quote",
"syn 2.0.117",
@ -8384,7 +8347,7 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [
"base64 0.22.1",
"bytes",
"encoding_rs",
"futures-channel",
"futures-core",
"futures-util",
"h2",
@ -8393,12 +8356,9 @@ dependencies = [
"http-body-util",
"hyper",
"hyper-rustls",
"hyper-tls",
"hyper-util",
"js-sys",
"log",
"mime",
"native-tls",
"percent-encoding",
"pin-project-lite",
"quinn",
@ -8409,7 +8369,6 @@ dependencies = [
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tokio-util",
"tower",
@ -8997,7 +8956,7 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom 7.1.3",
"nom",
]
[[package]]
@ -9303,6 +9262,7 @@ dependencies = [
"lee_core",
"log",
"logos-blockchain-core",
"logos-blockchain-http-api-common",
"logos-blockchain-key-management-system-service",
"logos-blockchain-zone-sdk",
"mempool",
@ -9378,6 +9338,15 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-big-array"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f"
dependencies = [
"serde",
]
[[package]]
name = "serde_arrays"
version = "0.2.0"
@ -10189,12 +10158,15 @@ dependencies = [
"common",
"env_logger",
"futures",
"hex",
"indexer_service",
"jsonrpsee",
"key_protocol",
"lee",
"lee_core",
"log",
"logos-blockchain-key-management-system-service",
"num-bigint 0.4.6",
"programs",
"sequencer_core",
"sequencer_service",
@ -10203,6 +10175,7 @@ dependencies = [
"serde_json",
"tempfile",
"testcontainers",
"time",
"tokio",
"tokio-util",
"url",
@ -10467,16 +10440,6 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.26.4"
@ -12058,7 +12021,7 @@ dependencies = [
"data-encoding",
"der-parser",
"lazy_static",
"nom 7.1.3",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror 2.0.18",

View File

@ -132,6 +132,7 @@ openssl = { version = "0.10", features = ["vendored"] }
openssl-probe = { version = "0.1.2" }
serde = { version = "1.0.60", default-features = false, features = ["derive"] }
serde_json = "1.0.81"
serde_yaml = "0.9.34"
serde_with = "3.16.1"
actix = "0.13.0"
actix-cors = "0.7.1"
@ -162,6 +163,7 @@ base64 = "0.22.1"
bip39 = "2.2.0"
hmac-sha512 = "1.1.7"
chrono = "0.4.41"
time = "0.3"
borsh = "1.5.7"
zstd = "0.13"
base58 = "0.2.0"
@ -172,13 +174,14 @@ tokio-retry = "0.3.0"
schemars = "1.2"
async-stream = "0.3.6"
logos-blockchain-common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-key-management-system-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-core = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-chain-broadcast-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-chain-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-zone-sdk = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-http-api-common = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "d8711bbc3d43d3ef9755ef9b73af32fd0f703160" }
logos-blockchain-common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-key-management-system-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-codec = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-core = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-chain-broadcast-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-chain-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-zone-sdk = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
logos-blockchain-http-api-common = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "0dc34e2c5a6e2ff772140378659489a602ee06bc" }
keycard-rs = { git = "https://github.com/keycard-tech/keycard-rs", rev = "9535a657ba04b1e6916de51777e22b4837c1a84d" }

View File

@ -24,7 +24,7 @@ build-artifacts:
just regenerate-test-fixture; \
fi
RISC0_DOCKER_CONTAINER_TAG := "r0.1.97.0"
RISC0_DOCKER_CONTAINER_TAG := "r0.1.91.1"
build-artifact methods_path features="":
@echo "Building artifacts for {{methods_path}}"

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

@ -1,48 +1,47 @@
blend:
common:
num_blend_layers: 3
num_blend_layers: 1
minimum_network_size: 30
protocol_name: /blend/integration-tests
data_replication_factor: 0
protocol_name: /logos-blockchain-LEZ-DEV/blend/1.0.0
data_replication_factor: 1
core:
scheduler:
cover:
message_frequency_per_round: 1.0
delayer:
maximum_release_delay_in_rounds: 3
maximum_release_delay_in_rounds: 1
minimum_messages_coefficient: 1
normalization_constant: 1.03
activity_threshold_sensitivity: 1
network:
kademlia_protocol_name: /integration/logos-blockchain/kad/1.0.0
identify_protocol_name: /integration/logos-blockchain/identify/1.0.0
chain_sync_protocol_name: /integration/logos-blockchain/chainsync/1.0.0
kademlia_protocol_name: /logos-blockchain-LEZ-DEV/kad/1.0.0
identify_protocol_name: /logos-blockchain-LEZ-DEV/identify/1.0.0
chain_sync_protocol_name: /logos-blockchain-LEZ-DEV/chainsync/1.0.0
cryptarchia:
epoch_config:
epoch_stake_distribution_stabilization: 3
epoch_period_nonce_buffer: 3
epoch_period_nonce_stabilization: 4
security_param: 10
security_param: 5
slot_activation_coeff:
numerator: 1
denominator: 2
learning_rate: 0.1
learning_rate: 0.5
sdp_config:
service_params:
BN:
inactivity_period: 1
retention_period: 1
inactivity_period: 2
epoch: 0
min_stake:
threshold: 1
timestamp: 0
gossipsub_protocol: /integration/logos-blockchain/cryptarchia/proto/1.0.0
gossipsub_protocol: /logos-blockchain-LEZ-DEV/cryptarchia/1.0.0
genesis_block:
header:
version: Bedrock
parent_block: '0000000000000000000000000000000000000000000000000000000000000000'
slot: 0
block_root: b5f8787ac23674822414c70eea15d842da38f2e806ede1a73cf7b5cf0277da07
block_root: cb5951ac1ffa1aa5d0e585fb54e784bd9c025b28d752324e98b3837f34648692
proof_of_leadership:
proof: '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
entropy_contribution: '0000000000000000000000000000000000000000000000000000000000000000'
@ -56,24 +55,134 @@ cryptarchia:
payload:
inputs: []
outputs:
- value: 1
pk: d204000000000000000000000000000000000000000000000000000000000000
- value: 100
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1
pk: ed266e6e887b9b97059dc1aa1b7b2e19b934291753c6336a163fe4ebaa28e717
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 1000000
pk: '2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26'
- value: 100000
pk: '6b2bcd3029fba573cff0c332dc4de7430faf5e261383d693d8dbb5b97665660a'
- value: 18446744073709551615
pk: c2a6a4a0981d5bdcf8ddeb8d7934fd8c5510efeb1053f613b45871670b6f7b19
- opcode: 17
payload:
channel_id: '0000000000000000000000000000000000000000000000000000000000000000'
# chain_id_len=12 (u64_le), chain_id=logos-devnet (utf-8),
# genesis_time=2026-01-10T07:47:56Z (u64_le), epoch_nonce=[0u8; 32]
inscription: '0c000000000000006c6f676f732d6465766e65742c046269000000000000000000000000000000000000000000000000000000000000000000000000'
inscription: '05302e322e3123766c6a2d2ddf918544bca603c5a291c7dd1b902d6769ff4b00021506780e075c06051a'
parent: '0000000000000000000000000000000000000000000000000000000000000000'
signer: '0000000000000000000000000000000000000000000000000000000000000000'
- opcode: 32
payload:
service_type: BN
locators:
- /ip4/65.109.51.37/udp/3400/quic-v1
provider_id: '59c662860b737f4e2515599adb3434856db8070b373a449ff66955ad3da6b473'
zk_id: '6b2bcd3029fba573cff0c332dc4de7430faf5e261383d693d8dbb5b97665660a'
locked_note_id: '7e449a14172fc90679f6fca7b49a2d58c305ebf7ac42ef20202e533c31115222'
ops_proofs:
- !ZkSig
pi_a: '0000000000000000000000000000000000000000000000000000000000000000'
pi_b: '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
pi_c: '0000000000000000000000000000000000000000000000000000000000000000'
- !Ed25519Sig '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
- !Ed25519Sig '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
- !ZkAndEd25519Sigs
zk_sig:
pi_a: '0000000000000000000000000000000000000000000000000000000000000000'
pi_b: '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
pi_c: '0000000000000000000000000000000000000000000000000000000000000000'
ed25519_sig: '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
faucet_pk: c2a6a4a0981d5bdcf8ddeb8d7934fd8c5510efeb1053f613b45871670b6f7b19
time:
slot_duration: '1.0'
slot_duration: '1.000000000'
mempool:
pubsub_topic: mantle_e2e_tests
pubsub_topic: /logos-blockchain-LEZ-DEV/mempool/1.0.0

View File

@ -1,7 +1,7 @@
services:
logos-blockchain-node-0:
image: ghcr.io/logos-blockchain/logos-blockchain@sha256:91d6c5bf07e07fcfba5e7cf07d21ee686a6bc4b9f6210f2d28bffbcad9a3729f
image: ghcr.io/logos-blockchain/logos-blockchain:0.2.1-lssa
ports:
- "${PORT:-18080}:18080/tcp"
volumes:

View File

@ -7,14 +7,6 @@ export POL_PROOF_DEV_MODE=true
# Use static configs mounted from host. Both node-config.yaml and
# deployment-settings.yaml have matching validator keys so the node
# can produce blocks as a single-validator network.
# Copy deployment-settings to a writable path because sed -i can't
# rename on a bind-mounted file.
cp /etc/logos-blockchain/deployment-settings.yaml /deployment-settings.yaml
# Set chain_start_time to "now" so the chain starts immediately.
sed -i "s/PLACEHOLDER_CHAIN_START_TIME/$(date -u '+%Y-%m-%d %H:%M:%S.000000 +00:00:00')/" \
/deployment-settings.yaml
exec /usr/bin/logos-blockchain-node \
/etc/logos-blockchain/node-config.yaml \
--deployment /deployment-settings.yaml
--deployment /etc/logos-blockchain/deployment-settings.yaml

View File

@ -38,17 +38,11 @@ programs.workspace = true
test_programs.workspace = true
testnet_initial_state.workspace = true
logos-blockchain-http-api-common.workspace = true
logos-blockchain-core.workspace = true
logos-blockchain-zone-sdk.workspace = true
logos-blockchain-key-management-system-service.workspace = true
anyhow.workspace = true
log.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
futures.workspace = true
hex.workspace = true
tempfile.workspace = true
bytesize.workspace = true
reqwest.workspace = true
borsh.workspace = true
num-bigint.workspace = true

View File

@ -1,43 +1,23 @@
#![expect(
clippy::tests_outside_test_module,
clippy::arithmetic_side_effects,
reason = "We don't care about these in tests"
)]
use std::{ops::Deref as _, time::Duration};
use std::time::Duration;
use anyhow::Context as _;
use borsh::BorshSerialize;
use common::transaction::LeeTransaction;
use futures::StreamExt as _;
use integration_tests::{
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, account_balance, get_account,
wait_for_indexer_to_catch_up,
};
use lee::{
AccountId, execute_and_prove, privacy_preserving_transaction, program::Program,
public_transaction,
execute_and_prove, privacy_preserving_transaction, program::Program, public_transaction,
};
use lee_core::{InputAccountIdentity, account::AccountWithMetadata};
use log::info;
use logos_blockchain_core::mantle::{ledger::Inputs, ops::channel::deposit::DepositOp};
use logos_blockchain_http_api_common::bodies::{
channel::ChannelDepositRequestBody,
wallet::{
balance::WalletBalanceResponseBody,
transfer_funds::{WalletTransferFundsRequestBody, WalletTransferFundsResponseBody},
},
};
use logos_blockchain_zone_sdk::{
CommonHttpClient, ZoneMessage, adapter::NodeHttpClient, indexer::ZoneIndexer,
};
use num_bigint::BigUint;
use sequencer_service_rpc::RpcClient as _;
use test_fixtures::public_mention;
use tokio::test;
use wallet::cli::{Command, execute_subcommand, programs::bridge::BridgeSubcommand};
const TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK: Duration = Duration::from_mins(2);
// const TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK: Duration = Duration::from_mins(2);
#[test]
async fn public_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> {
@ -249,377 +229,386 @@ async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> {
Ok(())
}
async fn submit_bedrock_deposit(
bedrock_addr: std::net::SocketAddr,
bedrock_account_pk: &str,
recipient_id: AccountId,
amount: u64,
) -> anyhow::Result<()> {
#[derive(BorshSerialize)]
struct DepositMetadata {
recipient_id: AccountId,
}
// async fn submit_bedrock_deposit(
// bedrock_addr: std::net::SocketAddr,
// bedrock_account_pk: &str,
// recipient_id: AccountId,
// amount: u64,
// ) -> anyhow::Result<()> {
// #[derive(BorshSerialize)]
// struct DepositMetadata {
// recipient_id: AccountId,
// }
// Encode deposit metadata
let metadata = borsh::to_vec(&DepositMetadata { recipient_id })
.context("Failed to encode deposit metadata")?
.try_into()
.context("Encoded metadata is too big")?;
// // Encode deposit metadata
// let metadata = borsh::to_vec(&DepositMetadata { recipient_id })
// .context("Failed to encode deposit metadata")?
// .try_into()
// .context("Encoded metadata is too big")?;
let channel_id = integration_tests::config::bedrock_channel_id();
let client = reqwest::Client::new();
// let channel_id = integration_tests::config::bedrock_channel_id();
// let client = reqwest::Client::new();
let query_balance = || async {
let balance_response = client
.get(format!(
"http://{bedrock_addr}/wallet/{bedrock_account_pk}/balance"
))
.send()
.await
.context("Failed to query Bedrock wallet balance")?;
// let mut balance = bedrock_wallet_balance(bedrock_addr, bedrock_account_pk).await?;
let balance_response = check_response_success(balance_response).await?;
// info!(
// "Queried Bedrock balance for key {bedrock_account_pk}: {:?}",
// balance.balance
// );
balance_response
.json::<WalletBalanceResponseBody>()
.await
.context("Failed to decode Bedrock balance response")
};
// if balance.balance < amount {
// anyhow::bail!(
// "Bedrock wallet with key {bedrock_account_pk} has insufficient balance {:?} for
// deposit amount {:?}", balance.balance,
// amount
// );
// }
let mut balance = query_balance().await?;
// let mut selected_note_id = balance
// .notes
// .iter()
// .find_map(|(note_id, value)| (*value == amount).then_some(*note_id));
info!(
"Queried Bedrock balance for key {bedrock_account_pk}: {:?}",
balance.balance
);
// if selected_note_id.is_none() {
// let transfer_body = WalletTransferFundsRequestBody {
// tip: None,
// change_public_key: balance.address,
// funding_public_keys: vec![balance.address],
// recipient_public_key: balance.address,
// amount,
// };
if balance.balance < amount {
anyhow::bail!(
"Bedrock wallet with key {bedrock_account_pk} has insufficient balance {:?} for deposit amount {:?}",
balance.balance,
amount
);
}
// let transfer_response = client
// .post(format!(
// "http://{bedrock_addr}/wallet/transactions/transfer-funds"
// ))
// .json(&transfer_body)
// .send()
// .await
// .context("Failed to submit Bedrock transfer-funds request")?;
// let transfer_response = check_response_success(transfer_response).await?;
let mut selected_note_id = balance
.notes
.iter()
.find_map(|(note_id, value)| (*value == amount).then_some(*note_id));
// let transfer: WalletTransferFundsResponseBody = transfer_response
// .json()
// .await
// .context("Failed to decode Bedrock transfer-funds response")?;
if selected_note_id.is_none() {
let transfer_body = WalletTransferFundsRequestBody {
tip: None,
change_public_key: balance.address,
funding_public_keys: vec![balance.address],
recipient_public_key: balance.address,
amount,
};
// info!(
// "Submitted transfer-funds to create exact deposit note, tx hash {:?}",
// transfer.hash
// );
let transfer_response = client
.post(format!(
"http://{bedrock_addr}/wallet/transactions/transfer-funds"
))
.json(&transfer_body)
.send()
.await
.context("Failed to submit Bedrock transfer-funds request")?;
let transfer_response = check_response_success(transfer_response).await?;
// let mut found_note = None;
// for _ in 0..20 {
// tokio::time::sleep(Duration::from_millis(500)).await;
// balance = bedrock_wallet_balance(bedrock_addr, bedrock_account_pk).await?;
// found_note = balance
// .notes
// .iter()
// .find_map(|(note_id, value)| (*value == amount).then_some(*note_id));
// if found_note.is_some() {
// break;
// }
// }
let transfer: WalletTransferFundsResponseBody = transfer_response
.json()
.await
.context("Failed to decode Bedrock transfer-funds response")?;
// selected_note_id = found_note;
// }
info!(
"Submitted transfer-funds to create exact deposit note, tx hash {:?}",
transfer.hash
);
// let Some(selected_note_id) = selected_note_id else {
// anyhow::bail!(
// "Failed to locate exact-value note {amount:?} for Bedrock deposit; available notes:
// {:?}", balance.notes,
// );
// };
let mut found_note = None;
for _ in 0..20 {
tokio::time::sleep(Duration::from_millis(500)).await;
balance = query_balance().await?;
found_note = balance
.notes
.iter()
.find_map(|(note_id, value)| (*value == amount).then_some(*note_id));
if found_note.is_some() {
break;
}
}
// let body = ChannelDepositRequestBody {
// tip: None,
// deposit: DepositOp {
// channel_id,
// inputs: Inputs::new(selected_note_id),
// metadata,
// },
// change_public_key: balance.address,
// funding_public_keys: vec![balance.address],
// max_tx_fee: u64::MAX.into(),
// };
selected_note_id = found_note;
}
// let response = client
// .post(format!("http://{bedrock_addr}/channel/deposit"))
// .json(&body)
// .send()
// .await
// .context("Failed to submit Bedrock deposit request")?;
// let response = check_response_success(response).await?;
let Some(selected_note_id) = selected_note_id else {
anyhow::bail!(
"Failed to locate exact-value note {amount:?} for Bedrock deposit; available notes: {:?}",
balance.notes,
);
};
// let body_text = response
// .text()
// .await
// .unwrap_or_else(|_| "<failed to decode>".to_owned());
// info!(
// "Successfully submitted Bedrock deposit request for recipient {recipient_id} and amount
// {amount}, response body: {body_text}", );
let body = ChannelDepositRequestBody {
tip: None,
deposit: DepositOp {
channel_id,
inputs: Inputs::new(selected_note_id),
metadata,
},
change_public_key: balance.address,
funding_public_keys: vec![balance.address],
max_tx_fee: 1_000_u64.into(),
};
// Ok(())
// }
let response = client
.post(format!("http://{bedrock_addr}/channel/deposit"))
.json(&body)
.send()
.await
.context("Failed to submit Bedrock deposit request")?;
let response = check_response_success(response).await?;
// /// The Bedrock wallet state of `bedrock_account_pk`: its total balance and the
// /// notes it owns, keyed by note id.
// async fn bedrock_wallet_balance(
// bedrock_addr: std::net::SocketAddr,
// bedrock_account_pk: &str,
// ) -> anyhow::Result<WalletBalanceResponseBody> {
// let response = reqwest::Client::new()
// .get(format!(
// "http://{bedrock_addr}/wallet/{bedrock_account_pk}/balance"
// ))
// .send()
// .await
// .context("Failed to query Bedrock wallet balance")?;
let body_text = response
.text()
.await
.unwrap_or_else(|_| "<failed to decode>".to_owned());
info!(
"Successfully submitted Bedrock deposit request for recipient {recipient_id} and amount {amount}, response body: {body_text}",
);
// check_response_success(response)
// .await?
// .json::<WalletBalanceResponseBody>()
// .await
// .context("Failed to decode Bedrock balance response")
// }
Ok(())
}
// async fn check_response_success(response: reqwest::Response) -> anyhow::Result<reqwest::Response>
// { if response.status().is_success() {
// Ok(response)
// } else {
// let status = response.status();
// let body_text = response.text().await.unwrap_or_default();
// anyhow::bail!("Request failed with status {status} and body {body_text}");
// }
// }
async fn check_response_success(response: reqwest::Response) -> anyhow::Result<reqwest::Response> {
if response.status().is_success() {
Ok(response)
} else {
let status = response.status();
let body_text = response.text().await.unwrap_or_default();
anyhow::bail!("Request failed with status {status} and body {body_text}");
}
}
// async fn wait_for_vault_balance(
// ctx: &TestContext,
// vault_id: AccountId,
// expected_balance: u128,
// ) -> anyhow::Result<()> {
// let timeout = TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK
// + Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS);
// tokio::time::timeout(timeout, async {
// loop {
// let balance = account_balance(ctx, vault_id).await?;
// if balance == expected_balance {
// return Ok(());
// }
// tokio::time::sleep(Duration::from_millis(500)).await;
// }
// })
// .await
// .with_context(|| {
// format!("Timed out waiting for vault {vault_id} balance to reach {expected_balance}")
// })?
// }
async fn wait_for_vault_balance(
ctx: &TestContext,
vault_id: AccountId,
expected_balance: u128,
) -> anyhow::Result<()> {
let timeout = TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK
+ Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS);
tokio::time::timeout(timeout, async {
loop {
let balance = account_balance(ctx, vault_id).await?;
if balance == expected_balance {
return Ok(());
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
})
.await
.with_context(|| {
format!("Timed out waiting for vault {vault_id} balance to reach {expected_balance}")
})?
}
// /// Test deposit and withdraw round trip.
// ///
// /// Implemented as one test instead of two separate tests for deposit and withdraw, because the
// /// withdraw test depends on the deposit to set up the necessary state (funds in vault) for
// testing /// withdraw functionality.
// #[test]
// async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Result<()> {
// let mut ctx = TestContext::new().await?;
/// Test deposit and withdraw round trip.
///
/// Implemented as one test instead of two separate tests for deposit and withdraw, because the
/// withdraw test depends on the deposit to set up the necessary state (funds in vault) for testing
/// withdraw functionality.
#[test]
async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Result<()> {
let mut ctx = TestContext::new().await?;
// let bedrock_account_pk = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26";
// let recipient_id = ctx.existing_public_accounts()[0];
// let amount = 1_u64;
// let vault_program_id = programs::vault().id();
// let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id,
// recipient_id);
let bedrock_account_pk = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26";
let recipient_id = ctx.existing_public_accounts()[0];
let amount = 1_u64;
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 = account_balance(&ctx, recipient_vault_id).await?;
// let recipient_balance_before = account_balance(&ctx, recipient_id).await?;
let vault_balance_before = account_balance(&ctx, recipient_vault_id).await?;
let recipient_balance_before = account_balance(&ctx, recipient_id).await?;
// // Submit deposit to Bedrock
// submit_bedrock_deposit(ctx.bedrock_addr(), bedrock_account_pk, recipient_id, amount)
// .await
// .context("Failed to submit Bedrock deposit for round-trip setup")?;
// Submit deposit to Bedrock
submit_bedrock_deposit(ctx.bedrock_addr(), bedrock_account_pk, recipient_id, amount)
.await
.context("Failed to submit Bedrock deposit for round-trip setup")?;
// // Wait for vault to receive the deposit (minted from bridge to vault)
// wait_for_vault_balance(
// &ctx,
// recipient_vault_id,
// vault_balance_before + u128::from(amount),
// )
// .await?;
// Wait for vault to receive the deposit (minted from bridge to vault)
wait_for_vault_balance(
&ctx,
recipient_vault_id,
vault_balance_before + u128::from(amount),
)
.await?;
// // Now claim funds from vault back to recipient
// let nonces = ctx
// .wallet()
// .get_accounts_nonces(&[recipient_id])
// .await
// .context("Failed to get nonce for vault claim")?;
// Now claim funds from vault back to recipient
let nonces = ctx
.wallet()
.get_accounts_nonces(&[recipient_id])
.await
.context("Failed to get nonce for vault claim")?;
// let signing_key = ctx
// .wallet()
// .storage()
// .key_chain()
// .pub_account_signing_key(recipient_id)
// .with_context(|| format!("Missing signing key for account {recipient_id}"))?;
let signing_key = ctx
.wallet()
.storage()
.key_chain()
.pub_account_signing_key(recipient_id)
.with_context(|| format!("Missing signing key for account {recipient_id}"))?;
// let claim_message = public_transaction::Message::try_new(
// vault_program_id,
// vec![recipient_id, recipient_vault_id],
// nonces,
// vault_core::Instruction::Claim {
// amount: u128::from(amount),
// },
// )
// .context("Failed to build vault claim message")?;
let claim_message = public_transaction::Message::try_new(
vault_program_id,
vec![recipient_id, recipient_vault_id],
nonces,
vault_core::Instruction::Claim {
amount: u128::from(amount),
},
)
.context("Failed to build vault claim message")?;
// let claim_witness_set =
// public_transaction::WitnessSet::for_message(&claim_message, &[signing_key]);
// let claim_tx = LeeTransaction::Public(lee::PublicTransaction::new(
// claim_message,
// claim_witness_set,
// ));
let claim_witness_set =
public_transaction::WitnessSet::for_message(&claim_message, &[signing_key]);
let claim_tx = LeeTransaction::Public(lee::PublicTransaction::new(
claim_message,
claim_witness_set,
));
// let claim_hash = ctx.sequencer_client().send_transaction(claim_tx).await?;
let claim_hash = ctx.sequencer_client().send_transaction(claim_tx).await?;
// tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// let claim_on_chain = ctx.sequencer_client().get_transaction(claim_hash).await?;
// let vault_balance_after_claim = account_balance(&ctx, recipient_vault_id).await?;
// let recipient_balance_after_claim = account_balance(&ctx, recipient_id).await?;
let claim_on_chain = ctx.sequencer_client().get_transaction(claim_hash).await?;
let vault_balance_after_claim = account_balance(&ctx, recipient_vault_id).await?;
let recipient_balance_after_claim = account_balance(&ctx, recipient_id).await?;
// assert!(
// claim_on_chain.is_some(),
// "Vault claim transaction must be included on-chain"
// );
// assert_eq!(
// vault_balance_after_claim, vault_balance_before,
// "Vault balance should return to initial state after claim"
// );
// assert_eq!(
// recipient_balance_after_claim,
// recipient_balance_before + u128::from(amount),
// "Recipient balance should increase by claimed amount"
// );
assert!(
claim_on_chain.is_some(),
"Vault claim transaction must be included on-chain"
);
assert_eq!(
vault_balance_after_claim, vault_balance_before,
"Vault balance should return to initial state after claim"
);
assert_eq!(
recipient_balance_after_claim,
recipient_balance_before + u128::from(amount),
"Recipient balance should increase by claimed amount"
);
// // The indexer must replay the deposit and claim blocks and reach the same
// // 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 = 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
// // of the async `get_account` method on `RpcClient`
// ctx.indexer_client().deref(),
// account_id.into(),
// )
// .await?;
// let sequencer_account = get_account(&ctx, account_id).await?;
// assert_eq!(
// indexer_account,
// sequencer_account.into(),
// "Indexer and sequencer diverged for account {account_id} after deposit"
// );
// }
// The indexer must replay the deposit and claim blocks and reach the same
// 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 = 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
// of the async `get_account` method on `RpcClient`
ctx.indexer_client().deref(),
account_id.into(),
)
.await?;
let sequencer_account = get_account(&ctx, account_id).await?;
assert_eq!(
indexer_account,
sequencer_account.into(),
"Indexer and sequencer diverged for account {account_id} after deposit"
);
}
// // Withdraw back to Bedrock and wait for finalized withdraw event.
// let sender_id = recipient_id;
// Withdraw back to Bedrock and wait for finalized withdraw event.
let sender_id = recipient_id;
// let observer = create_zone_indexer_observer(ctx.bedrock_addr())?;
// let observe_fut =
// wait_for_finalized_withdraw_op(&observer, ctx.bedrock_addr(), amount,
// bedrock_account_pk);
let observer = create_zone_indexer_observer(ctx.bedrock_addr())?;
let observe_fut = wait_for_finalized_withdraw_op(&observer, amount, bedrock_account_pk);
// let withdraw_fut = execute_subcommand(
// ctx.wallet_mut(),
// Command::Bridge(BridgeSubcommand::Withdraw {
// from: public_mention(sender_id),
// amount,
// bedrock_account_pk: bedrock_account_pk.to_owned(),
// }),
// );
let withdraw_fut = execute_subcommand(
ctx.wallet_mut(),
Command::Bridge(BridgeSubcommand::Withdraw {
from: public_mention(sender_id),
amount,
bedrock_account_pk: bedrock_account_pk.to_owned(),
}),
);
// let (observe_result, withdraw_result) = tokio::join!(observe_fut, withdraw_fut);
let (observe_result, withdraw_result) = tokio::join!(observe_fut, withdraw_fut);
// withdraw_result.context("Failed to execute wallet bridge withdraw command")?;
withdraw_result.context("Failed to execute wallet bridge withdraw command")?;
// observe_result
// .context("Failed while waiting for finalized withdraw event from zone indexer")?;
observe_result
.context("Failed while waiting for finalized withdraw event from zone indexer")?;
// // Sleep to observe sequencer log about validated withdraw event
// tokio::time::sleep(Duration::from_secs(1)).await;
// Sleep to observe sequencer log about validated withdraw event
tokio::time::sleep(Duration::from_secs(1)).await;
// Ok(())
// }
Ok(())
}
// fn create_zone_indexer_observer(
// bedrock_addr: std::net::SocketAddr,
// ) -> anyhow::Result<ZoneIndexer<NodeHttpClient>> {
// let bedrock_url = integration_tests::config::addr_to_url(
// integration_tests::config::UrlProtocol::Http,
// bedrock_addr,
// )
// .context("Failed to convert Bedrock addr to URL for zone indexer observer")?;
fn create_zone_indexer_observer(
bedrock_addr: std::net::SocketAddr,
) -> anyhow::Result<ZoneIndexer<NodeHttpClient>> {
let bedrock_url = integration_tests::config::addr_to_url(
integration_tests::config::UrlProtocol::Http,
bedrock_addr,
)
.context("Failed to convert Bedrock addr to URL for zone indexer observer")?;
// let node = NodeHttpClient::new(CommonHttpClient::new(None), bedrock_url);
let node = NodeHttpClient::new(CommonHttpClient::new(None), bedrock_url);
// Ok(ZoneIndexer::new(
// integration_tests::config::bedrock_channel_id(),
// node,
// ))
// }
Ok(ZoneIndexer::new(
integration_tests::config::bedrock_channel_id(),
node,
))
}
// /// Waits for a finalized withdraw that pays `expected_amount` to `receiver_pk`.
// ///
// /// A withdraw op releases channel-owned notes and carries nothing but their
// /// ids — the value and recipient live in the note itself. A released note keeps
// /// its id, value and public key, so the pairing is checked on the receiver's
// /// Bedrock wallet: one of the released notes must land there with the expected
// /// value.
// async fn wait_for_finalized_withdraw_op(
// observer: &ZoneIndexer<NodeHttpClient>,
// bedrock_addr: std::net::SocketAddr,
// expected_amount: u64,
// receiver_pk: &str,
// ) -> anyhow::Result<()> {
// let timeout = TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK
// + Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS);
async fn wait_for_finalized_withdraw_op(
observer: &ZoneIndexer<NodeHttpClient>,
expected_amount: u64,
receiver_pk: &str,
) -> anyhow::Result<()> {
let timeout = TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK
+ Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS);
// tokio::time::timeout(timeout, async {
// // The wallet can trail the channel event, so released notes accumulate
// // across polls instead of being checked once when first observed.
// let mut released_notes = HashSet::new();
let bedrock_account_pk_bytes = hex::decode(receiver_pk)
.context("Failed to decode expected receiver public key from hex")?;
let expected_receiver_pk =
logos_blockchain_key_management_system_service::keys::ZkPublicKey::from(
BigUint::from_bytes_le(&bedrock_account_pk_bytes),
);
// loop {
// let stream = observer
// .follow()
// .await
// .context("Failed to read zone indexer message batch")?;
// let mut stream = std::pin::pin!(stream);
tokio::time::timeout(timeout, async {
loop {
let stream = observer
.follow()
.await
.context("Failed to read zone indexer message batch")?;
let mut stream = std::pin::pin!(stream);
// while let Some(message) = stream.next().await {
// info!("Observed zone message {message:?}");
while let Some(message) = stream.next().await {
info!("Observed zone message {message:?}");
// if let ZoneMessage::Withdraw(withdraw) = message {
// released_notes.extend(withdraw.inputs.iter().copied());
// }
// }
let ZoneMessage::Withdraw(withdraw) = message else {
continue;
};
// if !released_notes.is_empty() {
// let balance = bedrock_wallet_balance(bedrock_addr, receiver_pk).await?;
// if released_notes
// .iter()
// .any(|note_id| balance.notes.get(note_id) == Some(&expected_amount))
// {
// return Ok(());
// }
// }
let mut iter = withdraw.outputs.iter();
let Some(note) = iter.next() else {
continue;
};
if iter.next().is_some() {
// Withdraw op should only have one output
continue;
}
if note.value == expected_amount && note.pk == expected_receiver_pk {
return Ok(());
}
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
})
.await
.with_context(|| {
format!("Timed out waiting for finalized withdraw message with amount {expected_amount}")
})?
}
// tokio::time::sleep(Duration::from_millis(500)).await;
// }
// })
// .await
// .with_context(|| {
// format!("Timed out waiting for finalized withdraw message with amount {expected_amount}")
// })?
// }

View File

@ -70,6 +70,7 @@ async fn multi_sequencer_committee_converges() -> Result<()> {
&BedrockConfig {
channel_id: config::bedrock_channel_id(),
node_url: config::addr_to_url(config::UrlProtocol::Http, bedrock_addr)?,
funding_key: config::bedrock_funding_key(),
auth: None,
},
&Ed25519Key::from_bytes(&key_a),

View File

@ -170,13 +170,13 @@ unsafe extern "C" {
fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult);
fn wallet_ffi_bridge_withdraw(
handle: *mut WalletHandle,
from: *const FfiBytes32,
amount: u64,
bedrock_account_pk: *const FfiBytes32,
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
// fn wallet_ffi_bridge_withdraw(
// handle: *mut WalletHandle,
// from: *const FfiBytes32,
// amount: u64,
// bedrock_account_pk: *const FfiBytes32,
// out_result: *mut FfiTransferResult,
// ) -> error::WalletFfiError;
fn wallet_ffi_get_vault_balance(
handle: *mut WalletHandle,
@ -1521,68 +1521,68 @@ fn restore_keys_from_seed_ffi() -> Result<()> {
Ok(())
}
#[test]
fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let home = tempfile::tempdir()?;
let FfiCreateWalletOutput {
wallet: wallet_ffi_handle,
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 = system_accounts::bridge_account_id().into();
let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
let amount = 100_u64;
// #[test]
// fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
// let ctx = BlockingTestContext::new()?;
// let home = tempfile::tempdir()?;
// let FfiCreateWalletOutput {
// wallet: wallet_ffi_handle,
// 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 = system_accounts::bridge_account_id().into();
// let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
// let amount = 100_u64;
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_bridge_withdraw(
wallet_ffi_handle,
&raw const from,
amount,
&raw const bedrock_account_pk,
&raw mut transfer_result,
)
.unwrap();
}
// let mut transfer_result = FfiTransferResult::default();
// unsafe {
// wallet_ffi_bridge_withdraw(
// wallet_ffi_handle,
// &raw const from,
// amount,
// &raw const bedrock_account_pk,
// &raw mut transfer_result,
// )
// .unwrap();
// }
info!("Waiting for next block creation");
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
// info!("Waiting for next block creation");
// std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
wallet_ffi_get_balance(
wallet_ffi_handle,
&raw const from,
true,
&raw mut out_balance,
)
.unwrap();
u128::from_le_bytes(out_balance)
};
// let from_balance = unsafe {
// let mut out_balance: [u8; 16] = [0; 16];
// wallet_ffi_get_balance(
// wallet_ffi_handle,
// &raw const from,
// true,
// &raw mut out_balance,
// )
// .unwrap();
// u128::from_le_bytes(out_balance)
// };
let bridge_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
wallet_ffi_get_balance(
wallet_ffi_handle,
&raw const bridge_account,
true,
&raw mut out_balance,
)
.unwrap();
u128::from_le_bytes(out_balance)
};
// let bridge_balance = unsafe {
// let mut out_balance: [u8; 16] = [0; 16];
// wallet_ffi_get_balance(
// wallet_ffi_handle,
// &raw const bridge_account,
// true,
// &raw mut out_balance,
// )
// .unwrap();
// u128::from_le_bytes(out_balance)
// };
assert_eq!(from_balance, 9900);
assert_eq!(bridge_balance, 1_000_100);
// assert_eq!(from_balance, 9900);
// assert_eq!(bridge_balance, 1_000_100);
unsafe {
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
// unsafe {
// wallet_ffi_free_transfer_result(&raw mut transfer_result);
// wallet_ffi_destroy(wallet_ffi_handle);
// }
Ok(())
}
// Ok(())
// }
#[test]
fn test_wallet_ffi_transfer_generic_public() -> Result<()> {

View File

@ -11,7 +11,8 @@
"max_retries": 5
},
"channel_id": "0101010101010101010101010101010101010101010101010101010101010101",
"node_url": "http://logos-blockchain-node-0:18080"
"node_url": "http://logos-blockchain-node-0:18080",
"funding_key": "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"
},
"genesis": [
{

View File

@ -7,5 +7,4 @@ license = { workspace = true }
[dependencies]
bridge_core.workspace = true
vault_core.workspace = true
authenticated_transfer_core.workspace = true
lee_core.workspace = true

View File

@ -104,33 +104,35 @@ fn main() {
}
}
Instruction::Withdraw {
amount,
amount: _,
bedrock_account_pk: _,
} => {
let [sender, bridge] = pre_states
.try_into()
.expect("Withdraw requires exactly 2 accounts");
panic!("Withdraws are disabled in the current version of LEZ");
assert_eq!(
bridge.account_id,
bridge_core::compute_bridge_account_id(self_program_id),
"Second account must be bridge PDA"
);
// let [sender, bridge] = pre_states
// .try_into()
// .expect("Withdraw requires exactly 2 accounts");
let auth_transfer_program_id = bridge.account.program_owner;
assert_eq!(
sender.account.program_owner, auth_transfer_program_id,
"Sender account must be owned by the authenticated transfer program"
);
// assert_eq!(
// bridge.account_id,
// bridge_core::compute_bridge_account_id(self_program_id),
// "Second account must be bridge PDA"
// );
let chained_calls = vec![ChainedCall::new(
auth_transfer_program_id,
vec![sender, bridge],
&authenticated_transfer_core::Instruction::Transfer {
amount: u128::from(amount),
},
)];
(unchanged_post_states(&pre_states_clone), chained_calls)
// let auth_transfer_program_id = bridge.account.program_owner;
// assert_eq!(
// sender.account.program_owner, auth_transfer_program_id,
// "Sender account must be owned by the authenticated transfer program"
// );
// let chained_calls = vec![ChainedCall::new(
// auth_transfer_program_id,
// vec![sender, bridge],
// &authenticated_transfer_core::Instruction::Transfer {
// amount: u128::from(amount),
// },
// )];
// (unchanged_post_states(&pre_states_clone), chained_calls)
}
};

View File

@ -26,6 +26,7 @@ cross_zone_inbox_core.workspace = true
logos-blockchain-key-management-system-service.workspace = true
logos-blockchain-core.workspace = true
logos-blockchain-http-api-common.workspace = true
anyhow.workspace = true
serde.workspace = true
serde_json.workspace = true

View File

@ -4,11 +4,15 @@ use anyhow::{Context as _, Result, anyhow, ensure};
use common::block::Block;
use futures::Stream;
use log::{info, warn};
pub use logos_blockchain_core::mantle::ops::channel::{Ed25519PublicKey, MsgId};
pub use logos_blockchain_core::mantle::{
ledger::NoteId,
ops::channel::{Ed25519PublicKey, MsgId},
};
use logos_blockchain_core::{
mantle::{
MantleTx, SignedMantleTx, Transaction as _,
SignedMantleTx,
channel::{SlotTimeframe, SlotTimeout},
gas::GasCost,
ops::{
Op, OpProof,
channel::{
@ -17,9 +21,12 @@ use logos_blockchain_core::{
inscribe::Inscription,
},
},
traits::Hashable as _,
transactions::{MantleTxBuilder, OpsProofs},
},
proofs::channel_multi_sig_proof::{ChannelMultiSigProof, IndexedSignature},
};
use logos_blockchain_http_api_common::bodies::wallet::fund::WalletFundRequestBody;
pub use logos_blockchain_key_management_system_service::keys::{
ED25519_SECRET_KEY_SIZE, Ed25519Key, ZkKey,
};
@ -29,9 +36,9 @@ use logos_blockchain_zone_sdk::{
adapter::{Node as _, NodeHttpClient},
indexer::ZoneIndexer,
sequencer::{
DepositInfo, Event, FinalizedOp, InscriptionInfo, OrphanedTx,
SequencerConfig as ZoneSdkSequencerConfig, TurnNotification, WithdrawArg, WithdrawInfo,
ZoneSequencer,
ChannelUpdateTx, DepositInfo, Event, FinalizedOp, FundingConfig, InscriptionInfo,
PendingTx, SequencerConfig as ZoneSdkSequencerConfig, TurnNotification, WithdrawArg,
WithdrawInfo, ZoneSequencer,
},
};
use tokio::sync::{mpsc, oneshot, watch};
@ -72,14 +79,29 @@ pub struct FollowUpdate {
/// persist the whole event in one write.
pub type OnFollowSink = Box<dyn Fn(FollowUpdate) + Send + 'static>;
/// What one publish produced.
pub struct PublishOutcome {
/// The `MsgId` zone-sdk assigned the published inscription.
pub this_msg: MsgId,
/// The checkpoint that now holds the inscription as pending.
pub checkpoint: SequencerCheckpoint,
/// Channel notes the bundled withdrawals release, empty for a plain
/// publish.
/// A [`ChannelWithdrawOp`](logos_blockchain_core::mantle::ops::channel::withdraw::ChannelWithdrawOp)
/// carries nothing but the note ids it releases, so these are the only
/// handle the local withdraw intent shares with the Bedrock Withdraw event
/// that later reports it.
pub released_notes: Vec<NoteId>,
}
/// Commands the drive task executes with `&mut sequencer`.
enum Command {
/// Publish an inscription (+ atomic withdrawals); responds with the assigned
/// `MsgId` and the checkpoint that now includes it as pending.
/// Publish an inscription (+ atomic withdrawals); responds with the
/// [`PublishOutcome`].
Publish {
inscription: Inscription,
withdrawals: Vec<WithdrawArg>,
resp: oneshot::Sender<Result<(MsgId, SequencerCheckpoint)>>,
resp: oneshot::Sender<Result<PublishOutcome>>,
},
}
@ -95,9 +117,8 @@ pub trait BlockPublisherTrait: Sized {
on_follow: OnFollowSink,
) -> Result<Self>;
/// Publish a block and return the `MsgId` zone-sdk assigned its inscription
/// together with the checkpoint that now holds it as pending. Zone-sdk
/// drives the actual submission and retries internally.
/// Publish a block and return what zone-sdk made of it. Zone-sdk drives the
/// actual submission and retries internally.
///
/// The checkpoint must be persisted with the block — restoring an older one
/// drops the inscription from the pending set, and it is never resubmitted.
@ -105,7 +126,7 @@ pub trait BlockPublisherTrait: Sized {
&self,
block: &Block,
withdrawals: Vec<WithdrawArg>,
) -> Result<(MsgId, SequencerCheckpoint)>;
) -> Result<PublishOutcome>;
fn channel_id(&self) -> ChannelId;
@ -167,6 +188,11 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
let zone_sdk_config = ZoneSdkSequencerConfig {
resubmit_interval,
funding: Some(FundingConfig {
funding_pk: config.funding_key,
max_tx_fee: GasCost::new(logos_blockchain_core::mantle::Value::MAX),
priority_fee: FundingConfig::DEFAULT_PRIORITY_FEE,
}),
..ZoneSdkSequencerConfig::default()
};
@ -209,15 +235,20 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
let published = if withdrawals.is_empty() {
sequencer.handle()
.publish(data_bounded)
.await
.context("Failed to publish block")
} else {
sequencer.handle()
.publish_atomic_withdraw(data_bounded, withdrawals)
.await
.context("Failed to publish block with withdrawals")
};
let msg_result = published
.map(|(result, checkpoint)| (result.tx.inscription().this_msg, checkpoint));
let msg_result = published.map(|(result, checkpoint)| PublishOutcome {
this_msg: result.tx.inscription().this_msg,
checkpoint,
released_notes: released_notes(&result.tx),
});
match &msg_result {
Ok(_) if withdraw_count == 0 => {
info!("Published block with the size of {data_byte_size} bytes");
@ -233,9 +264,6 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
}
},
event = sequencer.next_event() => {
let Some(event) = event else {
continue;
};
match event {
Event::BlocksProcessed {
checkpoint,
@ -245,12 +273,13 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
let adopted = channel_update
.adopted
.iter()
.filter_map(channel_update_inscription)
.filter_map(block_from_inscription)
.collect();
let orphaned = channel_update
.orphaned
.iter()
.map(orphan_inscription)
.filter_map(channel_update_inscription)
.filter_map(block_from_inscription)
.collect();
@ -295,6 +324,7 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
notification.ends_at_slot
);
}
Event::MempoolPending(_tx_hash) => {}
}
}
}
@ -324,7 +354,7 @@ impl BlockPublisherTrait for ZoneSdkPublisher {
&self,
block: &Block,
withdrawals: Vec<WithdrawArg>,
) -> Result<(MsgId, SequencerCheckpoint)> {
) -> Result<PublishOutcome> {
let data = borsh::to_vec(block).context("Failed to serialize block")?;
let data_bounded: Inscription = data
.try_into()
@ -394,16 +424,31 @@ fn block_from_inscription(inscription: &InscriptionInfo) -> Option<(MsgId, Block
.map(|block| (inscription.this_msg, block))
}
/// Channel notes the withdraws bundled with a published tx release; empty for a
/// plain inscription. See [`PublishOutcome::released_notes`].
fn released_notes(tx: &PendingTx) -> Vec<NoteId> {
match tx {
PendingTx::Inscription(_) => Vec::new(),
PendingTx::AtomicWithdraw(bundle) => bundle
.withdraws
.iter()
.flat_map(|withdraw| withdraw.op.inputs.iter().copied())
.collect(),
}
}
/// The inscription carried by an orphaned tx (plain or atomic-withdraw bundle).
const fn orphan_inscription(orphan: &OrphanedTx) -> &InscriptionInfo {
const fn channel_update_inscription(orphan: &ChannelUpdateTx) -> Option<&InscriptionInfo> {
match orphan {
OrphanedTx::Inscription(info) => info,
OrphanedTx::AtomicWithdraw(bundle) => &bundle.inscription,
ChannelUpdateTx::Inscription(info) => Some(info),
ChannelUpdateTx::AtomicWithdraw(bundle) => Some(&bundle.inscription),
ChannelUpdateTx::Custom(_signed_mantle_tx) => None,
}
}
/// Signs a `ChannelConfig` op (accredited keys + rotation params) with
/// `signing_key` and posts it straight to the bedrock node.
/// `signing_key`, funds it from `config.funding_key` via the node's wallet,
/// and posts it straight to the bedrock node.
///
/// A standalone one-shot — no running sequencer involved, so authorization is
/// holding the admin key: the L1 rejects non-admin signers. `Ok(())` means the
@ -416,12 +461,12 @@ pub async fn post_channel_config(
posting_timeframe: u32,
posting_timeout: u32,
configuration_threshold: u16,
withdraw_threshold: u16,
transfer_threshold: u16,
) -> Result<()> {
ensure!(!keys.is_empty(), "Channel key list must not be empty");
for (name, threshold) in [
("configuration_threshold", configuration_threshold),
("withdraw_threshold", withdraw_threshold),
("transfer_threshold", transfer_threshold),
] {
ensure!(
threshold >= 1 && usize::from(threshold) <= keys.len(),
@ -442,27 +487,51 @@ pub async fn post_channel_config(
posting_timeframe: SlotTimeframe::from(posting_timeframe),
posting_timeout: SlotTimeout::from(posting_timeout),
configuration_threshold,
withdraw_threshold,
};
let mantle_tx = MantleTx([Op::ChannelConfig(config_op)].into());
let tx_hash = mantle_tx.hash();
// The admin key is `keys[0]`, hence signature index 0.
let signature = IndexedSignature::new(
0,
signing_key.sign_payload(tx_hash.as_signing_bytes().as_ref()),
);
let proof = ChannelMultiSigProof::new(vec![signature])
.map_err(|err| anyhow!("Failed to assemble channel multi-sig proof: {err:?}"))?;
let signed_tx = SignedMantleTx {
ops_proofs: vec![OpProof::ChannelMultiSigProof(proof)],
mantle_tx,
transfer_threshold,
};
let node = NodeHttpClient::new(
CommonHttpClient::new(config.auth.clone().map(Into::into)),
config.node_url.clone(),
);
// Fund the op from the node's wallet: the node appends a fee transfer
// (paid from `funding_key`, change back to it) and returns its proof.
let tx_builder = MantleTxBuilder::new()
.extend_ops([Op::ChannelConfig(config_op)])
.map_err(|err| anyhow!("Too many ops in channel config transaction: {err:?}"))?;
let funded = node
.fund_tx(WalletFundRequestBody {
tip: None,
tx_builder,
change_public_key: config.funding_key,
funding_public_keys: vec![config.funding_key],
max_tx_fee: GasCost::new(logos_blockchain_core::mantle::Value::MAX),
priority_fee: FundingConfig::DEFAULT_PRIORITY_FEE,
})
.await
.context("Failed to fund channel config transaction")?;
let mantle_tx = funded.funded_tx;
// Sign the funded tx: the appended fee transfer changes the hash.
let tx_hash = mantle_tx.hash();
// The admin key is `keys[0]`, hence signature index 0.
let signature = IndexedSignature::new(
0,
signing_key.sign_payload(tx_hash.as_signing_bytes().as_ref()),
);
let proof = ChannelMultiSigProof::try_new(signature.into())
.map_err(|err| anyhow!("Failed to assemble channel multi-sig proof: {err:?}"))?;
// Proofs follow op order; funding appends the transfer as the last op.
let mut ops_proofs: OpsProofs = OpProof::ChannelMultiSigProof(proof).into();
if let Some(transfer_proof) = funded.transfer_proof {
ops_proofs
.try_push(transfer_proof)
.map_err(|err| anyhow!("Too many operation proofs: {err:?}"))?;
}
let signed_tx = SignedMantleTx::new(mantle_tx, ops_proofs);
node.post_transaction(signed_tx)
.await
.context("Failed to post channel config transaction")

View File

@ -12,6 +12,7 @@ pub use cross_zone_inbox_core::{CrossZoneConfig, CrossZonePeer};
use humantime_serde;
use lee::{AccountId, Balance};
use logos_blockchain_core::mantle::ops::channel::ChannelId;
use logos_blockchain_key_management_system_service::keys::ZkPublicKey;
use serde::{Deserialize, Serialize};
use url::Url;
@ -72,6 +73,7 @@ pub struct BedrockConfig {
pub node_url: Url,
/// Bedrock auth.
pub auth: Option<BasicAuth>,
pub funding_key: ZkPublicKey,
}
impl SequencerConfig {

View File

@ -41,7 +41,7 @@ use storage::sequencer::{
};
use crate::{
block_publisher::{BlockPublisherTrait, MsgId, ZoneSdkPublisher},
block_publisher::{BlockPublisherTrait, MsgId, NoteId, ZoneSdkPublisher},
block_store::SequencerStore,
task_group::{StoreRelease, TaskGroup},
};
@ -268,7 +268,7 @@ impl<BP: BlockPublisherTrait> SequencerCore<BP> {
let mut last_checkpoint = None;
for block in &pending_blocks {
let (_msg, checkpoint) = block_publisher
let outcome = block_publisher
.publish_block(block, vec![])
.await
.unwrap_or_else(|err| {
@ -277,7 +277,7 @@ impl<BP: BlockPublisherTrait> SequencerCore<BP> {
block.header.block_id
)
});
last_checkpoint = Some(checkpoint);
last_checkpoint = Some(outcome.checkpoint);
}
// These blocks are already stored, so only the sdk's pending set
@ -542,18 +542,21 @@ impl<BP: BlockPublisherTrait> SequencerCore<BP> {
.build_block_from_mempool()
.context("Failed to build block from mempool transactions")?;
let withdrawal_reconciliation_keys: Vec<_> = withdrawals
.iter()
.map(|withdraw| withdraw_event_reconciliation_key(&withdraw.outputs))
.collect::<Result<Vec<_>>>()
.context("Failed to build reconciliation keys for block withdrawals")?;
let (this_msg, checkpoint) = self
let block_publisher::PublishOutcome {
this_msg,
checkpoint,
released_notes,
} = self
.block_publisher
.publish_block(&block, withdrawals)
.await
.context("Failed to publish block to Bedrock")?;
let withdrawal_reconciliation_keys: Vec<_> = released_notes
.iter()
.map(withdrawal_reconciliation_key)
.collect();
self.record_produced_block(
this_msg,
&block,
@ -1146,20 +1149,12 @@ fn apply_follow_update(
let deposit_records: Vec<PendingDepositEventRecord> =
deposits.iter().map(pending_deposit_event_record).collect();
// A withdraw whose outputs we cannot read has no counter to reconcile
// against; log and drop it rather than fail the whole update.
// One reconciliation unit per released note, matching how the intents were
// recorded at publish time.
let consumed_withdrawals: Vec<WithdrawalReconciliationKey> = withdrawals
.iter()
.filter_map(|withdraw| {
withdraw_event_reconciliation_key(&withdraw.op.outputs)
.inspect_err(|err| {
error!(
"Failed to build reconciliation key for Bedrock Withdraw event with tx_hash {}: {err:#}",
hex::encode(withdraw.tx_hash.as_ref())
);
})
.ok()
})
.flat_map(|withdraw| withdraw.op.inputs.iter())
.map(withdrawal_reconciliation_key)
.collect();
// The lock is held across the persist below so disk writes land in apply
@ -1167,12 +1162,6 @@ fn apply_follow_update(
let (resubmit_txs, outcome) = {
let mut chain = chain.lock().expect("chain state mutex poisoned");
// User txs of orphaned blocks, returned to the mempool below.
let resubmit_txs: Vec<LeeTransaction> = orphaned
.iter()
.flat_map(|(_, block)| resubmittable_txs(block))
.collect();
// Outcomes align with `adopted`.
let outcomes = chain.apply_channel_update(&orphaned, &adopted);
let mut to_persist: Vec<(&Block, bool)> = adopted
@ -1206,6 +1195,22 @@ fn apply_follow_update(
AcceptOutcome::Parked(_) | AcceptOutcome::RetryableFailure(_) => {}
}
}
// User txs of orphaned blocks, returned to the mempool below.
//
// Computed after the finalized tier has advanced, and only for blocks
// above it: the zone-sdk reports a block as orphaned once LIB pruning
// drops its inscription from the channel lineage, so every block of
// ours is orphaned a poll or two after it finalizes. Those transactions
// are irreversibly included, and returning them to the mempool puts
// them back in every block we produce from then on.
let final_height = chain.final_tip().map(|tip| tip.block_id);
let resubmit_txs: Vec<LeeTransaction> = orphaned
.iter()
.filter(|(_, block)| final_height.is_none_or(|id| block.header.block_id > id))
.flat_map(|(_, block)| resubmittable_txs(block))
.collect();
// Snapshot the advanced final tier so a restart re-anchors on it.
let final_meta = final_advanced.then(|| {
let tip = chain.final_tip().expect("advanced final tier has a tip");
@ -1265,9 +1270,8 @@ fn apply_follow_update(
}
for withdrawal in &outcome.unmatched_withdrawals {
warn!(
"Unexpected Bedrock Withdraw event of {} to {}: no matching unseen withdraw found",
withdrawal.amount,
hex::encode(withdrawal.bedrock_account_pk)
"Unexpected Bedrock Withdraw event releasing channel note {}: no matching unseen withdraw found",
hex::encode(withdrawal.released_note_id)
);
}
@ -1643,35 +1647,21 @@ fn extract_bridge_withdraw_data(tx: &LeeTransaction) -> Option<WithdrawArg> {
})
}
fn withdraw_event_reconciliation_key(
outputs: &logos_blockchain_core::mantle::ledger::Outputs,
) -> Result<WithdrawalReconciliationKey> {
let [note] = outputs.as_ref().as_slice() else {
return Err(anyhow!(
"Unsupported withdraw output count for reconciliation: {}",
outputs.len()
));
};
// `extract_bridge_withdraw_data` maps [u8;32] LE -> BigUint -> ZkPublicKey.
// Reconcile by reversing that direction here.
let mut bedrock_account_pk = BigUint::from(note.pk.into_inner()).to_bytes_le();
if bedrock_account_pk.len() > 32 {
return Err(anyhow!(
"Withdraw recipient public key is too large: {} bytes",
bedrock_account_pk.len()
));
}
bedrock_account_pk.resize(32, 0);
let bedrock_account_pk: [u8; 32] = bedrock_account_pk
/// The reconciliation identity of one released channel note.
///
/// A `ChannelWithdrawOp` releases notes the channel already owns and carries
/// only their ids — the recipient key and value live in the note itself, which
/// neither the op nor the Bedrock Withdraw event reports. The note id is
/// therefore the one handle both sides share, and it is unique: a note is spent
/// once.
fn withdrawal_reconciliation_key(note_id: &NoteId) -> WithdrawalReconciliationKey {
let released_note_id: [u8; 32] = note_id
.as_bytes()
.as_ref()
.try_into()
.expect("Public key bytes were padded/truncated to 32 bytes");
.expect("`NoteId` is a 32-byte field element");
Ok(WithdrawalReconciliationKey {
amount: note.value,
bedrock_account_pk,
})
WithdrawalReconciliationKey { released_note_id }
}
/// Load signing key from file or generate a new one if it doesn't exist.

View File

@ -5,14 +5,17 @@ use common::block::Block;
use futures::Stream;
use logos_blockchain_core::{
header::HeaderId,
mantle::ops::channel::{ChannelId, MsgId},
mantle::{
ledger::{NoteId, Utxo},
ops::channel::{ChannelId, MsgId},
},
};
use logos_blockchain_key_management_system_service::keys::Ed25519Key;
use logos_blockchain_zone_sdk::{Slot, ZoneMessage, sequencer::WithdrawArg};
use tokio_util::sync::CancellationToken;
use crate::{
block_publisher::{BlockPublisherTrait, OnFollowSink, SequencerCheckpoint},
block_publisher::{BlockPublisherTrait, OnFollowSink, PublishOutcome, SequencerCheckpoint},
config::BedrockConfig,
};
@ -70,12 +73,16 @@ impl BlockPublisherTrait for MockBlockPublisher {
async fn publish_block(
&self,
block: &Block,
_bridge_withdrawals: Vec<WithdrawArg>,
) -> Result<(MsgId, SequencerCheckpoint)> {
withdrawals: Vec<WithdrawArg>,
) -> Result<PublishOutcome> {
// Deterministic per-block id so head dedup behaves in tests.
//
// TODO: should we allow more "mockability" here?
Ok((MsgId::from(block.header.hash.0), mock_checkpoint()))
Ok(PublishOutcome {
this_msg: MsgId::from(block.header.hash.0),
checkpoint: mock_checkpoint(),
released_notes: mock_released_notes(&withdrawals),
})
}
fn channel_id(&self) -> ChannelId {
@ -108,6 +115,20 @@ impl BlockPublisherTrait for MockBlockPublisher {
}
}
/// The notes the mock reports as released by `withdrawals`.
///
/// Zone-sdk picks the actual channel notes to release, so a mock has to invent
/// them: one note id per requested output, derived from the output itself so
/// tests can recompute the reconciliation keys of a block they produced.
#[must_use]
pub(crate) fn mock_released_notes(withdrawals: &[WithdrawArg]) -> Vec<NoteId> {
withdrawals
.iter()
.flat_map(|withdraw| withdraw.outputs.into_iter().enumerate())
.map(|(output_index, note)| Utxo::new([0; 32], output_index, *note).id())
.collect()
}
/// A zeroed checkpoint, for [`MockBlockPublisher::publish_block`] and for tests
/// building a [`crate::block_publisher::FollowUpdate`]. Tests only assert *that*
/// a checkpoint was persisted alongside its effects, never what is in it.

View File

@ -8,25 +8,19 @@ use common::{
test_utils::sequencer_sign_key_for_testing,
transaction::{LeeTransaction, clock_invocation},
};
use key_protocol::key_management::KeyChain;
use lee::{
Account, AccountId, Data, PrivacyPreservingTransaction, PrivateKey, PublicKey,
PublicTransaction, V03State,
error::LeeError,
execute_and_prove,
privacy_preserving_transaction::{Message, circuit::ProgramWithDependencies},
program::Program,
Account, AccountId, Data, PrivateKey, PublicKey, PublicTransaction, V03State, program::Program,
};
use lee_core::{
Commitment, InputAccountIdentity, Nullifier,
account::{AccountWithMetadata, Nonce},
program::PdaSeed,
};
use logos_blockchain_core::mantle::{
ledger::Inputs,
ops::channel::{ChannelId, MsgId, deposit::Metadata},
tx::TxHash,
use lee_core::{account::Nonce, program::PdaSeed};
use logos_blockchain_core::{
events::DepositRecreatedNotes,
mantle::{
TxHash,
ledger::Inputs,
ops::channel::{ChannelId, MsgId, deposit::Metadata},
},
};
use logos_blockchain_key_management_system_service::keys::ZkPublicKey;
use logos_blockchain_zone_sdk::sequencer::DepositInfo;
use mempool::MemPoolHandle;
use ping_core::{ReceiverInstruction, ping_record_pda};
@ -88,6 +82,7 @@ fn setup_sequencer_config() -> SequencerConfig {
channel_id: ChannelId::from([0; 32]),
node_url: "http://not-used-in-unit-tests".parse().unwrap(),
auth: None,
funding_key: ZkPublicKey::zero(),
},
retry_pending_blocks_timeout: Duration::from_mins(4),
genesis: vec![],
@ -1474,94 +1469,94 @@ async fn block_production_aborts_when_clock_account_data_is_corrupted() {
);
}
#[test]
fn private_bridge_withdraw_invocation_is_dropped() {
let sender_keys = KeyChain::new_os_random();
let sender_account_id = AccountId::for_regular_private_account(
&sender_keys.nullifier_public_key,
&sender_keys.viewing_public_key,
0,
);
let sender_private_account = Account {
program_owner: programs::authenticated_transfer().id(),
balance: 100,
nonce: Nonce(0xdead_beef),
data: Data::default(),
};
let bridge_account_id = system_accounts::bridge_account_id();
// #[test]
// fn private_bridge_withdraw_invocation_is_dropped() {
// let sender_keys = KeyChain::new_os_random();
// let sender_account_id = AccountId::for_regular_private_account(
// &sender_keys.nullifier_public_key,
// &sender_keys.viewing_public_key,
// 0,
// );
// let sender_private_account = Account {
// 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_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),
)]);
// 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),
// )]);
let sender_commitment = Commitment::new(&sender_account_id, &sender_private_account);
// let sender_commitment = Commitment::new(&sender_account_id, &sender_private_account);
let sender_pre = AccountWithMetadata::new(
sender_private_account,
true,
(
&sender_keys.nullifier_public_key,
&sender_keys.viewing_public_key,
0,
),
);
let bridge_pre = AccountWithMetadata::new(
state.get_account_by_id(bridge_account_id),
false,
bridge_account_id,
);
// let sender_pre = AccountWithMetadata::new(
// sender_private_account,
// true,
// (
// &sender_keys.nullifier_public_key,
// &sender_keys.viewing_public_key,
// 0,
// ),
// );
// let bridge_pre = AccountWithMetadata::new(
// state.get_account_by_id(bridge_account_id),
// false,
// bridge_account_id,
// );
let instruction = Program::serialize_instruction(bridge_core::Instruction::Withdraw {
amount: 1,
bedrock_account_pk: [0; 32],
})
.unwrap();
// let instruction = Program::serialize_instruction(bridge_core::Instruction::Withdraw {
// amount: 1,
// bedrock_account_pk: [0; 32],
// })
// .unwrap();
let program_with_deps = ProgramWithDependencies::new(
programs::bridge(),
[(
programs::authenticated_transfer().id(),
programs::authenticated_transfer(),
)]
.into(),
);
// let program_with_deps = ProgramWithDependencies::new(
// programs::bridge(),
// [(
// programs::authenticated_transfer().id(),
// programs::authenticated_transfer(),
// )]
// .into(),
// );
let (output, proof) = execute_and_prove(
vec![sender_pre, bridge_pre],
instruction,
vec![
InputAccountIdentity::PrivateAuthorizedUpdate {
vpk: sender_keys.viewing_public_key.clone(),
random_seed: [0; 32],
view_tag: 0,
nsk: sender_keys.private_key_holder.nullifier_secret_key,
membership_proof: state
.get_proof_for_commitment(&sender_commitment)
.expect("sender commitment must be in state"),
identifier: 0,
},
InputAccountIdentity::Public,
],
&program_with_deps,
)
.expect("Execution should succeed");
// let (output, proof) = execute_and_prove(
// vec![sender_pre, bridge_pre],
// instruction,
// vec![
// InputAccountIdentity::PrivateAuthorizedUpdate {
// vpk: sender_keys.viewing_public_key.clone(),
// random_seed: [0; 32],
// view_tag: 0,
// nsk: sender_keys.private_key_holder.nullifier_secret_key,
// membership_proof: state
// .get_proof_for_commitment(&sender_commitment)
// .expect("sender commitment must be in state"),
// identifier: 0,
// },
// InputAccountIdentity::Public,
// ],
// &program_with_deps,
// )
// .expect("Execution should succeed");
let message = Message::try_from_circuit_output(vec![bridge_account_id], vec![], output)
.expect("Message construction should succeed");
let witness_set =
lee::privacy_preserving_transaction::WitnessSet::for_message(&message, proof, &[]);
let tx =
LeeTransaction::PrivacyPreserving(PrivacyPreservingTransaction::new(message, witness_set));
let res = tx.execute_check_on_state(&mut state, 1, 0);
// let message = Message::try_from_circuit_output(vec![bridge_account_id], vec![], output)
// .expect("Message construction should succeed");
// let witness_set =
// lee::privacy_preserving_transaction::WitnessSet::for_message(&message, proof, &[]);
// let tx =
// LeeTransaction::PrivacyPreserving(PrivacyPreservingTransaction::new(message,
// witness_set)); let res = tx.execute_check_on_state(&mut state, 1, 0);
assert!(
matches!(res, Err(LeeError::InvalidInput(_))),
"Bridge withdraw invocation should be rejected in private execution"
);
}
// assert!(
// matches!(res, Err(LeeError::InvalidInput(_))),
// "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
@ -2022,6 +2017,7 @@ async fn follow_update_records_deposits_for_the_production_drain() {
inputs: Inputs::empty(),
amount: 5,
metadata: Metadata::try_from(metadata).expect("deposit metadata fits"),
notes: DepositRecreatedNotes::default(),
};
apply_follow_update(
@ -2176,6 +2172,68 @@ async fn follow_orphan_reverts_head_and_requeues_user_txs() {
);
}
#[tokio::test]
async fn follow_orphan_of_a_finalized_block_requeues_nothing() {
// The zone-sdk reports a block as orphaned once LIB pruning drops its
// inscription from the channel lineage, which happens a poll or two after
// every block of ours finalizes. Its transactions are irreversibly
// included, so requeueing them would put them back in every block we
// produce from then on.
let config = setup_sequencer_config();
let (mut sequencer, mempool_handle) =
SequencerCoreWithMockClients::start_from_config(config).await;
let acc1 = initial_public_user_accounts()[0].account_id;
let acc2 = initial_public_user_accounts()[1].account_id;
let tx = common::test_utils::create_transaction_native_token_transfer(
acc1,
0,
acc2,
10,
&create_signing_key_for_account1(),
);
mempool_handle
.push((TransactionOrigin::User, tx))
.await
.unwrap();
sequencer.produce_new_block().await.unwrap();
let block2 = sequencer.store.get_block_at_id(2).unwrap().unwrap();
apply_follow_update(
&sequencer.store.dbio(),
&sequencer.chain(),
&mempool_handle,
FollowUpdate {
finalized: vec![(MsgId::from(block2.header.hash.0), block2.clone())],
..empty_follow_update()
},
);
apply_follow_update(
&sequencer.store.dbio(),
&sequencer.chain(),
&mempool_handle,
FollowUpdate {
orphaned: vec![(MsgId::from(block2.header.hash.0), block2)],
..empty_follow_update()
},
);
assert_eq!(
sequencer.chain_height(),
2,
"an irreversible block cannot be reverted"
);
assert_eq!(
sequencer.with_state(|s| s.get_account_by_id(acc2).balance),
20010,
"the finalized transfer stands"
);
assert!(
sequencer.mempool.pop().is_none(),
"a transaction that is already irreversible must not be requeued"
);
}
#[tokio::test]
async fn follow_finalized_own_block_moves_final_tier_and_marks_store() {
let config = setup_sequencer_config();

View File

@ -298,219 +298,230 @@ fn deposit_event_record(
}
}
/// Builds a signed public bridge `Withdraw` transaction (the normal user path).
fn build_public_withdraw_tx(
sender: lee::AccountId,
nonce: u128,
amount: u64,
bedrock_account_pk: [u8; 32],
signing_key: &lee::PrivateKey,
) -> LeeTransaction {
let message = lee::public_transaction::Message::try_new(
programs::bridge().id(),
vec![sender, system_accounts::bridge_account_id()],
vec![nonce.into()],
bridge_core::Instruction::Withdraw {
amount,
bedrock_account_pk,
},
)
.unwrap();
let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
LeeTransaction::Public(lee::PublicTransaction::new(message, witness_set))
}
// /// Builds a signed public bridge `Withdraw` transaction (the normal user path).
// fn build_public_withdraw_tx(
// sender: lee::AccountId,
// nonce: u128,
// amount: u64,
// bedrock_account_pk: [u8; 32],
// signing_key: &lee::PrivateKey,
// ) -> LeeTransaction {
// let message = lee::public_transaction::Message::try_new(
// programs::bridge().id(),
// vec![sender, system_accounts::bridge_account_id()],
// vec![nonce.into()],
// bridge_core::Instruction::Withdraw {
// amount,
// bedrock_account_pk,
// },
// )
// .unwrap();
// let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
// LeeTransaction::Public(lee::PublicTransaction::new(message, witness_set))
// }
/// Cold-start backfill re-records an already-finalized deposit event as a
/// pending record before reconstruction replays the same deposit block.
/// Reconstruction must drop that record — its mint is permanently reflected in
/// the reconstructed state (the receipt PDA) — so the next production neither
/// re-mints the vault nor emits a stray deposit tx.
#[tokio::test]
async fn reconstructed_deposit_is_not_reminted_after_backfill_redelivery() {
let recipient = initial_public_user_accounts()[0].account_id;
let deposit_amount = 500_u64;
let withdraw_amount = 100_u64;
let bedrock_account_pk = [0x22_u8; 32];
let deposit_op_id = [0x0d_u8; 32];
// /// The reconciliation key a produced block carries for `withdraw_tx`, keyed on
// /// the note [`MockBlockPublisher`] reports as released for it.
// fn produced_withdraw_key(withdraw_tx: &LeeTransaction) -> WithdrawalReconciliationKey {
// let withdraw_arg = crate::extract_bridge_withdraw_data(withdraw_tx).expect("withdraw data");
// let [note_id] = crate::mock::mock_released_notes(std::slice::from_ref(&withdraw_arg))[..]
// else {
// panic!("A bridge withdraw releases exactly one note");
// };
// Sequencer A produces a deposit block then a withdraw block.
let config_a = bridge_funded_config();
let (mut seq_a, mempool_a) =
SequencerCoreWithMockClients::start_from_config(config_a.clone()).await;
// crate::withdrawal_reconciliation_key(&note_id)
// }
let deposit_record = deposit_event_record(deposit_op_id, deposit_amount, recipient);
let deposit_tx =
crate::build_bridge_deposit_tx_from_event(&deposit_record).expect("build deposit tx");
mempool_a
.push((TransactionOrigin::Sequencer, deposit_tx))
.await
.unwrap();
seq_a.produce_new_block().await.unwrap();
// /// Cold-start backfill re-records an already-finalized deposit event as a
// /// pending record before reconstruction replays the same deposit block.
// /// Reconstruction must drop that record — its mint is permanently reflected in
// /// the reconstructed state (the receipt PDA) — so the next production neither
// /// re-mints the vault nor emits a stray deposit tx.
// #[tokio::test]
// async fn reconstructed_deposit_is_not_reminted_after_backfill_redelivery() {
// let recipient = initial_public_user_accounts()[0].account_id;
// let deposit_amount = 500_u64;
// let withdraw_amount = 100_u64;
// let bedrock_account_pk = [0x22_u8; 32];
// let deposit_op_id = [0x0d_u8; 32];
let withdraw_tx = build_public_withdraw_tx(
recipient,
0,
withdraw_amount,
bedrock_account_pk,
&create_signing_key_for_account1(),
);
mempool_a
.push((TransactionOrigin::User, withdraw_tx.clone()))
.await
.unwrap();
seq_a.produce_new_block().await.unwrap();
// // Sequencer A produces a deposit block then a withdraw block.
// let config_a = bridge_funded_config();
// let (mut seq_a, mempool_a) =
// SequencerCoreWithMockClients::start_from_config(config_a.clone()).await;
let tip_a = seq_a.block_store().latest_block_meta().unwrap().unwrap();
let messages = channel_from_store(seq_a.block_store(), 10);
let tip_slot = messages.last().unwrap().1;
let channel_id = config_a.bedrock_config.channel_id;
// let deposit_record = deposit_event_record(deposit_op_id, deposit_amount, recipient);
// let deposit_tx =
// crate::build_bridge_deposit_tx_from_event(&deposit_record).expect("build deposit tx");
// mempool_a
// .push((TransactionOrigin::Sequencer, deposit_tx))
// .await
// .unwrap();
// seq_a.produce_new_block().await.unwrap();
let config_b = bridge_funded_config();
let (mut seq_b, _mempool_b) = SequencerCoreWithMockClients::start_from_config(config_b).await;
// let withdraw_tx = build_public_withdraw_tx(
// recipient,
// 0,
// withdraw_amount,
// bedrock_account_pk,
// &create_signing_key_for_account1(),
// );
// mempool_a
// .push((TransactionOrigin::User, withdraw_tx.clone()))
// .await
// .unwrap();
// seq_a.produce_new_block().await.unwrap();
// Backfill re-delivery: the deposit event is re-recorded as a pending record
// before reconstruction runs. The mint no longer flows through the mempool
// (that sink was removed); the store drain is the only source.
assert!(
seq_b
.block_store()
.dbio()
.add_pending_deposit_event(deposit_record.clone())
.unwrap()
);
// let tip_a = seq_a.block_store().latest_block_meta().unwrap().unwrap();
// let messages = channel_from_store(seq_a.block_store(), 10);
// let tip_slot = messages.last().unwrap().1;
// let channel_id = config_a.bedrock_config.channel_id;
let mock_b = MockBlockPublisher::with_canned_channel(channel_id, Some(tip_slot), messages);
SequencerCore::<MockBlockPublisher>::verify_and_reconstruct(
&mock_b,
&seq_b.store,
&seq_b.chain,
true,
)
.await
.expect("reconstruct");
// let config_b = bridge_funded_config();
// let (mut seq_b, _mempool_b) =
// SequencerCoreWithMockClients::start_from_config(config_b).await;
let tip_b = seq_b.block_store().latest_block_meta().unwrap().unwrap();
assert_eq!(tip_b.id, tip_a.id);
assert_eq!(tip_b.hash, tip_a.hash);
// // Backfill re-delivery: the deposit event is re-recorded as a pending record
// // before reconstruction runs. The mint no longer flows through the mempool
// // (that sink was removed); the store drain is the only source.
// assert!(
// seq_b
// .block_store()
// .dbio()
// .add_pending_deposit_event(deposit_record.clone())
// .unwrap()
// );
// Reconstruction replays the finalized deposit block, minting the receipt
// into state and dropping the re-recorded pending event — so the drain has
// nothing left to re-mint. This is the mechanism that protects against the
// re-delivery, in place of the removed mempool sink.
assert!(
seq_b
.block_store()
.dbio()
.get_pending_deposit_events()
.unwrap()
.is_empty(),
"reconstruction must drop the re-delivered pending deposit record"
);
// let mock_b = MockBlockPublisher::with_canned_channel(channel_id, Some(tip_slot), messages);
// SequencerCore::<MockBlockPublisher>::verify_and_reconstruct(
// &mock_b,
// &seq_b.store,
// &seq_b.chain,
// true,
// )
// .await
// .expect("reconstruct");
seq_b.produce_new_block().await.unwrap();
// let tip_b = seq_b.block_store().latest_block_meta().unwrap().unwrap();
// assert_eq!(tip_b.id, tip_a.id);
// assert_eq!(tip_b.hash, tip_a.hash);
let vault_id = vault_core::compute_vault_account_id(programs::vault().id(), recipient);
let bridge_id = system_accounts::bridge_account_id();
let state_b = seq_b.chain().lock().unwrap().head_state().clone();
let state_a = seq_a.chain().lock().unwrap().head_state().clone();
for account in [vault_id, bridge_id, recipient] {
assert_eq!(
state_b.get_account_by_id(account).balance,
state_a.get_account_by_id(account).balance,
"reconstructed balance mismatch for {account:?}",
);
}
assert_eq!(
state_b.get_account_by_id(vault_id).balance,
u128::from(deposit_amount),
"deposit must mint into the recipient vault exactly once, not twice"
);
// // Reconstruction replays the finalized deposit block, minting the receipt
// // into state and dropping the re-recorded pending event — so the drain has
// // nothing left to re-mint. This is the mechanism that protects against the
// // re-delivery, in place of the removed mempool sink.
// assert!(
// seq_b
// .block_store()
// .dbio()
// .get_pending_deposit_events()
// .unwrap()
// .is_empty(),
// "reconstruction must drop the re-delivered pending deposit record"
// );
let produced = seq_b
.block_store()
.get_block_at_id(tip_b.id + 1)
.unwrap()
.expect("produced block present");
assert!(
!produced
.body
.transactions
.iter()
.any(|tx| crate::extract_bridge_deposit_id(tx) == Some(HashType(deposit_op_id))),
"the re-delivered mint must be skipped, not re-included in a block"
);
// seq_b.produce_new_block().await.unwrap();
// A reconstructed withdraw's finalized L1 event was already re-delivered (and
// dropped) by cold-start backfill, so it will never be consumed again.
// Reconstruction must not count it, or the count stays phantom-inflated forever.
let withdraw_arg = crate::extract_bridge_withdraw_data(&withdraw_tx).expect("withdraw data");
let key = crate::withdraw_event_reconciliation_key(&withdraw_arg.outputs).expect("recon key");
assert!(
!seq_b
.block_store()
.dbio()
.consume_unseen_withdraw_count(key)
.unwrap(),
"reconstruction must not leave a phantom unseen-withdraw count"
);
}
// let vault_id = vault_core::compute_vault_account_id(programs::vault().id(), recipient);
// let bridge_id = system_accounts::bridge_account_id();
// let state_b = seq_b.chain().lock().unwrap().head_state().clone();
// let state_a = seq_a.chain().lock().unwrap().head_state().clone();
// for account in [vault_id, bridge_id, recipient] {
// assert_eq!(
// state_b.get_account_by_id(account).balance,
// state_a.get_account_by_id(account).balance,
// "reconstructed balance mismatch for {account:?}",
// );
// }
// assert_eq!(
// state_b.get_account_by_id(vault_id).balance,
// u128::from(deposit_amount),
// "deposit must mint into the recipient vault exactly once, not twice"
// );
/// A reconstructed withdraw block must not touch the unseen-withdraw counter.
/// Its finalized L1 Withdraw event was already re-delivered (and dropped as a
/// no-op) by cold-start backfill, so counting it during reconstruction would
/// leave a permanent phantom that nothing ever consumes.
#[tokio::test]
async fn reconstructed_withdraw_leaves_no_phantom_unseen_count() {
let recipient = initial_public_user_accounts()[0].account_id;
let withdraw_amount = 100_u64;
let bedrock_account_pk = [0x33_u8; 32];
// let produced = seq_b
// .block_store()
// .get_block_at_id(tip_b.id + 1)
// .unwrap()
// .expect("produced block present");
// assert!(
// !produced
// .body
// .transactions
// .iter()
// .any(|tx| crate::extract_bridge_deposit_id(tx) == Some(HashType(deposit_op_id))),
// "the re-delivered mint must be skipped, not re-included in a block"
// );
// Sequencer A produces a single withdraw block; treat its chain as the channel.
let config_a = bridge_funded_config();
let (mut seq_a, mempool_a) =
SequencerCoreWithMockClients::start_from_config(config_a.clone()).await;
let withdraw_tx = build_public_withdraw_tx(
recipient,
0,
withdraw_amount,
bedrock_account_pk,
&create_signing_key_for_account1(),
);
mempool_a
.push((TransactionOrigin::User, withdraw_tx.clone()))
.await
.unwrap();
seq_a.produce_new_block().await.unwrap();
// // A reconstructed withdraw's finalized L1 event was already re-delivered (and
// // dropped) by cold-start backfill, so it will never be consumed again.
// // Reconstruction must not count it, or the count stays phantom-inflated forever.
// let key = produced_withdraw_key(&withdraw_tx);
// assert!(
// !seq_b
// .block_store()
// .dbio()
// .consume_unseen_withdraw_count(key)
// .unwrap(),
// "reconstruction must not leave a phantom unseen-withdraw count"
// );
// }
let withdraw_arg = crate::extract_bridge_withdraw_data(&withdraw_tx).expect("withdraw data");
let key = crate::withdraw_event_reconciliation_key(&withdraw_arg.outputs).expect("recon key");
// Producing the withdraw counts it as unseen, awaiting its L1 event.
assert!(
seq_a
.block_store()
.dbio()
.consume_unseen_withdraw_count(key)
.unwrap(),
"producing a withdraw must count it as unseen"
);
// /// A reconstructed withdraw block must not touch the unseen-withdraw counter.
// /// Its finalized L1 Withdraw event was already re-delivered (and dropped as a
// /// no-op) by cold-start backfill, so counting it during reconstruction would
// /// leave a permanent phantom that nothing ever consumes.
// #[tokio::test]
// async fn reconstructed_withdraw_leaves_no_phantom_unseen_count() {
// let recipient = initial_public_user_accounts()[0].account_id;
// let withdraw_amount = 100_u64;
// let bedrock_account_pk = [0x33_u8; 32];
let messages = channel_from_store(seq_a.block_store(), 10);
let tip_slot = messages.last().unwrap().1;
let channel_id = config_a.bedrock_config.channel_id;
// // Sequencer A produces a single withdraw block; treat its chain as the channel.
// let config_a = bridge_funded_config();
// let (mut seq_a, mempool_a) =
// SequencerCoreWithMockClients::start_from_config(config_a.clone()).await;
// let withdraw_tx = build_public_withdraw_tx(
// recipient,
// 0,
// withdraw_amount,
// bedrock_account_pk,
// &create_signing_key_for_account1(),
// );
// mempool_a
// .push((TransactionOrigin::User, withdraw_tx.clone()))
// .await
// .unwrap();
// seq_a.produce_new_block().await.unwrap();
// Sequencer B reconstructs A's chain from a fresh store.
let config_b = bridge_funded_config();
let (store_b, chain_b) = fresh_store_and_chain(&config_b);
let mock_b = MockBlockPublisher::with_canned_channel(channel_id, Some(tip_slot), messages);
SequencerCore::<MockBlockPublisher>::verify_and_reconstruct(&mock_b, &store_b, &chain_b, true)
.await
.expect("reconstruct");
// let key = produced_withdraw_key(&withdraw_tx);
// // Producing the withdraw counts it as unseen, awaiting its L1 event.
// assert!(
// seq_a
// .block_store()
// .dbio()
// .consume_unseen_withdraw_count(key)
// .unwrap(),
// "producing a withdraw must count it as unseen"
// );
assert!(
!store_b.dbio().consume_unseen_withdraw_count(key).unwrap(),
"reconstruction must not leave a phantom unseen-withdraw count"
);
}
// let messages = channel_from_store(seq_a.block_store(), 10);
// let tip_slot = messages.last().unwrap().1;
// let channel_id = config_a.bedrock_config.channel_id;
// // Sequencer B reconstructs A's chain from a fresh store.
// let config_b = bridge_funded_config();
// let (store_b, chain_b) = fresh_store_and_chain(&config_b);
// let mock_b = MockBlockPublisher::with_canned_channel(channel_id, Some(tip_slot), messages);
// SequencerCore::<MockBlockPublisher>::verify_and_reconstruct(&mock_b, &store_b, &chain_b,
// true) .await
// .expect("reconstruct");
// assert!(
// !store_b.dbio().consume_unseen_withdraw_count(key).unwrap(),
// "reconstruction must not leave a phantom unseen-withdraw count"
// );
// }
/// A deposit whose L1 event was observed (an unfulfilled pending record
/// exists) and whose L2 mint is already contained in a finalized channel block.

View File

@ -11,7 +11,8 @@
"max_retries": 5
},
"channel_id": "0101010101010101010101010101010101010101010101010101010101010101",
"node_url": "http://localhost:18080"
"node_url": "http://localhost:18080",
"funding_key": "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"
},
"genesis": [
{

View File

@ -11,7 +11,8 @@
"max_retries": 5
},
"channel_id": "0101010101010101010101010101010101010101010101010101010101010101",
"node_url": "http://host.docker.internal:18080"
"node_url": "http://host.docker.internal:18080",
"funding_key": "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"
},
"genesis": [
{

View File

@ -31,9 +31,9 @@ struct Args {
/// Signatures required for future config changes.
#[clap(long, default_value_t = 1)]
configuration_threshold: u16,
/// Signatures required for channel withdrawals.
/// Signatures required for channel transfers.
#[clap(long, default_value_t = 1)]
withdraw_threshold: u16,
transfer_threshold: u16,
}
#[tokio::main]
@ -58,7 +58,7 @@ async fn main() -> Result<()> {
args.posting_timeframe,
args.posting_timeout,
args.configuration_threshold,
args.withdraw_threshold,
args.transfer_threshold,
)
.await
}

View File

@ -775,8 +775,8 @@ impl RocksDBIO {
/// returning one entry per occurrence that matched no local counter.
///
/// Occurrences are folded per key for the same reason as the deposit
/// records: two withdrawals in one update can share a reconciliation key,
/// and a per-occurrence disk read would miss the staged decrement.
/// records: should two withdrawals in one update share a reconciliation
/// key, a per-occurrence disk read would miss the staged decrement.
fn stage_consumed_withdrawals(
&self,
withdrawals: &[WithdrawalReconciliationKey],
@ -853,8 +853,8 @@ impl RocksDBIO {
/// Stages the unseen-withdraw increments for one update into `batch`.
///
/// Occurrences are folded per key for the same reason as
/// [`Self::stage_consumed_withdrawals`]: two intents in one update can share
/// a reconciliation key, and a per-occurrence disk read would miss the
/// [`Self::stage_consumed_withdrawals`]: should two intents in one update
/// share a reconciliation key, a per-occurrence disk read would miss the
/// staged increment and count the pair once.
fn stage_new_withdraw_intents(
&self,

View File

@ -421,10 +421,12 @@ impl SimpleWritableCell for PeerFloorCellRef<'_> {
}
}
/// Identity of one withdrawal, shared by the intent recorded when the
/// sequencer publishes it and the Bedrock Withdraw event that later reports
/// it: the id of the channel note the withdrawal releases.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WithdrawalReconciliationKey {
pub amount: u64,
pub bedrock_account_pk: [u8; 32],
pub released_note_id: [u8; 32],
}
#[derive(Debug, BorshSerialize, BorshDeserialize)]
@ -437,12 +439,9 @@ impl SimpleStorableCell for UnseenWithdrawCountCell {
const CF_NAME: &'static str = CF_META_NAME;
fn key_constructor(key_params: Self::KeyParams) -> DbResult<Vec<u8>> {
let WithdrawalReconciliationKey {
amount,
bedrock_account_pk,
} = key_params;
let WithdrawalReconciliationKey { released_note_id } = key_params;
borsh::to_vec(&(Self::CELL_NAME, amount, bedrock_account_pk)).map_err(|err| {
borsh::to_vec(&(Self::CELL_NAME, released_note_id)).map_err(|err| {
DbError::borsh_cast_message(
err,
Some(format!(

View File

@ -581,13 +581,11 @@ fn repeated_withdrawal_key_in_one_update_folds_once_per_occurrence() {
let (dbio, _genesis) = dbio_with_genesis(temp_dir.path());
let key = WithdrawalReconciliationKey {
amount: 7,
bedrock_account_pk: [3; 32],
released_note_id: [3; 32],
};
// Two local intents for the same key in one update — two withdrawals of the
// same amount to the same L1 key. A per-occurrence disk read would miss the
// staged increment and record the pair as one.
// Two local intents for the same key in one update. A per-occurrence disk
// read would miss the staged increment and record the pair as one.
dbio.store_update(&StoreUpdate {
new_withdraw_intents: &[key, key],
..StoreUpdate::new(&state_with_balance(100))
@ -626,8 +624,7 @@ fn unmatched_withdrawal_is_reported_and_writes_nothing() {
let (dbio, _genesis) = dbio_with_genesis(temp_dir.path());
let key = WithdrawalReconciliationKey {
amount: 5,
bedrock_account_pk: [4; 32],
released_note_id: [4; 32],
};
let outcome = dbio
.store_update(&StoreUpdate {

View File

@ -25,8 +25,10 @@ bip39.workspace = true
bytesize.workspace = true
env_logger.workspace = true
futures.workspace = true
hex.workspace = true
jsonrpsee = { workspace = true, features = ["ws-client"] }
log.workspace = true
num-bigint.workspace = true
serde.workspace = true
serde_json.workspace = true
tempfile.workspace = true
@ -34,3 +36,6 @@ testcontainers = { version = "0.27.3", features = ["docker-compose"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tokio-util.workspace = true
url.workspace = true
time.workspace = true
logos-blockchain-key-management-system-service.workspace = true

View File

@ -6,6 +6,8 @@ use indexer_service::{ChannelId, ClientConfig, IndexerConfig};
use key_protocol::key_management::{KeyChain, secret_holders::SeedHolder};
use lee::{AccountId, PrivateKey, PublicKey};
use lee_core::Identifier;
use logos_blockchain_key_management_system_service::keys::ZkPublicKey;
use num_bigint::BigUint;
use sequencer_core::config::{BedrockConfig, CrossZoneConfig, GenesisAction, SequencerConfig};
use url::Url;
use wallet::config::{MultiSequencerClientConfig, SequencerConnectionData, WalletConfig};
@ -76,29 +78,11 @@ impl std::fmt::Display for UrlProtocol {
}
pub fn sequencer_config(
partial: SequencerPartialConfig,
home: PathBuf,
bedrock_addr: SocketAddr,
genesis_transactions: Vec<GenesisAction>,
cross_zone: Option<CrossZoneConfig>,
) -> Result<SequencerConfig> {
sequencer_config_with_channel(
partial,
home,
bedrock_addr,
bedrock_channel_id(),
genesis_transactions,
cross_zone,
)
}
/// Like [`sequencer_config`] but with an explicit Bedrock `channel_id`, so tests
/// can point a sequencer at a fresh/empty channel (e.g. to model a wiped Bedrock).
pub fn sequencer_config_with_channel(
partial: SequencerPartialConfig,
home: PathBuf,
bedrock_addr: SocketAddr,
channel_id: ChannelId,
funding_key: ZkPublicKey,
genesis_transactions: Vec<GenesisAction>,
cross_zone: Option<CrossZoneConfig>,
) -> Result<SequencerConfig> {
@ -122,6 +106,7 @@ pub fn sequencer_config_with_channel(
channel_id,
node_url: addr_to_url(UrlProtocol::Http, bedrock_addr)
.context("Failed to convert bedrock addr to URL")?,
funding_key,
auth: None,
},
cross_zone,
@ -280,3 +265,12 @@ pub fn bedrock_channel_id_b() -> ChannelId {
.unwrap_or_else(|_| unreachable!());
ChannelId::from(channel_id)
}
/// Funding key of the Bedrock test node, matching `funding_pk` in `bedrock/node-config.yaml`.
#[must_use]
pub fn bedrock_funding_key() -> ZkPublicKey {
const PUBLIC_KEY_HEX: &str = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26";
let bytes = hex::decode(PUBLIC_KEY_HEX).expect("Fixed funding key must be valid hex");
ZkPublicKey::from(BigUint::from_bytes_le(&bytes))
}

View File

@ -131,11 +131,12 @@ impl SequencerSetup {
Vec::new()
};
let config = config::sequencer_config_with_channel(
let config = config::sequencer_config(
partial,
home.to_owned(),
bedrock_addr,
channel_id,
config::bedrock_funding_key(),
genesis_transactions,
cross_zone,
)