From 3224b45bbde4dc2e4d6f38f8499dedbab08cfc81 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sat, 23 Nov 2024 23:25:45 +0100 Subject: [PATCH 001/212] feat: new crate --- Cargo.lock | 1311 ++++++++- Cargo.toml | 2 + core/lib/via_validation/Cargo.toml | 29 + .../examples/zksync-era/abis/IVerifier.json | 44 + .../examples/zksync-era/abis/IZkSync.json | 2384 +++++++++++++++++ .../examples/zksync-era/contract.rs | 134 + .../examples/zksync-era/fetching.rs | 493 ++++ .../examples/zksync-era/main.rs | 106 + .../examples/zksync-era/types.rs | 30 + .../protocol_version/24/scheduler_key.json | 399 +++ core/lib/via_validation/src/block_header.rs | 145 + core/lib/via_validation/src/crypto.rs | 216 ++ core/lib/via_validation/src/errors.rs | 56 + .../lib/via_validation/src/l1_data_fetcher.rs | 44 + core/lib/via_validation/src/lib.rs | 9 + core/lib/via_validation/src/proof.rs | 65 + core/lib/via_validation/src/public_inputs.rs | 27 + core/lib/via_validation/src/types.rs | 66 + core/lib/via_validation/src/utils.rs | 30 + core/lib/via_validation/src/verification.rs | 208 ++ 20 files changed, 5706 insertions(+), 92 deletions(-) create mode 100644 core/lib/via_validation/Cargo.toml create mode 100644 core/lib/via_validation/examples/zksync-era/abis/IVerifier.json create mode 100644 core/lib/via_validation/examples/zksync-era/abis/IZkSync.json create mode 100644 core/lib/via_validation/examples/zksync-era/contract.rs create mode 100644 core/lib/via_validation/examples/zksync-era/fetching.rs create mode 100644 core/lib/via_validation/examples/zksync-era/main.rs create mode 100644 core/lib/via_validation/examples/zksync-era/types.rs create mode 100644 core/lib/via_validation/keys/protocol_version/24/scheduler_key.json create mode 100644 core/lib/via_validation/src/block_header.rs create mode 100644 core/lib/via_validation/src/crypto.rs create mode 100644 core/lib/via_validation/src/errors.rs create mode 100644 core/lib/via_validation/src/l1_data_fetcher.rs create mode 100644 core/lib/via_validation/src/lib.rs create mode 100644 core/lib/via_validation/src/proof.rs create mode 100644 core/lib/via_validation/src/public_inputs.rs create mode 100644 core/lib/via_validation/src/types.rs create mode 100644 core/lib/via_validation/src/utils.rs create mode 100644 core/lib/via_validation/src/verification.rs diff --git a/Cargo.lock b/Cargo.lock index 071f8d160..803ef0b75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addchain" version = "0.2.0" @@ -41,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -404,15 +414,26 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "syn 2.0.76", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures 0.3.30", + "pharos", + "rustc_version 0.4.0", +] + [[package]] name = "atoi" version = "2.0.0" @@ -439,6 +460,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -583,6 +616,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58", + "sha2 0.8.2", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -593,6 +642,12 @@ dependencies = [ "bitcoin_hashes", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.1" @@ -617,6 +672,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + [[package]] name = "bech32" version = "0.11.0" @@ -762,7 +823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6" dependencies = [ "base58ck", - "bech32", + "bech32 0.11.0", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -857,6 +918,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + [[package]] name = "bitvec" version = "1.0.1" @@ -864,7 +935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", - "radium", + "radium 0.7.0", "tap", "wyz", ] @@ -877,7 +948,7 @@ checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ "crypto-mac", "digest 0.9.0", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -942,14 +1013,26 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", - "generic-array", + "block-padding 0.2.1", + "generic-array 0.14.7", ] [[package]] @@ -958,7 +1041,16 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -1041,6 +1133,37 @@ dependencies = [ "unroll", ] +[[package]] +name = "boojum" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c986d4816d76dddb81594b94a59d2c2978a8a5e5695d6de1fdc3edd833e026" +dependencies = [ + "arrayvec 0.7.6", + "bincode", + "blake2 0.10.6", + "const_format", + "convert_case", + "crossbeam 0.8.4", + "crypto-bigint 0.5.5", + "derivative", + "ethereum-types", + "firestorm", + "itertools 0.10.5", + "lazy_static", + "num-modular", + "num_cpus", + "rand 0.8.5", + "rayon", + "serde", + "sha2 0.10.8", + "sha3_ce", + "smallvec", + "unroll", + "zksync_cs_derive", + "zksync_pairing", +] + [[package]] name = "borsh" version = "1.5.1" @@ -1065,6 +1188,12 @@ dependencies = [ "syn_derive", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + [[package]] name = "bs58" version = "0.5.1" @@ -1092,6 +1221,12 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "bytecheck" version = "0.6.12" @@ -1183,6 +1318,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.23", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cast" version = "0.3.0" @@ -1280,7 +1429,7 @@ version = "0.4.0" source = "git+https://github.com/eigerco/lumina.git#f11959550851afb8c2062b30e38cc87242467cdc" dependencies = [ "base64 0.22.1", - "bech32", + "bech32 0.11.0", "blockstore", "bytes", "celestia-proto", @@ -1424,6 +1573,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "circuit_definitions" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "circuit_encodings 0.150.16", + "crossbeam 0.8.4", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", +] + [[package]] name = "circuit_encodings" version = "0.140.1" @@ -1472,6 +1634,17 @@ dependencies = [ "zkevm_circuits 0.150.4", ] +[[package]] +name = "circuit_encodings" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "derivative", + "serde", + "zk_evm 0.150.16", + "zkevm_circuits 0.150.16", +] + [[package]] name = "circuit_sequencer_api" version = "0.133.0" @@ -1645,6 +1818,63 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "coins-bip32" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" +dependencies = [ + "bincode", + "bs58 0.4.0", + "coins-core", + "digest 0.10.7", + "getrandom", + "hmac", + "k256 0.11.6", + "lazy_static", + "serde", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32 0.7.3", + "blake2 0.10.6", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -1961,7 +2191,7 @@ dependencies = [ "crossterm_winapi", "libc", "mio 0.8.11", - "parking_lot", + "parking_lot 0.12.3", "signal-hook", "signal-hook-mio", "winapi", @@ -1988,7 +2218,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -2000,7 +2230,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -2012,7 +2242,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "typenum", ] @@ -2023,7 +2253,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array", + "generic-array 0.14.7", "subtle", ] @@ -2153,7 +2383,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2167,7 +2397,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2203,7 +2433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -2248,6 +2478,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.76", +] + [[package]] name = "derive_more" version = "1.0.0-beta.6" @@ -2275,13 +2516,22 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -2410,7 +2660,7 @@ dependencies = [ "der 0.6.1", "digest 0.10.7", "ff 0.12.1", - "generic-array", + "generic-array 0.14.7", "group 0.12.1", "pkcs8 0.9.0", "rand_core 0.6.4", @@ -2429,7 +2679,7 @@ dependencies = [ "crypto-bigint 0.5.5", "digest 0.10.7", "ff 0.13.0", - "generic-array", + "generic-array 0.14.7", "group 0.13.0", "pem-rfc7468", "pkcs8 0.10.2", @@ -2541,6 +2791,28 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + [[package]] name = "ethabi" version = "18.0.0" @@ -2566,8 +2838,10 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", "fixed-hash", + "impl-codec", "impl-rlp", "impl-serde", + "scale-info", "tiny-keccak 2.0.2", ] @@ -2575,14 +2849,229 @@ dependencies = [ name = "ethereum-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f26f9d8d80da18ca72aca51804c65eb2153093af3bec74fd5ce32aa0c1f665" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4be54dd2260945d784e06ccdeb5ad573e8f1541838cee13a1ab885485eaa0b" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c3c3e119a89f0a9a1e539e7faecea815f74ddcf7c90d0b00d1f524db2fdc9c" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4e5ad46aede34901f71afdb7bb555710ed9613d88d644245c657dc371aa228" +dependencies = [ + "Inflector", + "cfg-if 1.0.0", + "dunce", + "ethers-core", + "eyre", + "getrandom", + "hex", + "proc-macro2 1.0.86", + "quote 1.0.37", + "regex", + "reqwest 0.11.27", + "serde", + "serde_json", + "syn 1.0.109", + "toml 0.5.11", + "url", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f192e8e4cf2b038318aae01e94e7644e0659a76219e94bcd3203df744341d61f" +dependencies = [ + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2 1.0.86", + "quote 1.0.37", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "ethers-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" +dependencies = [ + "arrayvec 0.7.6", + "bytes", + "cargo_metadata 0.15.4", + "chrono", + "convert_case", + "elliptic-curve 0.12.3", + "ethabi", + "generic-array 0.14.7", + "hex", + "k256 0.11.6", + "once_cell", + "open-fastrlp", + "proc-macro2 1.0.86", + "rand 0.8.5", + "rlp", + "rlp-derive", + "serde", + "serde_json", + "strum 0.24.1", + "syn 1.0.109", + "thiserror", + "tiny-keccak 2.0.2", + "unicode-xid 0.2.5", +] + +[[package]] +name = "ethers-etherscan" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9713f525348e5dde025d09b0a4217429f8074e8ff22c886263cc191e87d8216" +dependencies = [ + "ethers-core", + "getrandom", + "reqwest 0.11.27", + "semver 1.0.23", + "serde", + "serde-aux", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71df7391b0a9a51208ffb5c7f2d068900e99d6b3128d3a4849d138f194778b7" +dependencies = [ + "async-trait", + "auto_impl 0.5.0", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8" +dependencies = [ + "async-trait", + "auto_impl 1.2.0", + "base64 0.13.1", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "getrandom", + "hashers", + "hex", + "http 0.2.12", + "once_cell", + "parking_lot 0.11.2", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f41ced186867f64773db2e55ffdd92959e094072a1d09a5e5e831d443204f98" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-rlp", - "impl-serde", - "primitive-types", - "uint", + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve 0.12.3", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", ] [[package]] @@ -2606,6 +3095,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fastrand" version = "2.1.1" @@ -2619,7 +3114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ "arrayvec 0.7.6", - "auto_impl", + "auto_impl 1.2.0", "bytes", ] @@ -2821,6 +3316,39 @@ dependencies = [ "tiny-keccak 1.5.0", ] +[[package]] +name = "franklin-crypto" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09876c8a2d5e706a8669f69d7db592ca9c48257cbfc4917fe32daf419a8ea78e" +dependencies = [ + "arr_macro", + "bit-vec", + "blake2 0.9.2", + "blake2-rfc_bellman_edition", + "blake2s_simd", + "boojum 0.30.9", + "byteorder", + "derivative", + "digest 0.9.0", + "hex", + "indexmap 1.9.3", + "itertools 0.10.5", + "lazy_static", + "num-bigint 0.4.6", + "num-derive 0.2.5", + "num-integer", + "num-traits", + "rand 0.4.6", + "serde", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "splitmut", + "tiny-keccak 1.5.0", + "zksync_bellman", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -2896,7 +3424,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -2905,6 +3433,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -2935,7 +3473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", - "send_wrapper", + "send_wrapper 0.4.0", ] [[package]] @@ -2975,6 +3513,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3029,7 +3576,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug", + "opaque-debug 0.3.1", "polyval", ] @@ -3177,7 +3724,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot", + "parking_lot 0.12.3", "quanta", "rand 0.8.5", "smallvec", @@ -3286,6 +3833,15 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "hashlink" version = "0.9.1" @@ -3304,6 +3860,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -3497,6 +4059,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.2" @@ -3508,10 +4084,10 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "log", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", ] @@ -3706,7 +4282,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -3739,6 +4315,18 @@ dependencies = [ "similar", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -3879,13 +4467,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.23.2", "pin-project", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -3902,13 +4490,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.24.3", "pin-project", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -3930,7 +4518,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "jsonrpsee-types 0.23.2", - "parking_lot", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "rustc-hash 1.1.0", @@ -3977,11 +4565,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core 0.23.2", "jsonrpsee-types 0.23.2", - "rustls", + "rustls 0.23.12", "rustls-platform-verifier", "serde", "serde_json", @@ -4002,11 +4590,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core 0.24.3", "jsonrpsee-types 0.24.3", - "rustls", + "rustls 0.23.12", "rustls-platform-verifier", "serde", "serde_json", @@ -4158,6 +4746,7 @@ dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", "sha2 0.10.8", + "sha3 0.10.8", ] [[package]] @@ -4228,7 +4817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4243,7 +4832,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ - "bs58", + "bs58 0.5.1", "hkdf", "multihash", "quick-protobuf", @@ -4969,12 +5558,43 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.6", + "auto_impl 1.2.0", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "openssl" version = "0.10.66" @@ -5181,7 +5801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.6", - "bitvec", + "bitvec 1.0.1", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", @@ -5206,6 +5826,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -5213,7 +5844,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -5229,12 +5874,35 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2 0.10.8", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -5321,6 +5989,16 @@ dependencies = [ "indexmap 2.4.0", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures 0.3.30", + "rustc_version 0.4.0", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -5425,7 +6103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug", + "opaque-debug 0.3.1", "universal-hash", ] @@ -5437,7 +6115,7 @@ checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "opaque-debug", + "opaque-debug 0.3.1", "universal-hash", ] @@ -5521,6 +6199,7 @@ dependencies = [ "impl-codec", "impl-rlp", "impl-serde", + "scale-info", "uint", ] @@ -5599,7 +6278,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -5829,6 +6508,12 @@ dependencies = [ "proc-macro2 1.0.86", ] +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + [[package]] name = "radium" version = "0.7.0" @@ -5949,6 +6634,15 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -6035,6 +6729,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -6044,6 +6739,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -6052,11 +6748,13 @@ dependencies = [ "system-configuration 0.5.1", "tokio", "tokio-native-tls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.25.4", "winreg", ] @@ -6077,7 +6775,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -6132,7 +6830,31 @@ dependencies = [ "arrayvec 0.7.6", "blake2 0.10.6", "byteorder", - "franklin-crypto", + "franklin-crypto 0.1.0", + "num-bigint 0.3.3", + "num-integer", + "num-iter", + "num-traits", + "rand 0.4.6", + "serde", + "sha3 0.9.1", + "smallvec", +] + +[[package]] +name = "rescue_poseidon" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def7c91dcd919a62ca93bff4d67f710f8ae099e2639458fc5e3862f5812491a3" +dependencies = [ + "addchain", + "arrayvec 0.7.6", + "blake2 0.10.6", + "byteorder", + "derivative", + "franklin-crypto 0.30.9", + "lazy_static", + "log", "num-bigint 0.3.3", "num-integer", "num-iter", @@ -6141,6 +6863,7 @@ dependencies = [ "serde", "sha3 0.9.1", "smallvec", + "typemap_rev", ] [[package]] @@ -6179,13 +6902,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rkyv" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ - "bitvec", + "bitvec 1.0.1", "bytecheck", "bytes", "hashbrown 0.12.3", @@ -6194,7 +6926,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -6218,6 +6950,17 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -6355,6 +7098,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.12" @@ -6366,7 +7121,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.7", "subtle", "zeroize", ] @@ -6420,13 +7175,13 @@ dependencies = [ "jni", "log", "once_cell", - "rustls", + "rustls 0.23.12", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", + "rustls-webpki 0.102.7", "security-framework", "security-framework-sys", - "webpki-roots", + "webpki-roots 0.26.3", "winapi", ] @@ -6436,6 +7191,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.7" @@ -6460,6 +7225,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6469,6 +7243,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if 1.0.0", + "derive_more 0.99.18", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.76", +] + [[package]] name = "schannel" version = "0.1.23" @@ -6484,6 +7282,28 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2 0.10.8", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "seahash" version = "4.1.0" @@ -6498,7 +7318,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct 0.1.1", "der 0.6.1", - "generic-array", + "generic-array 0.14.7", "pkcs8 0.9.0", "subtle", "zeroize", @@ -6512,7 +7332,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", "der 0.7.9", - "generic-array", + "generic-array 0.14.7", "pkcs8 0.10.2", "subtle", "zeroize", @@ -6623,6 +7443,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "sentry" version = "0.31.8" @@ -6728,7 +7554,7 @@ dependencies = [ "thiserror", "time", "url", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -6746,6 +7572,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-aux" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde-value" version = "0.7.0" @@ -6778,9 +7614,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -6878,6 +7714,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + [[package]] name = "sha2" version = "0.9.9" @@ -6888,7 +7736,7 @@ dependencies = [ "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -6922,7 +7770,7 @@ dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", "keccak", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -7051,7 +7899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" dependencies = [ "bytecount", - "cargo_metadata", + "cargo_metadata 0.14.2", "error-chain", "glob", "pulldown-cmark", @@ -7097,6 +7945,18 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "snark_wrapper" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374c01372ffa80be5ae488fb54cf58ade53fd5279aa5a0340a44fc1da96d71a1" +dependencies = [ + "derivative", + "rand 0.4.6", + "rescue_poseidon 0.30.9", + "serde", +] + [[package]] name = "snow" version = "0.9.6" @@ -7301,7 +8161,7 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "generic-array", + "generic-array 0.14.7", "hex", "hkdf", "hmac", @@ -7457,13 +8317,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "rustversion", + "syn 1.0.109", ] [[package]] @@ -7856,20 +8738,20 @@ dependencies = [ "pin-project-lite", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", ] [[package]] name = "tokio" -version = "1.39.3" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", "mio 1.0.2", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -7898,13 +8780,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", ] @@ -7935,6 +8827,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -8092,6 +8993,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -8176,9 +9087,15 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", + "toml 0.8.19", ] +[[package]] +name = "typemap_rev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" + [[package]] name = "typenum" version = "1.17.0" @@ -8365,6 +9282,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "uuid" version = "1.10.0" @@ -8411,6 +9338,29 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "via-validator-lib" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "circuit_definitions", + "clap 4.5.16", + "ethers", + "hex", + "once_cell", + "primitive-types", + "reqwest 0.11.27", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "zksync_types", +] + [[package]] name = "via_btc_client" version = "0.1.0" @@ -8780,6 +9730,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures 0.3.30", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.70" @@ -8800,6 +9765,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.3" @@ -8853,7 +9824,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -9077,6 +10048,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures 0.3.30", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -9214,6 +10204,20 @@ dependencies = [ "zk_evm_abstractions 0.150.4", ] +[[package]] +name = "zk_evm" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 0.150.16", +] + [[package]] name = "zk_evm_abstractions" version = "0.140.0" @@ -9253,6 +10257,18 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] +[[package]] +name = "zk_evm_abstractions" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "anyhow", + "num_enum 0.6.1", + "serde", + "static_assertions", + "zkevm_opcode_defs 0.150.16", +] + [[package]] name = "zkevm_circuits" version = "0.140.2" @@ -9261,7 +10277,7 @@ checksum = "8beed4cc1ab1f9d99a694506d18705e10059534b30742832be49637c4775e1f8" dependencies = [ "arrayvec 0.7.6", "bincode", - "boojum", + "boojum 0.2.2", "cs_derive", "derivative", "hex", @@ -9283,7 +10299,7 @@ checksum = "20f1a64d256cc5f5c58d19cf976cb45973df54e4e3010ca4a3e6fafe9f06075e" dependencies = [ "arrayvec 0.7.6", "bincode", - "boojum", + "boojum 0.2.2", "cs_derive", "derivative", "hex", @@ -9304,7 +10320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abdfaa95dfe0878fda219dd17a6cc8c28711e2067785910c0e06d3ffdca78629" dependencies = [ "arrayvec 0.7.6", - "boojum", + "boojum 0.2.2", "cs_derive", "derivative", "hex", @@ -9317,6 +10333,25 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] +[[package]] +name = "zkevm_circuits" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "arrayvec 0.7.6", + "boojum 0.30.9", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "smallvec", + "zkevm_opcode_defs 0.150.16", + "zksync_cs_derive", +] + [[package]] name = "zkevm_opcode_defs" version = "0.131.0" @@ -9376,6 +10411,22 @@ dependencies = [ "sha3 0.10.8", ] +[[package]] +name = "zkevm_opcode_defs" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "bitflags 2.6.0", + "blake2 0.10.6", + "ethereum-types", + "k256 0.13.3", + "lazy_static", + "p256", + "serde", + "sha2 0.10.8", + "sha3 0.10.8", +] + [[package]] name = "zksync_base_token_adjuster" version = "0.1.0" @@ -9411,12 +10462,35 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", + "strum 0.26.3", "thiserror", "tiny-keccak 2.0.2", "url", ] +[[package]] +name = "zksync_bellman" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fc1a740dfba0dd5e90a2689060910966c9c5ca837520428962ffe972223a61" +dependencies = [ + "arrayvec 0.7.6", + "bit-vec", + "blake2s_simd", + "byteorder", + "cfg-if 1.0.0", + "crossbeam 0.8.4", + "futures 0.3.30", + "hex", + "lazy_static", + "num_cpus", + "rand 0.4.6", + "serde", + "smallvec", + "tiny-keccak 1.5.0", + "zksync_pairing", +] + [[package]] name = "zksync_block_reverter" version = "0.1.0" @@ -9615,7 +10689,7 @@ dependencies = [ "thiserror", "tls-listener", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tracing", "vise", "zksync_concurrency", @@ -9817,6 +10891,18 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "zksync_cs_derive" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1326884175159e4b8138feb900d359f382e78a26344434fc9713b4cfb4f601bf" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "zksync_da_client" version = "0.1.0" @@ -9863,7 +10949,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum", + "strum 0.26.3", "thiserror", "tokio", "tracing", @@ -10103,6 +11189,34 @@ dependencies = [ "zksync_prover_interface", ] +[[package]] +name = "zksync_ff" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c1b1fc4f6d81f26b4e17506306153f355b50cd7aa3f324344a531aaf1cbcdd" +dependencies = [ + "byteorder", + "hex", + "rand 0.4.6", + "serde", + "zksync_ff_derive", +] + +[[package]] +name = "zksync_ff_derive" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24682c5be0f3983dc85832d7b0c7901b5668494417c7fcb21613cbee72df067c" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "proc-macro2 1.0.86", + "quote 1.0.37", + "serde", + "syn 1.0.109", +] + [[package]] name = "zksync_health_check" version = "0.1.0" @@ -10140,7 +11254,7 @@ version = "0.150.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9949f48ea1a9f9a0e73242d4d1e87e681095181827486b3fcc2cf93e5aa03280" dependencies = [ - "boojum", + "boojum 0.2.2", "derivative", "hex", "once_cell", @@ -10318,7 +11432,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "strum", + "strum 0.26.3", "test-casing", "thiserror", "thread_local", @@ -10625,6 +11739,19 @@ dependencies = [ "zksync_types", ] +[[package]] +name = "zksync_pairing" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835ac4c2544a9810c6c2cde05c536c5a8876e92e3c9a10bdff99ef784d404813" +dependencies = [ + "byteorder", + "cfg-if 1.0.0", + "rand 0.4.6", + "serde", + "zksync_ff", +] + [[package]] name = "zksync_proof_data_handler" version = "0.1.0" @@ -10711,7 +11838,7 @@ name = "zksync_prover_dal" version = "0.1.0" dependencies = [ "sqlx", - "strum", + "strum 0.26.3", "zksync_basic_types", "zksync_db_connection", ] @@ -10726,7 +11853,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", + "strum 0.26.3", "tokio", "zksync_multivm", "zksync_object_store", @@ -10838,11 +11965,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bac71750012656b207e8cdb67415823318909077d8c8e235111f0d2feeeeeda" dependencies = [ "ethereum-types", - "franklin-crypto", + "franklin-crypto 0.1.0", "handlebars", "hex", "paste", - "rescue_poseidon", + "rescue_poseidon 0.4.1", "serde", "serde_derive", "serde_json", @@ -11022,7 +12149,7 @@ dependencies = [ "bitcoin", "blake2 0.10.6", "chrono", - "derive_more", + "derive_more 1.0.0-beta.6", "hex", "itertools 0.10.5", "num", @@ -11033,7 +12160,7 @@ dependencies = [ "secp256k1 0.27.0", "serde", "serde_json", - "strum", + "strum 0.26.3", "thiserror", "tokio", "tracing", @@ -11169,7 +12296,7 @@ dependencies = [ "pin-project-lite", "rand 0.8.5", "rlp", - "rustls", + "rustls 0.23.12", "serde", "serde_json", "test-casing", diff --git a/Cargo.toml b/Cargo.toml index ffc0077d5..22e943399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ members = [ # VIA Protocol Related Crates "core/lib/via_btc_client", "core/lib/via_da_clients", + "core/lib/via_validation", "core/node/via_btc_watch", "core/node/via_da_dispatcher", "core/bin/via_server", @@ -316,6 +317,7 @@ zksync_logs_bloom_backfill = { version = "0.1.0", path = "core/node/logs_bloom_b # VIA Protocol Related Components via_btc_client= { version = "0.1.0", path = "core/lib/via_btc_client" } via_da_clients = { version = "0.1.0", path = "core/lib/via_da_clients" } +via_validator_lib = { version = "0.1.0", path = "core/lib/via_validation" } via_btc_watch = { version = "0.1.0", path = "core/node/via_btc_watch" } via_da_dispatcher = { version = "0.1.0", path = "core/node/via_da_dispatcher" } via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } diff --git a/core/lib/via_validation/Cargo.toml b/core/lib/via_validation/Cargo.toml new file mode 100644 index 000000000..4d92f7d25 --- /dev/null +++ b/core/lib/via_validation/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "via-validator-lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +circuit_definitions = {git = "https://github.com/matter-labs/zksync-protocol.git", tag = "v0.150.16"} + +zksync_types.workspace = true + +hex = "0.4.3" +serde_json = "1.0.133" +serde = {version = "1", features = ["derive"]} +clap = { version = "4.2.4", features = ["derive"] } +anyhow = "*" +reqwest = { version = "0.11", features = ["json"] } +tokio = { version = "1.41.1", features = ["full"] } +ethers = {version = "1"} +sha3 = "*" +once_cell = "1.7" +primitive-types = "0.12.2" +tracing = "0.1" +tracing-subscriber = "0.3.18" +thiserror = "1.0" +async-trait = "0.1.83" + +[lib] +name = "via_validator" +path = "src/lib.rs" diff --git a/core/lib/via_validation/examples/zksync-era/abis/IVerifier.json b/core/lib/via_validation/examples/zksync-era/abis/IVerifier.json new file mode 100644 index 000000000..2685bb996 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/abis/IVerifier.json @@ -0,0 +1,44 @@ +[ + { + "inputs": [], + "name": "verificationKeyHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "vkHash", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "name": "verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/core/lib/via_validation/examples/zksync-era/abis/IZkSync.json b/core/lib/via_validation/examples/zksync-era/abis/IZkSync.json new file mode 100644 index 000000000..07096eb84 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/abis/IZkSync.json @@ -0,0 +1,2384 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "name": "BlockCommit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "name": "BlockExecution", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "totalBatchesCommitted", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBatchesVerified", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBatchesExecuted", + "type": "uint256" + } + ], + "name": "BlocksRevert", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "previousLastVerifiedBatch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "currentLastVerifiedBatch", + "type": "uint256" + } + ], + "name": "BlocksVerification", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + }, + { + "internalType": "enum Diamond.Action", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "isFreezable", + "type": "bool" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct Diamond.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "initAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initCalldata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct Diamond.DiamondCutData", + "name": "diamondCut", + "type": "tuple" + } + ], + "name": "ExecuteUpgrade", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Freeze", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "isPorterAvailable", + "type": "bool" + } + ], + "name": "IsPorterAvailableStatusUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "oldNominator", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "oldDenominator", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "newNominator", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "newDenominator", + "type": "uint128" + } + ], + "name": "NewBaseTokenMultiplier", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "enum PubdataPricingMode", + "name": "pubdataPricingMode", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "batchOverheadL1Gas", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxPubdataPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxL2GasPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "priorityTxMaxPubdata", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "minimalL2GasPrice", + "type": "uint64" + } + ], + "indexed": false, + "internalType": "struct FeeParams", + "name": "oldFeeParams", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum PubdataPricingMode", + "name": "pubdataPricingMode", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "batchOverheadL1Gas", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxPubdataPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxL2GasPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "priorityTxMaxPubdata", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "minimalL2GasPrice", + "type": "uint64" + } + ], + "indexed": false, + "internalType": "struct FeeParams", + "name": "newFeeParams", + "type": "tuple" + } + ], + "name": "NewFeeParams", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "txId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "factoryDeps", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct L2CanonicalTransaction", + "name": "transaction", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "factoryDeps", + "type": "bytes[]" + } + ], + "name": "NewPriorityRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPriorityTxMaxGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPriorityTxMaxGasLimit", + "type": "uint256" + } + ], + "name": "NewPriorityTxMaxGasLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldTransactionFilterer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTransactionFilterer", + "type": "address" + } + ], + "name": "NewTransactionFilterer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + }, + { + "internalType": "enum Diamond.Action", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "isFreezable", + "type": "bool" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct Diamond.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "initAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initCalldata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct Diamond.DiamondCutData", + "name": "diamondCut", + "type": "tuple" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "proposalSalt", + "type": "bytes32" + } + ], + "name": "ProposeTransparentUpgrade", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "Unfreeze", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "ValidatorStatusUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum PubdataPricingMode", + "name": "validiumMode", + "type": "uint8" + } + ], + "name": "ValidiumModeStatusUpdate", + "type": "event" + }, + { + "inputs": [], + "name": "acceptAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseTokenGasPriceMultiplierDenominator", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseTokenGasPriceMultiplierNominator", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "contractL2", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "l2Value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "l2Calldata", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "l2GasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "l2GasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "factoryDeps", + "type": "bytes[]" + }, + { + "internalType": "address", + "name": "refundRecipient", + "type": "address" + } + ], + "internalType": "struct BridgehubL2TransactionRequest", + "name": "_request", + "type": "tuple" + } + ], + "name": "bridgehubRequestL2Transaction", + "outputs": [ + { + "internalType": "bytes32", + "name": "canonicalTxHash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum PubdataPricingMode", + "name": "pubdataPricingMode", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "batchOverheadL1Gas", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxPubdataPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxL2GasPerBatch", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "priorityTxMaxPubdata", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "minimalL2GasPrice", + "type": "uint64" + } + ], + "internalType": "struct FeeParams", + "name": "_newFeeParams", + "type": "tuple" + } + ], + "name": "changeFeeParams", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo", + "name": "_lastCommittedBatchData", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "timestamp", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "newStateRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "bootloaderHeapInitialContentsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "eventsQueueStateHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "systemLogs", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "pubdataCommitments", + "type": "bytes" + } + ], + "internalType": "struct IExecutor.CommitBatchInfo[]", + "name": "_newBatchesData", + "type": "tuple[]" + } + ], + "name": "commitBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_chainId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo", + "name": "_lastCommittedBatchData", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "timestamp", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "newStateRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "bootloaderHeapInitialContentsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "eventsQueueStateHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "systemLogs", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "pubdataCommitments", + "type": "bytes" + } + ], + "internalType": "struct IExecutor.CommitBatchInfo[]", + "name": "_newBatchesData", + "type": "tuple[]" + } + ], + "name": "commitBatchesSharedBridge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo[]", + "name": "_batchesData", + "type": "tuple[]" + } + ], + "name": "executeBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_chainId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo[]", + "name": "_batchesData", + "type": "tuple[]" + } + ], + "name": "executeBatchesSharedBridge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + }, + { + "internalType": "enum Diamond.Action", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "isFreezable", + "type": "bool" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct Diamond.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "initAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initCalldata", + "type": "bytes" + } + ], + "internalType": "struct Diamond.DiamondCutData", + "name": "_diamondCut", + "type": "tuple" + } + ], + "name": "executeUpgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "facets", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "", + "type": "bytes4[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IGetters.Facet[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_l2BatchNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2MessageIndex", + "type": "uint256" + }, + { + "internalType": "uint16", + "name": "_l2TxNumberInBatch", + "type": "uint16" + }, + { + "internalType": "bytes", + "name": "_message", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "_merkleProof", + "type": "bytes32[]" + } + ], + "name": "finalizeEthWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "freezeDiamond", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBaseToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBaseTokenBridge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBridgehub", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFirstUnprocessedPriorityTx", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getL2BootloaderBytecodeHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getL2DefaultAccountBytecodeHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getL2SystemContractsUpgradeBatchNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getL2SystemContractsUpgradeTxHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getName", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPendingAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPriorityQueueSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPriorityTxMaxGasLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolVersion", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPubdataPricingMode", + "outputs": [ + { + "internalType": "enum PubdataPricingMode", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStateTransitionManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalBatchesCommitted", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalBatchesExecuted", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalBatchesVerified", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalPriorityTxs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVerifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVerifierParams", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "recursionNodeLevelVkHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "recursionLeafLevelVkHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "recursionCircuitsSetVksHash", + "type": "bytes32" + } + ], + "internalType": "struct VerifierParams", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDiamondStorageFrozen", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_l2BatchNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2MessageIndex", + "type": "uint256" + } + ], + "name": "isEthWithdrawalFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_facet", + "type": "address" + } + ], + "name": "isFacetFreezable", + "outputs": [ + { + "internalType": "bool", + "name": "isFreezable", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "isFunctionFreezable", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "isValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchNumber", + "type": "uint256" + } + ], + "name": "l2LogsRootHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "merkleRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2GasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2GasPerPubdataByteLimit", + "type": "uint256" + } + ], + "name": "l2TransactionBaseCost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priorityQueueFrontOperation", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "canonicalTxHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expirationTimestamp", + "type": "uint64" + }, + { + "internalType": "uint192", + "name": "layer2Tip", + "type": "uint192" + } + ], + "internalType": "struct PriorityOperation", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo", + "name": "_prevBatch", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo[]", + "name": "_committedBatches", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "recursiveAggregationInput", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "serializedProof", + "type": "uint256[]" + } + ], + "internalType": "struct IExecutor.ProofInput", + "name": "_proof", + "type": "tuple" + } + ], + "name": "proveBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_chainId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo", + "name": "_prevBatch", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "batchNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "indexRepeatedStorageChanges", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "numberOfLayer1Txs", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "priorityOperationsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "l2LogsTreeRoot", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "internalType": "struct IExecutor.StoredBatchInfo[]", + "name": "_committedBatches", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "recursiveAggregationInput", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "serializedProof", + "type": "uint256[]" + } + ], + "internalType": "struct IExecutor.ProofInput", + "name": "_proof", + "type": "tuple" + } + ], + "name": "proveBatchesSharedBridge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_l2TxHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_l2BatchNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2MessageIndex", + "type": "uint256" + }, + { + "internalType": "uint16", + "name": "_l2TxNumberInBatch", + "type": "uint16" + }, + { + "internalType": "bytes32[]", + "name": "_merkleProof", + "type": "bytes32[]" + }, + { + "internalType": "enum TxStatus", + "name": "_status", + "type": "uint8" + } + ], + "name": "proveL1ToL2TransactionStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "l2ShardId", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "isService", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "txNumberInBatch", + "type": "uint16" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "value", + "type": "bytes32" + } + ], + "internalType": "struct L2Log", + "name": "_log", + "type": "tuple" + }, + { + "internalType": "bytes32[]", + "name": "_proof", + "type": "bytes32[]" + } + ], + "name": "proveL2LogInclusion", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "txNumberInBatch", + "type": "uint16" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct L2Message", + "name": "_message", + "type": "tuple" + }, + { + "internalType": "bytes32[]", + "name": "_proof", + "type": "bytes32[]" + } + ], + "name": "proveL2MessageInclusion", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contractL2", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_l2Value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_l2GasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l2GasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "_factoryDeps", + "type": "bytes[]" + }, + { + "internalType": "address", + "name": "_refundRecipient", + "type": "address" + } + ], + "name": "requestL2Transaction", + "outputs": [ + { + "internalType": "bytes32", + "name": "canonicalTxHash", + "type": "bytes32" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newLastBatch", + "type": "uint256" + } + ], + "name": "revertBatches", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_chainId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newLastBatch", + "type": "uint256" + } + ], + "name": "revertBatchesSharedBridge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newPendingAdmin", + "type": "address" + } + ], + "name": "setPendingAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_zkPorterIsAvailable", + "type": "bool" + } + ], + "name": "setPorterAvailability", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPriorityTxMaxGasLimit", + "type": "uint256" + } + ], + "name": "setPriorityTxMaxGasLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum PubdataPricingMode", + "name": "_pricingMode", + "type": "uint8" + } + ], + "name": "setPubdataPricingMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "_nominator", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "_denominator", + "type": "uint128" + } + ], + "name": "setTokenMultiplier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_transactionFilterer", + "type": "address" + } + ], + "name": "setTransactionFilterer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validator", + "type": "address" + }, + { + "internalType": "bool", + "name": "_active", + "type": "bool" + } + ], + "name": "setValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchNumber", + "type": "uint256" + } + ], + "name": "storedBatchHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "transferEthToSharedBridge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unfreezeDiamond", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_protocolVersion", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + }, + { + "internalType": "enum Diamond.Action", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "isFreezable", + "type": "bool" + }, + { + "internalType": "bytes4[]", + "name": "selectors", + "type": "bytes4[]" + } + ], + "internalType": "struct Diamond.FacetCut[]", + "name": "facetCuts", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "initAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initCalldata", + "type": "bytes" + } + ], + "internalType": "struct Diamond.DiamondCutData", + "name": "_cutData", + "type": "tuple" + } + ], + "name": "upgradeChainFromVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/core/lib/via_validation/examples/zksync-era/contract.rs b/core/lib/via_validation/examples/zksync-era/contract.rs new file mode 100644 index 000000000..35d2e8617 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/contract.rs @@ -0,0 +1,134 @@ +use std::str::FromStr; + +use async_trait::async_trait; +use ethers::{ + abi::Abi, + contract::Contract, + prelude::{Address, Http, Provider}, + types::H256, +}; +use via_validator::{ + block_header::{BlockAuxilaryOutput, VerifierParams}, + errors::VerificationError, + l1_data_fetcher::L1DataFetcher, + proof::L1BatchProof, + types::BatchL1Data, +}; + +use crate::fetching::{ + fetch_batch_commit_tx, fetch_batch_protocol_version, fetch_l1_commit_data, fetch_proof_from_l1, + fetch_verifier_param_from_l1, +}; + +pub struct ContractConfig { + pub provider: Provider, + pub diamond_proxy_contract: Contract>, + pub verifier_contract_abi: Abi, +} + +impl ContractConfig { + pub fn new(l1_rpc_url: &str) -> Result { + let provider = Provider::::try_from(l1_rpc_url) + .map_err(|e| VerificationError::ProviderError(e.to_string()))?; + + let diamond_proxy_abi: Abi = serde_json::from_slice(include_bytes!("abis/IZkSync.json")) + .map_err(|e| VerificationError::Other(e.to_string()))?; + let verifier_contract_abi: Abi = + serde_json::from_slice(include_bytes!("abis/IVerifier.json")) + .map_err(|e| VerificationError::Other(e.to_string()))?; + + // Diamond proxy contract address on mainnet. + let diamond_proxy_address = Address::from_str("0x32400084c286cf3e17e7b677ea9583e60a000324") + .map_err(|e| VerificationError::Other(e.to_string()))?; + + let diamond_proxy_contract = + Contract::new(diamond_proxy_address, diamond_proxy_abi, provider.clone()); + + Ok(Self { + provider, + diamond_proxy_contract, + verifier_contract_abi, + }) + } +} + +#[async_trait] +impl L1DataFetcher for ContractConfig { + async fn get_verification_key_hash( + &self, + block_number: u64, + ) -> Result { + let verifier_address: Address = self + .diamond_proxy_contract + .method::<_, Address>("getVerifier", ())? + .block(block_number) + .call() + .await + .map_err(|e| VerificationError::ContractError(e.to_string()))?; + + let verifier_contract = Contract::new( + verifier_address, + self.verifier_contract_abi.clone(), + self.provider.clone(), + ); + + let vk_hash: H256 = verifier_contract + .method::<_, H256>("verificationKeyHash", ())? + .block(block_number) + .call() + .await + .map_err(|e| VerificationError::ContractError(e.to_string()))?; + + Ok(vk_hash) + } + + async fn get_protocol_version(&self, batch_number: u64) -> Result { + fetch_batch_protocol_version(batch_number).await + } + + async fn get_batch_commit_tx_hash( + &self, + batch_number: u64, + ) -> Result<(String, Option), VerificationError> { + fetch_batch_commit_tx(batch_number).await + } + + async fn get_l1_commit_data( + &self, + batch_number: u64, + ) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError> { + let protocol_version = self.get_protocol_version(batch_number).await?; + let protocol_version_id = protocol_version.parse::().map_err(|_| { + VerificationError::FetchError("Failed to parse protocol version".to_string()) + })?; + fetch_l1_commit_data( + batch_number, + protocol_version_id, + &self.provider.url().to_string(), + ) + .await + } + + async fn get_proof_from_l1( + &self, + batch_number: u64, + ) -> Result<(L1BatchProof, u64), VerificationError> { + let protocol_version = self.get_protocol_version(batch_number).await?; + let protocol_version_id = protocol_version.parse::().map_err(|_| { + VerificationError::FetchError("Failed to parse protocol version".to_string()) + })?; + fetch_proof_from_l1( + batch_number, + &self.provider.url().to_string(), + protocol_version_id, + ) + .await + } + + async fn get_verifier_params( + &self, + block_number: u64, + ) -> Result { + Ok(fetch_verifier_param_from_l1(block_number, &self.provider.url().to_string()).await) + } +} diff --git a/core/lib/via_validation/examples/zksync-era/fetching.rs b/core/lib/via_validation/examples/zksync-era/fetching.rs new file mode 100644 index 000000000..43dd3a5a0 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/fetching.rs @@ -0,0 +1,493 @@ +use std::str::FromStr; + +use circuit_definitions::{ + circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, + snark_wrapper::franklin_crypto::bellman::bn256::Bn256, +}; +use ethers::{ + abi::{ethabi, ethereum_types, Abi, Address, Function, Token}, + contract::BaseContract, + providers::{Http, Middleware, Provider}, + types::TxHash, +}; +use once_cell::sync::Lazy; +use primitive_types::{H256, U256}; +use reqwest::StatusCode; +use via_validator::{ + block_header, + block_header::{BlockAuxilaryOutput, VerifierParams}, + crypto::deserialize_proof, + errors::VerificationError, + proof::L1BatchProof, + types::{BatchL1Data, L1BatchAndProofData}, +}; + +use crate::types::{JSONL2RPCResponse, JSONL2SyncRPCResponse, L1BatchRangeJson}; + +pub static BLOCK_COMMIT_EVENT_SIGNATURE: Lazy = Lazy::new(|| { + ethabi::long_signature( + "BlockCommit", + &[ + ethabi::ParamType::Uint(256), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ], + ) +}); + +// Fetches given batch information from Era RPC +pub async fn fetch_batch_protocol_version(batch_number: u64) -> Result { + tracing::info!( + "Fetching batch {} protocol version from zkSync Era mainnet", + batch_number + ); + + let domain = "https://mainnet.era.zksync.io"; + + let client = reqwest::Client::new(); + + let response = client + .post(domain) + .header("Content-Type", "application/json") + .body(format!( + r#"{{ + "jsonrpc": "2.0", + "method": "zks_getL1BatchBlockRange", + "params": [{}], + "id": "1" + }}"#, + batch_number + )) + .send() + .await?; + + if response.status().is_success() { + let json = response.json::().await?; + let l2_block_hex = json.result[0].clone(); + let without_prefix = l2_block_hex.trim_start_matches("0x"); + let l2_block = i64::from_str_radix(without_prefix, 16); + + let response_2 = client + .post(domain) + .header("Content-Type", "application/json") + .body(format!( + r#"{{ + "jsonrpc": "2.0", + "method": "en_syncL2Block", + "params": [{}, false], + "id": "1" + }}"#, + l2_block.unwrap() + )) + .send() + .await?; + + if response_2.status().is_success() { + let json_2 = response_2.json::().await?; + let version = json_2 + .result + .protocol_version + .strip_prefix("Version") + .unwrap(); + + tracing::info!("Batch {} has protocol version {}", batch_number, version); + + Ok(version.to_string()) + } else { + Err(VerificationError::Other( + "Failed to fetch protocol version".to_string(), + )) + } + } else { + Err(VerificationError::Other( + "Failed to fetch protocol version".to_string(), + )) + } +} + +// Fetches given batch information from Era RPC +pub async fn fetch_batch_commit_tx( + batch_number: u64, +) -> Result<(String, Option), VerificationError> { + tracing::info!( + "Fetching batch {} information from zkSync Era", + batch_number + ); + + let domain = "https://mainnet.era.zksync.io"; + let client = reqwest::Client::new(); + + let response = client + .post(domain) + .header("Content-Type", "application/json") + .body(format!( + r#"{{ + "jsonrpc": "2.0", + "method": "zks_getL1BatchDetails", + "params": [{}, false], + "id": "1" + }}"#, + batch_number + )) + .send() + .await?; + + if response.status().is_success() { + let json = response.json::().await?; + + Ok((json.result.commit_tx_hash, json.result.prove_tx_hash)) + } else { + Err(VerificationError::FetchError( + "Failed to fetch batch commit transaction".to_string(), + )) + } +} + +pub async fn fetch_l1_data( + batch_number: u64, + protocol_version: u16, + rpc_url: &str, +) -> Result { + let commit_data = fetch_l1_commit_data(batch_number, protocol_version, rpc_url).await?; + + let (batch_l1_data, aux_output) = commit_data; + + let proof_info = fetch_proof_from_l1(batch_number, rpc_url, protocol_version).await?; + + let (proof_data, block_number) = proof_info; + + let verifier_params = fetch_verifier_param_from_l1(block_number, rpc_url).await; + + Ok(L1BatchAndProofData { + batch_l1_data, + aux_output, + scheduler_proof: proof_data.scheduler_proof, + verifier_params, + block_number, + }) +} + +pub async fn fetch_l1_commit_data( + batch_number: u64, + protocol_version: u16, + rpc_url: &str, +) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError> { + let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); + + let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); + let (function_name, fallback_fn_name) = if protocol_version < 23 { + ("commitBatches", None) + } else { + ("commitBatchesSharedBridge", Some("commitBatches")) + }; + + let function = contract_abi.functions_by_name(function_name).unwrap()[0].clone(); + let fallback_function = + fallback_fn_name.map(|fn_name| contract_abi.functions_by_name(fn_name).unwrap()[0].clone()); + + let previous_batch_number = batch_number - 1; + let address = + ethereum_types::Address::from_str("32400084c286cf3e17e7b677ea9583e60a000324").unwrap(); + + let mut roots = vec![]; + let mut l1_block_number = 0; + let mut calldata = vec![]; + let mut prev_batch_commitment = H256::default(); + let mut curr_batch_commitment = H256::default(); + for b_number in [previous_batch_number, batch_number] { + let (commit_tx, _) = fetch_batch_commit_tx(b_number).await?; + + let tx = client + .get_transaction(TxHash::from_str(&commit_tx).unwrap()) + .await?; + + let tx = tx.unwrap(); + l1_block_number = tx.block_number.unwrap().as_u64(); + calldata = tx.input.to_vec(); + + let found_data = + find_state_data_from_log(b_number, &function, fallback_function.clone(), &calldata)?; + + let found_data = found_data.unwrap(); + + let batch_commitment = client + .get_transaction_receipt(tx.hash) + .await? + .unwrap() + .logs + .iter() + .find(|log| { + log.address == address + && log.topics.len() == 4 + && log.topics[0] == *BLOCK_COMMIT_EVENT_SIGNATURE + && log.topics[1] == H256::from_low_u64_be(b_number) + }) + .map(|log| log.topics[3]); + + if batch_commitment.is_none() { + return Err(VerificationError::FetchError( + "Failed to find batch commitment".to_string(), + )); + } + + if b_number == previous_batch_number { + prev_batch_commitment = batch_commitment.unwrap(); + } else { + curr_batch_commitment = batch_commitment.unwrap(); + } + + roots.push(found_data); + } + + let aux_output = block_header::parse_aux_data(&function, &calldata)?; + + assert_eq!(roots.len(), 2); + + let (previous_enumeration_counter, previous_root) = roots[0].clone(); + let (new_enumeration_counter, new_root) = roots[1].clone(); + + tracing::info!( + "Will be verifying a proof for state transition from root {} to root {}", + format!("0x{}", hex::encode(&previous_root)), + format!("0x{}", hex::encode(&new_root)) + ); + + let base_contract: BaseContract = contract_abi.into(); + let contract_instance = base_contract.into_contract::>(address, client); + let bootloader_code_hash = contract_instance + .method::<_, H256>("getL2BootloaderBytecodeHash", ()) + .unwrap() + .block(l1_block_number) + .call() + .await + .unwrap(); + let default_aa_code_hash = contract_instance + .method::<_, H256>("getL2DefaultAccountBytecodeHash", ()) + .unwrap() + .block(l1_block_number) + .call() + .await + .unwrap(); + + tracing::info!( + "Will be using bootloader code hash {} and default AA code hash {}", + format!("0x{}", hex::encode(bootloader_code_hash.as_bytes())), + format!("0x{}", hex::encode(default_aa_code_hash.as_bytes())) + ); + println!("\n"); + let result = BatchL1Data { + previous_enumeration_counter, + previous_root, + new_enumeration_counter, + new_root, + bootloader_hash: *bootloader_code_hash.as_fixed_bytes(), + default_aa_hash: *default_aa_code_hash.as_fixed_bytes(), + prev_batch_commitment, + curr_batch_commitment, + }; + + Ok((result, aux_output)) +} + +fn find_state_data_from_log( + batch_number: u64, + function: &Function, + fallback_function: Option, + calldata: &[u8], +) -> Result)>, VerificationError> { + use ethers::abi; + + if calldata.len() < 5 { + return Err(VerificationError::FetchError( + "Calldata is too short".to_string(), + )); + } + + let mut parsed_input = function.decode_input(&calldata[4..]).unwrap_or_else(|_| { + fallback_function + .unwrap() + .decode_input(&calldata[4..]) + .unwrap() + }); + + let second_param = parsed_input.pop().unwrap(); + let first_param = parsed_input.pop().unwrap(); + + let abi::Token::Tuple(first_param) = first_param else { + return Err(VerificationError::FetchError( + "Failed to parse first param".to_string(), + )); + }; + + let abi::Token::Uint(_previous_l2_block_number) = first_param[0].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse first param".to_string(), + )); + }; + // if _previous_l2_block_number.0[0] != batch_number { + // return Err(VerificationError::FetchError( + // "Batch number mismatch".to_string(), + // )); + // } + let abi::Token::Uint(previous_enumeration_index) = first_param[2].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse second param".to_string(), + )); + }; + let _previous_enumeration_index = previous_enumeration_index.0[0]; + + let abi::Token::Array(inner) = second_param else { + return Err(VerificationError::FetchError( + "Failed to parse second param".to_string(), + )); + }; + + let mut found_params = None; + + for inner in inner.into_iter() { + let abi::Token::Tuple(inner) = inner else { + return Err(VerificationError::FetchError( + "Failed to parse inner tuple".to_string(), + )); + }; + let abi::Token::Uint(new_l2_block_number) = inner[0].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse new l2 block number".to_string(), + )); + }; + let new_l2_block_number = new_l2_block_number.0[0]; + if new_l2_block_number == batch_number { + let abi::Token::Uint(new_enumeration_index) = inner[2].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse new enumeration index".to_string(), + )); + }; + let new_enumeration_index = new_enumeration_index.0[0]; + + let abi::Token::FixedBytes(state_root) = inner[3].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse state root".to_string(), + )); + }; + + assert_eq!(state_root.len(), 32); + + found_params = Some((new_enumeration_index, state_root)); + } else { + continue; + } + } + + Ok(found_params) +} + +pub async fn fetch_proof_from_l1( + batch_number: u64, + rpc_url: &str, + protocol_version: u16, +) -> Result<(L1BatchProof, u64), VerificationError> { + let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); + + let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); + + let function_name = if protocol_version < 23 { + "proveBatches" + } else { + "proveBatchesSharedBridge" + }; + + let function = contract_abi.functions_by_name(function_name).unwrap()[0].clone(); + + let (_, prove_tx) = fetch_batch_commit_tx(batch_number) + .await + .map_err(|_| StatusCode::BAD_REQUEST) + .unwrap(); + + if prove_tx.is_none() { + let msg = format!( + "Proof doesn't exist for batch {}, please try again soon. Exiting...", + batch_number, + ); + tracing::error!("{}", msg); + return Err(VerificationError::FetchError(msg)); + }; + + let tx = client + .get_transaction(TxHash::from_str(&prove_tx.unwrap()).unwrap()) + .await + .map_err(|_| StatusCode::BAD_REQUEST) + .unwrap() + .unwrap(); + + let l1_block_number = tx.block_number.unwrap().as_u64(); + let calldata = tx.input.to_vec(); + + let parsed_input = function.decode_input(&calldata[4..]).unwrap(); + + let Token::Tuple(proof) = parsed_input.as_slice().last().unwrap() else { + return Err(VerificationError::FetchError( + "Failed to parse proof from input".to_string(), + )); + }; + + assert_eq!(proof.len(), 2); + + let Token::Array(serialized_proof) = proof[1].clone() else { + return Err(VerificationError::FetchError( + "Failed to parse proof from input".to_string(), + )); + }; + + let proof = serialized_proof + .iter() + .filter_map(|e| { + if let Token::Uint(x) = e { + Some(*x) + } else { + None + } + }) + .collect::>(); + + if serialized_proof.is_empty() { + let msg = format!("Proof doesn't exist for batch {}, exiting...", batch_number,); + tracing::error!("{}", msg); + return Err(VerificationError::FetchError(msg)); + } + + let x: circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof = deserialize_proof(proof); + Ok(( + L1BatchProof { + aggregation_result_coords: [[0u8; 32]; 4], + scheduler_proof: x, + inputs: vec![], // TODO + }, + l1_block_number, + )) +} + +pub async fn fetch_verifier_param_from_l1(block_number: u64, rpc_url: &str) -> VerifierParams { + let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); + let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); + + let base_contract: BaseContract = contract_abi.into(); + let address = Address::from_str("32400084c286cf3e17e7b677ea9583e60a000324").unwrap(); + let contract_instance = base_contract.into_contract::>(address, client); + let ( + recursion_node_level_vk_hash, + recursion_leaf_level_vk_hash, + recursion_circuits_set_vk_hash, + ) = contract_instance + .method::<_, (H256, H256, H256)>("getVerifierParams", ()) + .unwrap() + .block(block_number) + .call() + .await + .unwrap(); + + VerifierParams { + recursion_node_level_vk_hash: recursion_node_level_vk_hash.to_fixed_bytes(), + recursion_leaf_level_vk_hash: recursion_leaf_level_vk_hash.to_fixed_bytes(), + recursion_circuits_set_vk_hash: recursion_circuits_set_vk_hash.to_fixed_bytes(), + } +} diff --git a/core/lib/via_validation/examples/zksync-era/main.rs b/core/lib/via_validation/examples/zksync-era/main.rs new file mode 100644 index 000000000..3a2c366e6 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/main.rs @@ -0,0 +1,106 @@ +// src/main.rs + +mod contract; +mod fetching; +mod types; + +use clap::Parser; +use tracing::{error, info}; +use via_validator::{ + errors::VerificationError, + l1_data_fetcher::L1DataFetcher, + proof::L1BatchProof, + public_inputs::generate_inputs, + types::{DataJsonOutput, L1BatchAndProofData, VerificationKeyHashJsonOutput}, + utils::check_verification_key, + verification::verify_snark, +}; + +use crate::{contract::ContractConfig, fetching::fetch_l1_data}; + +#[derive(Debug, Parser)] +#[command(author = "Via", version, about = "Boojum CLI verifier")] +struct Cli { + /// Batch number to check proof for + #[arg(long, default_value = "493000")] + batch: u64, +} + +#[tokio::main] +async fn main() -> Result<(), VerificationError> { + // Initialize tracing subscriber for logging + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); + + let args = Cli::parse(); + let batch_number = args.batch; + let l1_rpc = "https://rpc.ankr.com/eth".to_string(); + + info!( + "Starting Boojum CLI verifier with config: l1_rpc={}; batch #{}", + l1_rpc, batch_number + ); + + let contract = ContractConfig::new(&l1_rpc)?; + + let protocol_version = contract.get_protocol_version(batch_number).await?; + let protocol_version_id = protocol_version.parse::().map_err(|_| { + VerificationError::FetchError("Failed to parse protocol version".to_string()) + })?; + + info!("Protocol version: {}", protocol_version); + + check_verification_key(protocol_version_id).await?; + + let resp = fetch_l1_data(batch_number, protocol_version_id, &l1_rpc).await?; + + let L1BatchAndProofData { + aux_output, + mut scheduler_proof, + batch_l1_data, + verifier_params: _, + block_number, + } = resp.clone(); + + let vk_hash = contract.get_verification_key_hash(block_number).await?; + + let snark_vk_scheduler_key_file = format!( + "keys/protocol_version/{}/scheduler_key.json", + protocol_version_id + ); + + let inputs = generate_inputs(batch_l1_data.clone()); + + scheduler_proof.inputs = inputs.clone(); + + let batch_proof = L1BatchProof { + aggregation_result_coords: aux_output.prepare_aggregation_result_coords(), + scheduler_proof, + inputs, + }; + + // Verify the proof + let verify_resp = verify_snark( + &snark_vk_scheduler_key_file, + batch_proof.clone(), + Some(vk_hash), + ) + .await; + + if let Ok((input, _, computed_vk_hash)) = verify_resp { + let mut data = DataJsonOutput::from(resp); + data.verification_key_hash = VerificationKeyHashJsonOutput { + layer_1_vk_hash: vk_hash.into(), + computed_vk_hash: computed_vk_hash.into(), + }; + data.public_input = input; + data.is_proof_valid = true; + + info!("VERIFIED"); + } else { + error!("Failed to verify proof due to an error."); + } + + Ok(()) +} diff --git a/core/lib/via_validation/examples/zksync-era/types.rs b/core/lib/via_validation/examples/zksync-era/types.rs new file mode 100644 index 000000000..ff75565b1 --- /dev/null +++ b/core/lib/via_validation/examples/zksync-era/types.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct L1BatchRangeJson { + pub result: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JSONL2SyncRPCResponse { + pub result: L2SyncDetails, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct L2SyncDetails { + #[serde(rename = "protocolVersion")] + pub protocol_version: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JSONL2RPCResponse { + pub result: L1BatchJson, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct L1BatchJson { + #[serde(rename = "commitTxHash")] + pub commit_tx_hash: String, + #[serde(rename = "proveTxHash")] + pub prove_tx_hash: Option, +} diff --git a/core/lib/via_validation/keys/protocol_version/24/scheduler_key.json b/core/lib/via_validation/keys/protocol_version/24/scheduler_key.json new file mode 100644 index 000000000..2e02eafe6 --- /dev/null +++ b/core/lib/via_validation/keys/protocol_version/24/scheduler_key.json @@ -0,0 +1,399 @@ +{ + "n": 16777215, + "num_inputs": 1, + "state_width": 4, + "num_witness_polys": 0, + "gate_setup_commitments": [ + { + "x": [ + 14543631136906534221, + 11532161447842416044, + 11114175029926010938, + 1228896787564295039 + ], + "y": [ + 13293602262342424489, + 8897930584356943159, + 13256028170406220369, + 3214939367598363288 + ], + "infinity": false + }, + { + "x": [ + 11488992528554025682, + 12016824828223971094, + 11942004360057333370, + 316831626296641307 + ], + "y": [ + 304673622018339856, + 7139037552557818730, + 12475560967982555143, + 1055588351918295250 + ], + "infinity": false + }, + { + "x": [ + 2274984630539920017, + 5398167177582250136, + 16440396753384808945, + 1037682586893548769 + ], + "y": [ + 10168660308952593373, + 16526369642614237721, + 569062739734175056, + 155645558476901406 + ], + "infinity": false + }, + { + "x": [ + 14005362797509427677, + 2662603874351919260, + 14261489165672308143, + 1470528288349794782 + ], + "y": [ + 11144229651170108862, + 11439490264313454962, + 114993091474760680, + 1037267173208738614 + ], + "infinity": false + }, + { + "x": [ + 10726125240955612787, + 1916320162213728495, + 1058608086768277905, + 1651114031905829493 + ], + "y": [ + 13237242732587628574, + 4774776044666137690, + 14401013098807103799, + 2514139699916115771 + ], + "infinity": false + }, + { + "x": [ + 14434760601334248377, + 5316938318287831815, + 6221098547630910324, + 980422841280734466 + ], + "y": [ + 9201886393750447942, + 3840149540273146267, + 18179910191622136829, + 1563809864380914603 + ], + "infinity": false + }, + { + "x": [ + 9586697317366528906, + 2325800863365957883, + 1243781259615311278, + 3048012003267036960 + ], + "y": [ + 612821620743617231, + 1510385666449513894, + 9368337288452385056, + 2949736812933507034 + ], + "infinity": false + }, + { + "x": [ + 11830690209042008764, + 11761396005838073769, + 18271188400274886574, + 2896734446482773484 + ], + "y": [ + 1890606551566554401, + 10220931290312275762, + 3256711195869515344, + 2466626485328709457 + ], + "infinity": false + } + ], + "gate_selectors_commitments": [ + { + "x": [ + 10865727529243127085, + 4083978853392244827, + 14303622309482785753, + 2263042021033673595 + ], + "y": [ + 3019601017411802529, + 880444282195426618, + 9998743525359587628, + 2891421025832200233 + ], + "infinity": false + }, + { + "x": [ + 5208608554346323426, + 8575970970223832576, + 2966209169082345602, + 239576408267301488 + ], + "y": [ + 17715084817752316452, + 2726293100894160682, + 17920596859559317135, + 3485576345363305439 + ], + "infinity": false + } + ], + "permutation_commitments": [ + { + "x": [ + 14761045450946573029, + 17157644513453531531, + 2555518804134782053, + 1415819224310783987 + ], + "y": [ + 17265629196749977462, + 4128711855633066822, + 8435602817910411328, + 1408116296902303196 + ], + "infinity": false + }, + { + "x": [ + 3307267823832528482, + 2406249680085831639, + 9091964031261402109, + 2846274000290842933 + ], + "y": [ + 17374905554931807856, + 6690578002079222163, + 11809376320193686210, + 2676076649992974574 + ], + "infinity": false + }, + { + "x": [ + 3159118708748226574, + 5508845413629697013, + 13350869305506486049, + 689297560178790472 + ], + "y": [ + 15696011303896469684, + 12551611148155235140, + 14438660833518031207, + 425021756161657108 + ], + "infinity": false + }, + { + "x": [ + 18349397811516917436, + 4473982696343317918, + 13070312540813307819, + 2109468484629113245 + ], + "y": [ + 13254534552549721008, + 17388411854346636521, + 17875890960520499518, + 1062184221180884481 + ], + "infinity": false + } + ], + "total_lookup_entries_length": 1787472, + "lookup_selector_commitment": { + "x": [ + 9324906502432882695, + 14977861238256290580, + 12538013124354067293, + 3408438202312564138 + ], + "y": [ + 14942105932194201701, + 12210090881357612547, + 14774705021036784261, + 2531694948512337448 + ], + "infinity": false + }, + "lookup_tables_commitments": [ + { + "x": [ + 10873859091125335643, + 3906092213625635374, + 17046157606087980048, + 3193402705223440293 + ], + "y": [ + 10158946293873382504, + 2171386304067884865, + 6918663094168980658, + 350601565475975409 + ], + "infinity": false + }, + { + "x": [ + 12822112641313049260, + 3646552465186399021, + 10324071010773924047, + 2209084192380614662 + ], + "y": [ + 11045141628975531869, + 12589678537679955590, + 3065046617868727674, + 2099447669854151830 + ], + "infinity": false + }, + { + "x": [ + 11395032673621937545, + 3000063650268118516, + 7857619430005721792, + 805706808484810738 + ], + "y": [ + 6817063666434679427, + 1646386051225388537, + 4677946977082722827, + 1369650305976868514 + ], + "infinity": false + }, + { + "x": [ + 2885179371868476351, + 159944842081142878, + 6092294387055034894, + 213843603626505240 + ], + "y": [ + 11868113133779277990, + 8509646480531194854, + 14088068011597639414, + 707070630614027545 + ], + "infinity": false + } + ], + "lookup_table_type_commitment": { + "x": [ + 1732877442096985191, + 7537030715658833452, + 14073502080301311448, + 2178792007727681099 + ], + "y": [ + 8513095304113652904, + 6581396660744182779, + 13939755637576387431, + 2477157044961106453 + ], + "infinity": false + }, + "non_residues": [ + [ + 5, + 0, + 0, + 0 + ], + [ + 7, + 0, + 0, + 0 + ], + [ + 10, + 0, + 0, + 0 + ] + ], + "g2_elements": [ + { + "x": { + "c0": [ + 5106727233969649389, + 7440829307424791261, + 4785637993704342649, + 1729627375292849782 + ], + "c1": [ + 10945020018377822914, + 17413811393473931026, + 8241798111626485029, + 1841571559660931130 + ] + }, + "y": { + "c0": [ + 5541340697920699818, + 16416156555105522555, + 5380518976772849807, + 1353435754470862315 + ], + "c1": [ + 6173549831154472795, + 13567992399387660019, + 17050234209342075797, + 650358724130500725 + ] + }, + "infinity": false + }, + { + "x": { + "c0": [ + 9089143573911733168, + 11482283522806384523, + 13585589533905622862, + 79029415676722370 + ], + "c1": [ + 5692040832573735873, + 16884514497384809355, + 16717166481813659368, + 2742131088506155463 + ] + }, + "y": { + "c0": [ + 9604638503594647125, + 1289961608472612514, + 6217038149984805214, + 2521661352385209130 + ], + "c1": [ + 17168069778630926308, + 11309277837895768996, + 15154989611154567813, + 359271377050603491 + ] + }, + "infinity": false + } + ] + } \ No newline at end of file diff --git a/core/lib/via_validation/src/block_header.rs b/core/lib/via_validation/src/block_header.rs new file mode 100644 index 000000000..ce68c1be6 --- /dev/null +++ b/core/lib/via_validation/src/block_header.rs @@ -0,0 +1,145 @@ +use ethers::{ + abi::{Function, Token}, + utils::keccak256, +}; +use serde::{Deserialize, Serialize}; +use zksync_types::{commitment::SerializeCommitment, l2_to_l1_log::L2ToL1Log, H256}; + +use crate::{errors::VerificationError, utils::to_fixed_bytes}; + +/// Represents auxiliary output data extracted from a block. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockAuxilaryOutput { + pub system_logs_hash: [u8; 32], + pub state_diff_hash: [u8; 32], + pub bootloader_heap_initial_content_hash: [u8; 32], + pub event_queue_state_hash: [u8; 32], +} + +impl BlockAuxilaryOutput { + /// Flattens the struct fields into a single byte vector. + pub fn into_flattened_bytes(&self) -> Vec { + let mut result = Vec::with_capacity(128); + result.extend_from_slice(&self.system_logs_hash); + result.extend_from_slice(&self.state_diff_hash); + result.extend_from_slice(&self.bootloader_heap_initial_content_hash); + result.extend_from_slice(&self.event_queue_state_hash); + result + } + + /// Prepares the aggregation result coordinates. + pub fn prepare_aggregation_result_coords(&self) -> [[u8; 32]; 4] { + [ + self.system_logs_hash, + self.state_diff_hash, + self.bootloader_heap_initial_content_hash, + self.event_queue_state_hash, + ] + } +} + +/// Parses auxiliary data from the given calldata using the provided function ABI. +pub fn parse_aux_data( + func: &Function, + calldata: &[u8], +) -> Result { + if calldata.len() < 5 { + return Err(VerificationError::FetchError( + "Calldata is too short".to_string(), + )); + } + + let mut parsed_calldata = func + .decode_input(&calldata[4..]) + .map_err(|e| VerificationError::FetchError(e.to_string()))?; + + let committed_batch = parsed_calldata.pop().ok_or_else(|| { + VerificationError::FetchError("Failed to deconstruct committed batch".to_string()) + })?; + + let committed_batch = if let Token::Array(committed_batch) = committed_batch { + committed_batch + } else { + return Err(VerificationError::FetchError( + "Failed to deconstruct committed batch".to_string(), + )); + }; + + let committed_batch = if let Token::Tuple(ref tuple) = committed_batch[0] { + tuple + } else { + return Err(VerificationError::FetchError( + "Failed to deconstruct committed batch".to_string(), + )); + }; + + if committed_batch.len() != 10 { + return Err(VerificationError::FetchError( + "Unexpected committed batch format".to_string(), + )); + } + + let bootloader_contents_hash = if let Token::FixedBytes(bytes) = &committed_batch[6] { + bytes + } else { + return Err(VerificationError::FetchError( + "Failed to extract bootloader_contents_hash".to_string(), + )); + }; + + let event_queue_state_hash = if let Token::FixedBytes(bytes) = &committed_batch[7] { + bytes + } else { + return Err(VerificationError::FetchError( + "Failed to extract event_queue_state_hash".to_string(), + )); + }; + + let sys_logs = if let Token::Bytes(bytes) = &committed_batch[8] { + bytes + } else { + return Err(VerificationError::FetchError( + "Failed to extract sys_logs".to_string(), + )); + }; + + if bootloader_contents_hash.len() != 32 || event_queue_state_hash.len() != 32 { + return Err(VerificationError::FetchError( + "Invalid hash length in committed batch".to_string(), + )); + } + + let bootloader_contents_hash_buffer = to_fixed_bytes(bootloader_contents_hash); + let event_queue_state_hash_buffer = to_fixed_bytes(event_queue_state_hash); + + if sys_logs.len() % L2ToL1Log::SERIALIZED_SIZE != 0 { + return Err(VerificationError::FetchError( + "sys_logs length is not a multiple of L2ToL1Log::SERIALIZED_SIZE".to_string(), + )); + } + + let state_diff_hash_sys_log = sys_logs + .chunks(L2ToL1Log::SERIALIZED_SIZE) + .map(L2ToL1Log::from_slice) + .find(|log| log.key == H256::from_low_u64_be(2_u64)) + .ok_or_else(|| { + VerificationError::FetchError("Failed to find state_diff_hash in sys_logs".to_string()) + })?; + + let system_logs_hash = keccak256(sys_logs); + + Ok(BlockAuxilaryOutput { + system_logs_hash, + state_diff_hash: to_fixed_bytes(state_diff_hash_sys_log.value.as_bytes()), + bootloader_heap_initial_content_hash: bootloader_contents_hash_buffer, + event_queue_state_hash: event_queue_state_hash_buffer, + }) +} + +/// Verifier config params describing the circuit to be verified. +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub struct VerifierParams { + pub recursion_node_level_vk_hash: [u8; 32], + pub recursion_leaf_level_vk_hash: [u8; 32], + pub recursion_circuits_set_vk_hash: [u8; 32], +} diff --git a/core/lib/via_validation/src/crypto.rs b/core/lib/via_validation/src/crypto.rs new file mode 100644 index 000000000..ee466f72c --- /dev/null +++ b/core/lib/via_validation/src/crypto.rs @@ -0,0 +1,216 @@ +use circuit_definitions::{ + ethereum_types::U256, + snark_wrapper::franklin_crypto::bellman::{ + bn256::{Bn256, Fr}, + plonk::better_better_cs::{cs::Circuit, proof::Proof}, + CurveAffine, Engine, PrimeField, PrimeFieldRepr, + }, +}; + +/// Transforms a U256 element into a prime field element. +fn u256_to_scalar(el: &U256) -> F +where + F::Repr: PrimeFieldRepr + Default, +{ + let mut bytes = [0u8; 32]; + el.to_big_endian(&mut bytes); + + let mut repr = F::Repr::default(); + repr.read_be(&bytes[..]) + .expect("Failed to read bytes into field representation"); + + F::from_repr(repr).expect("Failed to convert U256 to scalar") +} + +/// Transforms a point represented as a pair of U256 into its affine representation. +fn deserialize_g1(point: (U256, U256)) -> ::G1Affine { + if point == (U256::zero(), U256::zero()) { + return ::G1Affine::zero(); + } + + let x_scalar = u256_to_scalar(&point.0); + let y_scalar = u256_to_scalar(&point.1); + + ::G1Affine::from_xy_unchecked(x_scalar, y_scalar) +} + +/// Transforms a field element represented as U256 into the field representation. +fn deserialize_fe(felt: U256) -> Fr { + u256_to_scalar(&felt) +} + +/// Deserializes a proof from a vector of U256 elements. +pub fn deserialize_proof>(mut proof: Vec) -> Proof { + let opening_proof_at_z_omega = { + let y = proof + .pop() + .expect("Missing y-coordinate for opening_proof_at_z_omega"); + let x = proof + .pop() + .expect("Missing x-coordinate for opening_proof_at_z_omega"); + deserialize_g1((x, y)) + }; + + let opening_proof_at_z = { + let y = proof + .pop() + .expect("Missing y-coordinate for opening_proof_at_z"); + let x = proof + .pop() + .expect("Missing x-coordinate for opening_proof_at_z"); + deserialize_g1((x, y)) + }; + + let linearization_poly_opening_at_z = deserialize_fe( + proof + .pop() + .expect("Missing linearization_poly_opening_at_z"), + ); + let quotient_poly_opening_at_z = + deserialize_fe(proof.pop().expect("Missing quotient_poly_opening_at_z")); + let lookup_table_type_poly_opening_at_z = deserialize_fe( + proof + .pop() + .expect("Missing lookup_table_type_poly_opening_at_z"), + ); + let lookup_selector_poly_opening_at_z = deserialize_fe( + proof + .pop() + .expect("Missing lookup_selector_poly_opening_at_z"), + ); + let lookup_t_poly_opening_at_z_omega = deserialize_fe( + proof + .pop() + .expect("Missing lookup_t_poly_opening_at_z_omega"), + ); + let lookup_t_poly_opening_at_z = + deserialize_fe(proof.pop().expect("Missing lookup_t_poly_opening_at_z")); + let lookup_grand_product_opening_at_z_omega = deserialize_fe( + proof + .pop() + .expect("Missing lookup_grand_product_opening_at_z_omega"), + ); + let lookup_s_poly_opening_at_z_omega = deserialize_fe( + proof + .pop() + .expect("Missing lookup_s_poly_opening_at_z_omega"), + ); + let copy_permutation_grand_product_opening_at_z_omega = deserialize_fe( + proof + .pop() + .expect("Missing copy_permutation_grand_product_opening_at_z_omega"), + ); + + let mut copy_permutation_polys_openings_at_z = vec![]; + for _ in 0..3 { + copy_permutation_polys_openings_at_z.push(deserialize_fe( + proof + .pop() + .expect("Missing copy_permutation_polys_openings_at_z"), + )); + } + copy_permutation_polys_openings_at_z.reverse(); + + let gate_selectors_openings_at_z = vec![( + 0_usize, + deserialize_fe(proof.pop().expect("Missing gate_selectors_openings_at_z")), + )]; + + let state_polys_openings_at_dilations = { + let fe = deserialize_fe( + proof + .pop() + .expect("Missing state_polys_openings_at_dilations"), + ); + vec![(1_usize, 3_usize, fe)] + }; + + let mut state_polys_openings_at_z = vec![]; + for _ in 0..4 { + state_polys_openings_at_z.push(deserialize_fe( + proof.pop().expect("Missing state_polys_openings_at_z"), + )); + } + state_polys_openings_at_z.reverse(); + + let mut quotient_poly_parts_commitments = vec![]; + for _ in 0..4 { + let y = proof + .pop() + .expect("Missing y-coordinate for quotient_poly_parts_commitments"); + let x = proof + .pop() + .expect("Missing x-coordinate for quotient_poly_parts_commitments"); + quotient_poly_parts_commitments.push(deserialize_g1((x, y))); + } + quotient_poly_parts_commitments.reverse(); + + let lookup_grand_product_commitment = { + let y = proof + .pop() + .expect("Missing y-coordinate for lookup_grand_product_commitment"); + let x = proof + .pop() + .expect("Missing x-coordinate for lookup_grand_product_commitment"); + deserialize_g1((x, y)) + }; + + let lookup_s_poly_commitment = { + let y = proof + .pop() + .expect("Missing y-coordinate for lookup_s_poly_commitment"); + let x = proof + .pop() + .expect("Missing x-coordinate for lookup_s_poly_commitment"); + deserialize_g1((x, y)) + }; + + let copy_permutation_grand_product_commitment = { + let y = proof + .pop() + .expect("Missing y-coordinate for copy_permutation_grand_product_commitment"); + let x = proof + .pop() + .expect("Missing x-coordinate for copy_permutation_grand_product_commitment"); + deserialize_g1((x, y)) + }; + + let mut state_polys_commitments = vec![]; + for _ in 0..4 { + let y = proof + .pop() + .expect("Missing y-coordinate for state_polys_commitments"); + let x = proof + .pop() + .expect("Missing x-coordinate for state_polys_commitments"); + state_polys_commitments.push(deserialize_g1((x, y))); + } + state_polys_commitments.reverse(); + + let mut proof_obj: Proof = Proof::empty(); + + proof_obj.state_polys_commitments = state_polys_commitments; + proof_obj.copy_permutation_grand_product_commitment = copy_permutation_grand_product_commitment; + proof_obj.lookup_s_poly_commitment = Some(lookup_s_poly_commitment); + proof_obj.lookup_grand_product_commitment = Some(lookup_grand_product_commitment); + proof_obj.quotient_poly_parts_commitments = quotient_poly_parts_commitments; + proof_obj.state_polys_openings_at_z = state_polys_openings_at_z; + proof_obj.state_polys_openings_at_dilations = state_polys_openings_at_dilations; + proof_obj.gate_selectors_openings_at_z = gate_selectors_openings_at_z; + proof_obj.copy_permutation_polys_openings_at_z = copy_permutation_polys_openings_at_z; + proof_obj.copy_permutation_grand_product_opening_at_z_omega = + copy_permutation_grand_product_opening_at_z_omega; + proof_obj.lookup_s_poly_opening_at_z_omega = Some(lookup_s_poly_opening_at_z_omega); + proof_obj.lookup_grand_product_opening_at_z_omega = + Some(lookup_grand_product_opening_at_z_omega); + proof_obj.lookup_t_poly_opening_at_z = Some(lookup_t_poly_opening_at_z); + proof_obj.lookup_t_poly_opening_at_z_omega = Some(lookup_t_poly_opening_at_z_omega); + proof_obj.lookup_selector_poly_opening_at_z = Some(lookup_selector_poly_opening_at_z); + proof_obj.lookup_table_type_poly_opening_at_z = Some(lookup_table_type_poly_opening_at_z); + proof_obj.quotient_poly_opening_at_z = quotient_poly_opening_at_z; + proof_obj.linearization_poly_opening_at_z = linearization_poly_opening_at_z; + proof_obj.opening_proof_at_z = opening_proof_at_z; + proof_obj.opening_proof_at_z_omega = opening_proof_at_z_omega; + + proof_obj +} diff --git a/core/lib/via_validation/src/errors.rs b/core/lib/via_validation/src/errors.rs new file mode 100644 index 000000000..c1e01e5bf --- /dev/null +++ b/core/lib/via_validation/src/errors.rs @@ -0,0 +1,56 @@ +use ethers::abi::ethabi; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum VerificationError { + #[error("Network not supported")] + UnsupportedNetwork, + + #[error("Failed to fetch data: {0}")] + FetchError(String), + + #[error("Verification key hash mismatch")] + VerificationKeyHashMismatch, + + #[error("Proof verification failed")] + ProofVerificationFailed, + + #[error("Invalid proof")] + InvalidProof, + + #[error("Abi error: {0}")] + AbiError(ethers::contract::AbiError), + + #[error("Provider error: {0}")] + ProviderError(String), + + #[error("Contract error: {0}")] + ContractError(String), + + #[error("Other error: {0}")] + Other(String), +} + +impl From for VerificationError { + fn from(e: reqwest::Error) -> Self { + VerificationError::FetchError(e.to_string()) + } +} + +impl From for VerificationError { + fn from(e: ethers::providers::ProviderError) -> Self { + VerificationError::FetchError(e.to_string()) + } +} + +impl From for VerificationError { + fn from(e: ethabi::Error) -> Self { + VerificationError::Other(e.to_string()) + } +} + +impl From for VerificationError { + fn from(e: ethers::contract::AbiError) -> Self { + VerificationError::AbiError(e) + } +} diff --git a/core/lib/via_validation/src/l1_data_fetcher.rs b/core/lib/via_validation/src/l1_data_fetcher.rs new file mode 100644 index 000000000..6346d0a85 --- /dev/null +++ b/core/lib/via_validation/src/l1_data_fetcher.rs @@ -0,0 +1,44 @@ +use async_trait::async_trait; +use primitive_types::H256; + +use crate::{ + block_header::{BlockAuxilaryOutput, VerifierParams}, + errors::VerificationError, + proof::L1BatchProof, + types::BatchL1Data, +}; + +/// Trait for fetching data from L1 necessary for verification. +#[async_trait] +pub trait L1DataFetcher { + /// Fetches the verification key hash from L1 for a given block number. + async fn get_verification_key_hash(&self, block_number: u64) + -> Result; + + /// Fetches the protocol version for a given batch number. + async fn get_protocol_version(&self, batch_number: u64) -> Result; + + /// Fetches batch commit transaction hash for a given batch number. + async fn get_batch_commit_tx_hash( + &self, + batch_number: u64, + ) -> Result<(String, Option), VerificationError>; + + /// Fetches L1 commit data for a given batch number. + async fn get_l1_commit_data( + &self, + batch_number: u64, + ) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError>; + + /// Fetches proof data from L1 for a given batch number. + async fn get_proof_from_l1( + &self, + batch_number: u64, + ) -> Result<(L1BatchProof, u64), VerificationError>; + + /// Fetches verifier parameters from L1 for a given block number. + async fn get_verifier_params( + &self, + block_number: u64, + ) -> Result; +} diff --git a/core/lib/via_validation/src/lib.rs b/core/lib/via_validation/src/lib.rs new file mode 100644 index 000000000..88ecbeae1 --- /dev/null +++ b/core/lib/via_validation/src/lib.rs @@ -0,0 +1,9 @@ +pub mod block_header; +pub mod crypto; +pub mod errors; +pub mod l1_data_fetcher; +pub mod proof; +pub mod public_inputs; +pub mod types; +pub mod utils; +pub mod verification; diff --git a/core/lib/via_validation/src/proof.rs b/core/lib/via_validation/src/proof.rs new file mode 100644 index 000000000..7cd0d97f3 --- /dev/null +++ b/core/lib/via_validation/src/proof.rs @@ -0,0 +1,65 @@ +use circuit_definitions::{ + circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, + snark_wrapper::franklin_crypto::bellman::{ + bn256::Bn256, + plonk::{ + better_better_cs::{ + proof::Proof as ZkSyncProof, setup::VerificationKey, verifier::verify, + }, + commitments::transcript::keccak_transcript::RollingKeccakTranscript, + }, + }, +}; + +use crate::{errors::VerificationError, types::Fr}; + +/// Trait for a proof that can be verified. +pub trait Proof { + /// Verifies the proof with the given verification key and public inputs. + fn verify( + &self, + verification_key: VerificationKey, + ) -> Result; + + /// Returns the public inputs of the proof. + fn get_public_inputs(&self) -> &[Fr]; +} + +/// A struct representing an L1 batch proof. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct L1BatchProof { + pub aggregation_result_coords: [[u8; 32]; 4], + pub scheduler_proof: ZkSyncProof, + pub inputs: Vec, +} + +impl Proof for L1BatchProof { + fn verify( + &self, + vk: VerificationKey, + ) -> Result { + // Ensure the proof's 'n' matches the verification key's 'n'. + let mut scheduler_proof = self.scheduler_proof.clone(); + scheduler_proof.n = vk.n; + + tracing::debug!("Verifying proof with n = {}", scheduler_proof.n); + + // Verify the proof + verify::<_, _, RollingKeccakTranscript<_>>(&vk, &scheduler_proof, None) + .map_err(|_| VerificationError::ProofVerificationFailed) + } + + fn get_public_inputs(&self) -> &[Fr] { + &self.inputs + } +} + +impl Default for L1BatchProof { + fn default() -> Self { + Self { + aggregation_result_coords: [[0u8; 32]; 4], + scheduler_proof: ZkSyncProof::empty(), + inputs: vec![], + } + } +} diff --git a/core/lib/via_validation/src/public_inputs.rs b/core/lib/via_validation/src/public_inputs.rs new file mode 100644 index 000000000..2f030f636 --- /dev/null +++ b/core/lib/via_validation/src/public_inputs.rs @@ -0,0 +1,27 @@ +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::{ + pairing::bn256::Fr, PrimeField, +}; +use ethers::types::U256; +use sha3::{Digest, Keccak256}; + +use crate::{types::BatchL1Data, utils::to_fixed_bytes}; + +/// Computes the public inputs for a given batch. +/// Public inputs require us to fetch multiple data from L1 (like state hash etc). +pub fn generate_inputs(batch_l1_data: BatchL1Data) -> Vec { + // Prepare the input fields + let input_fields = [ + batch_l1_data.prev_batch_commitment.to_fixed_bytes(), + batch_l1_data.curr_batch_commitment.to_fixed_bytes(), + ]; + let encoded_input_params = input_fields.into_iter().flatten().collect::>(); + + // Compute the Keccak256 hash of the input parameters + let input_keccak_hash = to_fixed_bytes(&Keccak256::digest(&encoded_input_params)); + let input_u256 = U256::from_big_endian(&input_keccak_hash); + + // Shift the input as per the protocol's requirement + let shifted_input = input_u256 >> 32; + + vec![Fr::from_str(&shifted_input.to_string()).unwrap()] +} diff --git a/core/lib/via_validation/src/types.rs b/core/lib/via_validation/src/types.rs new file mode 100644 index 000000000..8458f54d9 --- /dev/null +++ b/core/lib/via_validation/src/types.rs @@ -0,0 +1,66 @@ +pub use circuit_definitions::snark_wrapper::franklin_crypto::bellman::bn256::Fr; +use circuit_definitions::{ + circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, + snark_wrapper::franklin_crypto::bellman::{ + bn256::Bn256, plonk::better_better_cs::proof::Proof, + }, +}; +use ethers::types::H256; +use serde::{Deserialize, Serialize}; + +use crate::block_header::{BlockAuxilaryOutput, VerifierParams}; + +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct BatchL1Data { + pub previous_enumeration_counter: u64, + pub previous_root: Vec, + // Enumeration counter (used for L2 -> L1 communication). + pub new_enumeration_counter: u64, + // Storage root. + pub new_root: Vec, + // Hash of the account abstraction code. + pub default_aa_hash: [u8; 32], + // Hash of the bootloader.yul code. + pub bootloader_hash: [u8; 32], + pub prev_batch_commitment: H256, + pub curr_batch_commitment: H256, +} + +#[derive(Debug, Clone)] +pub struct L1BatchAndProofData { + pub batch_l1_data: BatchL1Data, + pub aux_output: BlockAuxilaryOutput, + pub scheduler_proof: Proof, + pub verifier_params: VerifierParams, + pub block_number: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct VerificationKeyHashJsonOutput { + pub layer_1_vk_hash: [u8; 32], + pub computed_vk_hash: [u8; 32], +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DataJsonOutput { + pub batch_l1_data: BatchL1Data, + pub aux_input: BlockAuxilaryOutput, + pub verifier_params: VerifierParams, + pub verification_key_hash: VerificationKeyHashJsonOutput, + pub public_input: Fr, + pub is_proof_valid: bool, +} + +impl From for DataJsonOutput { + fn from(batch: L1BatchAndProofData) -> Self { + Self { + batch_l1_data: batch.batch_l1_data, + aux_input: batch.aux_output, + verifier_params: batch.verifier_params, + verification_key_hash: VerificationKeyHashJsonOutput::default(), + public_input: Fr::default(), + is_proof_valid: false, + } + } +} diff --git a/core/lib/via_validation/src/utils.rs b/core/lib/via_validation/src/utils.rs new file mode 100644 index 000000000..d58a59d4d --- /dev/null +++ b/core/lib/via_validation/src/utils.rs @@ -0,0 +1,30 @@ +use std::env; + +use crate::errors::VerificationError; + +/// Checks if the verification key exists for a given protocol version. +pub async fn check_verification_key(protocol_version: u16) -> Result<(), VerificationError> { + let file_path = format!( + "keys/protocol_version/{}/scheduler_key.json", + protocol_version + ); + let current_dir = env::current_dir().map_err(|e| VerificationError::Other(e.to_string()))?; + let file = current_dir.join(file_path); + let file_exists = file.exists(); + + if !file_exists { + Err(VerificationError::Other(format!( + "Verification key for protocol version {} is missing. Please add it to the keys folder.", + protocol_version + ))) + } else { + Ok(()) + } +} + +pub fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { + let mut result = [0u8; 32]; + result.copy_from_slice(ins); + + result +} diff --git a/core/lib/via_validation/src/verification.rs b/core/lib/via_validation/src/verification.rs new file mode 100644 index 000000000..7a529a228 --- /dev/null +++ b/core/lib/via_validation/src/verification.rs @@ -0,0 +1,208 @@ +use std::fs; + +use circuit_definitions::{ + boojum::{ + field::goldilocks::GoldilocksField, + pairing::{ff::PrimeFieldRepr, Engine}, + }, + circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, + snark_wrapper::franklin_crypto::bellman::{ + pairing::bn256::{Bn256, Fq}, + plonk::better_better_cs::{cs::Circuit, setup::VerificationKey}, + CurveAffine, PrimeField, + }, +}; +use primitive_types::H256; +use serde::{Deserialize, Serialize}; +use tracing::{error, info}; + +use crate::{errors::VerificationError, proof::Proof, types::Fr}; + +/// Wrapper for the auxiliary output witness. +#[derive(Debug, Serialize, Deserialize)] +pub struct AuxOutputWitnessWrapper( + pub circuit_definitions::zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness< + GoldilocksField, + >, +); + +/// Verifies a SNARK proof with a given verification key, checking the verification key hash if provided. +/// Returns the public input, auxiliary witness, and computed VK hash on success. +pub async fn verify_snark( + snark_vk_scheduler_key_file: &str, + proof: impl Proof, + vk_hash_from_l1: Option, +) -> Result<(Fr, AuxOutputWitnessWrapper, H256), VerificationError> { + info!("Verifying SNARK wrapped FRI proof."); + info!( + "Loading verification key from {}", + snark_vk_scheduler_key_file + ); + + // Load the verification key from the specified file. + let verification_key_content = + fs::read_to_string(snark_vk_scheduler_key_file).map_err(|e| { + VerificationError::Other(format!( + "Failed to read verification key from {}: {}", + snark_vk_scheduler_key_file, e + )) + })?; + + // Deserialize the verification key. + let vk_inner: VerificationKey = + serde_json::from_str(&verification_key_content).map_err(|e| { + VerificationError::Other(format!("Failed to deserialize verification key: {}", e)) + })?; + + // Compute the VK hash and check against the provided hash if any. + let vk_hash = check_verification_key(&vk_inner, vk_hash_from_l1)?; + + // Verify the proof. + let is_valid = proof.verify(vk_inner)?; + + if !is_valid { + error!("Proof is INVALID"); + return Err(VerificationError::ProofVerificationFailed); + } else { + info!("Proof is VALID"); + } + + // Extract the public input from the proof. + let public_inputs = proof.get_public_inputs(); + let public_input = public_inputs + .first() + .cloned() + .ok_or_else(|| VerificationError::Other("No public inputs found in proof".to_string()))?; + + // Create the auxiliary witness (placeholder implementation). + let aux_witness = AuxOutputWitnessWrapper( + circuit_definitions::zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness { + l1_messages_linear_hash: [0u8; 32], + rollup_state_diff_for_compression: [0u8; 32], + bootloader_heap_initial_content: [0u8; 32], + events_queue_state: [0u8; 32], + eip4844_linear_hashes: [[0u8; 32]; 16], + eip4844_output_commitment_hashes: [[0u8; 32]; 16], + }, + ); + + Ok((public_input, aux_witness, vk_hash)) +} + +/// Checks that the hash of the verification key matches the supplied hash. +/// Returns the computed VK hash on success. +fn check_verification_key( + verification_key: &VerificationKey, + vk_hash_from_l1: Option, +) -> Result { + if let Some(vk_hash_from_l1) = vk_hash_from_l1 { + let computed_vk_hash = calculate_verification_key_hash(verification_key); + + info!("Verification Key Hash Check:"); + info!( + " Verification Key Hash from L1: 0x{}", + hex::encode(vk_hash_from_l1) + ); + info!( + " Computed Verification Key Hash: 0x{}", + hex::encode(computed_vk_hash) + ); + + if computed_vk_hash != vk_hash_from_l1 { + return Err(VerificationError::VerificationKeyHashMismatch); + } + + Ok(computed_vk_hash) + } else { + info!("Supplied VK hash is None, skipping check..."); + Ok(H256::default()) + } +} + +/// Calculates the hash of a verification key. +pub fn calculate_verification_key_hash>( + verification_key: &VerificationKey, +) -> H256 { + use sha3::{Digest, Keccak256}; + + let mut res = Vec::new(); + + // Serialize gate setup commitments. + for gate_setup in &verification_key.gate_setup_commitments { + let (x, y) = gate_setup.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize gate selectors commitments. + for gate_selector in &verification_key.gate_selectors_commitments { + let (x, y) = gate_selector.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize permutation commitments. + for permutation in &verification_key.permutation_commitments { + let (x, y) = permutation.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize lookup selector commitment if present. + if let Some(lookup_selector) = &verification_key.lookup_selector_commitment { + let (x, y) = lookup_selector.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize lookup tables commitments. + for table_commit in &verification_key.lookup_tables_commitments { + let (x, y) = table_commit.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize table type commitment if present. + if let Some(lookup_table) = &verification_key.lookup_table_type_commitment { + let (x, y) = lookup_table.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize flag for using recursive part. + Fq::default() + .into_repr() + .write_be(&mut res) + .expect("Failed to write recursive flag"); + + // Compute Keccak256 hash of the serialized data. + let mut hasher = Keccak256::new(); + hasher.update(&res); + let computed_vk_hash = hasher.finalize(); + + H256::from_slice(&computed_vk_hash) +} From 7dd795541be28075fc5bdf5986ec5cc644a9a482 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sat, 30 Nov 2024 12:58:08 +0330 Subject: [PATCH 002/212] withdrawal component init in btc client lib --- core/lib/via_btc_client/src/withdrawal/fee.rs | 0 core/lib/via_btc_client/src/withdrawal/mod.rs | 4 ++++ core/lib/via_btc_client/src/withdrawal/utxo.rs | 0 3 files changed, 4 insertions(+) create mode 100644 core/lib/via_btc_client/src/withdrawal/fee.rs create mode 100644 core/lib/via_btc_client/src/withdrawal/mod.rs create mode 100644 core/lib/via_btc_client/src/withdrawal/utxo.rs diff --git a/core/lib/via_btc_client/src/withdrawal/fee.rs b/core/lib/via_btc_client/src/withdrawal/fee.rs new file mode 100644 index 000000000..e69de29bb diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs new file mode 100644 index 000000000..fb3cd0dda --- /dev/null +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -0,0 +1,4 @@ +struct WithdrawalBuilder { + utxos: Vec, + client: Arc, +} \ No newline at end of file diff --git a/core/lib/via_btc_client/src/withdrawal/utxo.rs b/core/lib/via_btc_client/src/withdrawal/utxo.rs new file mode 100644 index 000000000..e69de29bb From 27b88542a4ee896ad062d2cb95a0dbbbe1c0909f Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 1 Dec 2024 22:26:44 +0100 Subject: [PATCH 003/212] feat: add 25 protocol version vk, reconstructed traits and functionality --- .../examples/zksync-era/contract.rs | 59 +-- .../examples/zksync-era/fetching.rs | 90 +--- .../examples/zksync-era/main.rs | 67 +-- .../protocol_version/25/scheduler_key.json | 399 ++++++++++++++++++ core/lib/via_validation/src/block_header.rs | 145 ------- .../lib/via_validation/src/l1_data_fetcher.rs | 27 +- core/lib/via_validation/src/lib.rs | 1 - core/lib/via_validation/src/proof.rs | 20 +- core/lib/via_validation/src/public_inputs.rs | 2 +- core/lib/via_validation/src/types.rs | 47 --- core/lib/via_validation/src/utils.rs | 2 +- core/lib/via_validation/src/verification.rs | 71 ++-- 12 files changed, 472 insertions(+), 458 deletions(-) create mode 100644 core/lib/via_validation/keys/protocol_version/25/scheduler_key.json delete mode 100644 core/lib/via_validation/src/block_header.rs diff --git a/core/lib/via_validation/examples/zksync-era/contract.rs b/core/lib/via_validation/examples/zksync-era/contract.rs index 35d2e8617..7b53d37f6 100644 --- a/core/lib/via_validation/examples/zksync-era/contract.rs +++ b/core/lib/via_validation/examples/zksync-era/contract.rs @@ -7,18 +7,13 @@ use ethers::{ prelude::{Address, Http, Provider}, types::H256, }; +use tracing::debug; use via_validator::{ - block_header::{BlockAuxilaryOutput, VerifierParams}, - errors::VerificationError, - l1_data_fetcher::L1DataFetcher, - proof::L1BatchProof, - types::BatchL1Data, + errors::VerificationError, l1_data_fetcher::L1DataFetcher, proof::ViaZKProof, + public_inputs::generate_inputs, utils::check_verification_key, }; -use crate::fetching::{ - fetch_batch_commit_tx, fetch_batch_protocol_version, fetch_l1_commit_data, fetch_proof_from_l1, - fetch_verifier_param_from_l1, -}; +use crate::fetching::{fetch_batch_protocol_version, fetch_l1_commit_data, fetch_proof_from_l1}; pub struct ContractConfig { pub provider: Provider, @@ -86,49 +81,31 @@ impl L1DataFetcher for ContractConfig { fetch_batch_protocol_version(batch_number).await } - async fn get_batch_commit_tx_hash( - &self, - batch_number: u64, - ) -> Result<(String, Option), VerificationError> { - fetch_batch_commit_tx(batch_number).await - } - - async fn get_l1_commit_data( - &self, - batch_number: u64, - ) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError> { - let protocol_version = self.get_protocol_version(batch_number).await?; - let protocol_version_id = protocol_version.parse::().map_err(|_| { - VerificationError::FetchError("Failed to parse protocol version".to_string()) - })?; - fetch_l1_commit_data( - batch_number, - protocol_version_id, - &self.provider.url().to_string(), - ) - .await - } - async fn get_proof_from_l1( &self, batch_number: u64, - ) -> Result<(L1BatchProof, u64), VerificationError> { + ) -> Result<(ViaZKProof, u64), VerificationError> { let protocol_version = self.get_protocol_version(batch_number).await?; let protocol_version_id = protocol_version.parse::().map_err(|_| { VerificationError::FetchError("Failed to parse protocol version".to_string()) })?; - fetch_proof_from_l1( + debug!( + "Protocol version: {} for batch # {}", + protocol_version, batch_number + ); + check_verification_key(protocol_version_id).await?; + + let (mut proof, block_number) = fetch_proof_from_l1( batch_number, &self.provider.url().to_string(), protocol_version_id, ) - .await - } + .await?; + let batch_l1_data = + fetch_l1_commit_data(batch_number, &self.provider.url().to_string()).await?; + let inputs = generate_inputs(&batch_l1_data); + proof.proof.inputs = inputs.clone(); - async fn get_verifier_params( - &self, - block_number: u64, - ) -> Result { - Ok(fetch_verifier_param_from_l1(block_number, &self.provider.url().to_string()).await) + Ok((proof, block_number)) } } diff --git a/core/lib/via_validation/examples/zksync-era/fetching.rs b/core/lib/via_validation/examples/zksync-era/fetching.rs index 43dd3a5a0..5b0a89826 100644 --- a/core/lib/via_validation/examples/zksync-era/fetching.rs +++ b/core/lib/via_validation/examples/zksync-era/fetching.rs @@ -5,7 +5,7 @@ use circuit_definitions::{ snark_wrapper::franklin_crypto::bellman::bn256::Bn256, }; use ethers::{ - abi::{ethabi, ethereum_types, Abi, Address, Function, Token}, + abi::{ethabi, ethereum_types, Abi, Function, Token}, contract::BaseContract, providers::{Http, Middleware, Provider}, types::TxHash, @@ -14,17 +14,12 @@ use once_cell::sync::Lazy; use primitive_types::{H256, U256}; use reqwest::StatusCode; use via_validator::{ - block_header, - block_header::{BlockAuxilaryOutput, VerifierParams}, - crypto::deserialize_proof, - errors::VerificationError, - proof::L1BatchProof, - types::{BatchL1Data, L1BatchAndProofData}, + crypto::deserialize_proof, errors::VerificationError, proof::ViaZKProof, types::BatchL1Data, }; use crate::types::{JSONL2RPCResponse, JSONL2SyncRPCResponse, L1BatchRangeJson}; -pub static BLOCK_COMMIT_EVENT_SIGNATURE: Lazy = Lazy::new(|| { +static BLOCK_COMMIT_EVENT_SIGNATURE: Lazy = Lazy::new(|| { ethabi::long_signature( "BlockCommit", &[ @@ -143,43 +138,14 @@ pub async fn fetch_batch_commit_tx( } } -pub async fn fetch_l1_data( - batch_number: u64, - protocol_version: u16, - rpc_url: &str, -) -> Result { - let commit_data = fetch_l1_commit_data(batch_number, protocol_version, rpc_url).await?; - - let (batch_l1_data, aux_output) = commit_data; - - let proof_info = fetch_proof_from_l1(batch_number, rpc_url, protocol_version).await?; - - let (proof_data, block_number) = proof_info; - - let verifier_params = fetch_verifier_param_from_l1(block_number, rpc_url).await; - - Ok(L1BatchAndProofData { - batch_l1_data, - aux_output, - scheduler_proof: proof_data.scheduler_proof, - verifier_params, - block_number, - }) -} - pub async fn fetch_l1_commit_data( batch_number: u64, - protocol_version: u16, rpc_url: &str, -) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError> { +) -> Result { let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); - let (function_name, fallback_fn_name) = if protocol_version < 23 { - ("commitBatches", None) - } else { - ("commitBatchesSharedBridge", Some("commitBatches")) - }; + let (function_name, fallback_fn_name) = ("commitBatchesSharedBridge", Some("commitBatches")); let function = contract_abi.functions_by_name(function_name).unwrap()[0].clone(); let fallback_function = @@ -191,7 +157,6 @@ pub async fn fetch_l1_commit_data( let mut roots = vec![]; let mut l1_block_number = 0; - let mut calldata = vec![]; let mut prev_batch_commitment = H256::default(); let mut curr_batch_commitment = H256::default(); for b_number in [previous_batch_number, batch_number] { @@ -203,7 +168,7 @@ pub async fn fetch_l1_commit_data( let tx = tx.unwrap(); l1_block_number = tx.block_number.unwrap().as_u64(); - calldata = tx.input.to_vec(); + let calldata = tx.input.to_vec(); let found_data = find_state_data_from_log(b_number, &function, fallback_function.clone(), &calldata)?; @@ -239,8 +204,6 @@ pub async fn fetch_l1_commit_data( roots.push(found_data); } - let aux_output = block_header::parse_aux_data(&function, &calldata)?; - assert_eq!(roots.len(), 2); let (previous_enumeration_counter, previous_root) = roots[0].clone(); @@ -274,7 +237,6 @@ pub async fn fetch_l1_commit_data( format!("0x{}", hex::encode(bootloader_code_hash.as_bytes())), format!("0x{}", hex::encode(default_aa_code_hash.as_bytes())) ); - println!("\n"); let result = BatchL1Data { previous_enumeration_counter, previous_root, @@ -286,7 +248,7 @@ pub async fn fetch_l1_commit_data( curr_batch_commitment, }; - Ok((result, aux_output)) + Ok(result) } fn find_state_data_from_log( @@ -381,11 +343,11 @@ fn find_state_data_from_log( Ok(found_params) } -pub async fn fetch_proof_from_l1( +pub(crate) async fn fetch_proof_from_l1( batch_number: u64, rpc_url: &str, protocol_version: u16, -) -> Result<(L1BatchProof, u64), VerificationError> { +) -> Result<(ViaZKProof, u64), VerificationError> { let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); @@ -456,38 +418,6 @@ pub async fn fetch_proof_from_l1( } let x: circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof = deserialize_proof(proof); - Ok(( - L1BatchProof { - aggregation_result_coords: [[0u8; 32]; 4], - scheduler_proof: x, - inputs: vec![], // TODO - }, - l1_block_number, - )) -} -pub async fn fetch_verifier_param_from_l1(block_number: u64, rpc_url: &str) -> VerifierParams { - let client = Provider::::try_from(rpc_url).expect("Failed to connect to provider"); - let contract_abi: Abi = Abi::load(&include_bytes!("abis/IZkSync.json")[..]).unwrap(); - - let base_contract: BaseContract = contract_abi.into(); - let address = Address::from_str("32400084c286cf3e17e7b677ea9583e60a000324").unwrap(); - let contract_instance = base_contract.into_contract::>(address, client); - let ( - recursion_node_level_vk_hash, - recursion_leaf_level_vk_hash, - recursion_circuits_set_vk_hash, - ) = contract_instance - .method::<_, (H256, H256, H256)>("getVerifierParams", ()) - .unwrap() - .block(block_number) - .call() - .await - .unwrap(); - - VerifierParams { - recursion_node_level_vk_hash: recursion_node_level_vk_hash.to_fixed_bytes(), - recursion_leaf_level_vk_hash: recursion_leaf_level_vk_hash.to_fixed_bytes(), - recursion_circuits_set_vk_hash: recursion_circuits_set_vk_hash.to_fixed_bytes(), - } + Ok((ViaZKProof { proof: x }, l1_block_number)) } diff --git a/core/lib/via_validation/examples/zksync-era/main.rs b/core/lib/via_validation/examples/zksync-era/main.rs index 3a2c366e6..d04e754b4 100644 --- a/core/lib/via_validation/examples/zksync-era/main.rs +++ b/core/lib/via_validation/examples/zksync-era/main.rs @@ -1,5 +1,3 @@ -// src/main.rs - mod contract; mod fetching; mod types; @@ -7,16 +5,10 @@ mod types; use clap::Parser; use tracing::{error, info}; use via_validator::{ - errors::VerificationError, - l1_data_fetcher::L1DataFetcher, - proof::L1BatchProof, - public_inputs::generate_inputs, - types::{DataJsonOutput, L1BatchAndProofData, VerificationKeyHashJsonOutput}, - utils::check_verification_key, - verification::verify_snark, + errors::VerificationError, l1_data_fetcher::L1DataFetcher, verification::verify_snark, }; -use crate::{contract::ContractConfig, fetching::fetch_l1_data}; +use crate::contract::ContractConfig; #[derive(Debug, Parser)] #[command(author = "Via", version, about = "Boojum CLI verifier")] @@ -28,12 +20,12 @@ struct Cli { #[tokio::main] async fn main() -> Result<(), VerificationError> { - // Initialize tracing subscriber for logging tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .init(); let args = Cli::parse(); + let batch_number = args.batch; let l1_rpc = "https://rpc.ankr.com/eth".to_string(); @@ -44,60 +36,19 @@ async fn main() -> Result<(), VerificationError> { let contract = ContractConfig::new(&l1_rpc)?; - let protocol_version = contract.get_protocol_version(batch_number).await?; - let protocol_version_id = protocol_version.parse::().map_err(|_| { - VerificationError::FetchError("Failed to parse protocol version".to_string()) - })?; - - info!("Protocol version: {}", protocol_version); - - check_verification_key(protocol_version_id).await?; - - let resp = fetch_l1_data(batch_number, protocol_version_id, &l1_rpc).await?; - - let L1BatchAndProofData { - aux_output, - mut scheduler_proof, - batch_l1_data, - verifier_params: _, - block_number, - } = resp.clone(); + let (proof, block_number) = contract.get_proof_from_l1(batch_number).await?; let vk_hash = contract.get_verification_key_hash(block_number).await?; - let snark_vk_scheduler_key_file = format!( - "keys/protocol_version/{}/scheduler_key.json", - protocol_version_id - ); - - let inputs = generate_inputs(batch_l1_data.clone()); - - scheduler_proof.inputs = inputs.clone(); - - let batch_proof = L1BatchProof { - aggregation_result_coords: aux_output.prepare_aggregation_result_coords(), - scheduler_proof, - inputs, - }; + let protocol_version = contract.get_protocol_version(batch_number).await?; // Verify the proof - let verify_resp = verify_snark( - &snark_vk_scheduler_key_file, - batch_proof.clone(), - Some(vk_hash), - ) - .await; - - if let Ok((input, _, computed_vk_hash)) = verify_resp { - let mut data = DataJsonOutput::from(resp); - data.verification_key_hash = VerificationKeyHashJsonOutput { - layer_1_vk_hash: vk_hash.into(), - computed_vk_hash: computed_vk_hash.into(), - }; - data.public_input = input; - data.is_proof_valid = true; + let verify_resp = verify_snark(&protocol_version, proof, Some(vk_hash)).await; + if let Ok((input, computed_vk_hash)) = verify_resp { info!("VERIFIED"); + info!("Public input: {}", input); + info!("Computed VK hash: {}", computed_vk_hash); } else { error!("Failed to verify proof due to an error."); } diff --git a/core/lib/via_validation/keys/protocol_version/25/scheduler_key.json b/core/lib/via_validation/keys/protocol_version/25/scheduler_key.json new file mode 100644 index 000000000..25921368c --- /dev/null +++ b/core/lib/via_validation/keys/protocol_version/25/scheduler_key.json @@ -0,0 +1,399 @@ +{ + "n": 16777215, + "num_inputs": 1, + "state_width": 4, + "num_witness_polys": 0, + "gate_setup_commitments": [ + { + "x": [ + 14543631136906534221, + 11532161447842416044, + 11114175029926010938, + 1228896787564295039 + ], + "y": [ + 13293602262342424489, + 8897930584356943159, + 13256028170406220369, + 3214939367598363288 + ], + "infinity": false + }, + { + "x": [ + 11488992528554025682, + 12016824828223971094, + 11942004360057333370, + 316831626296641307 + ], + "y": [ + 304673622018339856, + 7139037552557818730, + 12475560967982555143, + 1055588351918295250 + ], + "infinity": false + }, + { + "x": [ + 2274984630539920017, + 5398167177582250136, + 16440396753384808945, + 1037682586893548769 + ], + "y": [ + 10168660308952593373, + 16526369642614237721, + 569062739734175056, + 155645558476901406 + ], + "infinity": false + }, + { + "x": [ + 14005362797509427677, + 2662603874351919260, + 14261489165672308143, + 1470528288349794782 + ], + "y": [ + 11144229651170108862, + 11439490264313454962, + 114993091474760680, + 1037267173208738614 + ], + "infinity": false + }, + { + "x": [ + 10726125240955612787, + 1916320162213728495, + 1058608086768277905, + 1651114031905829493 + ], + "y": [ + 13237242732587628574, + 4774776044666137690, + 14401013098807103799, + 2514139699916115771 + ], + "infinity": false + }, + { + "x": [ + 14434760601334248377, + 5316938318287831815, + 6221098547630910324, + 980422841280734466 + ], + "y": [ + 9201886393750447942, + 3840149540273146267, + 18179910191622136829, + 1563809864380914603 + ], + "infinity": false + }, + { + "x": [ + 9586697317366528906, + 2325800863365957883, + 1243781259615311278, + 3048012003267036960 + ], + "y": [ + 612821620743617231, + 1510385666449513894, + 9368337288452385056, + 2949736812933507034 + ], + "infinity": false + }, + { + "x": [ + 11830690209042008764, + 11761396005838073769, + 18271188400274886574, + 2896734446482773484 + ], + "y": [ + 1890606551566554401, + 10220931290312275762, + 3256711195869515344, + 2466626485328709457 + ], + "infinity": false + } + ], + "gate_selectors_commitments": [ + { + "x": [ + 10865727529243127085, + 4083978853392244827, + 14303622309482785753, + 2263042021033673595 + ], + "y": [ + 3019601017411802529, + 880444282195426618, + 9998743525359587628, + 2891421025832200233 + ], + "infinity": false + }, + { + "x": [ + 5208608554346323426, + 8575970970223832576, + 2966209169082345602, + 239576408267301488 + ], + "y": [ + 17715084817752316452, + 2726293100894160682, + 17920596859559317135, + 3485576345363305439 + ], + "infinity": false + } + ], + "permutation_commitments": [ + { + "x": [ + 14761045450946573029, + 17157644513453531531, + 2555518804134782053, + 1415819224310783987 + ], + "y": [ + 17265629196749977462, + 4128711855633066822, + 8435602817910411328, + 1408116296902303196 + ], + "infinity": false + }, + { + "x": [ + 3307267823832528482, + 2406249680085831639, + 9091964031261402109, + 2846274000290842933 + ], + "y": [ + 17374905554931807856, + 6690578002079222163, + 11809376320193686210, + 2676076649992974574 + ], + "infinity": false + }, + { + "x": [ + 3159118708748226574, + 5508845413629697013, + 13350869305506486049, + 689297560178790472 + ], + "y": [ + 15696011303896469684, + 12551611148155235140, + 14438660833518031207, + 425021756161657108 + ], + "infinity": false + }, + { + "x": [ + 18349397811516917436, + 4473982696343317918, + 13070312540813307819, + 2109468484629113245 + ], + "y": [ + 13254534552549721008, + 17388411854346636521, + 17875890960520499518, + 1062184221180884481 + ], + "infinity": false + } + ], + "total_lookup_entries_length": 1787472, + "lookup_selector_commitment": { + "x": [ + 9324906502432882695, + 14977861238256290580, + 12538013124354067293, + 3408438202312564138 + ], + "y": [ + 14942105932194201701, + 12210090881357612547, + 14774705021036784261, + 2531694948512337448 + ], + "infinity": false + }, + "lookup_tables_commitments": [ + { + "x": [ + 10873859091125335643, + 3906092213625635374, + 17046157606087980048, + 3193402705223440293 + ], + "y": [ + 10158946293873382504, + 2171386304067884865, + 6918663094168980658, + 350601565475975409 + ], + "infinity": false + }, + { + "x": [ + 12822112641313049260, + 3646552465186399021, + 10324071010773924047, + 2209084192380614662 + ], + "y": [ + 11045141628975531869, + 12589678537679955590, + 3065046617868727674, + 2099447669854151830 + ], + "infinity": false + }, + { + "x": [ + 11395032673621937545, + 3000063650268118516, + 7857619430005721792, + 805706808484810738 + ], + "y": [ + 6817063666434679427, + 1646386051225388537, + 4677946977082722827, + 1369650305976868514 + ], + "infinity": false + }, + { + "x": [ + 2885179371868476351, + 159944842081142878, + 6092294387055034894, + 213843603626505240 + ], + "y": [ + 11868113133779277990, + 8509646480531194854, + 14088068011597639414, + 707070630614027545 + ], + "infinity": false + } + ], + "lookup_table_type_commitment": { + "x": [ + 1732877442096985191, + 7537030715658833452, + 14073502080301311448, + 2178792007727681099 + ], + "y": [ + 8513095304113652904, + 6581396660744182779, + 13939755637576387431, + 2477157044961106453 + ], + "infinity": false + }, + "non_residues": [ + [ + 5, + 0, + 0, + 0 + ], + [ + 7, + 0, + 0, + 0 + ], + [ + 10, + 0, + 0, + 0 + ] + ], + "g2_elements": [ + { + "x": { + "c0": [ + 5106727233969649389, + 7440829307424791261, + 4785637993704342649, + 1729627375292849782 + ], + "c1": [ + 10945020018377822914, + 17413811393473931026, + 8241798111626485029, + 1841571559660931130 + ] + }, + "y": { + "c0": [ + 5541340697920699818, + 16416156555105522555, + 5380518976772849807, + 1353435754470862315 + ], + "c1": [ + 6173549831154472795, + 13567992399387660019, + 17050234209342075797, + 650358724130500725 + ] + }, + "infinity": false + }, + { + "x": { + "c0": [ + 9089143573911733168, + 11482283522806384523, + 13585589533905622862, + 79029415676722370 + ], + "c1": [ + 5692040832573735873, + 16884514497384809355, + 16717166481813659368, + 2742131088506155463 + ] + }, + "y": { + "c0": [ + 9604638503594647125, + 1289961608472612514, + 6217038149984805214, + 2521661352385209130 + ], + "c1": [ + 17168069778630926308, + 11309277837895768996, + 15154989611154567813, + 359271377050603491 + ] + }, + "infinity": false + } + ] +} diff --git a/core/lib/via_validation/src/block_header.rs b/core/lib/via_validation/src/block_header.rs deleted file mode 100644 index ce68c1be6..000000000 --- a/core/lib/via_validation/src/block_header.rs +++ /dev/null @@ -1,145 +0,0 @@ -use ethers::{ - abi::{Function, Token}, - utils::keccak256, -}; -use serde::{Deserialize, Serialize}; -use zksync_types::{commitment::SerializeCommitment, l2_to_l1_log::L2ToL1Log, H256}; - -use crate::{errors::VerificationError, utils::to_fixed_bytes}; - -/// Represents auxiliary output data extracted from a block. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BlockAuxilaryOutput { - pub system_logs_hash: [u8; 32], - pub state_diff_hash: [u8; 32], - pub bootloader_heap_initial_content_hash: [u8; 32], - pub event_queue_state_hash: [u8; 32], -} - -impl BlockAuxilaryOutput { - /// Flattens the struct fields into a single byte vector. - pub fn into_flattened_bytes(&self) -> Vec { - let mut result = Vec::with_capacity(128); - result.extend_from_slice(&self.system_logs_hash); - result.extend_from_slice(&self.state_diff_hash); - result.extend_from_slice(&self.bootloader_heap_initial_content_hash); - result.extend_from_slice(&self.event_queue_state_hash); - result - } - - /// Prepares the aggregation result coordinates. - pub fn prepare_aggregation_result_coords(&self) -> [[u8; 32]; 4] { - [ - self.system_logs_hash, - self.state_diff_hash, - self.bootloader_heap_initial_content_hash, - self.event_queue_state_hash, - ] - } -} - -/// Parses auxiliary data from the given calldata using the provided function ABI. -pub fn parse_aux_data( - func: &Function, - calldata: &[u8], -) -> Result { - if calldata.len() < 5 { - return Err(VerificationError::FetchError( - "Calldata is too short".to_string(), - )); - } - - let mut parsed_calldata = func - .decode_input(&calldata[4..]) - .map_err(|e| VerificationError::FetchError(e.to_string()))?; - - let committed_batch = parsed_calldata.pop().ok_or_else(|| { - VerificationError::FetchError("Failed to deconstruct committed batch".to_string()) - })?; - - let committed_batch = if let Token::Array(committed_batch) = committed_batch { - committed_batch - } else { - return Err(VerificationError::FetchError( - "Failed to deconstruct committed batch".to_string(), - )); - }; - - let committed_batch = if let Token::Tuple(ref tuple) = committed_batch[0] { - tuple - } else { - return Err(VerificationError::FetchError( - "Failed to deconstruct committed batch".to_string(), - )); - }; - - if committed_batch.len() != 10 { - return Err(VerificationError::FetchError( - "Unexpected committed batch format".to_string(), - )); - } - - let bootloader_contents_hash = if let Token::FixedBytes(bytes) = &committed_batch[6] { - bytes - } else { - return Err(VerificationError::FetchError( - "Failed to extract bootloader_contents_hash".to_string(), - )); - }; - - let event_queue_state_hash = if let Token::FixedBytes(bytes) = &committed_batch[7] { - bytes - } else { - return Err(VerificationError::FetchError( - "Failed to extract event_queue_state_hash".to_string(), - )); - }; - - let sys_logs = if let Token::Bytes(bytes) = &committed_batch[8] { - bytes - } else { - return Err(VerificationError::FetchError( - "Failed to extract sys_logs".to_string(), - )); - }; - - if bootloader_contents_hash.len() != 32 || event_queue_state_hash.len() != 32 { - return Err(VerificationError::FetchError( - "Invalid hash length in committed batch".to_string(), - )); - } - - let bootloader_contents_hash_buffer = to_fixed_bytes(bootloader_contents_hash); - let event_queue_state_hash_buffer = to_fixed_bytes(event_queue_state_hash); - - if sys_logs.len() % L2ToL1Log::SERIALIZED_SIZE != 0 { - return Err(VerificationError::FetchError( - "sys_logs length is not a multiple of L2ToL1Log::SERIALIZED_SIZE".to_string(), - )); - } - - let state_diff_hash_sys_log = sys_logs - .chunks(L2ToL1Log::SERIALIZED_SIZE) - .map(L2ToL1Log::from_slice) - .find(|log| log.key == H256::from_low_u64_be(2_u64)) - .ok_or_else(|| { - VerificationError::FetchError("Failed to find state_diff_hash in sys_logs".to_string()) - })?; - - let system_logs_hash = keccak256(sys_logs); - - Ok(BlockAuxilaryOutput { - system_logs_hash, - state_diff_hash: to_fixed_bytes(state_diff_hash_sys_log.value.as_bytes()), - bootloader_heap_initial_content_hash: bootloader_contents_hash_buffer, - event_queue_state_hash: event_queue_state_hash_buffer, - }) -} - -/// Verifier config params describing the circuit to be verified. -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub struct VerifierParams { - pub recursion_node_level_vk_hash: [u8; 32], - pub recursion_leaf_level_vk_hash: [u8; 32], - pub recursion_circuits_set_vk_hash: [u8; 32], -} diff --git a/core/lib/via_validation/src/l1_data_fetcher.rs b/core/lib/via_validation/src/l1_data_fetcher.rs index 6346d0a85..112f8d108 100644 --- a/core/lib/via_validation/src/l1_data_fetcher.rs +++ b/core/lib/via_validation/src/l1_data_fetcher.rs @@ -1,12 +1,7 @@ use async_trait::async_trait; use primitive_types::H256; -use crate::{ - block_header::{BlockAuxilaryOutput, VerifierParams}, - errors::VerificationError, - proof::L1BatchProof, - types::BatchL1Data, -}; +use crate::{errors::VerificationError, proof::ViaZKProof}; /// Trait for fetching data from L1 necessary for verification. #[async_trait] @@ -18,27 +13,9 @@ pub trait L1DataFetcher { /// Fetches the protocol version for a given batch number. async fn get_protocol_version(&self, batch_number: u64) -> Result; - /// Fetches batch commit transaction hash for a given batch number. - async fn get_batch_commit_tx_hash( - &self, - batch_number: u64, - ) -> Result<(String, Option), VerificationError>; - - /// Fetches L1 commit data for a given batch number. - async fn get_l1_commit_data( - &self, - batch_number: u64, - ) -> Result<(BatchL1Data, BlockAuxilaryOutput), VerificationError>; - /// Fetches proof data from L1 for a given batch number. async fn get_proof_from_l1( &self, batch_number: u64, - ) -> Result<(L1BatchProof, u64), VerificationError>; - - /// Fetches verifier parameters from L1 for a given block number. - async fn get_verifier_params( - &self, - block_number: u64, - ) -> Result; + ) -> Result<(ViaZKProof, u64), VerificationError>; } diff --git a/core/lib/via_validation/src/lib.rs b/core/lib/via_validation/src/lib.rs index 88ecbeae1..02c3af456 100644 --- a/core/lib/via_validation/src/lib.rs +++ b/core/lib/via_validation/src/lib.rs @@ -1,4 +1,3 @@ -pub mod block_header; pub mod crypto; pub mod errors; pub mod l1_data_fetcher; diff --git a/core/lib/via_validation/src/proof.rs b/core/lib/via_validation/src/proof.rs index 7cd0d97f3..bb2b38c96 100644 --- a/core/lib/via_validation/src/proof.rs +++ b/core/lib/via_validation/src/proof.rs @@ -14,7 +14,7 @@ use circuit_definitions::{ use crate::{errors::VerificationError, types::Fr}; /// Trait for a proof that can be verified. -pub trait Proof { +pub trait ProofTrait { /// Verifies the proof with the given verification key and public inputs. fn verify( &self, @@ -27,19 +27,17 @@ pub trait Proof { /// A struct representing an L1 batch proof. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct L1BatchProof { - pub aggregation_result_coords: [[u8; 32]; 4], - pub scheduler_proof: ZkSyncProof, - pub inputs: Vec, +pub struct ViaZKProof { + pub proof: ZkSyncProof, } -impl Proof for L1BatchProof { +impl ProofTrait for ViaZKProof { fn verify( &self, vk: VerificationKey, ) -> Result { // Ensure the proof's 'n' matches the verification key's 'n'. - let mut scheduler_proof = self.scheduler_proof.clone(); + let mut scheduler_proof = self.proof.clone(); scheduler_proof.n = vk.n; tracing::debug!("Verifying proof with n = {}", scheduler_proof.n); @@ -50,16 +48,14 @@ impl Proof for L1BatchProof { } fn get_public_inputs(&self) -> &[Fr] { - &self.inputs + &self.proof.inputs } } -impl Default for L1BatchProof { +impl Default for ViaZKProof { fn default() -> Self { Self { - aggregation_result_coords: [[0u8; 32]; 4], - scheduler_proof: ZkSyncProof::empty(), - inputs: vec![], + proof: ZkSyncProof::empty(), } } } diff --git a/core/lib/via_validation/src/public_inputs.rs b/core/lib/via_validation/src/public_inputs.rs index 2f030f636..14739e3d0 100644 --- a/core/lib/via_validation/src/public_inputs.rs +++ b/core/lib/via_validation/src/public_inputs.rs @@ -8,7 +8,7 @@ use crate::{types::BatchL1Data, utils::to_fixed_bytes}; /// Computes the public inputs for a given batch. /// Public inputs require us to fetch multiple data from L1 (like state hash etc). -pub fn generate_inputs(batch_l1_data: BatchL1Data) -> Vec { +pub fn generate_inputs(batch_l1_data: &BatchL1Data) -> Vec { // Prepare the input fields let input_fields = [ batch_l1_data.prev_batch_commitment.to_fixed_bytes(), diff --git a/core/lib/via_validation/src/types.rs b/core/lib/via_validation/src/types.rs index 8458f54d9..196e09c24 100644 --- a/core/lib/via_validation/src/types.rs +++ b/core/lib/via_validation/src/types.rs @@ -1,15 +1,7 @@ pub use circuit_definitions::snark_wrapper::franklin_crypto::bellman::bn256::Fr; -use circuit_definitions::{ - circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, - snark_wrapper::franklin_crypto::bellman::{ - bn256::Bn256, plonk::better_better_cs::proof::Proof, - }, -}; use ethers::types::H256; use serde::{Deserialize, Serialize}; -use crate::block_header::{BlockAuxilaryOutput, VerifierParams}; - #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct BatchL1Data { pub previous_enumeration_counter: u64, @@ -25,42 +17,3 @@ pub struct BatchL1Data { pub prev_batch_commitment: H256, pub curr_batch_commitment: H256, } - -#[derive(Debug, Clone)] -pub struct L1BatchAndProofData { - pub batch_l1_data: BatchL1Data, - pub aux_output: BlockAuxilaryOutput, - pub scheduler_proof: Proof, - pub verifier_params: VerifierParams, - pub block_number: u64, -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct VerificationKeyHashJsonOutput { - pub layer_1_vk_hash: [u8; 32], - pub computed_vk_hash: [u8; 32], -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DataJsonOutput { - pub batch_l1_data: BatchL1Data, - pub aux_input: BlockAuxilaryOutput, - pub verifier_params: VerifierParams, - pub verification_key_hash: VerificationKeyHashJsonOutput, - pub public_input: Fr, - pub is_proof_valid: bool, -} - -impl From for DataJsonOutput { - fn from(batch: L1BatchAndProofData) -> Self { - Self { - batch_l1_data: batch.batch_l1_data, - aux_input: batch.aux_output, - verifier_params: batch.verifier_params, - verification_key_hash: VerificationKeyHashJsonOutput::default(), - public_input: Fr::default(), - is_proof_valid: false, - } - } -} diff --git a/core/lib/via_validation/src/utils.rs b/core/lib/via_validation/src/utils.rs index d58a59d4d..ad406fb31 100644 --- a/core/lib/via_validation/src/utils.rs +++ b/core/lib/via_validation/src/utils.rs @@ -22,7 +22,7 @@ pub async fn check_verification_key(protocol_version: u16) -> Result<(), Verific } } -pub fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { +pub(crate) fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { let mut result = [0u8; 32]; result.copy_from_slice(ins); diff --git a/core/lib/via_validation/src/verification.rs b/core/lib/via_validation/src/verification.rs index 7a529a228..506c6e79d 100644 --- a/core/lib/via_validation/src/verification.rs +++ b/core/lib/via_validation/src/verification.rs @@ -1,10 +1,7 @@ use std::fs; use circuit_definitions::{ - boojum::{ - field::goldilocks::GoldilocksField, - pairing::{ff::PrimeFieldRepr, Engine}, - }, + boojum::pairing::{ff::PrimeFieldRepr, Engine}, circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, snark_wrapper::franklin_crypto::bellman::{ pairing::bn256::{Bn256, Fq}, @@ -13,35 +10,32 @@ use circuit_definitions::{ }, }; use primitive_types::H256; -use serde::{Deserialize, Serialize}; -use tracing::{error, info}; - -use crate::{errors::VerificationError, proof::Proof, types::Fr}; +use sha3::{Digest, Keccak256}; +use tracing::debug; -/// Wrapper for the auxiliary output witness. -#[derive(Debug, Serialize, Deserialize)] -pub struct AuxOutputWitnessWrapper( - pub circuit_definitions::zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness< - GoldilocksField, - >, -); +use crate::{errors::VerificationError, proof::ProofTrait, types::Fr}; /// Verifies a SNARK proof with a given verification key, checking the verification key hash if provided. /// Returns the public input, auxiliary witness, and computed VK hash on success. pub async fn verify_snark( - snark_vk_scheduler_key_file: &str, - proof: impl Proof, + protocol_version: &str, + proof: impl ProofTrait, vk_hash_from_l1: Option, -) -> Result<(Fr, AuxOutputWitnessWrapper, H256), VerificationError> { - info!("Verifying SNARK wrapped FRI proof."); - info!( +) -> Result<(Fr, H256), VerificationError> { + debug!("Verifying SNARK wrapped FRI proof."); + + let snark_vk_scheduler_key_file = format!( + "keys/protocol_version/{}/scheduler_key.json", + protocol_version + ); + debug!( "Loading verification key from {}", snark_vk_scheduler_key_file ); // Load the verification key from the specified file. - let verification_key_content = - fs::read_to_string(snark_vk_scheduler_key_file).map_err(|e| { + let verification_key_content = fs::read_to_string(snark_vk_scheduler_key_file.clone()) + .map_err(|e| { VerificationError::Other(format!( "Failed to read verification key from {}: {}", snark_vk_scheduler_key_file, e @@ -55,16 +49,13 @@ pub async fn verify_snark( })?; // Compute the VK hash and check against the provided hash if any. - let vk_hash = check_verification_key(&vk_inner, vk_hash_from_l1)?; + let vk_hash = check_verification_key_hash(&vk_inner, vk_hash_from_l1)?; // Verify the proof. let is_valid = proof.verify(vk_inner)?; if !is_valid { - error!("Proof is INVALID"); return Err(VerificationError::ProofVerificationFailed); - } else { - info!("Proof is VALID"); } // Extract the public input from the proof. @@ -74,36 +65,24 @@ pub async fn verify_snark( .cloned() .ok_or_else(|| VerificationError::Other("No public inputs found in proof".to_string()))?; - // Create the auxiliary witness (placeholder implementation). - let aux_witness = AuxOutputWitnessWrapper( - circuit_definitions::zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness { - l1_messages_linear_hash: [0u8; 32], - rollup_state_diff_for_compression: [0u8; 32], - bootloader_heap_initial_content: [0u8; 32], - events_queue_state: [0u8; 32], - eip4844_linear_hashes: [[0u8; 32]; 16], - eip4844_output_commitment_hashes: [[0u8; 32]; 16], - }, - ); - - Ok((public_input, aux_witness, vk_hash)) + Ok((public_input, vk_hash)) } /// Checks that the hash of the verification key matches the supplied hash. /// Returns the computed VK hash on success. -fn check_verification_key( +fn check_verification_key_hash( verification_key: &VerificationKey, vk_hash_from_l1: Option, ) -> Result { if let Some(vk_hash_from_l1) = vk_hash_from_l1 { let computed_vk_hash = calculate_verification_key_hash(verification_key); - info!("Verification Key Hash Check:"); - info!( + debug!("Verification Key Hash Check:"); + debug!( " Verification Key Hash from L1: 0x{}", hex::encode(vk_hash_from_l1) ); - info!( + debug!( " Computed Verification Key Hash: 0x{}", hex::encode(computed_vk_hash) ); @@ -114,17 +93,15 @@ fn check_verification_key( Ok(computed_vk_hash) } else { - info!("Supplied VK hash is None, skipping check..."); + debug!("Supplied VK hash is None, skipping check..."); Ok(H256::default()) } } /// Calculates the hash of a verification key. -pub fn calculate_verification_key_hash>( +fn calculate_verification_key_hash>( verification_key: &VerificationKey, ) -> H256 { - use sha3::{Digest, Keccak256}; - let mut res = Vec::new(); // Serialize gate setup commitments. From 8a5dd0c9a30f164b1a181612c1c49d90812e5bbf Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 1 Dec 2024 22:46:41 +0100 Subject: [PATCH 004/212] chore: renaming --- Cargo.lock | 8 ++--- core/lib/via_validation/Cargo.toml | 31 +++++++++---------- .../abis/IVerifier.json | 0 .../abis/IZkSync.json | 0 .../contract.rs | 2 +- .../fetching.rs | 2 +- .../main.rs | 4 +-- .../types.rs | 0 core/lib/via_validation/src/utils.rs | 8 +++-- core/lib/via_validation/src/verification.rs | 20 +++++++----- 10 files changed, 39 insertions(+), 36 deletions(-) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/abis/IVerifier.json (100%) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/abis/IZkSync.json (100%) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/contract.rs (99%) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/fetching.rs (99%) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/main.rs (93%) rename core/lib/via_validation/examples/{zksync-era => zksync-era-verification-cli}/types.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 803ef0b75..2b86f1817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9339,7 +9339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "via-validator-lib" +name = "via-proof-verfication" version = "0.1.0" dependencies = [ "anyhow", @@ -9350,7 +9350,7 @@ dependencies = [ "hex", "once_cell", "primitive-types", - "reqwest 0.11.27", + "reqwest 0.12.7", "serde", "serde_json", "sha3 0.10.8", @@ -10277,7 +10277,7 @@ checksum = "8beed4cc1ab1f9d99a694506d18705e10059534b30742832be49637c4775e1f8" dependencies = [ "arrayvec 0.7.6", "bincode", - "boojum 0.2.2", + "boojum 0.30.9", "cs_derive", "derivative", "hex", @@ -10299,7 +10299,7 @@ checksum = "20f1a64d256cc5f5c58d19cf976cb45973df54e4e3010ca4a3e6fafe9f06075e" dependencies = [ "arrayvec 0.7.6", "bincode", - "boojum 0.2.2", + "boojum 0.30.9", "cs_derive", "derivative", "hex", diff --git a/core/lib/via_validation/Cargo.toml b/core/lib/via_validation/Cargo.toml index 4d92f7d25..80012fceb 100644 --- a/core/lib/via_validation/Cargo.toml +++ b/core/lib/via_validation/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "via-validator-lib" +name = "via-proof-verfication" version = "0.1.0" edition = "2021" @@ -8,22 +8,19 @@ circuit_definitions = {git = "https://github.com/matter-labs/zksync-protocol.git zksync_types.workspace = true -hex = "0.4.3" -serde_json = "1.0.133" -serde = {version = "1", features = ["derive"]} -clap = { version = "4.2.4", features = ["derive"] } -anyhow = "*" -reqwest = { version = "0.11", features = ["json"] } -tokio = { version = "1.41.1", features = ["full"] } +hex.workspace = true +serde_json.workspace = true +serde.workspace = true +clap = { workspace = true, features = ["derive"]} +anyhow.workspace = true +reqwest = { workspace = true, features = ["json"]} +tokio.workspace = true ethers = {version = "1"} -sha3 = "*" -once_cell = "1.7" +sha3.workspace = true +once_cell.workspace = true primitive-types = "0.12.2" -tracing = "0.1" -tracing-subscriber = "0.3.18" -thiserror = "1.0" -async-trait = "0.1.83" +tracing.workspace = true +tracing-subscriber.workspace = true +thiserror.workspace = true +async-trait.workspace = true -[lib] -name = "via_validator" -path = "src/lib.rs" diff --git a/core/lib/via_validation/examples/zksync-era/abis/IVerifier.json b/core/lib/via_validation/examples/zksync-era-verification-cli/abis/IVerifier.json similarity index 100% rename from core/lib/via_validation/examples/zksync-era/abis/IVerifier.json rename to core/lib/via_validation/examples/zksync-era-verification-cli/abis/IVerifier.json diff --git a/core/lib/via_validation/examples/zksync-era/abis/IZkSync.json b/core/lib/via_validation/examples/zksync-era-verification-cli/abis/IZkSync.json similarity index 100% rename from core/lib/via_validation/examples/zksync-era/abis/IZkSync.json rename to core/lib/via_validation/examples/zksync-era-verification-cli/abis/IZkSync.json diff --git a/core/lib/via_validation/examples/zksync-era/contract.rs b/core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs similarity index 99% rename from core/lib/via_validation/examples/zksync-era/contract.rs rename to core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs index 7b53d37f6..e3e0ae22c 100644 --- a/core/lib/via_validation/examples/zksync-era/contract.rs +++ b/core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs @@ -8,7 +8,7 @@ use ethers::{ types::H256, }; use tracing::debug; -use via_validator::{ +use via_proof_verfication::{ errors::VerificationError, l1_data_fetcher::L1DataFetcher, proof::ViaZKProof, public_inputs::generate_inputs, utils::check_verification_key, }; diff --git a/core/lib/via_validation/examples/zksync-era/fetching.rs b/core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs similarity index 99% rename from core/lib/via_validation/examples/zksync-era/fetching.rs rename to core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs index 5b0a89826..2b4f6762a 100644 --- a/core/lib/via_validation/examples/zksync-era/fetching.rs +++ b/core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs @@ -13,7 +13,7 @@ use ethers::{ use once_cell::sync::Lazy; use primitive_types::{H256, U256}; use reqwest::StatusCode; -use via_validator::{ +use via_proof_verfication::{ crypto::deserialize_proof, errors::VerificationError, proof::ViaZKProof, types::BatchL1Data, }; diff --git a/core/lib/via_validation/examples/zksync-era/main.rs b/core/lib/via_validation/examples/zksync-era-verification-cli/main.rs similarity index 93% rename from core/lib/via_validation/examples/zksync-era/main.rs rename to core/lib/via_validation/examples/zksync-era-verification-cli/main.rs index d04e754b4..96786ed1c 100644 --- a/core/lib/via_validation/examples/zksync-era/main.rs +++ b/core/lib/via_validation/examples/zksync-era-verification-cli/main.rs @@ -4,7 +4,7 @@ mod types; use clap::Parser; use tracing::{error, info}; -use via_validator::{ +use via_proof_verfication::{ errors::VerificationError, l1_data_fetcher::L1DataFetcher, verification::verify_snark, }; @@ -50,7 +50,7 @@ async fn main() -> Result<(), VerificationError> { info!("Public input: {}", input); info!("Computed VK hash: {}", computed_vk_hash); } else { - error!("Failed to verify proof due to an error."); + error!("Failed to verify proof due to an error : {:?}", verify_resp); } Ok(()) diff --git a/core/lib/via_validation/examples/zksync-era/types.rs b/core/lib/via_validation/examples/zksync-era-verification-cli/types.rs similarity index 100% rename from core/lib/via_validation/examples/zksync-era/types.rs rename to core/lib/via_validation/examples/zksync-era-verification-cli/types.rs diff --git a/core/lib/via_validation/src/utils.rs b/core/lib/via_validation/src/utils.rs index ad406fb31..8ff555849 100644 --- a/core/lib/via_validation/src/utils.rs +++ b/core/lib/via_validation/src/utils.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{env, path::PathBuf}; use crate::errors::VerificationError; @@ -8,8 +8,10 @@ pub async fn check_verification_key(protocol_version: u16) -> Result<(), Verific "keys/protocol_version/{}/scheduler_key.json", protocol_version ); - let current_dir = env::current_dir().map_err(|e| VerificationError::Other(e.to_string()))?; - let file = current_dir.join(file_path); + let base_dir = + env::var("CARGO_MANIFEST_DIR").map_err(|e| VerificationError::Other(e.to_string()))?; + let base_path = PathBuf::from(base_dir); + let file = base_path.join(file_path); let file_exists = file.exists(); if !file_exists { diff --git a/core/lib/via_validation/src/verification.rs b/core/lib/via_validation/src/verification.rs index 506c6e79d..964c8c3cf 100644 --- a/core/lib/via_validation/src/verification.rs +++ b/core/lib/via_validation/src/verification.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{env, fs, path::PathBuf}; use circuit_definitions::{ boojum::pairing::{ff::PrimeFieldRepr, Engine}, @@ -33,14 +33,18 @@ pub async fn verify_snark( snark_vk_scheduler_key_file ); + let base_dir = + env::var("CARGO_MANIFEST_DIR").map_err(|e| VerificationError::Other(e.to_string()))?; + let base_path = PathBuf::from(base_dir); + let file = base_path.join(snark_vk_scheduler_key_file.clone()); + // Load the verification key from the specified file. - let verification_key_content = fs::read_to_string(snark_vk_scheduler_key_file.clone()) - .map_err(|e| { - VerificationError::Other(format!( - "Failed to read verification key from {}: {}", - snark_vk_scheduler_key_file, e - )) - })?; + let verification_key_content = fs::read_to_string(file).map_err(|e| { + VerificationError::Other(format!( + "Failed to read verification key from {}: {}", + snark_vk_scheduler_key_file, e + )) + })?; // Deserialize the verification key. let vk_inner: VerificationKey = From 757f88d03df5d2ab202ce318834b89240de8d715 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Mon, 2 Dec 2024 17:07:45 +0100 Subject: [PATCH 005/212] fix: rename crate, typos --- Cargo.lock | 2 +- Cargo.toml | 2 +- core/lib/{via_validation => via_verification}/Cargo.toml | 2 +- .../examples/zksync-era-verification-cli/abis/IVerifier.json | 0 .../examples/zksync-era-verification-cli/abis/IZkSync.json | 0 .../examples/zksync-era-verification-cli/contract.rs | 2 +- .../examples/zksync-era-verification-cli/fetching.rs | 2 +- .../examples/zksync-era-verification-cli/main.rs | 2 +- .../examples/zksync-era-verification-cli/types.rs | 0 .../keys/protocol_version/24/scheduler_key.json | 0 .../keys/protocol_version/25/scheduler_key.json | 0 core/lib/{via_validation => via_verification}/src/crypto.rs | 0 core/lib/{via_validation => via_verification}/src/errors.rs | 2 +- .../{via_validation => via_verification}/src/l1_data_fetcher.rs | 0 core/lib/{via_validation => via_verification}/src/lib.rs | 0 core/lib/{via_validation => via_verification}/src/proof.rs | 0 .../{via_validation => via_verification}/src/public_inputs.rs | 0 core/lib/{via_validation => via_verification}/src/types.rs | 0 core/lib/{via_validation => via_verification}/src/utils.rs | 0 .../{via_validation => via_verification}/src/verification.rs | 0 20 files changed, 7 insertions(+), 7 deletions(-) rename core/lib/{via_validation => via_verification}/Cargo.toml (95%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/abis/IVerifier.json (100%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/abis/IZkSync.json (100%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/contract.rs (99%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/fetching.rs (99%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/main.rs (98%) rename core/lib/{via_validation => via_verification}/examples/zksync-era-verification-cli/types.rs (100%) rename core/lib/{via_validation => via_verification}/keys/protocol_version/24/scheduler_key.json (100%) rename core/lib/{via_validation => via_verification}/keys/protocol_version/25/scheduler_key.json (100%) rename core/lib/{via_validation => via_verification}/src/crypto.rs (100%) rename core/lib/{via_validation => via_verification}/src/errors.rs (95%) rename core/lib/{via_validation => via_verification}/src/l1_data_fetcher.rs (100%) rename core/lib/{via_validation => via_verification}/src/lib.rs (100%) rename core/lib/{via_validation => via_verification}/src/proof.rs (100%) rename core/lib/{via_validation => via_verification}/src/public_inputs.rs (100%) rename core/lib/{via_validation => via_verification}/src/types.rs (100%) rename core/lib/{via_validation => via_verification}/src/utils.rs (100%) rename core/lib/{via_validation => via_verification}/src/verification.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 2b86f1817..0c8381ec1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9339,7 +9339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "via-proof-verfication" +name = "via-verification" version = "0.1.0" dependencies = [ "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 22e943399..4047edf5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ members = [ # VIA Protocol Related Crates "core/lib/via_btc_client", "core/lib/via_da_clients", - "core/lib/via_validation", + "core/lib/via_verification", "core/node/via_btc_watch", "core/node/via_da_dispatcher", "core/bin/via_server", diff --git a/core/lib/via_validation/Cargo.toml b/core/lib/via_verification/Cargo.toml similarity index 95% rename from core/lib/via_validation/Cargo.toml rename to core/lib/via_verification/Cargo.toml index 80012fceb..98c4fe804 100644 --- a/core/lib/via_validation/Cargo.toml +++ b/core/lib/via_verification/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "via-proof-verfication" +name = "via-verification" version = "0.1.0" edition = "2021" diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/abis/IVerifier.json b/core/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json similarity index 100% rename from core/lib/via_validation/examples/zksync-era-verification-cli/abis/IVerifier.json rename to core/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/abis/IZkSync.json b/core/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json similarity index 100% rename from core/lib/via_validation/examples/zksync-era-verification-cli/abis/IZkSync.json rename to core/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs similarity index 99% rename from core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs rename to core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs index e3e0ae22c..200cebc86 100644 --- a/core/lib/via_validation/examples/zksync-era-verification-cli/contract.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs @@ -8,7 +8,7 @@ use ethers::{ types::H256, }; use tracing::debug; -use via_proof_verfication::{ +use via_verification::{ errors::VerificationError, l1_data_fetcher::L1DataFetcher, proof::ViaZKProof, public_inputs::generate_inputs, utils::check_verification_key, }; diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs similarity index 99% rename from core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs rename to core/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs index 2b4f6762a..b6c451eb6 100644 --- a/core/lib/via_validation/examples/zksync-era-verification-cli/fetching.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs @@ -13,7 +13,7 @@ use ethers::{ use once_cell::sync::Lazy; use primitive_types::{H256, U256}; use reqwest::StatusCode; -use via_proof_verfication::{ +use via_verification::{ crypto::deserialize_proof, errors::VerificationError, proof::ViaZKProof, types::BatchL1Data, }; diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/main.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs similarity index 98% rename from core/lib/via_validation/examples/zksync-era-verification-cli/main.rs rename to core/lib/via_verification/examples/zksync-era-verification-cli/main.rs index 96786ed1c..029f661d4 100644 --- a/core/lib/via_validation/examples/zksync-era-verification-cli/main.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs @@ -4,7 +4,7 @@ mod types; use clap::Parser; use tracing::{error, info}; -use via_proof_verfication::{ +use via_verification::{ errors::VerificationError, l1_data_fetcher::L1DataFetcher, verification::verify_snark, }; diff --git a/core/lib/via_validation/examples/zksync-era-verification-cli/types.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/types.rs similarity index 100% rename from core/lib/via_validation/examples/zksync-era-verification-cli/types.rs rename to core/lib/via_verification/examples/zksync-era-verification-cli/types.rs diff --git a/core/lib/via_validation/keys/protocol_version/24/scheduler_key.json b/core/lib/via_verification/keys/protocol_version/24/scheduler_key.json similarity index 100% rename from core/lib/via_validation/keys/protocol_version/24/scheduler_key.json rename to core/lib/via_verification/keys/protocol_version/24/scheduler_key.json diff --git a/core/lib/via_validation/keys/protocol_version/25/scheduler_key.json b/core/lib/via_verification/keys/protocol_version/25/scheduler_key.json similarity index 100% rename from core/lib/via_validation/keys/protocol_version/25/scheduler_key.json rename to core/lib/via_verification/keys/protocol_version/25/scheduler_key.json diff --git a/core/lib/via_validation/src/crypto.rs b/core/lib/via_verification/src/crypto.rs similarity index 100% rename from core/lib/via_validation/src/crypto.rs rename to core/lib/via_verification/src/crypto.rs diff --git a/core/lib/via_validation/src/errors.rs b/core/lib/via_verification/src/errors.rs similarity index 95% rename from core/lib/via_validation/src/errors.rs rename to core/lib/via_verification/src/errors.rs index c1e01e5bf..fd66523b3 100644 --- a/core/lib/via_validation/src/errors.rs +++ b/core/lib/via_verification/src/errors.rs @@ -39,7 +39,7 @@ impl From for VerificationError { impl From for VerificationError { fn from(e: ethers::providers::ProviderError) -> Self { - VerificationError::FetchError(e.to_string()) + VerificationError::ProviderError(e.to_string()) } } diff --git a/core/lib/via_validation/src/l1_data_fetcher.rs b/core/lib/via_verification/src/l1_data_fetcher.rs similarity index 100% rename from core/lib/via_validation/src/l1_data_fetcher.rs rename to core/lib/via_verification/src/l1_data_fetcher.rs diff --git a/core/lib/via_validation/src/lib.rs b/core/lib/via_verification/src/lib.rs similarity index 100% rename from core/lib/via_validation/src/lib.rs rename to core/lib/via_verification/src/lib.rs diff --git a/core/lib/via_validation/src/proof.rs b/core/lib/via_verification/src/proof.rs similarity index 100% rename from core/lib/via_validation/src/proof.rs rename to core/lib/via_verification/src/proof.rs diff --git a/core/lib/via_validation/src/public_inputs.rs b/core/lib/via_verification/src/public_inputs.rs similarity index 100% rename from core/lib/via_validation/src/public_inputs.rs rename to core/lib/via_verification/src/public_inputs.rs diff --git a/core/lib/via_validation/src/types.rs b/core/lib/via_verification/src/types.rs similarity index 100% rename from core/lib/via_validation/src/types.rs rename to core/lib/via_verification/src/types.rs diff --git a/core/lib/via_validation/src/utils.rs b/core/lib/via_verification/src/utils.rs similarity index 100% rename from core/lib/via_validation/src/utils.rs rename to core/lib/via_verification/src/utils.rs diff --git a/core/lib/via_validation/src/verification.rs b/core/lib/via_verification/src/verification.rs similarity index 100% rename from core/lib/via_validation/src/verification.rs rename to core/lib/via_verification/src/verification.rs From 9decc09dbdf1adf44e00e055a430b5b89716771d Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Mon, 2 Dec 2024 20:40:10 +0100 Subject: [PATCH 006/212] fix: review fixes --- .../zksync-era-verification-cli/contract.rs | 3 +- .../zksync-era-verification-cli/main.rs | 9 +- core/lib/via_verification/src/crypto.rs | 94 ++++++++- core/lib/via_verification/src/utils.rs | 70 +++++-- core/lib/via_verification/src/verification.rs | 184 ++---------------- 5 files changed, 163 insertions(+), 197 deletions(-) diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs index 200cebc86..a045e626b 100644 --- a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs @@ -10,7 +10,7 @@ use ethers::{ use tracing::debug; use via_verification::{ errors::VerificationError, l1_data_fetcher::L1DataFetcher, proof::ViaZKProof, - public_inputs::generate_inputs, utils::check_verification_key, + public_inputs::generate_inputs, }; use crate::fetching::{fetch_batch_protocol_version, fetch_l1_commit_data, fetch_proof_from_l1}; @@ -93,7 +93,6 @@ impl L1DataFetcher for ContractConfig { "Protocol version: {} for batch # {}", protocol_version, batch_number ); - check_verification_key(protocol_version_id).await?; let (mut proof, block_number) = fetch_proof_from_l1( batch_number, diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs index 029f661d4..c716d3323 100644 --- a/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs @@ -38,17 +38,12 @@ async fn main() -> Result<(), VerificationError> { let (proof, block_number) = contract.get_proof_from_l1(batch_number).await?; - let vk_hash = contract.get_verification_key_hash(block_number).await?; - - let protocol_version = contract.get_protocol_version(batch_number).await?; - // Verify the proof - let verify_resp = verify_snark(&protocol_version, proof, Some(vk_hash)).await; + let verify_resp = verify_snark(&contract, proof, batch_number, block_number).await; - if let Ok((input, computed_vk_hash)) = verify_resp { + if let Ok(input) = verify_resp { info!("VERIFIED"); info!("Public input: {}", input); - info!("Computed VK hash: {}", computed_vk_hash); } else { error!("Failed to verify proof due to an error : {:?}", verify_resp); } diff --git a/core/lib/via_verification/src/crypto.rs b/core/lib/via_verification/src/crypto.rs index ee466f72c..d64677f24 100644 --- a/core/lib/via_verification/src/crypto.rs +++ b/core/lib/via_verification/src/crypto.rs @@ -1,11 +1,17 @@ use circuit_definitions::{ + boojum::pairing::bn256::Fq, ethereum_types::U256, snark_wrapper::franklin_crypto::bellman::{ bn256::{Bn256, Fr}, - plonk::better_better_cs::{cs::Circuit, proof::Proof}, + plonk::better_better_cs::{ + cs::{Circuit, VerificationKey}, + proof::Proof, + }, CurveAffine, Engine, PrimeField, PrimeFieldRepr, }, }; +use primitive_types::H256; +use sha3::{Digest, Keccak256}; /// Transforms a U256 element into a prime field element. fn u256_to_scalar(el: &U256) -> F @@ -214,3 +220,89 @@ pub fn deserialize_proof>(mut proof: Vec) -> Proof>( + verification_key: &VerificationKey, +) -> H256 { + let mut res = Vec::new(); + + // Serialize gate setup commitments. + for gate_setup in &verification_key.gate_setup_commitments { + let (x, y) = gate_setup.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize gate selectors commitments. + for gate_selector in &verification_key.gate_selectors_commitments { + let (x, y) = gate_selector.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize permutation commitments. + for permutation in &verification_key.permutation_commitments { + let (x, y) = permutation.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize lookup selector commitment if present. + if let Some(lookup_selector) = &verification_key.lookup_selector_commitment { + let (x, y) = lookup_selector.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize lookup tables commitments. + for table_commit in &verification_key.lookup_tables_commitments { + let (x, y) = table_commit.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize table type commitment if present. + if let Some(lookup_table) = &verification_key.lookup_table_type_commitment { + let (x, y) = lookup_table.as_xy(); + x.into_repr() + .write_be(&mut res) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut res) + .expect("Failed to write y coordinate"); + } + + // Serialize flag for using recursive part. + Fq::default() + .into_repr() + .write_be(&mut res) + .expect("Failed to write recursive flag"); + + // Compute Keccak256 hash of the serialized data. + let mut hasher = Keccak256::new(); + hasher.update(&res); + let computed_vk_hash = hasher.finalize(); + + H256::from_slice(&computed_vk_hash) +} diff --git a/core/lib/via_verification/src/utils.rs b/core/lib/via_verification/src/utils.rs index 8ff555849..1dff7d48e 100644 --- a/core/lib/via_verification/src/utils.rs +++ b/core/lib/via_verification/src/utils.rs @@ -1,9 +1,24 @@ -use std::{env, path::PathBuf}; +use std::{env, fs, path::PathBuf}; -use crate::errors::VerificationError; +use circuit_definitions::{ + boojum::pairing::bn256::Bn256, circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, + snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::cs::VerificationKey, +}; +use tracing::debug; + +use crate::{ + crypto::calculate_verification_key_hash, errors::VerificationError, + l1_data_fetcher::L1DataFetcher, +}; + +/// Load the verification key for a given batch number. +pub async fn load_verification_key( + l1_data_fetcher: &F, + batch_number: u64, + l1_block_number: u64, +) -> Result, VerificationError> { + let protocol_version = l1_data_fetcher.get_protocol_version(batch_number).await?; -/// Checks if the verification key exists for a given protocol version. -pub async fn check_verification_key(protocol_version: u16) -> Result<(), VerificationError> { let file_path = format!( "keys/protocol_version/{}/scheduler_key.json", protocol_version @@ -11,17 +26,42 @@ pub async fn check_verification_key(protocol_version: u16) -> Result<(), Verific let base_dir = env::var("CARGO_MANIFEST_DIR").map_err(|e| VerificationError::Other(e.to_string()))?; let base_path = PathBuf::from(base_dir); - let file = base_path.join(file_path); - let file_exists = file.exists(); - - if !file_exists { - Err(VerificationError::Other(format!( - "Verification key for protocol version {} is missing. Please add it to the keys folder.", - protocol_version - ))) - } else { - Ok(()) - } + let file = base_path.join(&file_path); + + // Load the verification key from the specified file. + let verification_key_content = fs::read_to_string(file).map_err(|e| { + VerificationError::Other(format!( + "Failed to read verification key from {}: {}", + file_path, e + )) + })?; + let vk_inner: VerificationKey = + serde_json::from_str(&verification_key_content).map_err(|e| { + VerificationError::Other(format!("Failed to deserialize verification key: {}", e)) + })?; + + // Get the verification key hash from L1. + let vk_hash_from_l1 = l1_data_fetcher + .get_verification_key_hash(l1_block_number) + .await?; + + // Calculate the verification key hash from the verification key. + let computed_vk_hash = calculate_verification_key_hash(&vk_inner); + + // Check that the verification key hash from L1 matches the computed hash. + debug!("Verification Key Hash Check:"); + debug!( + " Verification Key Hash from L1: 0x{}", + hex::encode(vk_hash_from_l1) + ); + debug!( + " Computed Verification Key Hash: 0x{}", + hex::encode(computed_vk_hash) + ); + + (computed_vk_hash == vk_hash_from_l1) + .then_some(vk_inner) + .ok_or(VerificationError::VerificationKeyHashMismatch) } pub(crate) fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { diff --git a/core/lib/via_verification/src/verification.rs b/core/lib/via_verification/src/verification.rs index 964c8c3cf..28b2e8971 100644 --- a/core/lib/via_verification/src/verification.rs +++ b/core/lib/via_verification/src/verification.rs @@ -1,64 +1,20 @@ -use std::{env, fs, path::PathBuf}; - -use circuit_definitions::{ - boojum::pairing::{ff::PrimeFieldRepr, Engine}, - circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, - snark_wrapper::franklin_crypto::bellman::{ - pairing::bn256::{Bn256, Fq}, - plonk::better_better_cs::{cs::Circuit, setup::VerificationKey}, - CurveAffine, PrimeField, - }, +use crate::{ + errors::VerificationError, l1_data_fetcher::L1DataFetcher, proof::ProofTrait, types::Fr, + utils::load_verification_key, }; -use primitive_types::H256; -use sha3::{Digest, Keccak256}; -use tracing::debug; - -use crate::{errors::VerificationError, proof::ProofTrait, types::Fr}; /// Verifies a SNARK proof with a given verification key, checking the verification key hash if provided. /// Returns the public input, auxiliary witness, and computed VK hash on success. -pub async fn verify_snark( - protocol_version: &str, - proof: impl ProofTrait, - vk_hash_from_l1: Option, -) -> Result<(Fr, H256), VerificationError> { - debug!("Verifying SNARK wrapped FRI proof."); - - let snark_vk_scheduler_key_file = format!( - "keys/protocol_version/{}/scheduler_key.json", - protocol_version - ); - debug!( - "Loading verification key from {}", - snark_vk_scheduler_key_file - ); - - let base_dir = - env::var("CARGO_MANIFEST_DIR").map_err(|e| VerificationError::Other(e.to_string()))?; - let base_path = PathBuf::from(base_dir); - let file = base_path.join(snark_vk_scheduler_key_file.clone()); - - // Load the verification key from the specified file. - let verification_key_content = fs::read_to_string(file).map_err(|e| { - VerificationError::Other(format!( - "Failed to read verification key from {}: {}", - snark_vk_scheduler_key_file, e - )) - })?; - - // Deserialize the verification key. - let vk_inner: VerificationKey = - serde_json::from_str(&verification_key_content).map_err(|e| { - VerificationError::Other(format!("Failed to deserialize verification key: {}", e)) - })?; - - // Compute the VK hash and check against the provided hash if any. - let vk_hash = check_verification_key_hash(&vk_inner, vk_hash_from_l1)?; +pub async fn verify_snark( + l1_data_fetcher: &F, + proof: P, + batch_number: u64, + l1_block_number: u64, +) -> Result { + let vk_inner = load_verification_key(l1_data_fetcher, batch_number, l1_block_number).await?; // Verify the proof. - let is_valid = proof.verify(vk_inner)?; - - if !is_valid { + if !proof.verify(vk_inner)? { return Err(VerificationError::ProofVerificationFailed); } @@ -69,121 +25,5 @@ pub async fn verify_snark( .cloned() .ok_or_else(|| VerificationError::Other("No public inputs found in proof".to_string()))?; - Ok((public_input, vk_hash)) -} - -/// Checks that the hash of the verification key matches the supplied hash. -/// Returns the computed VK hash on success. -fn check_verification_key_hash( - verification_key: &VerificationKey, - vk_hash_from_l1: Option, -) -> Result { - if let Some(vk_hash_from_l1) = vk_hash_from_l1 { - let computed_vk_hash = calculate_verification_key_hash(verification_key); - - debug!("Verification Key Hash Check:"); - debug!( - " Verification Key Hash from L1: 0x{}", - hex::encode(vk_hash_from_l1) - ); - debug!( - " Computed Verification Key Hash: 0x{}", - hex::encode(computed_vk_hash) - ); - - if computed_vk_hash != vk_hash_from_l1 { - return Err(VerificationError::VerificationKeyHashMismatch); - } - - Ok(computed_vk_hash) - } else { - debug!("Supplied VK hash is None, skipping check..."); - Ok(H256::default()) - } -} - -/// Calculates the hash of a verification key. -fn calculate_verification_key_hash>( - verification_key: &VerificationKey, -) -> H256 { - let mut res = Vec::new(); - - // Serialize gate setup commitments. - for gate_setup in &verification_key.gate_setup_commitments { - let (x, y) = gate_setup.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize gate selectors commitments. - for gate_selector in &verification_key.gate_selectors_commitments { - let (x, y) = gate_selector.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize permutation commitments. - for permutation in &verification_key.permutation_commitments { - let (x, y) = permutation.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize lookup selector commitment if present. - if let Some(lookup_selector) = &verification_key.lookup_selector_commitment { - let (x, y) = lookup_selector.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize lookup tables commitments. - for table_commit in &verification_key.lookup_tables_commitments { - let (x, y) = table_commit.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize table type commitment if present. - if let Some(lookup_table) = &verification_key.lookup_table_type_commitment { - let (x, y) = lookup_table.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); - } - - // Serialize flag for using recursive part. - Fq::default() - .into_repr() - .write_be(&mut res) - .expect("Failed to write recursive flag"); - - // Compute Keccak256 hash of the serialized data. - let mut hasher = Keccak256::new(); - hasher.update(&res); - let computed_vk_hash = hasher.finalize(); - - H256::from_slice(&computed_vk_hash) + Ok(public_input) } From 479d16dbefb2911373f8f834efb19143cc4cd67a Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 3 Dec 2024 09:38:44 +0330 Subject: [PATCH 007/212] add basic impl --- core/lib/via_btc_client/src/lib.rs | 1 + core/lib/via_btc_client/src/withdrawal/mod.rs | 248 +++++++++++++++++- 2 files changed, 247 insertions(+), 2 deletions(-) diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index 44969c42f..a736b2004 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -4,6 +4,7 @@ pub mod types; pub(crate) mod client; pub mod indexer; pub mod inscriber; +pub mod withdrawal; #[cfg(feature = "regtest")] pub mod regtest; pub(crate) mod signer; diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index fb3cd0dda..53bb46f88 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -1,4 +1,248 @@ -struct WithdrawalBuilder { - utxos: Vec, +// Withdrawal Builder Service +// This service has main method, that receives a list of bitcoin address and amount to withdraw and also L1batch proofDaReference reveal transaction id +// and then it will use client to get available utxo, and then perform utxo selection based on the total amount of the withdrawal +// and now we know the number of input and output we can estimate the fee and perform final utxo selection +// create a unsigned transaction and return it to the caller + +use std::sync::Arc; + +use anyhow::Result; +use bitcoin::{ + absolute, + transaction, + Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, + Witness, +}; +use tracing::{debug, info, instrument}; + +use crate::{ + client::BitcoinClient, + traits::BitcoinOps, + types::BitcoinNetwork, +}; + +#[derive(Debug)] +pub struct WithdrawalBuilder { client: Arc, + bridge_address: Address, +} + +#[derive(Debug)] +pub struct WithdrawalRequest { + pub address: Address, + pub amount: Amount, +} + +#[derive(Debug)] +pub struct UnsignedWithdrawalTx { + pub tx: Transaction, + pub txid: Txid, + pub utxos: Vec<(OutPoint, TxOut)>, + pub change_amount: Amount, +} + +impl WithdrawalBuilder { + #[instrument(skip(rpc_url, auth), target = "bitcoin_withdrawal")] + pub async fn new( + rpc_url: &str, + network: BitcoinNetwork, + auth: bitcoincore_rpc::Auth, + bridge_address: Address, + ) -> Result { + info!("Creating new WithdrawalBuilder"); + let client = Arc::new(BitcoinClient::new(rpc_url, network, auth)?); + + Ok(Self { + client, + bridge_address, + }) + } + + #[instrument(skip(self, withdrawals), target = "bitcoin_withdrawal")] + pub async fn create_unsigned_withdrawal_tx( + &self, + withdrawals: Vec, + ) -> Result { + debug!("Creating unsigned withdrawal transaction"); + + // Calculate total amount needed + let total_amount: Amount = withdrawals + .iter() + .try_fold(Amount::ZERO, |acc, w| acc.checked_add(w.amount)) + .ok_or_else(|| anyhow::anyhow!("Withdrawal amount overflow"))?; + + // Get available UTXOs from bridge address + let utxos = self.get_available_utxos().await?; + + // Select UTXOs for the withdrawal + let selected_utxos = self.select_utxos(&utxos, total_amount).await?; + + // Calculate total input amount + let total_input_amount: Amount = selected_utxos + .iter() + .try_fold(Amount::ZERO, |acc, (_, txout)| { + acc.checked_add(txout.value) + }) + .ok_or_else(|| anyhow::anyhow!("Input amount overflow"))?; + + // Estimate fee + let fee_rate = self.client.get_fee_rate(1).await?; + let fee_amount = self.estimate_fee(selected_utxos.len() as u32, withdrawals.len() as u32, fee_rate)?; + + // Verify we have enough funds + let total_needed = total_amount + .checked_add(fee_amount) + .ok_or_else(|| anyhow::anyhow!("Total amount overflow"))?; + + if total_input_amount < total_needed { + return Err(anyhow::anyhow!( + "Insufficient funds: have {}, need {}", + total_input_amount, + total_needed + )); + } + + // Create inputs + let inputs: Vec = selected_utxos + .iter() + .map(|(outpoint, _)| TxIn { + previous_output: *outpoint, + script_sig: ScriptBuf::default(), + sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: Witness::default(), + }) + .collect(); + + // Create outputs for withdrawals + let mut outputs: Vec = withdrawals + .into_iter() + .map(|w| TxOut { + value: w.amount, + script_pubkey: w.address.script_pubkey(), + }) + .collect(); + + // Add change output if needed + let change_amount = total_input_amount + .checked_sub(total_needed) + .ok_or_else(|| anyhow::anyhow!("Change amount calculation overflow"))?; + + if change_amount.to_sat() > 0 { + outputs.push(TxOut { + value: change_amount, + script_pubkey: self.bridge_address.script_pubkey(), + }); + } + + // Create unsigned transaction + let unsigned_tx = Transaction { + version: transaction::Version::TWO, + lock_time: absolute::LockTime::ZERO, + input: inputs, + output: outputs, + }; + + let txid = unsigned_tx.compute_txid(); + + debug!("Unsigned withdrawal transaction created successfully"); + + Ok(UnsignedWithdrawalTx { + tx: unsigned_tx, + txid, + utxos: selected_utxos, + change_amount, + }) + } + + #[instrument(skip(self), target = "bitcoin_withdrawal")] + async fn get_available_utxos(&self) -> Result> { + let utxos = self.client.fetch_utxos(&self.bridge_address).await?; + Ok(utxos) + } + + #[instrument(skip(self, utxos), target = "bitcoin_withdrawal")] + async fn select_utxos( + &self, + utxos: &[(OutPoint, TxOut)], + target_amount: Amount, + ) -> Result> { + // Simple implementation - could be improved with better UTXO selection algorithm + let mut selected = Vec::new(); + let mut total = Amount::ZERO; + + for utxo in utxos { + selected.push(utxo.clone()); + total = total + .checked_add(utxo.1.value) + .ok_or_else(|| anyhow::anyhow!("Amount overflow during UTXO selection"))?; + + if total >= target_amount { + break; + } + } + + if total < target_amount { + return Err(anyhow::anyhow!( + "Insufficient funds: have {}, need {}", + total, + target_amount + )); + } + + Ok(selected) + } + + #[instrument(skip(self), target = "bitcoin_withdrawal")] + fn estimate_fee(&self, input_count: u32, output_count: u32, fee_rate: u64) -> Result { + // Estimate transaction size + let base_size = 10_u64; // version + locktime + let input_size = 148_u64 * u64::from(input_count); // approximate size per input + let output_size = 34_u64 * u64::from(output_count); // approximate size per output + + let total_size = base_size + input_size + output_size; + let fee = fee_rate * total_size; + + Ok(Amount::from_sat(fee)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + use bitcoin::Network; + + #[tokio::test] + #[ignore] // Remove this to run against a local Bitcoin node + async fn test_withdrawal_builder() -> Result<()> { + let network = Network::Regtest; + let bridge_address = Address::from_str("bcrt1q6rhpng9evgu7ul6k0kr8f8sdre3hy9ym8t7g5h")? + .require_network(network)?; + + let builder = WithdrawalBuilder::new( + "http://localhost:18443", + BitcoinNetwork::Regtest, + bitcoincore_rpc::Auth::None, + bridge_address, + ) + .await?; + + let withdrawals = vec![ + WithdrawalRequest { + address: Address::from_str("bcrt1qg3y8889zzz0qvg3xhm4e9j8z9wp7524fn0qxya")? + .require_network(network)?, + amount: Amount::from_btc(0.1)?, + }, + WithdrawalRequest { + address: Address::from_str("bcrt1qf6em9yq7h8zmmwl9q8ue73x34dj9ql9xl7t4ph")? + .require_network(network)?, + amount: Amount::from_btc(0.2)?, + }, + ]; + + let withdrawal_tx = builder.create_unsigned_withdrawal_tx(withdrawals).await?; + assert!(!withdrawal_tx.utxos.is_empty()); + + Ok(()) + } } \ No newline at end of file From 635e931b7bb1047569e3ba93ece29057a181072d Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 3 Dec 2024 09:42:54 +0330 Subject: [PATCH 008/212] add basic impl --- core/lib/via_btc_client/src/lib.rs | 2 +- core/lib/via_btc_client/src/withdrawal/mod.rs | 48 +++++++++---------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index a736b2004..9a86fee97 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -4,8 +4,8 @@ pub mod types; pub(crate) mod client; pub mod indexer; pub mod inscriber; -pub mod withdrawal; #[cfg(feature = "regtest")] pub mod regtest; pub(crate) mod signer; pub(crate) mod utils; +pub mod withdrawal; diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index 53bb46f88..07bbd68c6 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -8,18 +8,12 @@ use std::sync::Arc; use anyhow::Result; use bitcoin::{ - absolute, - transaction, - Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, - Witness, + absolute, transaction, Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, + TxOut, Txid, Witness, }; use tracing::{debug, info, instrument}; -use crate::{ - client::BitcoinClient, - traits::BitcoinOps, - types::BitcoinNetwork, -}; +use crate::{client::BitcoinClient, traits::BitcoinOps, types::BitcoinNetwork}; #[derive(Debug)] pub struct WithdrawalBuilder { @@ -52,7 +46,7 @@ impl WithdrawalBuilder { info!("Creating new WithdrawalBuilder"); let client = Arc::new(BitcoinClient::new(rpc_url, network, auth)?); - Ok(Self { + Ok(Self { client, bridge_address, }) @@ -64,7 +58,7 @@ impl WithdrawalBuilder { withdrawals: Vec, ) -> Result { debug!("Creating unsigned withdrawal transaction"); - + // Calculate total amount needed let total_amount: Amount = withdrawals .iter() @@ -73,27 +67,29 @@ impl WithdrawalBuilder { // Get available UTXOs from bridge address let utxos = self.get_available_utxos().await?; - + // Select UTXOs for the withdrawal let selected_utxos = self.select_utxos(&utxos, total_amount).await?; - + // Calculate total input amount let total_input_amount: Amount = selected_utxos .iter() - .try_fold(Amount::ZERO, |acc, (_, txout)| { - acc.checked_add(txout.value) - }) + .try_fold(Amount::ZERO, |acc, (_, txout)| acc.checked_add(txout.value)) .ok_or_else(|| anyhow::anyhow!("Input amount overflow"))?; // Estimate fee let fee_rate = self.client.get_fee_rate(1).await?; - let fee_amount = self.estimate_fee(selected_utxos.len() as u32, withdrawals.len() as u32, fee_rate)?; + let fee_amount = self.estimate_fee( + selected_utxos.len() as u32, + withdrawals.len() as u32, + fee_rate, + )?; // Verify we have enough funds let total_needed = total_amount .checked_add(fee_amount) .ok_or_else(|| anyhow::anyhow!("Total amount overflow"))?; - + if total_input_amount < total_needed { return Err(anyhow::anyhow!( "Insufficient funds: have {}, need {}", @@ -145,7 +141,7 @@ impl WithdrawalBuilder { let txid = unsigned_tx.compute_txid(); debug!("Unsigned withdrawal transaction created successfully"); - + Ok(UnsignedWithdrawalTx { tx: unsigned_tx, txid, @@ -198,7 +194,7 @@ impl WithdrawalBuilder { let base_size = 10_u64; // version + locktime let input_size = 148_u64 * u64::from(input_count); // approximate size per input let output_size = 34_u64 * u64::from(output_count); // approximate size per output - + let total_size = base_size + input_size + output_size; let fee = fee_rate * total_size; @@ -208,17 +204,19 @@ impl WithdrawalBuilder { #[cfg(test)] mod tests { - use super::*; use std::str::FromStr; + use bitcoin::Network; - + + use super::*; + #[tokio::test] #[ignore] // Remove this to run against a local Bitcoin node async fn test_withdrawal_builder() -> Result<()> { let network = Network::Regtest; let bridge_address = Address::from_str("bcrt1q6rhpng9evgu7ul6k0kr8f8sdre3hy9ym8t7g5h")? .require_network(network)?; - + let builder = WithdrawalBuilder::new( "http://localhost:18443", BitcoinNetwork::Regtest, @@ -226,7 +224,7 @@ mod tests { bridge_address, ) .await?; - + let withdrawals = vec![ WithdrawalRequest { address: Address::from_str("bcrt1qg3y8889zzz0qvg3xhm4e9j8z9wp7524fn0qxya")? @@ -245,4 +243,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} From 117e3c9a8ae9fff75460c6b626ebd48a23a77c22 Mon Sep 17 00:00:00 2001 From: Miroslav Pavlovic Date: Tue, 3 Dec 2024 09:56:56 +0100 Subject: [PATCH 009/212] refactor: helper function for point serialization --- core/lib/via_verification/src/crypto.rs | 66 +++++++++---------------- 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/core/lib/via_verification/src/crypto.rs b/core/lib/via_verification/src/crypto.rs index d64677f24..f1f7a2104 100644 --- a/core/lib/via_verification/src/crypto.rs +++ b/core/lib/via_verification/src/crypto.rs @@ -221,6 +221,18 @@ pub fn deserialize_proof>(mut proof: Vec) -> Proof(point: &E::G1Affine, mut buffer: &mut Vec) -> anyhow::Result<()> { + let (x, y) = point.as_xy(); + x.into_repr() + .write_be(&mut buffer) + .expect("Failed to write x coordinate"); + y.into_repr() + .write_be(&mut buffer) + .expect("Failed to write y coordinate"); + Ok(()) +} + /// Calculates the hash of a verification key. pub(crate) fn calculate_verification_key_hash>( verification_key: &VerificationKey, @@ -229,68 +241,38 @@ pub(crate) fn calculate_verification_key_hash>( // Serialize gate setup commitments. for gate_setup in &verification_key.gate_setup_commitments { - let (x, y) = gate_setup.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(gate_setup, &mut res) + .expect("Failed to serialize gate setup commitment"); } // Serialize gate selectors commitments. for gate_selector in &verification_key.gate_selectors_commitments { - let (x, y) = gate_selector.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(gate_selector, &mut res) + .expect("Failed to serialize gate selectors commitment"); } // Serialize permutation commitments. for permutation in &verification_key.permutation_commitments { - let (x, y) = permutation.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(permutation, &mut res) + .expect("Failed to serialize permutation commitment"); } // Serialize lookup selector commitment if present. if let Some(lookup_selector) = &verification_key.lookup_selector_commitment { - let (x, y) = lookup_selector.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(lookup_selector, &mut res) + .expect("Failed to serialize lookup selector commitment"); } // Serialize lookup tables commitments. for table_commit in &verification_key.lookup_tables_commitments { - let (x, y) = table_commit.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(table_commit, &mut res) + .expect("Failed to serialize lookup tables commitment"); } // Serialize table type commitment if present. if let Some(lookup_table) = &verification_key.lookup_table_type_commitment { - let (x, y) = lookup_table.as_xy(); - x.into_repr() - .write_be(&mut res) - .expect("Failed to write x coordinate"); - y.into_repr() - .write_be(&mut res) - .expect("Failed to write y coordinate"); + serialize_point::(lookup_table, &mut res) + .expect("Failed to serialize lookup table type commitment"); } // Serialize flag for using recursive part. From e57020c35fb22e5da1f26c7ecfcd16d6f8032d6d Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 3 Dec 2024 12:45:49 +0330 Subject: [PATCH 010/212] add op_return --- core/lib/via_btc_client/src/withdrawal/mod.rs | 56 +++++++++++++++++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index 07bbd68c6..0469fbb22 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -8,8 +8,8 @@ use std::sync::Arc; use anyhow::Result; use bitcoin::{ - absolute, transaction, Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, - TxOut, Txid, Witness, + absolute, hashes::Hash, script::PushBytesBuf, transaction, Address, Amount, OutPoint, + ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, }; use tracing::{debug, info, instrument}; @@ -35,6 +35,8 @@ pub struct UnsignedWithdrawalTx { pub change_amount: Amount, } +const OP_RETURN_PREFIX: &[u8] = b"VIA_PROTOCOL:WITHDRAWAL:"; + impl WithdrawalBuilder { #[instrument(skip(rpc_url, auth), target = "bitcoin_withdrawal")] pub async fn new( @@ -52,10 +54,11 @@ impl WithdrawalBuilder { }) } - #[instrument(skip(self, withdrawals), target = "bitcoin_withdrawal")] + #[instrument(skip(self, withdrawals, proof_txid), target = "bitcoin_withdrawal")] pub async fn create_unsigned_withdrawal_tx( &self, withdrawals: Vec, + proof_txid: Txid, ) -> Result { debug!("Creating unsigned withdrawal transaction"); @@ -77,11 +80,18 @@ impl WithdrawalBuilder { .try_fold(Amount::ZERO, |acc, (_, txout)| acc.checked_add(txout.value)) .ok_or_else(|| anyhow::anyhow!("Input amount overflow"))?; - // Estimate fee + // Create OP_RETURN output with proof txid + let op_return_data = self.create_op_return_script(proof_txid)?; + let op_return_output = TxOut { + value: Amount::ZERO, + script_pubkey: op_return_data, + }; + + // Estimate fee (including OP_RETURN output) let fee_rate = self.client.get_fee_rate(1).await?; let fee_amount = self.estimate_fee( selected_utxos.len() as u32, - withdrawals.len() as u32, + withdrawals.len() as u32 + 1, // +1 for OP_RETURN output fee_rate, )?; @@ -118,6 +128,9 @@ impl WithdrawalBuilder { }) .collect(); + // Add OP_RETURN output + outputs.push(op_return_output); + // Add change output if needed let change_amount = total_input_amount .checked_sub(total_needed) @@ -200,6 +213,18 @@ impl WithdrawalBuilder { Ok(Amount::from_sat(fee)) } + + // Helper function to create OP_RETURN script + fn create_op_return_script(&self, proof_txid: Txid) -> Result { + let mut data = Vec::with_capacity(OP_RETURN_PREFIX.len() + 32); + data.extend_from_slice(OP_RETURN_PREFIX); + data.extend_from_slice(&proof_txid.as_raw_hash().to_byte_array()); + + let mut encoded_data = PushBytesBuf::with_capacity(data.len()); + encoded_data.extend_from_slice(&data).ok(); + + Ok(ScriptBuf::new_op_return(encoded_data)) + } } #[cfg(test)] @@ -238,9 +263,28 @@ mod tests { }, ]; - let withdrawal_tx = builder.create_unsigned_withdrawal_tx(withdrawals).await?; + let proof_txid = + Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")?; + + let withdrawal_tx = builder + .create_unsigned_withdrawal_tx(withdrawals, proof_txid) + .await?; assert!(!withdrawal_tx.utxos.is_empty()); + // Verify OP_RETURN output exists and contains our data + let op_return_output = withdrawal_tx + .tx + .output + .iter() + .find(|output| output.script_pubkey.is_op_return()) + .expect("OP_RETURN output not found"); + + assert!(op_return_output + .script_pubkey + .as_bytes() + .windows(OP_RETURN_PREFIX.len()) + .any(|window| window == OP_RETURN_PREFIX)); + Ok(()) } } From 8bd87d78ba705ac705f75c938cfa6edce52a65e6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:47:58 +0100 Subject: [PATCH 011/212] feat: upgrade the protocol to bitcoin version --- contracts | 2 +- core/lib/basic_types/src/protocol_version.rs | 7 ++-- core/lib/basic_types/src/vm.rs | 3 +- core/lib/contracts/src/lib.rs | 14 ++++++++ core/lib/multivm/src/utils/mod.rs | 30 ++++++++++++++++++ core/lib/multivm/src/versions/vm_latest/vm.rs | 1 + core/lib/multivm/src/vm_instance.rs | 9 ++++++ core/node/api_server/src/tx_sender/mod.rs | 5 +++ core/node/commitment_generator/src/utils.rs | 13 ++++++++ etc/env/base/chain.toml | 4 +-- etc/env/base/contracts.toml | 8 ++--- etc/env/file_based/genesis.yaml | 8 ++--- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 0 -> 76320 bytes .../vm_bitcoin/gas_test.yul/gas_test.yul.zbin | Bin 0 -> 72416 bytes .../playground_batch.yul.zbin | Bin 0 -> 76512 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 0 -> 72928 bytes 16 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 etc/multivm_bootloaders/vm_bitcoin/fee_estimate.yul/fee_estimate.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_bitcoin/gas_test.yul/gas_test.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_bitcoin/playground_batch.yul/playground_batch.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_bitcoin/proved_batch.yul/proved_batch.yul.zbin diff --git a/contracts b/contracts index f5148ca1e..4fde2cb06 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit f5148ca1e8d7124c468295123e245426fba3c71d +Subproject commit 4fde2cb06d1d1c4ac0e5fac230f12305dd42e59c diff --git a/core/lib/basic_types/src/protocol_version.rs b/core/lib/basic_types/src/protocol_version.rs index 265c06987..312e8e8af 100644 --- a/core/lib/basic_types/src/protocol_version.rs +++ b/core/lib/basic_types/src/protocol_version.rs @@ -68,15 +68,16 @@ pub enum ProtocolVersionId { Version23, Version24, Version25, + Version26, } impl ProtocolVersionId { pub const fn latest() -> Self { - Self::Version24 + Self::Version26 } pub const fn next() -> Self { - Self::Version25 + Self::Version26 } pub fn try_from_packed_semver(packed_semver: U256) -> Result { @@ -120,6 +121,7 @@ impl ProtocolVersionId { ProtocolVersionId::Version23 => VmVersion::Vm1_5_0SmallBootloaderMemory, ProtocolVersionId::Version24 => VmVersion::Vm1_5_0IncreasedBootloaderMemory, ProtocolVersionId::Version25 => VmVersion::Vm1_5_0IncreasedBootloaderMemory, + ProtocolVersionId::Version26 => VmVersion::VmBitcoin1_0_0, } } @@ -270,6 +272,7 @@ impl From for VmVersion { ProtocolVersionId::Version23 => VmVersion::Vm1_5_0SmallBootloaderMemory, ProtocolVersionId::Version24 => VmVersion::Vm1_5_0IncreasedBootloaderMemory, ProtocolVersionId::Version25 => VmVersion::Vm1_5_0IncreasedBootloaderMemory, + ProtocolVersionId::Version26 => VmVersion::VmBitcoin1_0_0, } } } diff --git a/core/lib/basic_types/src/vm.rs b/core/lib/basic_types/src/vm.rs index c178c853b..2a0a33a35 100644 --- a/core/lib/basic_types/src/vm.rs +++ b/core/lib/basic_types/src/vm.rs @@ -16,12 +16,13 @@ pub enum VmVersion { Vm1_4_2, Vm1_5_0SmallBootloaderMemory, Vm1_5_0IncreasedBootloaderMemory, + VmBitcoin1_0_0, } impl VmVersion { /// Returns the latest supported VM version. pub const fn latest() -> VmVersion { - Self::Vm1_5_0IncreasedBootloaderMemory + Self::VmBitcoin1_0_0 } } diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index a7ef0e5b2..3298c4a90 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -399,6 +399,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn playground_bitcoin_1_0_0() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_bitcoin/playground_batch.yul/playground_batch.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn estimate_gas_pre_virtual_blocks() -> Self { let bootloader_bytecode = read_zbin_bytecode( "etc/multivm_bootloaders/vm_1_3_2/fee_estimate.yul/fee_estimate.yul.zbin", @@ -462,6 +469,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn estimate_gas_bitcoin_1_0_0() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_bitcoin/fee_estimate.yul/fee_estimate.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn hashes(&self) -> BaseSystemContractsHashes { BaseSystemContractsHashes { bootloader: self.bootloader.hash, diff --git a/core/lib/multivm/src/utils/mod.rs b/core/lib/multivm/src/utils/mod.rs index 5d8fba7a2..d46dbe385 100644 --- a/core/lib/multivm/src/utils/mod.rs +++ b/core/lib/multivm/src/utils/mod.rs @@ -58,6 +58,11 @@ pub fn derive_base_fee_and_gas_per_pubdata( batch_fee_input.into_pubdata_independent(), ) } + VmVersion::VmBitcoin1_0_0 => { + crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_pubdata_independent(), + ) + } } } @@ -84,6 +89,7 @@ pub fn get_batch_base_fee(l1_batch_env: &L1BatchEnv, vm_version: VmVersion) -> u VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env) } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), } } @@ -212,6 +218,9 @@ pub fn derive_overhead( VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::utils::overhead::derive_overhead(encoded_len) } + VmVersion::VmBitcoin1_0_0 => { + crate::vm_latest::utils::overhead::derive_overhead(encoded_len) + } } } @@ -245,6 +254,9 @@ pub fn get_bootloader_encoding_space(version: VmVersion) -> u32 { crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, ) } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::get_bootloader_tx_encoding_space( + crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, + ), } } @@ -267,6 +279,7 @@ pub fn get_bootloader_max_txs_in_batch(version: VmVersion) -> usize { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::MAX_TXS_IN_BATCH } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, } } @@ -290,6 +303,7 @@ pub fn gas_bootloader_batch_tip_overhead(version: VmVersion) -> u32 { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, } } @@ -313,6 +327,9 @@ pub fn circuit_statistics_bootloader_batch_tip_overhead(version: VmVersion) -> u VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD as usize } + VmVersion::VmBitcoin1_0_0 => { + crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD as usize + } } } @@ -336,6 +353,9 @@ pub fn execution_metrics_bootloader_batch_tip_overhead(version: VmVersion) -> us VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD as usize } + VmVersion::VmBitcoin1_0_0 => { + crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD as usize + } } } @@ -360,6 +380,7 @@ pub fn get_max_gas_per_pubdata_byte(version: VmVersion) -> u64 { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::MAX_GAS_PER_PUBDATA_BYTE } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::MAX_GAS_PER_PUBDATA_BYTE, } } @@ -393,6 +414,9 @@ pub fn get_used_bootloader_memory_bytes(version: VmVersion) -> usize { crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, ) } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::get_used_bootloader_memory_bytes( + crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, + ), } } @@ -426,6 +450,9 @@ pub fn get_used_bootloader_memory_words(version: VmVersion) -> usize { crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, ) } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::get_used_bootloader_memory_bytes( + crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, + ), } } @@ -450,6 +477,7 @@ pub fn get_max_batch_gas_limit(version: VmVersion) -> u64 { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::BATCH_GAS_LIMIT } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::BATCH_GAS_LIMIT, } } @@ -476,6 +504,7 @@ pub fn get_eth_call_gas_limit(version: VmVersion) -> u64 { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::ETH_CALL_GAS_LIMIT } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::ETH_CALL_GAS_LIMIT, } } @@ -499,6 +528,7 @@ pub fn get_max_batch_base_layer_circuits(version: VmVersion) -> usize { VmVersion::Vm1_5_0SmallBootloaderMemory | VmVersion::Vm1_5_0IncreasedBootloaderMemory => { crate::vm_latest::constants::MAX_BASE_LAYER_CIRCUITS } + VmVersion::VmBitcoin1_0_0 => crate::vm_latest::constants::MAX_BASE_LAYER_CIRCUITS, } } diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index 1c85133e1..5d9528913 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -52,6 +52,7 @@ impl TryFrom for MultiVMSubversion { match value { VmVersion::Vm1_5_0SmallBootloaderMemory => Ok(Self::SmallBootloaderMemory), VmVersion::Vm1_5_0IncreasedBootloaderMemory => Ok(Self::IncreasedBootloaderMemory), + VmVersion::VmBitcoin1_0_0 => Ok(Self::IncreasedBootloaderMemory), _ => Err(VmVersionIsNotVm150Error), } } diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index 0e4cefd3c..4cd1d65e1 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -245,6 +245,15 @@ impl VmInstance { ); VmInstance::Vm1_5_0(vm) } + VmVersion::VmBitcoin1_0_0 => { + let vm = crate::vm_latest::Vm::new_with_subversion( + l1_batch_env, + system_env, + storage_view, + crate::vm_latest::MultiVMSubversion::IncreasedBootloaderMemory, + ); + VmInstance::Vm1_5_0(vm) + } } } diff --git a/core/node/api_server/src/tx_sender/mod.rs b/core/node/api_server/src/tx_sender/mod.rs index c6f652da0..3e40f7937 100644 --- a/core/node/api_server/src/tx_sender/mod.rs +++ b/core/node/api_server/src/tx_sender/mod.rs @@ -107,6 +107,8 @@ pub struct MultiVMBaseSystemContracts { pub(crate) vm_1_5_0_small_memory: BaseSystemContracts, /// Contracts to be used after the 1.5.0 upgrade pub(crate) vm_1_5_0_increased_memory: BaseSystemContracts, + /// Contracts to be used after the bitcoin upgrade + pub(crate) vm_bitcoin: BaseSystemContracts, } impl MultiVMBaseSystemContracts { @@ -138,6 +140,7 @@ impl MultiVMBaseSystemContracts { ProtocolVersionId::Version24 | ProtocolVersionId::Version25 => { self.vm_1_5_0_increased_memory } + ProtocolVersionId::Version26 => self.vm_bitcoin, } } } @@ -181,6 +184,7 @@ impl ApiContracts { vm_1_5_0_small_memory: BaseSystemContracts::estimate_gas_1_5_0_small_memory(), vm_1_5_0_increased_memory: BaseSystemContracts::estimate_gas_post_1_5_0_increased_memory(), + vm_bitcoin: BaseSystemContracts::estimate_gas_bitcoin_1_0_0(), }, eth_call: MultiVMBaseSystemContracts { pre_virtual_blocks: BaseSystemContracts::playground_pre_virtual_blocks(), @@ -194,6 +198,7 @@ impl ApiContracts { vm_1_5_0_small_memory: BaseSystemContracts::playground_1_5_0_small_memory(), vm_1_5_0_increased_memory: BaseSystemContracts::playground_post_1_5_0_increased_memory(), + vm_bitcoin: BaseSystemContracts::estimate_gas_bitcoin_1_0_0(), }, } } diff --git a/core/node/commitment_generator/src/utils.rs b/core/node/commitment_generator/src/utils.rs index 86643b6b5..90cd477ab 100644 --- a/core/node/commitment_generator/src/utils.rs +++ b/core/node/commitment_generator/src/utils.rs @@ -76,6 +76,14 @@ impl CommitmentComputer for RealCommitmentComputer { .collect(), ), )), + VmVersion::VmBitcoin1_0_0 => Ok(H256( + circuit_sequencer_api_1_5_0::commitments::events_queue_commitment_fixed( + &events_queue + .iter() + .map(|x| to_log_query_1_5_0(*x)) + .collect(), + ), + )), _ => anyhow::bail!("Unsupported protocol version: {protocol_version:?}"), } } @@ -111,6 +119,11 @@ impl CommitmentComputer for RealCommitmentComputer { &full_bootloader_memory, ), )), + VmVersion::VmBitcoin1_0_0 => Ok(H256( + circuit_sequencer_api_1_5_0::commitments::initial_heap_content_commitment_fixed( + &full_bootloader_memory, + ), + )), _ => unreachable!(), } } diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 5a8117139..29c9312f1 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -90,8 +90,8 @@ fee_model_version = "V2" validation_computational_gas_limit = 300000 save_call_traces = true -bootloader_hash = "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e" -default_aa_hash = "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32" +bootloader_hash = "0x010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491" +default_aa_hash = "0x01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f" protective_reads_persistence_enabled = false diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 5d5d584ab..5d947b95b 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,13 +26,13 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x01afc682f1b12cd5bcdacd0e04505ffdd4aafe459e44150c422a86437ae13e4e" -GENESIS_BATCH_COMMITMENT = "0xe3ace05ee94258b46086c437763f8c669c58b2a24f11f8b719cf2efaec9daaed" +GENESIS_ROOT = "0xa8ba1e76b4d8560bee8c039c91d88b4860cae79b05d4b2d656f0d38d7856a2dd" +GENESIS_BATCH_COMMITMENT = "0x53de9f8fb086c1cc78e337800264fd9beb7a35fc56dd4a7afce5b3e9f2475251" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" -GENESIS_PROTOCOL_VERSION = "24" -GENESIS_PROTOCOL_SEMANTIC_VERSION = "0.24.2" +GENESIS_PROTOCOL_VERSION = "26" +GENESIS_PROTOCOL_SEMANTIC_VERSION = "0.26.0" L1_WETH_BRIDGE_IMPL_ADDR = "0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" L1_WETH_BRIDGE_PROXY_ADDR = "0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" L1_WETH_TOKEN_ADDR = "0x5E6D086F5eC079ADFF4FB3774CDf3e8D6a34F7E9" diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index c7889f81b..8950256bc 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -1,11 +1,11 @@ -genesis_root: 0x01afc682f1b12cd5bcdacd0e04505ffdd4aafe459e44150c422a86437ae13e4e +genesis_root: 0xa8ba1e76b4d8560bee8c039c91d88b4860cae79b05d4b2d656f0d38d7856a2dd genesis_rollup_leaf_index: 54 -genesis_batch_commitment: 0xe3ace05ee94258b46086c437763f8c669c58b2a24f11f8b719cf2efaec9daaed +genesis_batch_commitment: 0x53de9f8fb086c1cc78e337800264fd9beb7a35fc56dd4a7afce5b3e9f2475251 genesis_protocol_semantic_version: '0.24.1' # deprecated genesis_protocol_version: 24 -default_aa_hash: 0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32 -bootloader_hash: 0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e +default_aa_hash: 0x01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f +bootloader_hash: 0x010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491 l1_chain_id: 9 l2_chain_id: 270 fee_account: '0x0000000000000000000000000000000000000001' diff --git a/etc/multivm_bootloaders/vm_bitcoin/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_bitcoin/fee_estimate.yul/fee_estimate.yul.zbin new file mode 100644 index 0000000000000000000000000000000000000000..121cf3ba20836253fd14ed8bca5b46138efddcb7 GIT binary patch literal 76320 zcmeHw37lM2neVx^^{sR#UFjs<=_Tpg(uh%zBrHxNNL4n721rO)Ms(;RT?tK+?oM|n zBsyvnP#%iPxZxo442rm+GJ*~wN(T{enQ?T+Wj2i?>htN0I*#k;Wd7gxopYDdx2n2Q z)nVQ|8-BTU?m6c>=X~ee&vI2l(O*LK=qDaYM|I*cm|U3{Q_4Lxxzf2^Ie4=wc^Uq7 z9M8E;sg@l|9XSu_X-B2b)h+z~3dv7jA?4F0=biLkZR38>y!4_tsxV#PC&PCVOdkukNI%@OWuDZSq@8}A z2ZF=%;yzE~-;?=J9^n_c{lFmR2lOWCb)3HhZ-fqpB;P$7{rWxiAM=m-&hdQzfu8S-^k=GRzVrjb=6M1E$uq5=G=HFrdzdcJ zh{nqx;9>0UsVe9E8NGEFKW%@c=cyA#ci}x~i|D{T2k8RR8b7K7X&R62ujhF^YwU}X}oO@dEf!iH}i3FE80gp$*V*2ZH)_ZA_qC)k57Gz7i}`&cp6P_g{QYq~&xUT&sg=x+UFkgVNd?o)-%cv;JVI&B zUrutR@OkPa=Iak@KJQA=Jm3#DKPQEb74aj(O(lf?Q;UV4Q;UVa zlS$!w@G0|sa*@1u7D+j$p!uHXX~E6F1kveQnosJ79>1YWL#Ku=4V@ag)O0#)x?C4a zmz`+WVY&qW)IyhS*J*q$)$;`eF&>Gu3F;4YKJ}OQ(thtao_Z}__w?n|Zzvmh8&D7q zC`fd^0rd)aUSQGZh5G$Q>-`JmJ=F&vbhs7bAiJxumMf^-Eh#7Sr^P{466v+*u zH`V5(&Sd>da*_0<^y6ZJ+xD@t{KoY|`8Gd*ywr+NzRho!RDsX)9jb4`7k&=9N$}b0^0=Hs22UEV0iJG; z;;Cs^@RYe-@TBcRC!_I{VZ68ac*ga^V4&6lV9uQEK|08i*A@R0Brk7TFC(iL6{J-x@^N$APF3iC*O_vdrs^J^x3hUrkw|^La9V51ILM zg)h8jO^?kFM(59chx9M|p!6@R={&3FFMC^*&a;PUoQ}%gCi6GX@XsAGf7$oT{LPz^ z`I|RS=sbG|&)<>R&Yvs%NBAUuQ`xuk{Q7i`e$xC6q8|fl5fux zDTAl1@Llgb9+&eigQsSKgZXPQc=|#VPc5$#Jh=}Go3039mNy!iO#=gG6p0a4Uh4A8D z<4&`l-;Vwe-F{A~yNFMET|I8RzZLI)rRli`<6D7zrRCIEmh%&UDD7h4kV}bYYWz8l z(e~ouqjw3xD|J)k zpQ8o`>ad%;WL^L->eqnn2L}{{p5Q|@IbH&K$DPE#1-upe7M{7-jqbk4d(y;g-@5xF z?-%;-ug5qTj)nIFjE7H_^+T2-e??o6ACKoC-|`dOYVa4%G5p*d!*8t<{z23)V3v%Z z&iF>k`00!vq>Z1><3U>c>1rOekMxj^FL8g6zDcJ+P7*f-T|kbIUq40dP3t(?%Od{! z2RxKP{0Bfy+%V-x{1Fj3(*J|ec-f4&62+&`p9KiN6-f@Y>Ha~lrOpn~H|QUBQo#SO zK)FKO16AlS$d9MPAm66LS5|>PpZXbUzef1%57Ru*ILYrg27KSDh%Xh%x8xq9cSWA0 zf2ZX)#bI_~^5I4wA$)mAlU~sB8^3h?&BzV$b5&1T=3ON&<$2NmZ?ZQjddx%l*P^yc zp5%-|I2=o{J<@Wwwu9O+LEPVzjytEe2^^j7P36TdN%d2Gz&TUruO&T31j=cUMV{?J z#K&%f@pYdb$CAqM-K)~1SLaftuj8p4srXg$PwjSEA-Qpk@lP1Jn)w|=6K{^1pI93Y5Aj^f|S>3vJZLO$t}Xq&PjSa zs{}sA4Y*{M2tNz{0)DpeqN4b4uS)Vf2mI{MQ=4w5uVOnsKU?kefNx|zR%@@={DzpB8eb>0=B_G^WIOBMJcw}SrF2w!RYMJ;qZ zwHx@{!SkUIrN9qhaj8#_Nv7wFmJcmjAEz-@px5LvJ?~fct>k%9t5>PNL;Wi;|CpE7 zzma)zZv~ye<}z?wpAdcMz5(w9&kB~ljVS;q`t%>bbX>nsSm+f(XM=B#IAf`hFxjd zkr2-;uNQpUm)8WJ_(S}|KS93=ZGTagZe`ws{P=kf@-4dc*R^GxjQCBj7pT5q{gd#e z<*6^1oK+&16Sf7LalvHdFvb-)pzbms2uI)B7S5E${sY$;1_E%;3=DsQE z%j-VskH0<%IYRTV5_2W5Ya37P^13$oBCk7?2U`I4*MhGJ{b~CvkR$Q-SCAi1Z$Z9A zZ?4#1LB0)N*4u;p8sQr|<^7GRkVwf{ZnY)*_pf9riJw%@(rn_6zd zep4j(**{RUo&q`6_CW8nwr`PyTg ztF*pFcG3a@j3@kQ(c4ZQ>$(FGyG!gzvY!~=mE~URNusx%L54%?Fj`M&e?i+}t)~k< zeL3IaFrKMfXov96ae?%w#2*#MM?t>L@Bh0Be4*2zevR-|I~;S+srydnCuFbX_G>%sFwzB@Oz~GST(-j(z$YYr zqTz$zu(%|6@b`xqJC5zi=I3``p;{4lGx%yjX_W+D3LpFY)xsXZX)$~#c6%TX?eS5Z zaKMM7TpNFPRl#4q^YgAM@ayzDG@i+C0=;3J;?K7jzuJ9wmG&i$d))Nl-dzQLz2o!! z4g`?cPKSL7d6h;9rN3|dME|GJv3q?M= zfICd(oyA&C7Nj4@CpcEzK#BZPxit(2%%kOSGvp@A`{Zh=4>`y6qj9m^#kzgsr;XI^ ztj44F4_AnrRg2f#>mB!Cd$6-ld4TRuZe1vry#@GC#j*hozJ=X4QCVx`3r`2H^ z{}QCZ-?%OZ9h%H&1Ad9*iU91q<@z7l<_y` z0gn_1gp7`?W0dhXTYjYROY#l#kpXU*pV*(I?&*DOOC3+>b|xL>2T)AM8(ZJ2>2{Hs zPh%G(SueDHQqQ-h>&$0SmH5}}cbt!QXg(3sVg12!1NnL#vI)F$gvuLx)AvVp{6RTe zgg-5R)I)zbPMPduf70y#OzU-^8&i6HQ1+p_H>JYyNm5z`>g-=29`)M5ABPlT`GjW~I0=G7^RN9Kwrhj+Te0uU>l<6I#^XDvZ_lUL z_d&jmZ=shUzef0~Cu-lf-akwGUd!RLe+fRi749@5hXs-|X1{%#)&treQu8S;*gVkl zdA9deGdxs>%G0_&*#n1+{y>`Lt&TVP_Fsb6YjW7*h<{z~FGW&m~ z!0)7=%>L;2gRTmcMm+f}F!jAy=eZrJ6ynV1<9VX=t=Sh~&SgM6bALXJanI$t=SK)W z4PVD?79&k~Hg<>6s|F8DSIA#COFP7zhj20Padrse9JTDHXvLakF+?9kFGrAeH=1#1 z`Y_`${r6_s-;dU|e(KIRAAxZ)K6yU}h#7pq^d|PQ(6_(7y43f_K1=A1oZ4;5$gFindM~=kIO&~1$vg&{Ul!bILRlZNUoARTbPvihgsKa zPUI!d;^_T7C{O$iKh~r2^aJ{s#Kv@|qWNR_0lRA@9S5mcpXiC}Q}-&a zyFOv9yWRzYBdRp}VWzb{QSfV_Ta>HiVn*AU4=M7Kh+a*5+`k;waqwQbPokfd+h~FXq-On3+CiY0pdL%*i9k8c?gC4lt6zP!x*h478e5sOg_cD1-~?j@jer$z81sTYf9sl3>CO*#(Lr0*YS()SVI zoFe2(a8H4`#~`imHAwH1{e5NbDbR8%_o(hi9&!nORqi`t_hvoFztDXaZnbq@@e2ce z6E7cvd`mveSm!nVfbkcq$>YlFygk4?>l>!CF`~cdJp?X%vm+#TZ)Z7pZ`u7XGR`1B zew;zRHBPI*4Z^s+oEw^4y zd>Vtlg@|AYpRnHa@$Ej{>ydTZY5xA&zj9dKP`sj#=;SccjQ29@ktxgz^wZhDfZV&4 z<3GI4;9}kUE~@_}nzssZf9ZFiPvhw<$hYal#6|plb`*DMKBMhPj)zdZk@>;>>nik0;jZeR#962dUp;pAjB*fytl~G@YMG zb|X!-jU##?#$ zDD)WQ$B!$>xA5lQPm)8w$$snrf6_V-=CMHf8D;|XF8KlAk5Jsig5&-T_cO4+ZTzEp zWL+@6pFw>KJ~a@AtbF0bjdV zzp!0859?eZITzS#)$~lAdZ4PF;dP@r@TAwBs_Ge`2QA0Y-dj0t&|}$ifnR6Sz1VX> ze*Am}`8M6lzP2FWhF`DWY4jzo*OGXt@X0*bv`iP~oW)YaP1&BCRlF4JuxgF$Yg=2; z`-Ay>i?Qcau1WOuVuXT4zUzByl82-p&}$sejqXcpyHxlHvtZ86%x3+a_IpV?CXVE< z@9TX#^AX44ezdx(v-!Ep4;s5cjA#^b(iK@Y58t4-E@ z6xItiqPm)uU($_&WbX%dLOlNk`8I#cx%MDGem`T7Z}Gp<`_F>?jC!Abx07f3>&E#) z!k@oypXrLay_onY_peIzk>0rs{iGy0}@#m;Hn$UW-mv*0aWcSojhe zN61gJ=Pe6R750%<-G3=^H<&kj-mC17^6zEv&pYe&4vG&Aw0+o*57_ho1f(Dr-EX5@ z0SRpn5t&w8m-^?(y3~hf*ex~gi&$`_(8(#}chP#A>}TvkH*&a#5i(Ku+WoFW@v%;o zS03KC@eLHGsczh!r4;OF^-Bx`<>~%H=e)L$EHANsRr97IY4Wew9?5+$}I+7FG#=GR7#_t&BE68!=`cHoj! z%ca)VFweiyd?j+~A@44sUw^&#K_gEgm$5Em%gZTqUd+f#N|QXdU+iS)0O zkKUg|e9C^GzTYUIbDM5NP6zol@<~f#^d2Qc_e5{Ubr14F*!o52CHFrI@wv+C&BOO{4v?{n8w5uQ8~;OvH!4df!`cA4C@C zPWXEbvQM^d`fLM^X`YCz*dNA^6xnx3^L;z!Uij70E;8i%250DT!fs^$z(X42#BM!F z%esqFCu@07l=2IA0pF#bQ& zVE8uvA8jyvyZ=WT4Bzhmbc5mB{eN>6_#YDaun=LvhVXYU+6&MB&#JUvt9)8!!T)K4 z;Zyu5-2W>h@X4MK`*<_G59t%zE)Y94&^PgRYLIW+16!)V7dtzsUnBgw^#qMCjHgQ@ zcmkU0)I;)pq(F}Uyut7(J{|7=zcm=XO-H|IFnrpV6z>1OHyA$cGY-Sw+FS?*Fy&YlL67{51CO52JXg8!qjO2;=>w4Tewgh%o%22z>IRQ}E|W z4@=zm<&@tx?fZ4sJYb!R<~hiZpNAmd*2C4{lN_E)__;ZTPy1x*=>H6Q`s1j->Bld7 zo#=PSx-JB_dT)&d5{77rw}|?hg)!khHLKm>rQ(7 zowB+84%tll{0{J2XuGE@eZo${xL~rU?*D&;{yoeu+4*MO!S?5NMd+t? z{<7iQdUW?3!yj%ie4D?<>V#iS{(P`b_!|GYSIm)o{6J&+=hL4pA74Mm@LyLa{A%-e zN1gC({;}gZk2Dy*9gn)M!SL;MgIC$`aqj61toN>x`=Q*`cs@aTUGY9k_YA$B>>zzU z-Ws`OV#j7Zr|Hr_;x($FXkBj#~Tda){7sj z6TZ#YWCw-gZJ(+F|C@EvZ?*Yw7}dC(Cz$(d)&ac#68 zRpVImQGP`z&K2)(`tg3wKFr5*2+c*ybZORff==5s};{doEh+PC95)!@^7&Lw<_LkIn< z(tp({an2e0`E5C5ua}wgNxk43)@#r&&}$1nWb|5n>tqYxWAqvf7wENx4;#H^?(IrG zll9~rt&{odH2OTK)^9=F`#V+W6!@$A91i<=T5j0uWo6>l3;(GM{(I7SURPAJTc=$3 zRgM3i6t91RJ!KyLWyU=8&*ePmxOIT{|2)BXKPGk_hcwa%_CMMtW}puf^isUZ=U1)Wzj@h8%&Av?w$ zh`^`yMbZE3>3vB5+WNm<{ag)xo%(r(-ITZJ*xajb>CLvcl%eC!+T?cIt(uNIqjGz} z%_mlVPQym7~M<<>u?f1&(Xdoz@8 z*~`E-pHIS5?x*~v$OT|W^sSLgDeX6$YVzg&FPwKW_qvLFoOby81?kw$ZD|GBChiAf*>I~(_w-?m6@oeNVXr~`2ITfU}4@?^7kz~bDwTX?$h;Ba-VK*I*sSD#PEcT(n-p)A#2F-yf3iETNpf z7uVdA+az%`C2_gn9$j<4Zd%{Bn=a}2*f#D5>9t;(Jblg@2&MHK9M9wLD!0Gbj7#p> zX+NmbdcGV_&iDEAMDdvdjYIRtBBV*r3V*=q((~3Y^M-phYP+AnoD-*Wi39%pnf}Xj zD_R+h-0PY#_Z}g9DC2s$KdvaL*9xEU7izx>e0{H; zQeJu`(bo*WnZ9HCTAcUvAlJ_0uR;nR(RtIe@IKG)fj`18e+Sj%pTzXyas6h09(6sG z7q}EBE2vgG-#Lo=m-cF`+Xk|M7n?Ymcr z{BM7@zQ4xzkDOV3H@5w3tNlE;k5gum_GuP`&s1Vf%=i%v2kQ|Z;(Ot>d>6cZjn)1j zx8F3Q{c`Qr+TO*H_EL}!o_Z5-3$o(-SukumFRT{n@uZS`&-bEV2tPw^i~LDp-2&sq zz3iLCKhg4ArP6tl^Lf4gFeLKJJvD94B`2p?5BTSf3nVWA$LMj%pEhwGr;X()-yh`5 zBkHf`yqSCLBrns?N^&WI0S<)przI!&{;gf0|3A}m%dF3l{3X6PB6!PImcOj#m=5~I zUV%I$KKJi8nzbISEQbNm)~9NvgTDKE)##Vc%6PJ5uT-)xq@S2v;Br|APx11wyq!UK zWnk@xcbC9&J9 z$$jeo?BqV#I~dE7?-+i=c+Y@d()%m2T~@pudLg+J!< zjpSIm=6zUav3-YlM}hbq`>P0VWQfrFj*~R}G~!-_SLLjd^-_&T2XU}RxO|fBF?HPg zvG_X$)E>#5+0XMF>2)3hY^yn))1V}u{XAF$Skd1QX*c#cwi zgl{j!bc*-uTo4`OTJl|uF@*W@hOZ%(^aZp_V1Pf zzJF2K9$UmK8K;5no*sV;?3Oh4JAa3{{ksNVj(mqXW99$UP{E3j9t$80?3h+oSn*Dd5nPd2GZZLfEH^TjYw88Lg{2Xa8e7pbC zQTRAdlBe~UYzypn$Qt~~z1`Nn<@RAC&(g=MFL~c`d(rTp){{dUARf-mp)b_er(C-rxuFhUGo>d$ZoJ?VgDCR~!6b;$TO# zW8IqMlONx3=JvcWwHM3xwc_I=4Z_EJpI&_U`*O4%=_tkHCz}&`3FrxNN0yu5EAW?F zRBp|Hf5^svgWIR`xg;;j>BXxo zd136>GX6)$qPpjs{f~}jJ>P-d__X*R#{R*5w0XTQWcIDG-CJ(ITF0rvPw?ZIPqO%~ z3h5!kM|dy#3E$rfzt48yeW)DjaT=0xZq8TKwyz!Ci1L4S3FJTp{n~L^-Soivwd0~F z|C7EG{c&RW-^k0^?O#OPmiLFj4wmO0Yrj+z5J{+nQss4KC}I3wMofjb%XmFW)|v8= zbr`D0@3VAnpwQV?d4EkPKX%G*`;-#uOA1^OZTnNqN;;71rf zVfw&&EBtj6XNlj(ME6GzbT0DOr4$4s*%yPyx1XltE<uSF_ zc0WxA=BdDbf$XR0Fnaz(@27DfFK&aJ_*f_&MC;dBk4t&{Wc`CQ+finomcB#AZ-38Y z%J@~XpQiSC;_o11o+__%P;iUArMU1AC+R^D=6L&+L1N9*u&eZv9 z$$loW!D(!>%2RvLlSDU5KP&i8c$MM1SEX5>E&a0DXJX{&EZg}fO`jU?3B*|iFAW~g z5A=8jZTR@^6XQ$Pcj3R}q??-IU#&hSI~MKoQR^-R6a zxOB6YFDCA?4)G|=FZOvbyD>}yX=Q9F4ZA05gJQolm$jFLZ?*77NRmc*TtW}Q*; zBkPPa_|Mk^s!Uvk`g;U)FW+q5Nol zFfIO;(LaoL6ej(K{=5|w-m3h4c<#HARp@LjI}VCBtO(`Dk0Yob?T3=@Nr&pkjiV0u zDrw?%ykA80KgPWjarPqSNf|#p<<#;$X~5C@Nt&YjNyx3>`Tq*zEs&%3xa|3h$6HX} z!W*rVvfNFe-xNo{IT!j~+fu|0ZlH0=ywa2PSC;N6uVlBRc^(71CcZyGzTF?LPwh$^ z(bk6$o5yFb%#j|{{1@Oie!M}xJzkC9j;~|D2H*9>H7)axXwufy%RemZcwR8OnHyzt;zE)z}I2onX{Pn&g%TZ-M9%1_Hmw zcVqB|_RY4TJ`}0L-$Cs{S(0m=r$zYzaZHwbMviyASLCl&NBV*GAH$j9{`3B8ZI_bYMS7F`MJlzD*KxEQK%9c@2=d3K2oKth@XwE6 zxlIjpuh;fGfvMtmVIhj_880p87}8iz$N7cMOSImiE>eEFHh-)0LX4c`RWH^lVTX0T zRKt6k{H@OIdcHIsF}s$(mC*hc>^;m|*GF}E5BMZIKkMsv{{C;*uZ2#s&%iv>Jm~vH z)VWBrUm){M$0CWI@O~xJAM8e&A3?OI2{?!86I$#^q6WxY1D-=TF!uPHC@asGt(P$3`fsx0UU`0dpGY}bv3 z&ocb|#O2A{GH-gUk1cNQ!~{5WXV ztuq{l>~8hT3*J=nEWt;5tKb9m7$0ek525F-Pig%3i(f$a?<4$>9|u17+r>d0nUAFK z!Q*B=Og|DQTl1m!qoz~RkA(g%H0Y4~5#6^I%!_;<%fAN)W~kslagxjn_WAR?B-uYk zKlM60@-Z)+e<}U)=c7;4J?$I7cxYZ^e2Hz`4=?Qr-V;oxdOos10H1rv_QQ|XbjkI6 z{=q&W!q4Xn-jUu&{*(Ae#@_-}q^4-RdD)K{iZ{voL9?$%@3)5-g@;XWOk7IJO-IX3 z(Z1t>?hTfFBzY|IcCcK0s*Ifccf&`ZYwB;UauR%8AiB|VvJ2fSGM}YoUsKxn?Q?w2 z%W*iq(+R#hg7&k|gd8h$Zz=1KL5`}z@z3BrrR^MY}c909#y{1^33LqbD_AeZP5M1UX5y4Py|w#l3`6aTim zP>pwaVL3R`S^<7tJdiCQePA&c|;AsEW zjrzCUh{X{dy6oR}Ur-irbidGwP=5Tlg8CNTj6Dal(BpY^#lP(uHhM_Mi;TVC+jR}v z$3pvH2Y^ex&m^nQe{`?b^hR`5kH5Fvf`2m71<3P8!Kd}bQ2*Vl8w}s}XNq$Se=rK) z?9;4y|B!WmTlSO&!KHIiA$({1qHtLb)k7~9zOySD4Bv_mWS`Yw_;&xFGsp0sJIC-( zi^2yTGXFwi$a?V^Iz7wpj%HUz;WeCI^!j1L|`1-r1@$nMOYQ6Hl zOngS>19l0=VIco6C;bAw8A+S>=Gnb5n&15*D}7Nk?bq8pUbr^wX8q_BMsqYJ5J_;)&?<2f7$f|JJY;Vh#p<->0f|AgZ`+Af1#yNc$w=ZUiR z1U1ze%8#`tLiv_Gk!Ai2<=b``pVJNH*9xEcJyhR@&++k4ey#BNUd2#-8-AVrpAoNT zc$lxc)~|b>)czdN37xN2<<`x*@6&cAuV42(UX~7IoI!p(9)o;~4u}lNAH`GFMb4^1 zcXiI2Yu`h|@X-8;!s|b1y#9*E8Q{gH9~ozmUoT$Iu7cM(`B|}FhFKJO0w+kz7ZXQT z5;vsnIz{qV-VYH~pm|raAK72`Lz?0*{Wb2pf1~Ulo8o=CqSR5uj}RZr4kUG432-_A1@W~(z|EeMlJ__lReS{L=j(JR zZp-D)P3Ur|Je7mGI+OMVAUw$ZoXRBmoDZqFFnpBb{Uvy>*E0}ryp`%>%D5kC<)I%a zcQWsb0G(n4DtjL0m&Qx+ETqxlMcf|Xvs{|?->>5LPMY_JyL!L$6rE!yxc<7fj&Eh= zqrcD(_i)?;lg9Ga*RPh`CAt!Q?Km7?>e->?#OStfT{qyYvIvxkQHTQTZ*M?W8{8m&SG2|Y6H!zlO!Je2m5C`!o@Fx2wQqlNQ z&tqlr2{DCv3-aUf8RT2|koZ!lzCC`HlcD??;S)b;xe&Q;qvzc^zC`Oihp-S4sMFmR+9Zo+fy`)~sVv{G8(G#P1Xz1f4G5uIW^{Z@~N&xR&Te zb5BM}^diArE27h=C3ub$+69LtAht0$LTsp-p{`_DTb%RSKxfj==Ad9V2pa`t?Z z6U(nD%XiEdq5N3-3FTY#L-%i0gwJ|0RKG^}Dut;6Utu5cl)`$=GOYa;$c~x04|s~~ zm*d+93_7^W#L3ZN(p#jLpjWY8Q`5bA%buai^IZQ+CtfQZ( zAC6-!I|NLjkN7vTE@}Fwj2+brI>jC%KK~1yrBZUSbrbidE@1aj2?$Q zLG$)(4cFYKhJF2W`CWQ*UQB7ZFuQYOz=MUin%5P}*!9as^}G;Wk{&Ya@#Y>qUMI)< z-b7C31@a|4FBi>nUX+r1f)Vc!J6ZOzE#KhJ2cP3yewBuo)cbE_za=`L;}{C(X1;_Z zo_xPYDwUJ(ec*h_^9f7PN4HSEx&I@f?*qX;CW@OV#rFnc|E2H|$xFmJybr;DdM@N3 z`z@f0BH;z}&uQ4n^4zYUL#7V-8uF!|2dw^)e?^*^^h6WnR|Zdg&nyHv_=y4(d>+c2m+?@A_akQaa(u{hMbAGq z|2FOCe1rC1W!FHV6bQJwi_cM|=1F{Tx>@K+sfYNzn)g1wKcv4|@|F4^zh5WivtF|~ zk0s^r*6;KF`xkQgn^LC!nVcTN{x70irS7M6+DqO>X=qoDclAPM6i9A(DSodW%X0a& zn#cLe-!1fpwC-nPzfQA^JO1?$PC2yqny}-p0wBsC2 z3ZDFZa>xgMDIiAsF>nrSrSvyBL3lOizk0X%=f8A)|Gd;qQh&zzuSq%2G`n+Iy@S#} zod2o_-@PiECx5ONI^_n!o4=22mhI>`R3cxw9Tl8ot8E-N>2VB#&w1Yc^LB>>PdY94 zHDdsYagC?dI-mF95;Jfb_Gq5qI0?3odSN4B9-(BwBg^owO8kw~OX~Z{kVW%}xRca_ zABsA?z!}Xy-H)N?SM*;B`)m<+UH&_vGqX?8Jv9?O*QM=8yq9>dN~ET!9gLIY69Du5 zz}UyVlI91LB>B^_f79fnziHL!-K+gFDrfo4itf*aFyZ(s^_TQ5kYUEldYkjrvfc-^ zU6_vAg}op5<&bUPaNH}DA1miV`Ia0LyD*e*!)LoQlwTwKATEswd=bZ;*gouCA@if- zwPIgg2dt<>AMtmXUOY{A^4?L?odhTTyjAb}gf3)1TJJ+;@y7e?LizFI3hG;U^UqtQ z9I*@ac`L5ZU{1Cx;OjL)+1d&yZ563;tSF*A-l9@`^CUr z+hDj>zsbG#I|!|LM7fpIz5r_+{+& z`1laywYFb-A0fVjJc*_sw$lFhe{}grOg_tn)3tm|z?>ohDECmvdhZ4rr}w6^@{CkW zXDB~bo`v#ld8XHGu!TqKd9&V{=o5YH$UWSBu>YW6J;Xt8fSk!*0R3FRb5NguqWki8 zq4%WHwcZ{CKW3+Neje{BeOS^>$CBdbs3hO7=dIOxJ)LAf0e*$p5nd|Ke67-a&ceF{ z&9a=!sMHcP*OVD#`#CM=USLRZx!#|PotK>kN=YuLXUe%Rl`e^$nOVd3`(13dUk7&qDVVy_Izc_G*dj0bZ*0@RRTdjfbMzZ`amu_NTYu_Fe>A3}MyH?l9( z`v_=027J2$lgsvlJhu{ZG2zSbFV!C-_$o*D^y7Gv_*rx>=ot5t=!j~2&RdlqZ_2(1 zphEOS*FPe@kpfiDc{AYIb^x!Bgy^Sc`a*l43s2wQEawWmKPgMkBu7?+^5feJ>f7`z z^~>`MuPcYfW7lW9hwz4ZCwd>&_6iUbjRH@jFaXmWdCG0311;Y?#nT8Njv@pe}dv0-pkE=gP%H4 zi@vYUenD;b?RgVMt^h%>YrWU{cCYvu;L8&d|I+6|W*7egU$7qY-mIT*vGkPScM%>w z{lm^}=cK-eCEyFuA4s2$@xK%CpgyWa@{P)ya!3=Nb=tcdsPe;=KiuJm^de`WKNuYcv;k57Rl%l&1SUOax-x#*vty0%=2GVl8% z@2L|N{uV|G&rG(`DBl`bq!T%D7=liRO7 z#|sxK^E>(E;e44aevSOWD*1;gOnAJ1AdCNusT-lm6+a#SP)wOhuOibQ;AeDyX?%Pb zxSu_Oo^kF}rH0fq&K>;hS2j4W`Q=IHzUh^(_~<`Ak(~an`uNt*A3EjvFaOOqQZIe= z-LP{i{2e-XutKgBoIhETv8LJr-#;2fv<*)A`4huCM~ajC#w}F(`8$f+ zCr8H*t}Bf}{|0~9q)_p1_h@Aj^Wl#b5AG>K7L9Kl8QT}kkDotYnkbF$FAc3bI8xj* zyxlZxM(=HO&$!Yk>SFgfxZdRgW6hh7$kl>kNs)o|>$&%64OD*4|W867#Tv}bJc zpcg-Y9pj^WKvLeW()dVew>L3X+#Z>MO7Ka0R>^mKw3cba^lGJto_a4UjU%ET{#(Cs z^QyDX8t}%7{-?%r*^on>;t1Nn+27d+rq$*-8L z7TkYyYiV+l#1m=WO{=|Yc8_k~6;{5PPyaQq4OIpd$-O(A3iOxJ@6lGo01elO{@w?! z-aJ0KABt~iv(V7y@!{>Ib9Awt#fi-*Avxw{2n6a*j&2{_?OQIB2QZ0~-j3n%36dfg z7Pek^^(7lNY+b)CR4e$ouCT3e^``X~U$E`M;AQ9+Y~|zs%YON2rOK(t9;lQJv--zJ zherch7*}}mz_!uJ;%>0vrr|xqGs}*b_U;=VFAZG+>*Cr{F=BfVyiqW35rW<1Zx|il zHeMW=fV3YT9f@l(^e%Dh&-Y#*O2_=HD4%{e(Y%9KC}Jw=SMNIc$6qL)8=JE({1#NH ziD%=;j?tO+H|T3kX~*bzY4doAWSl+friueNc5KJ>l@;9XRo=BQ{KH*}{4R`*l}6Zr z0O7()Hr!(hWxl@!eslT1@e*|Q2#MaYSUYKH`Kp|Q@n1Fp@)#*I{;|=@`VsX(GV9q2 zizArr5RQdw5b7!Ohx*SVC$roi^0$p@0TEZG;`IFFQ`2#E{CBNu@?t-t=cJ$a?Vdcx zo7lH~duhVR{F(VtJYQ3sC}{%o!G?cm`?GA3J^OZ_KfZHfD@b7y*eqK(3>d%R z|4i)};n1*^6C}q=JNAtXJqu`z$8!EiYef-#aH6tq+cj31K7yXa+bY$Z*R9|VZx809 zxUOX>w4CMqJxCyF~DwTI5}#zrSW9mB=lmvU)?hI09< zbtku9w>R9~8NXo{jZO^1GxA``0Kuc)?$NMFAFVw7>OhtG-&@*0qs{P(OSJwuWx^u| zm{b(^;@aVzEHsT?^5_L7ZSvaUNEk`GE67%AXX4t*;fu+!;qY+7UE|*qfvYhik6!G( zes4tvC{AEINrgX>AI$e<%8dNmOU`-VKkj^J-?7fU-}$#?W;>S-~8Ll zw!Y`%pii4bQ(;hso=C69^#u8%|1K}?9)=o;I3Hm^F~5KK)Vsf4M*jZR6nD&zGS7+P z{?fJs6dNl|5GNRI26tsY^{5PddHs`5J;H_1?ZTRku`LWw@W5j8=q1Ka`VZ)dN5BNh zWD?G0gtBg*6v&R@kzouYYGT0_9o}(pYec7nI}_-a*y`$iTRt2&Z9a&we4F$p4_q=n zymL5Yw_UfZG6U}z!g5H3zbpRqQhzSviUsY96tm07+l?a^K)S&s7U6gujCElcnQrm2m1>38w-QEfgN_U$Q?p zxVTE?bd~(eMs|&iUOxiL@FowA&E)P)g{|AJ-f-#q^;d7*bjh|Vz^rW8A6}XGnlHmA zDu-WGaiXI5RK?2XwHm9Up#1oe@90Md;pguu9)ROHIzBvka6_pCpA!^|qT&4TdjrMK zhad?Y)isDni5d^*M-;mT;O9?TffqZU0!60L(DRYrr@T;d#?OF0$v;OYy)kmH{c?9c z@k{q3kN@GiL+|+8n?KP!zI9jUme*YJ$dQZNuKwKkJ)2)O5TjrE{mS@p_E|ssUN~+4 zhS=NX{*XO;TncYOJ0cAaoq_kT>lgkVT@)fFxr^E=c&$JN7a z#}tpey5@D;Ly|O-C5c1l9*%h%ygGF5bdZSob?DrqF>fiZ{;+u;%%4F4o2?T(4ixG( z1(_FT7gi!7EUi3Bj(qzc zy_nbjtFiIYX}alvX#L#EKfLFB@%yxqrPANF170vPEQ9SC+g%D9LA#5U^=Bp6@4B_? zUn}J&U)%q1wo(D)wN}Zmi2N#b|M_Q2zq7ZBeTr?N75}i7U-3^z2EhKH#L0@L%uF~{ zjK^=?x#X4ze3*|mkWJec|HOV5PHQt0mZ#>gaAuX?KmXnx7gQ{A=$y*R?a(=cYe8{{ zJWP-QNfv|z(Ss!>qDaag9p~&BP9&{;UOM z+&@`a!J9FK^xUX-&9J|Qus=3x6?9?$M}9!-viOAk1=}KGnsWh@KT|VH{lGsMo}4J{o-vnY%m%*~5N`Ww7M!~FOaI^$ zA5PqlbN~K~EphM7yC41fD(uZE|99s_TdyjU>zVhF`HA6gnxAw0(xz7MoE)u`tJI5M zwDk`!UVHW0!nU;+UVZWU!ln4RX;V=DhL?9#lplzmOkOgE@XX}6*LNPg){zn%?REZ| z@^!=ljz^@LRQediod?wzJGbq=d}2uRpQ&fi?5aaWAi@TEh}`&McPck zGS6Za;-rYwp5n+s2tHna=7qd6u;O07rsY)&Cg1#=qgVdoS!X@$ob|Ok-q!qzkKLbp Q*K=NW#(noZ_5H>F1v$(u&Hw-a literal 0 HcmV?d00001 diff --git a/etc/multivm_bootloaders/vm_bitcoin/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_bitcoin/gas_test.yul/gas_test.yul.zbin new file mode 100644 index 0000000000000000000000000000000000000000..902bff3d75dc38d5a3b11875ce6e59e15515faf6 GIT binary patch literal 72416 zcmeHw3wT{smH$5Xbx!(7(zH#JG-*$yi2P@ewgMW2;a=ME&Wn@NYe4(HY3`jG)eIYmx-=g3k^K^9l`$rx5|JGW2pU1xE-kY0y z1Aczqd|&Q8XYalC-s`>A-e(_`QuIlwUj2=)w4=K5HI!bP8du7_Exp#cQ8~D?E`0(1 zJC5(%pwz-2D>ZW}u8%k>b1JuYR3EMnr|BB)GxDA1@*Zl*L#Vyzp2z!1W#qtG%okkskMCnDZZcPmRz24)GJj7)#QF&s8o^eJ5IZL3)+3g zX~#U&y@Tu99Ue`}R|8ZzeKgwPlT95a_@7A)Qaz>m`_OkF#KL; zQ0>9^ej<2qXE22V*J{t4sMPdATo0%&+>v=_RD0$$!l$X1Qki9Ro%U%yAc8YZ(2qDi zX0F`7$9NwEoD@hj&@s8{E_B>R^%Ci$l%H9vuBY-0;|bSln&!7Un|J;g-`Pw)HG%Il zHC|Ls@ocj05cQ{&w=aDze|wpi)3>^o=AoS2kl@KZgYlHdG#THyEMJ2s7|-eKAj6@4 z7+x*|y5f_&(0N3@Q^(V{TabQSm-=y3c2Hf%_b-z2>_t*PTXH@?_tjP&2PUpoqdJ-} zAL1v&cT&ucOMqz_hkGCBP58V*uAMbZ2ZF~yYpvg<~WR>j`KBs9>RDE1W)jx zR^pn*ug9l)^z|A&k8XXvQD67!>tVT`H9tSB=eLmN*DJiO>L7k`zoPFyYTbWK?o+?0*X@24zc#6r?mzJN689hZ zn>2*z5i@_);bcx=JxBZy$hG@V1g~Sqs!#EJl>4{w{uH;5l;2^MXVHEjQhsN=-2LYo z@R=Tw_I1K1ysO=qYY+Gge6Zm2f>+gr`@|P2<*=NsboI4!49WeXhqV4z{cZ#=O8JmK z=%Gc>S2Lt1^3FKq3(N}I_7OaX;kn-e*F#PhgPpIUdPCq^l0%hBQGY0By}0NWT|Uj_ z5DG1irrx)8z5mel4s*RlW%a(37I+vN_je>s{VhPfw2Uj0=6=7M&eOOSP3wA(x9D+Y zTXgv#m)|Po;94pNatxfb!1-2=?bM?8>3WansNQna%SnH^9OJbY`W1LiO}o0E+yTb# zGmJlAN44nsF4te}4UzqIFvB9@?KHF}y!kDP>>R4U7Z_Iy|3{ar+#%5)?t58Z(@;sD zIIhZ5JI5U-c!aPSf|quuNgp{16 zfDXa)O?&UnJTK_KtLXkpJ@3PM{K}PiL$V57F8r3FaSSNZl&vIgKZbKZd8= zE^Y7LtnoA+#}mp4PcO6Z)F0sKT7##4na=?pm#@dKay;Kf0iG~U;34HR9?4!M@)vG1 zeiuVG3Z8O|NB0TPk>s$T>5|P25&adxI~n(v7(Vi394fb~8h#f4k%qrgk1NmP>Z~#@ z=8MIcgC3Xg)9M!C^O1mln$ID!%;yU}WYO;}LO<_AGCtsw`P|d=^QPl`?%hE1bd)zO z^lQ;@z3YU2-ur}pkbjXYmVfw3*D?J-!y@Pt@OeM@mFsCf2A^yC?TXXS6Z!`9!#Ih4 zLm0<^g7hd)ftT?mc<9A_l;ip!&1>kHxQ@Y-dr0ep8#SJ8jpGUB#OLp^@nqV!ypQ@{6yT}lTEWx88+iQ6 zeFK*Zp3q1wB)qu)>fXxs{@*Yj;@ej%bu-DyYFE!2_pitO%QZjuiXI8{#<<7j&NGHS zIhXoLy;kGTfu2Tta=VKJH>*dwiLAF2eml!|KwcqbJKKK6(BL~`#R!)1y2mT1JWFO$SFkNoY^>Pl&8Op`~ zcm{q7@ZS1)V{bsGV^KQf_`-iukLnYgw(SDPnNBWm{h}^ET%r8Sy8K9m@~`M|u85Bl z{#m=ozaIC`gmtW~?L#Jou+VJtS&jK#hM|nTmx0N&; zmDFk7eBxJoH{|%U+V=>BblGysp~C@^U1w~ zLeDnfh3Ki=czM9bFVO9OQ{~|kHTd`gzh-=Vs6jr4ZZ8nMwO&qL`#kgU+h)nfhb!>$ zc_ANPH3vR6dX4n@&D4IS*6Y(wqF#T_^!5{>-sX8}yV45%J455_wB*&&`)W1tGJtx1 zsJ9Df*ZLjdclSS#7cD^S{}Y-KcCCF&+&@Xp=zdnGh6E1kksou3)H8S^I}pR$P%_@y zk-wpFSF(rgyLI{D3hm#e%a2qj|A>^kzXD#WdW1hPlN8xKeCxQu zQ9}dpIq60p{=1G33M!ZUy8_kYJVh)0pmI;e?zaW^o!EUq(DhTGBg0|44lh^w@sQrd ze0NpMCvjdTQl32Du)UQ}stLax{U1Az@Z07Yertp9GlYLo1ERtHy2*nXzn$@e(lt6C z%JaeXMtx0rfB2DVSYPvaaD9!w2AQk*{a!YfCoSqcDS(>1cgB(YIWo%dVboAO-)rYd z7r$HEgC%-g&^wuvz^;a`<94LAc##dV73+tSOuRRREUHSO?J@5hOQv@G)B-hpS zvgF}Iy_?LhVYw|2B!|`DH>j6YyYMUW4D27cw*h|z!bd7IEqa9QoAH-aJ|)-6>5z4} zvh_-7cOG$a{#KrOszL(d!ymK3)q;jAW2Xll*(FY4(?p7v+4t*Ouly zsMnTLhYM;Uub;giwHISRtVdkYBg*0YE5@Ib{v9{pjWuH2Ah@Y#9rmk2xi;;!9#T$0 zw-b2AuT$ysM6R8q^t{#yp8`KbAGjwX*Mi4Tu2Ih8(|Sn7@!~#_W_m9Q^8V;}9sMVSd(1UtDv+HNb$hFmvN;L<*$Tj!_`W|`hw$n5py3(K5 zj&ZX*q-h>)z&P^>Ex~m0i+SSAKy*|(T3m`Xy z*S3pfUdOaMdD8dCv}e@e0Y!cz?<4TY&J{XFD%x3*`>;G&uY~2cURhcLzW7UF`+DIo zs{vp9y*a~It(qU&9G~`EwB5{fP~LLt7g((1rx`!Y_-ROsGQZ|P&r7M9vtIZfa9F+^ z<+C1=d>LK}w$7N}Rx0z`EI$oy3G2hwoaQ^iwf;QpOT;I|aZKwESzpk;67oY9yJ>-=_62`BNk87fbz4hwV2F z6a5lBI1bNYf5FXY=lK>L+Ijq)suOg;7@AE7uRq>jv*DB2YrYfte*yPbS^qVvUyrH* zU-&lcKbddCa!bFcPPoM2TW^i?Bg!wgK{l=;x*d({0ufWSOb5J(&v~O@Ei2=HNPzo{9&FFKewAW)_YNn{@GuiyZ!Z!tpUH$`7xhhc1VMY z-wuD1^y8CSKkEF3TIl%V-D^MQvhwb*Z0ccZMUzg<0pZ{(XeF2p{g znNwjc#17)i$zok7oTrTk%0E|`hj$$FbEr@3_6_<0-irx7hN=CjX@s4OFXK;{bq5o_ zf~>QOKZ#!{?}qic+3X8nbh(xv(r=(g3vgS6URP$_Lh1d#U5+n&Th51hqO;ELk)j73 zlv=9gCh!x|Y!_PpN7GyLb<6!|O7**R{SHUseB=fTVIHt6&||M8yj7vA#lNo2-?HC2 zy3MT=poMQOWdn^^gJZKM4|XgUTex1dS}^h^4d~^WJkR=$OG{K%2%b}v z4;Oug#@c@THqXe3i9Z*LAD|Y& z?$18&NOYIDsg~Yk305ieXgL#X}zUYk7t3yd2MnB`cLKOAWVPkm$V~H z!+qtQL-Psst!m@;t?<73H7hWfQ${VVe&{--!VdFOKfmF=+jtzmg`e_^?;@6Gd1 zv@QTW?hQiJgno0&gQlSJS&#oV56bKA;d)SgdUWVH($i}|cgU%G8}ik#$KkrDlbI&F zOL=?p-p%@dUh>8s?E_~%ad_R6#8v#WH0POdE$xp4d1kIRy$Jj@fb~uB&j2``^t`Q7 zdD$NT^)JtJ=HvUh-K&gTV~K*sSz$kSOYq!C^7EYTA+S67UwZ$bdxM4>tpDfac}=~~ zyT#As#qPR#pMtBO*L3ysn|Q7XdM13XGk2kWu2Vk;n%yt!$rYaKG=AjA^f>a+Q`aL- zcue@A#fKjpdEVHomG^8kZnyKE3=jA+e!A$Z2>(>r$Df?{>;)v&bM`(S_e&f%*wtd^k$*);HPV8iuZ%d|ESZ?E6uZtod$NHxA@gN_k^-_g=T#%ndyWPA# z!Ev^S%x;nF{Z{6)&|cbnAma|plgAyF+v7I&*5p-MDX+L-rei3u=s`!Sxan zyI6kq!gzndI>5pTeolk&f8d7&`=wGFB+oOeb!pNY;;#`N5VyC&cOm*=UMEo8NY_`L z3Vm@a`-7c9{49CEKd7ijBz_Ldlj$3lTlCd=z_8rrAHiE#UMGA7a~b2?lJ*liVOPoT zqC5rr+2wf(A9fySi|7A3uy5lImIKMpb*#^;pHn@_1Gd2vpCP%pi1{OwM|)nvk70T8 zyuxw|Z>m?1f05(!JXXLj*&}ph`%Lp5fY(io8_n-oaJ=8=afbf4Jx(-_<;9Z68Me3J zYq`;RM#dA#Q7E@Bm|r}3N7aCD+p*;NRiOjmgO9MTVfJ~mUuXCsSl2Lmtjo|%$5kEL z|L1@s(1sHZ!5g#_y# z-czz}rs?s#;a@H1d9T2@lHnC}f-MUlAr&Z~-;Bzb1#O;qV z`eZriL3%~#NAUU;_6mEiVLlA)oGoWE@31_X55w}foGm9Y<@K*PoaM|JN$X#nw~VZB z+5I)T{?#BIy;|#EGX795?eR!3pnZX zWq1Te^!h=TOO?J_zR3uob z{|@ADcpPn>>RxbH@4Jn^AbJ4L1-7$4y9`+<9=9_aeM0=g@d3$?1AD1x|J`mVucP!l zXkRe*tM_*X>+31rciw(H)E%``*zb8ZeWzGnTd=Q+_?#SGJnUPXE%1HlP&9UzsY(N@dotO zf=xzm>Ud;saWM2za{L?k!;2vA$8r=R@v?GGuVa78N^m;tf5cBswkM%qY|EcK7Z{XR z*q;)V+xxsA9<2Am{V94M=1M0|@wQrt=QBtz2KzD%|2xY_-?t;u>W5x*zm59fz4nEY zcT)?X_e7uS{YmJD=z@K6tS?pn33{K=y6FDRcI3)uB%jUr^o9(-LtjFF2Ky+C{xth! z)@XfNuilXTA!hvngVfKJ(mKa@dH&QqN4aE(<`J#~mg&t#_tS{p4e4gnUHt#B+|s+s z=zF~n9P^U(JEHeMM={8E+3ip<13G!zP_KXsqvyo$s+iaJw#U|88-Gq0`*?{@j-h?8 zq~GKm#vTlV&L0IYiClX-9Lo20tGx1Ye+fUydz@N{Q{t3DT&QlrG*F+;@pDe?*wH)9 z`9IZiTkM+h1?*pYPgJ;%$R^re$G@Dnh}cwCyM=N%Qf^{$G~Z`R|9+gCFl=G!@)7ksZC&($=Z2tU~TJ}bKb zd&}|@fn(VR?@hlZ^Zv2SyDXkF`3QLYcpsP+10DM+=~?eB0uN-8=c+bJ+=zWXEN}EY8Ts!hPfZh-E1X-u zjO-Tn-SGXi+&_|{a|2|50eve+&N+B%EDmp&KRfyZJ16!49c9R$13%I}D)%n*hdhdV zxAcnw&M&y1)ANL%$ofL#3y)dJwX7Q|b+pz8PfPtJ$OXY)Yd-uRHW@y}d!TG@ z-@=bKHP7((&olg2G#Ng}Pa*!jv*#DS`^zT7x9NLUli}O=IkU;|?eU*c9lm#|=!bTs zx0B@CTVK7rZv8^}?TCDO2dj^-ZuqM$_=lPd-_kGMfhNP}cpxG_Z)h_7J_|pWH5oqb ztB=sv{bme4`C}YkxL>3D5qoU=RpRG|_Bz?m56dlo%Kdr`_!6gt?dyc!u$`s(Me+2F z7@mNp2JJZIw<7Sp*EbnHh<@$?$1iD2o3dG#Ngv zLq*|#zsc||{JT#!89v3i(eeLF9DYsxL;2}rBl@XM{osvJf06c{SIMyG9AKl z%g%VU;LG#VVf$vom*?2#557DvHD~xXKY4CE9u4-fu6BHR?--tcnE>_hJ`m)O)Z(w1 zI2Y?2-MF94NPMlbXUMsx*(^V&M(0=FgL3o!FDFgsnBbG){Tz$G0yg0I6^aLW)K;u$ z6zSTW>$EcMQ-3P0pWmV9N*G>7KVO?!ChxDvER*L`@ZKKemmTEu`8^jZy;SZyOQjy3 z=lTHkFYC_KAN=cb{v58spXdSW4$Z@VsXqL-A}(M&L7W=FKRpQfeB$5zqUZ^|PhYit ziRqy{vZIBL;TrlOEKio-pu7$HY(Zyy>h$0A^Pz1gaeLBVbUqK|=}Dgv--tdVzqQaY zRB^oG*M{ZE;|BL4V@w}E{QSrV@;ev^_FL`} zc`?`RSPvrk39jF3U4J}&y$CivS|9pycKL3LKi&V0^JmciHi3`-bIPx`9h_r(TVAcW z$)kK1@YghbV8cItp5d=;5WbK0@blWC@8_g%b^Aac+HvnM;^PbW;q}sAaQ)^c^>63r z=sAo+l)iW_h}U;ypR9W~z8?g)E5-Z2+|TKCF9+AB;ckU>9q)7-Zk(^Zy)iuuK=E?S zoA+U$V0Ln5^VO#6{nriO#@ogw!?(vz`L#kwmw*qTpXY@S|2y7a-SnuXM}Du#@U1+6 zcj`RDKc&g=ZF>K1gYa!VLw-agPvUK`;m76NJ3lVxI5&N*eoyyWikI8&Hhuw~6W};G zH^}SI$}L9UpH1)Q)^YLy-Y@FlecBu+=QdGX-1cd(HODVm-fz_QMdKHk_jEh@dp1y59VaiN@t8Qx{UV;@kacx=&-swU zaliW|#M=d>Ry~aM?zPZ9jp`+n2ip?If6cg%^1H`I;-F+dFpQ%tKeOR+TYig-H`GUU z!?*Q=l|S`f9>K!fmYea3lCh@+9GOB#f4zxwHW|J>{+}hoZ$Avp6UndH*K^+YWcU9+$^Fk6zGd&-|JP*r_V|A~&+vcTWcaj> z5!J7wO@?plr$4aZJGjO^@Hx}h)=z)jWcaj?H;SLP$KX?bnBOboewOZ6UU!uJ!IAQ0 zza`ukVfiiY-_?LG`LVElo$#^!vN1Z?@%ue7Jk6cHmcQlR8-v>o{BwTZ{XF9*+}~}l zHxi#58`;;IjGwT*jsIHkiBB4UZ~Jxb7vg@Kd9DcW7melbm%PfvAJ#fiZ#K{CYHD`t zbW8ADBF7)S8D9UR1v!dKmRxM&5OY3WdJV@l^R!-P;tb<+s^* z|3k|zRKR-&o`EQ`zuuT#=)gXNB)ibzKhJo-{yE0`+h&P(Z0}M*hz(AJO&3^f#X8 zcfkK0yY=^8`o{WntR43E#IMJ!>wVVsq;)-It}!zwb3C8=MLVsR;5w!H!t>$m=d7p6 z-ww_RL~Z>X;cTC~i=QvG;svvP?z-cB(dVvL_?6c4WqgtHM876dZu!eVhdGZ=&Y69q z&=)h6^HwPD2LJ9koA+m<&tFHzZR=|uSERhrdEY?uUeR9(&x9w{9Vt)lFKln)nc^eD zW1gRz!vz5L;lGmifq3tr{^^?WzLW~MJR|Frb@LlPZy4|!z`-A)C~OGt?HxxPe;eM< zd?T)Xb1rs9&c*gKYMT7-)!DpWKgrYjNyn2$U*dcvf>YsqY?NFp>n6D&_T!a%2E`{G z-^TRV&gJ-hY#l$=@bo#@*teLM^_ZMqC&}sat<8DYuB@vl*NvZtZO+Ng>T|QRCB0s< zmB&Hx!D=F&e%>66%;%`@^Za9aiu5%iK=jGD?H4xCxj30|v`uX9Z*!dzkbAB1}1ANYP=Zk}R#rf9aOYhw@ zpNJgUawdEq>Yrr356kO?&-jb&SsexI>v$8ep;ajyCRzb{bBwSG=kIp?vw zfH1^&!TVhyXVLfEq@D%$Uys)~-7n|!r4;%bh`vX{ydN-izQEJh@;(4OX$!^{eNxwZ z0hT{1`c~<4aF9Ll(QivQf9|IP*PK5Cd&l}W@55dW`M!$qYW54$dB3D5RH~okio}Ai zt@nB@f7O^bJJ?6o=*n*w80lkKPd7Hy-oZFMuIAU-of+L zgR%~+^|#7o^Mv=j)~Cawzueoh=K1XOG?kP7KJmFc^8k`NnZfosHK-unBYLfep-4$Wl+8w`gc(4Ez0MRUM2mD`FFyuD-8J?H``(J+ z2k(6tS2h1b#tEeXocBfWn5-`=`ym8}@GAO<{0z}oOEka1yg*)IXtG3yNEM{gi}m~!EJ@VDVZ+1GHy z@rh64=h}b|?}EZZ++p66wxVB;ljiku;YS)j-iycc<>wFvXdFCl^7{ilP2*kmnV@}D zd#UXT&VPhHV?0`Rh0a%s+&BFP?_F0)&Q1JNJ#X{=0BxVj&PfaOo>LHg%Ht31NTBze zb{CoXoA-p1edwq0%+)^7`HYNL-A{m*d9nwt z)n7%trM11uE!FfnN$efyOL`XamM6Z$Ig8E>kPF59`_JZJ`RtJB`Rpe0i=pS^cHl^02e8iwdIj-UmG>MPy)SxnHv0T_Emy3+ zB6`cx|4oyt_y1O|gb!!wcm1Zy)snbeE#GA14t8!G%))CSfm#k@as7Pp<;}n4%ik=% zOc{O8@Ao5pUPa&Y`v=6oH+oNZ%WON$Y## zx2I08q3`+JB{>hZrrxLVlfPeE?~}g;KYlr$M+xj4;$E|F#QUI?pNCyY?<9K&*A{Y# zcuwb?(wui%euDAK5Mq!$&DOnd_e8SC%YRq^E-y_sSL$upexHq=l8V#=VzF2ai8C-6x>%%zwE=t`N7-{5iIgGnf`2^wmu)S%=!(}R@f zTz<9TH}E6#Th`V&Kre%#q(N@=U)nJU+|(@;=gxP=d-Lzb3O|* z(R`L!qo1c@)~ z)L(wD;L|?8RGIhI>%4hz-m}TaDh+?5-cK^y_|u#d&*zv1c@QW&1k4xUKjl-#Nv`AX z%j^6PO?SwP=$-jFht7Ki;1>{I{6Enz_^+RXg1$wbzwZ6ql#d}jY4$7YbIRrmzB#9? zY4D-mV&m86lr;^$jURnZS<~R#<3A%#U-zz5p6Kemv-)!{o!YN}z|GZu@^dep$VrNP zirrk%WAvF>x0&DPUZ_8^o8B!N5C59X=id32e?jYDls8!I#P;LCkKjCFXI{@kLEo^x zpWFEvoi8)^0pXzUJNFsWboCXd`%mCX}=VG7m1$1y6AHwUpD{LZ8vPa^%rry zWyALt+xU<3Z^QlnN%j8SCoFvt__gr=65^502O6d~$0MDe)ASDg#^)s-G5L3#1=6ZmMo~S1fFpPuT9#Hqz(Q?ixKhyXQ@jNBA@%m^S#w@_m%G@5%)t36+=? zuUEr3<98ng|G3-7>rS#RlaH-4Q9Hix{UynB*F)9!=|svC*T*8|R=!W^yubU5!+Dhz z*r!JLcV|S8U>ve9Dx>)P03$!lAMlYXtzQNE!0@_UHPH2NuzsbWFv;&2n%lmd6&D#k zL;TDBi#sHF3~!&rtDdLh>BN0GD+UdJ$-bNwB@OSn-k0M*k6?Xd#cq>7fE@rnL3VlX zq4sNV&Hk04Q`dPi-U|Enh|Bog?z-v3?@0ljK1=+J&e3tTIB&(qI3LpD$uaBno&f}=Z*TFiU+26tEzol2FeJ=OWj`J|-qi8)c^{nhK>%#AwF&=194JV`b zd0{rhw@P2HHu*W^KhOs1;RId2f&6MBC|_f{R-VQK`$>G$^#;Lz%C8RJeFFKQn^6B+ zvtPx;FSG0iInWuxtHyf@`B=eAljnoAI_f7iWW&dMvlw5p4ve^_UHW(W1z)*!y1Y~H z1=gkd;5)$=>@MN!BMd*woXvcq`O2(&>h;JjsFfnm7yLnS)JEi~KwqpQGQS}IyjJ{% zbY`0R$?H7oaBhgk6d7nbp z1C`_u?}Nd7BIU_)7`C_NP}+xbYVVulbKoL!9&Zn!#ix({G2Ss4{OH4YZe@KF?C0}d z#Phhn;yfr1acoyuo;;7RJU$L3@0X9XPnt&q@Ksv#jqEES`tiKG;9Cn{L0=GGWt@86 zGY>d=--#RFchUuY&Gf&B@m85WHvN+E7PhzWhJ7b8?i9vNPi-1}JFeIH)TY6=@pC503*@O;__xQe z^QldPZ#^et&fiFWZWVf-<0IGy`F==$Kdiq$FW=x7lIP=jKQ1{>P&$z0J}`egZc^?e zC<4AviTtq^`hj|BGI@LaI?jffVAFX15Y`X=66g*&wWwgc^G~eGBl|$} zgB9oTEAPXoU!eLNcahzsc#&$Y&74NJ#cx6Wg8c~c^QWo4_9KG03(Ih7pywCbpGSpS zaTgY-$e;1E@;pQq>+V<|?8XR+tZy(xDzEc7h^}8@I@EqO)-U0QbuZQMo~L-L8*`Z9 z`Dp)7+bhN^^eM=o<1P4mpj*!_UEc>j$I>^q+$-SY|I6Yp;Vy79SH>J(gaTp;xB zxkKB@Q=GNTfAAZH4>QaUJ;;ADo`Utztce3SFG36;er-Gs==q?G&-)1cX88F%{l*?= zvdrJBa~v;pze3~vv`k+5b=NrKsK3e3H**ogSMHSf(O^xYx8rI*+8rnQ^&tLa{H1do zcRMOK#OHXSp3FD5Q`T{F2OQ#8-_6T?JjcTLMLGIaE#N2Mw_C@vJp)G0a{ONOo=1au zY~peFX56{0JU-pN=i3@@(-;R}z%k+dh&^vL_>}eW9{316?v|{`2W~Q#pojM8w<`?!}eyuf9fcq3!WEXx}-TihF;L??$-gmjG&eoj4LL4E_2l1bc+Zob?1Eg)U_9Q(p~ng<-HP!Tnda_Dd7@t% zDYyJuiCb4@D#GWuB~qRYKWuNo7r#5we^R_R5Gl9YYkLbmcu7C;fqp#-~9pAdVPvZT+C&#xvKdU%jj&CF7iSvz=TjQ1ZHd1cSm+=`X zuM@sXL7(uv`MC-5n>fDhS*-ar$fr2<#J7N><6AEt-}d~Q=0lEed;Yf~-aMj5q&#_E zVS5X2#-D>*==1zMiEn#W8#`qA3xQuJ@h8(A_RZ}3t2-XE&QtSl$9xLVk3ZD>Mts!> z{8fNQ_R;Kb`B;|j>Ct3Vf_G!p4)lbe;bF_bbjG;=bEU$ zYB9IRve~Mf!AdUTVI9<5v!~Y{GozLMs5P~$m zk6;;fsT^^G#3!8Z(S8~HusaCG1OPf%Cgk@7@;B2sSo6W*OQ;Pdmok@oe%|GOIS zIX~V2{JUzvZ*=^xBlw_?)?bR@;i{qa>)tD7yMDcLhxRKk=6POTkq=~^VRV17hd_qluZee*cKErYwAICC2!g725tS9FV zpX4c$Um||u{8I0$b$*G~wMcKIoO<$0fTQzE*0~+M*uy}0_Bg*3;RAbKHXkM9E!2k= z-U9uf#<+>TmsZFtG5=tGpfBxfV0t%__o)yEB(KwgpEwQx9_0It`uhs~eWiTUxY#dO z-h<2!@2JRcU{m7lEHY3ydAPnfDuJ7Kj}^vQYG; zQg`xwwcx{4U#(fF?X3C;-`^Z{_g}&FufaJMq=%I{fv<olNUAy?1JOD*bM$mwpr7?;95RaUM?#o`UrxlmowHILKaMzvNmOZ+epOYW7L? z;rGoL2S}vb2m1=Ik@jW#B&THG-|Y4;_J#W-tHO7mXyJX5eb;Ka44y-oWk0Y5Gc=F< zJk0|>0>d9l>3IbEQm+;~>1#P34R}vYXgsag<-A@^nC5Hj=gJfRII@1&_YsCqb|t6! z@L#3AD(%wxd4CiUJ)xha9i9`v0rWTir329-c*d{DU_BcCNne-nnOV;}r4Dt>*!bS;td!9u<@c`ziRJ zBR>boF!Nr?Hhi`Vk@7m>hyEJ~ z_)6$P`hd=T8?{{(zXsTF>anYUle{mn?_S|ov8#RmSP^f$9u+B1o>$o3!dtK}F@tfF zU!eCT!ara?q3C+thYUd@tfPM?W>zC01^a1`iwr*qAYaVVgTzlMl z|6kL_ZRhvTZu0mo_-6lK)5dS(=dAf1zjtPn;oIXsW1iuEzRB?G@>`*=+5dyweS_o< z`Xqk+&(`(Vt?O@?Yt{?LYyFsldqf6Pp4XDR2){Re)yFF8GcqyVk@7@+7Ad#&nT~Ie z>ehDNC~Be#DUEOHiNv3GXX9-$wKp2>c2V zm;DF%-a^O)!C^g`~t_< zVSTr5{z8A?i&fZnHv@Xe{+m@Ft;o-$M~;n@C-)b&xA|GxSC$vfzeMI^w>R-H&J$#Q zzef8jWLG13b;4{@;$=F|iTKml-G3nZ0AE+31K^9uP4Uc}_XCh$5{3WeCd0S&zV=7v zZTw%A@h9gK%JJnrCUS)md9IY64<$KS?ZnTkKs-U`-mZGDp|{p!*}0upu?o*C7MOlO z5b3wS4E$b+Ga#3I&hC7_KT7YPn%(ookPEhBt3Iy3KVjJ^;m4(fXT$&Sb36G`Kd)%+ zgHGML-tn0KovJ_6PpwG5>HC~-!nLV~>s9xl-chyd;f+{}sokpkQJ?5p3+{t#QPir3 zFh1lu!{_dKEVKCcEIt*hrQdeNEe}j%%9TDXUFS?3u2@d6>9egkSvsRsssyC!{q#eJ z^VKS#e5gkG;Z46kxM{=IO&c#cy|87|C1-5fWH*puR{X!ju5Vp?_Z~WI-HKi6`THZI z+s8&HM<%CAqf@a8F1zEdi{AR=(SvVv-o1bH=%@et`W2Dtv-s&y|Gud> zc?eV9>tpg$rGr!c{_&j?#o-ciwsCHXp9mKD}mn_40=fADKEh zIE9B?Dt<}_OWXHP#aKF4cl-W{35dj|gX5*`Q>Edp2hZKH1C$KvOdZ@UUt8enc07@Ht>!y}_Rb%jXFvY)f3D|B;N>+%~(b;|Aqk|j*T8y+B-gV$WNX?wf1B^Ym_?y+Q66o?$X3)X^%fSUfgcT7?d+weGJEc zeQ5$Ief`-nF}AltQ?6k~y|%n*tbARK^7S>!Us9p`%;Ka!UYhX7_itl4gaBSPF*dr> zj6axPh4$x;?m6UdI(zWAm#$myZ!eDe`zK3O^|(#v77UDv-;gG^Isu*q=yfNaIN*;L zCyINmu@T%ImsJ-4Emr<8W?hr=Jo!zJ!9K<2gVVtbD#UlN!5XrmEID)Q*M9by@(?mZ4v(sa!(9Sj2##mE)5R~ z4-HO?Y%iUxtL-dK4x)yXn41w0Xgf8weQZzQSxg-SnWp?5BNLOPrOqmBIqQ;h&p2bt zrmc}y;m?hQt%XZAZ#w79t!ITdBfsFw&;8T#=;PHIXYRYbS~1-F|9X66EY!70m8TAF z9h)ldff#Nc**j8RccQd!|HwpX_}l}fiCv{))b(R`oF%A)Nhr08>3~g<(hbBkM0;N_dh}3(@Q(XCQ5@7C6ZC;HH5Hdoxcl?Yk0%@ zRTv*Hjk19U;o$`u?laYLPo0PL%gUdL5^U-ysjl%vKL(3$RX-U21(QJUXoc~Qk5#u{ zXb+TcVlRmiZuPbu%B8Sv#JU?^qWy~~SgiCx`PMNlU`chVs?Q(YeI%((aIfw3y!dw* zIoZ$sd!|nIC--mPUYaycNO^f2&lDeN1_{7Me`x=(VwJu7_nhn_$k{Zpb8-t0*v{4#x9H09jneB>R=82*jG9bfmZ(W zT&>@ane@lB3E)xe8rjK8)#!bnZh&Z0yWoRGkhG_Y?xo%)cU2GHr^ZL3(=8j|WEd)x zmC=oTm+h-6AjQdpiS5iy(l4wR%nj>%^vAC|`SxGjbm#tOyZ1fu<6>sfz^yyKyW+Ti z>>9lGmltgL%g=y6Z5GW$K^Rn#-Aoz@%Ei82SllxLGh_VzD2z(K|Lw^S{&SMdci)KJc(=ph^T&> z@}~}-J2A3z1b&hET)Mlu0Ph&yVX7v6U-T#E2eeG85cV%x%&xQc2VcC~zE|Tq#=jwa z@-+M{lCIkz={f-Fs{yQ9ae7Vrkc|55(KDfa5gU?gzJFwN>ZB8N!)STAcE;P}s&#;} zWi`rMYm_gpQJ$?)e!=MO(Xq=$!5RM4q49F*-dxzS^^!Br-?ZtHEt}8XS_7C>4FANh zkRJ$;(=Fhy!!qBaP1unC${YFKJU%v-ZOJf$0ZL>{MF!<0}1wJP0$!W zPCD@?{}R2ne?zVAf!3rDe`*AN-c)h#xMV~r7+R+;fB&ODvD-wi_4vmHOaz8BS3S|n z3BM!#bK*VPcS7~pt!;1J9?_(+BDuKwl*0*k!&_IMawNP+_;vLuk0;!vy!c(_en>xq z0(M&`c^;^=(p0SQjd*iMabzN-d?1<90Pw@)7_&ya!j`Gx1Se=hLm2Dn@7n&UJ$A#o zh$(Zcj4nsN_bor+c5rKaqI8_@I%L|QwE7SKcfR-(ZCI)Hp*q#dw;uGvnPZt~@A#fl z)JfV?tZrYc!TyWud;YUpdHOAD?rN!40cBLDT9wXfg(z#QQC^j}HQIjvCtXkMtKt7* zGf>qJ_5@V@=*$Gv3pjnMs;g86=esv8zb@7u?x$U8^Y&#wvhPK&wVMjhRm*3zu*UD7 z{>z`9S+&a5Cs#L)SD!qz0UU|U#w0nYha-$z18Oz;h%L${8zzj2O}Z3A!d++68QnE&FUBa8+?K5*!qyFEU2@K*!uj~Qd9!Ja9f)sOQC0qtJ()Up9O;>< z3BUhTM6IJG1lk*eHQ`G~s`LN$-PJ`L4wKm5=t568ysE!`(0O20F_4txsx{W9{x`W* z%jM>NbXZnum8*1^iWR<#HJFRUeQ$B}5EK`$AM-+21z3rnlS-s5x!mE?4e)17|W<8+&!M&+p|A~l^PJj(5N`qiyU zEm^13kqgucK$5^i^(PqL48O13)lM^)+r;IRI>GtWa<121gIDrMDb<`h59k*nJ)l|* zT&0kIA@$FcLpzpne?7vB>YQo9HtTqaX5>H7X?7k0o&-oX(DHHby-KB;s9Y?)l=4#j z>L!Axl1xu8rKSgv>`CXGSK*mXdEv}$EY95 z$qdmuN;Pa&Ps3vkx+(9cIen4FmrM^b9;%1&Wl~IMmATyc61|_fJaG;^8}d?5Lj%?0 zsPv$E8RuUi@bnc@K0WNbo$}QVZU>D^4~pXz<_r8}{7!=TW63sYhdUtSq{b!f^zk?l z9v&BWouYCpyw?_j-45KUj{F+fhI2NnRBiZ>wL>6V1>Qe*e^WSU-?nA^BDA zg=km4_;fRkC$&TO-|(g3Q^S{rPYqvcKAkgPUKGoh?Wosb zzJ&Z#!yI>?+Dme2=R1z4UXJXp-e&b10)uV?3d#WmiO(;= zdwD#cYVqgObp94A|LKxX??VpS-AnOnlj?N0^0UPqcdXemMbP2L!JkU?HiYP+l!tMGJzg}T;W=j<<3>~!KLrCx z_}nWXMX>*iV84zKo}mPl!(W2s2XOWe79o$}(+pos1wj9x+%t8#=jn1Yi#49)Vy@>| z3HEauf2QHHjK>Y|h`hSbPUN^fn{>Goi!`3}BF6LV#2~>Ne0N;b$@4c`&9$?w-LOO zr}s2}C8!HA1J%jhas5Q91!mbiz9{emu_}dR)@(5RE^^ZCb5E z{t?4R*+ZI-UMBR3=c7fh)cDQ#<+$DC;guRcruU+sn07T}h0hnr_}y#9&lS1w7HWQ6 z`0?oYxo?s7Wj`+M%W6K)>ha6o9Od)u4E57d*_&nj78v=tMaD1t9vQy{(=vVw76_kb zZ{hJfKG*ScMgEAMByTGFCLUj(&(TgAzag|^KrN*L!sl6`Ll^P^M>f-a(WeZZvLbgq z3%Fm-cMP2t5+00SqoLCmqjYL~h0w{pPv```BmRP%=jc7hosQDU)pSDpUq*04C->z- zC->c&PP0)u0Zx4W1Dj6f{RQt~IzS%?pD%b5x5I0k5jwdyh3J$;&5cACci5d}JHH$4 zA-?^*Qtu!+>2YT`x1Px>MD4LR&LHo-?dj`lj!@$kjBX!uMC z_`3w2I1@Oi-`6Fjz0k=8O8+4t>1XQnNlBabpFHWXJx%~l{crw&#-p4aM2DtF1^<7W zeq!#;{j}S+Ef|L*)Nk!i7LCKS6FUxbrL!|z;{6W`oltLv>Gl?#?g7`c`~`H*qkW72 zO8ViB0AC*5crD=I-z89I;r1skvhef>9(uo*`q_DU_^U#{(Q36=b;H&`)bI@X#mw(3 zkmFFkdjNi8$RAeX|2L}tM8x3`;P!m95#_`FZ^xihtWgKbT&JBKc&ACI4_Fe~F*}eDs6y zSag2@)8UieOo@5_3cy#j1n_t|2XJei;8w!FWS;Ri&olm}8u7mn@8>Z}W}eRUM#{|7 znLbFHc{=w8X+2L@3#fjicj@>Nw+HDPbQVYK9Y=dnWd8nM9ajQU z6E{pb5`RQQj_m(XG+tH|SEBe7+Ortpw*u**7TrGBwba@We}n(wCk669jdJ;xdn)i@ z0FURx0B-Z)kqY=1Q9DERSBanJ!!!=mPnvg}1if!kB$pfyNbWawSM*8x_ga5b9A+;D zAJgdLL@y6%vI|;&ZN%hhDz;mvKZy-BH49aP+MUMSJ#K&%i^L3Z* z$MW*{-7C{PZ*Dwc<`X6kKF50Q)AcN~>hbAPr~W*w>se~mqblJ~XnG~r3%xMFBtK44 z(+lf1M6bVR{7aOF{}4lIhK47(abF5P$cOZG6X@M|ehuKZJls$Le~o%sEfIc& zzTvordk*NANB>nKH7$CC?VHc%ITIgsS|pxXwB94{&HCkfshs;4T7Na8zJZnx`s+Rv zR|S1rKBMK1J?9}yl8 za>#O)xQyjQ$HP<_>vPSR%bNK5jmduLe+=<5ZCXD z9#PIU!aofeslUO^fqsdTjz{y0K%UKeTK^~~FXeTb{6p?{a+}DrbB6BEYQc|w124HH zBF{p*F^lvdy4!@%a4S5W_`W* z)4skY{3IVTKYSh9m2df2NxqeF58(0R9>6WW_1Cp!os8s-=Tmt02J4?l8UN1LOU`Q1 zOQL6!M$e{<-N5=B{HLU1e~|Tcp8Pzs4zB$+R98y>tglMH`TkdV{pP+t>FeuWYLCA@ z2|Yq~Kqcl&Usuh*PX_(fm0DG$B?{IA8|5dPEtSD;7Y{jUHX&u;yt(PS0K;if6;oD$nzU3$g}i6kk|PB2XLFdZ({rb{pw6#_sxW# znYG{oY5KK>;;w-@#ZBSU)0y)`;6O7vVSG;zPW4se@}tth`Lq?fB4 zC*{)nXopIPzw7(IY2*LOzA0^&Qa?2Ip?8OR552c$8{1Wt;CWWlci67d`WE>~iwQBF zm`{t{c5+zP9ff_p1z)MbePW6EYw5v z=eR)nQ!*cS-)7OhmD}42i#soLci$eZukPb2{sHw<beH|`#h4S4JW==I$6#?u=-}@U zGkzTVlMA2RIi#8(pN3wID6Nu^OOaz=z8cvBJ3B@W#cvPvq1``<6At)zlxx%P_6qc? zb$srqfWO9hho&=xi|CAgzK!)=qnTH`@2XJ0#BooVKit2rfWOxM`ST70kl0U$e+hk+ zMvS9CeAcM_y(Y&KzrNUii_Qle^5^l_w_5Abb48EpdE`4q&%rMg{p@ z=Nmb)J38*7M1QH~^^6C?qxJAY=uOu5$u;sm^c=MV-IDhuF4lahuAk)T62R4*`lI&` zmx-HIir3rg9q&Q^^Hjf%!;-xk2;sNn2O z&Ck|)V!5WXaxMd1C@wDc;Xz~XkbepC7kkYLHbbrGZC3w<=VH_Yyv=KwUetey4=5*% z{jNd$&$ipy^8Ik%2Y9*pR*iPwy_4{xwc3B0#xxUlnYe`aeJisL(lg#}mFS=EE@GH~qEd+ofhajbD&t zyU_GWJ>HtHGoM2PNq)_K$3>`z#uG6ewjZoFxEZ`2-vC)TPUVfi>CZ=@`dF@sDy z{w&fn6puvwahWG^$kiqe$#H`caY)i@;W%XAuh{xY{EYx^`!ljXHGo@s*p)bB0Jrgr zo)6&F;=c*{qMUxLasH~>*#C!KaQfL!=s2V@cA_<G-IC+*P{@Byaey7ghPCg`6q3^%>JKg$UE6p zvp@Py@Kv7Dh$myul>0%f^SlwMl#VB#E_-YC1(`>Hi$E`z6|1V8R((F&eFP{_%oj;{e%?hRnlimk`n(g>v{_lIf=74 zdVdeflYCrr|70eehpW42w<__6+g-_;L2LwrGefb}xKhVuT4uF9QJB}lwkTKY#fIFj)Q#Vev#->MsExMow^?; z{o@uBecZp{`T{>aXY7rR#|Xa!@OXX<;1)mnej3R;^uPPJKK@f%_f3$02kNOmuKV&n z$Y7t&e@{K%C;p0i4(3CM69oIzoYXYQGsTTadd+^!oa}3I|IYXU4(~%FaS^$Mo&X-C z<^5SH4}Rcs(_}{m;15ZB3gwb<_cC|8X_Y$~IH*yS>MeQtc zFG1En4;Ftvfx8Lf47tX=2ZOX<&V8=N>&Hnla{qw7uORECa^l}L=r~Y=zJH)W-$#IR ziqI>;Jq6|-gS5WaAbmjg_m#M(K8rR|B# z3j=t(ehA=}ekfY!HS+;8U#O&y%dhj&e46bI^VvA@U-TXV7jv`Yq<3%Oe%|TLh(0e` zuakZT@c4cPaI2qsohhJ$t!K$j4utk?+3#yQpgYZoOepu&)L!(C>?h`#iuYIJY3RoO zJn(Lcd|3*8UoL?cj|S}R)5|t>!9y0sYhhq9l+zqH-KB?tJgsT zxXnMZZWO?)#IF`^r zHT}G@%K@+|xqz~lQBz%9D@_mecE-Q+*EK|X062;-P1{RKAxc9-S> zkdKi6ZQ*gh!R-wEZ=3#jJ+dws-_GED3%}N*6i*hrg$MkeKyGK|mriaay;`H*Hs^St zNAJg{@NoJqd}c)Xki@Tiwr1xnO`U>%# z=zQXnbKU2#04sIJ$-ny+^&{lRTXd3sh2ZgYDmf0O{dn>`!0d-Xn%1!by@oXTDGLyD zVZX(v8|bx{<&6E(1z6__>AC+t{yVQ5)j%h`?o`pv2tQ~&hWcb*TbJd}1@k&}w0)HvU@YoyK0`dM$~UikvKfPs@B^&RMKL+?4&fImJsMN2}M% zzP1f{y+4@Gw-|p;H8+U8UWQPx=y!c@P4cL;19pw$xzT-TEtiQLftu#r%v{#rX}_1$ zW8z5u`hHsS7a@+r?PzjU`@$!zJZk&~(Fdv(egO4<8KO~CZkaO|y+VA$^8}J3hx`TF zH^KEp_9V`aStP8T;$sQ-wwsc+Eq?@ z$Zz2rD9%=$xIIfL_|fW7bOYt-{zB)1mJhBRMgK76STG$))BKA4k?aTK^C^B7eqYZQ zc%Fy+I}BdEAHvi_e9U;$;7#afN+(q}=xh0#q_&8E=X@_`)KC0)5xq;qOBX&b;wP5A z4;F-mKOMm1`7eMM@sYM`CSLp-i=R$ce_x>c`&+6%)E`@3>)qeqh5AeU3;fuDOIoct zwV{e}{=Jqf(Np&poxl6I(WlVMSeLQ&<+KAiq56%!q%`SsOJB~J@1lCs+*6Fsme-r2 zFHwrlhtvJtGa`rfITb%nMi&*pz7XBaylQA5xKF0U{YlVViv1xsdVf-fpC7$HiR`bG zkKUg|a?0~QeZNt_=QiJno(|wu%1K519M=f(ZN2fcUY$q$a?kCl)8~aDIihtYrZ=8u zK5pVZecJAeoe2B@vktXO!?`_p{{~6VneU_bC>g#demkXmke9&MFTgIje~9*P&h3fX zThkuqTfUbWbgJfF<|X&*_MD{lg!sYc_c`fF*k6{P5FX1uWC>3mrF6XIG3z({R~`p@ zzonVS$vrYyk2mer{;$559_^=lW>l8q_chb4486#21HH0zUJFmIm*l}iKJ_>m(24r#t`$J`5lp41Bf`>pO;-B0+9JU`I% z!friD%esqFXKH=0OUf_V1I)UXdB*=xo$-@g zhUx!co$=fB|6HB%+wFg#&iL*2f40u}?e@Q+0{**1KP*95urBi5gZjeb|LY3%SF4}8 zE&Ttd&iE;Q6mI`>BKXOl5dU~P<%jHv?H7oj8rYk7KQ(|`{(!rq0)FwcgZHb%U$dQ{ z{)OrEj0l}-w?jNH3hD9xtTTR!Plwz8t2*Pi`RKpujGy);h1>sVo$=E?<1qfq>x|#F z)4!}Uep}D}tj_oo7JYtNXZ$vOo?B=9v>q28-{;jCzfJ$E>WrV}vElX?qWIlP`kCU< zt3vv_O8x2ngz5{uZ|Q&c-z|8R_-oeB#()2hC|zpCOZy_ibRViSeu_tg@$ZS?r+IV= z^Letv5;uM^!CPkid7U*5dObLR$B#n*x9xBx{IWkZc)#BG<^0k7;ph9bL-eb%{YCur zlIVQXk6-pU(eIFTX85~di!V0wSgdQbV^q!e$W(f>oEx3n_sACKzy>@&h2lY+bnz7$ zues;1GwJbn%I5bwWX1gX1Ln_nmE=#JzqbVNc=`u$i$9C#|HCTjf2dCM$6oXZ{g0hq z`nwxNPw0Kjs^#gROkBL;M|Ga>*!plPqOZWvHO6CXKVW>G@n1L3_$Q+H-PcmO<-;ZA zgX7g9c)WZB?^lwKYUi8wJb~MbSZ`{^&M@#N*)cjNOY1RY*GPYeUAu+p z^1hOEk@;T$kEcrjx9KA92XwRTCbe@QM0fjro3Gzu=^YaV2vY@!N88Uj%Cj*AG}{B{-W`|r%L{Z{-_84H(eFw|E7cgkMO^T@h3mu ztUK8AxzPy!R4-pPe%p?Y%`^Ueb;fVY*JO?OE9svP)QDfxzxhS;q#xg3pZ59uXY0qC z=NbQB)rh~+_`S78{I>kq@tn`p8NVHm+Fxh<_PW7Q8$ZswJQ3@?=gR$1?s<4VM0Q>A zK1+A4UQc$Az7V-aZ`pLY-^OeC1^-s(`G?)F;}zR9@;@9KT z{GK}5O?#d0-Sugoum5bleN6@Y->bks|7yc6z5J!9URFJce&_^4-&^`WMuyT5Jey@~swmEO7a%vgh z3#j8+CF59?yHz4#&7HI@07<6`pG`0O;XPL81_Z=6Im@g zTx~z?cI=I|qhcJ3)`M4t;wka-O+Oy9_+hm8RN@NuxZCTvKaRG$X1ehD2gqyq>z||e z-E$qjZ_}-o-j?3V(*C`CC?4V^Zui@QUv1L+_5NJan(yfxhr|*XX*^ej_H))7 zKksv%NBrc6RndOcE^*GH{rt8bve(PZ`J^7m4cj%?7udBW?>Ba>wso>4cNn_{#|3t6 z$$iGInR~mEk7qkMPwQmm~nE zg8p6U9Iq>?xvf(!`MRcmSBlp^A)Yc0|6Vi>ee*dEI&SULJxluZG}1kb?~LpDwVbCb zLH8EiL>n6?t&;97IA4_~duq|W1uHO&->es?y2D4V3*8}Wv2?fB zY37;kzTVN_#d0^|eEqH92bFYqKmU-!`}W;U*!Q1Ts&0Ox?H~OUjd#e8vF$-6KZ*Pc zIx*LlFQ)u5dbL*jTnT@T_PNM!+FFpNW z$;f=%9@X26kDXrqLG?M%V=ahH;+*YW-fePjP^aG)O{3g{y8NA7{=-FZoR?&L4>0`h zA~^g5hJQpqKf~odUQ`bE<)S_J+WFu=Cx!WM%Phk`9ff1xQMCP^vCCeIaXkv(d*nJ}(AjK-kSp$ltNZE~fe^&3s4qClO!Lc}-qN zsG9D4&d%pIAcFtcj>izbzm7dvIH%T6^I>4;dt_-_3B$dV+^5@<&gpnrj^-6hpJeo7 z`FnMN@tDNPGDAH7R1KSH{;(9Wl|1=XD#PEcT)Ii))A#2F-yf3iETNpf7uVdA+aPf? zC2_gn9$j<4Zd%{Bn;zEju^rqFvTHpwc>0_*2ukZW=HBntA=59pXQ%ZgI<3dc@#K6T zhC{}Q=GDPCp<_ssofY}O;*TD;J{dRMt5Mzk1m>K05~v3J@iXmDQ_K0BDxDkTapZe( zGv?kSgb(?9(XB`Pent7#;>#?_Q9dL`wwwvy2l^+T?*n+X_?dp8`YYhq_v(Rf)BVI> zMe}C*j_J#BuG52FyMVt6DRM;TP0vGqj`JZ0L|^_6s)3)u{NnNZ3;l7_@1eZlrTqbU z)nvn+6S$9gKrN#25xLgqLshBoj$xvKcA_|c2Rm^R(P#J$tt;eSuY^K<1AHroZlC#H zTH-R6Q}canxkr2%5b1k#5>?$N-r6Vn)_gw+vwIKqW`QqUZwu12|BSLD^}AOl`JUZY z$oCPF@3e^zICJ`LZ0q?}{W-25r_3Vt(6bG`-+cKyY+oI zi6O4Pp{V{+_2T>FRn@m6QeP7K!Beln*nzG1ein3_&I_xhx<9ET>*uAv7I}u=7X6ci zDxkRLIjKRJpJ@H9Qt2G&`J7&V*d_YQJtu9>B`2rZ4*2Je^Q13E18Q&sq@&CwR8Jen$6D59#YZiGxC4k{!bAN>$6*J_&k%iO?p=m?fxU*2$6q(Z3OcjE z@}b|GHujL;M>%~za3*>`aO-bnJlx+=zZjc*FNDU2>L+`-f#_l2!uQ~B!-q28o^?E0 zmvbZcxquJf3lyYYKJ-$1PSrlpeF))x_;i^kd(dFjS5p5c zwf@g6)#J04_=&`d(_pV0=@)$e%efhP%IJTDTMr-w*>K=@5s&qwXRtZxUft_;0$2g?;2ul?nrh@WZnzUa|8=<_yMQq~`=ze0M; z(*N3D3%=KUs&Yl^FMpIP3}2#G_z?U>_TEWoKE%EV;zQ$i{ZEyvB~iIr{wD1|Ktn3r ziNE{*}q>7+f911 zwBApPKF{GhN2JepC1{>T`ri0UTHhPLJ+Z!mzL)PaiCX@OGkPvUG+Y#^Vq*bTqjTR zj{R3eH*!QMzYSx+_9>0H7~4r_wXCOVIy#7x-OuHd?2oBa-mk^qF`)WL@63Ii=gF?C zxy?`7F4gq8P`)?S_5^+JxIb>|ofK?IwnO-^4P$tm^=cx;`{z`O<)iIfrFtpfOEKSK zy!m@9e!g;gW#1j{(Z!k~{&EzLN%f|46oN&bG=@~<0y13xmqrE|g;nQhWO`Hojw znSFq2nBztPUva;d|E;cHrI^o_KT@90(h7Qj`7)*XEY&Cb{Zf5%+!x66cu+{bmqGK~ z(*D^}Uimm1eE8VR&mewU|0(%ybL)={y&U;&bH;){YT&v&ZtyOU9NG6AHygVTPP>q( zq0=TFt2F+NGXJ0R{L{?$`94uU4gw;_`pL+3*w1Rq>2YWO7o`E2m;2ZB{akI(X%5R@ zRPR>3?~URy#E)jb-h)WzA&2vY{|$A<5A_ylzrO!#-rE1bJh%U|QT#Z6lB4yTY*YDt z&aK+7fWV!q{p5Ylt$U38X}h`K=(E$a&$$it5npF}H68Ffme0Rr`4_YfMt)Y06WJ#R zKZ4_kt?+3`k5J@9^gZ^6%Y3=2dnH<5Vdw+KgN(F3VCbX$i1hrPFQ)qHLXVHsi5~BN zZ0X_elSZ9YFC4$1y1ey_=G%e_?XN`jQ@lCYjb)X$?S7uzqi!>wl?_Yq;Jf={cLA+9Q}NJr;YY+8u>!L*sbnp zezqI=p>o+SNkcKu&pD0i_Q#_cQN56DhkihN@h9Kcu+A5?U0E}qu-$FDJgOJS4l@7w z-yuFd=ZogH4-#>-+b|bvf`2T}gYslL(f+Om{*@qO%j?xJ&iLI;lYbDno7bIWJt`Mj zuc7xiKl?b6=k`u-hUx+T<$wb6jXz%Br(&u-1dm-G3&E{8w9;|^>=_QnRoXry^mo@# zy%W1zb^!Fmc*^(Ev|U1){VOw0 zD{hze+TR74HuEjnms9;X@%NN5PIoY$Vel)=^S&$XmhZ^5ca-8!X;%my&!55jHh&Tw z!gRr~v4871gFN5KB{&|E^>FVv(^0L_`&uMFXXOv+@_i6V;cqEFM0`s0S7*}u&Iy#` zw7-sM_ID)6UrP3X?+NbVJ&wa9&!F|l#7Ws-w&F8pUkmmtFrJh?|A^kSQ#Cr>W8!m& zf8c#!K3BsxkY7z|gVWfql_NZ`pR}H_;_rn139meU_sTTexfS0s`&Ep8HOG2>p!rkN zJ%M=ay!7W6x<5lUetbWQ=_TvHnAbE*{Z6mYE3;a|TZLX=T`CWG5PHGx621Pw_|v2= zBXMc7?y1)!S3FDW0~3$gh&UC-7yCt+Ul4!p7r!Bynx=YkI*z(4GeqqQtw#!cC_SX- zSLaE5I%(D;1wI>Ik1Ucu-wvpu$hsu;kM#$&m-L5x7rwo{lpMnn5`N=f%ma1oZDr+<-r;gU&4Tr{HQeBU)q1$!uH8^ z_ z1MOqRWQNpNNxAb!Dq1kJ~$sl4_hTr=;&GMpOdyj1)1 zgr>s0E3MB%q~$zB8td*j2hsjaZMUe2?LbrIe5-vMxw5s~t8A zbjP1Hub?#XgG%W67W_SoTgNALc@Oj?KR@f+cm9qr9nU=ieAz$o$BpkPQFPvr=LIs} zosHT~p6~QC|G{q*K1?w`bo`s96V9bbJJMzzz;O{`0P$<1^MHB;bXq5Z9z?iZ$VQg1__Gmi4uCsbg1q^@B6s$oj}Xt*3S-cEz|qZ`I){5o#e z^hjpduXR*ri0^GdIq7d^kF4Wn4mz|R={4jeALm$@zJQ}%e29wa+YWqGe+SmQ9d1X4 zzoXpQ=l5e1x5G2-&g|g!>GwPPHQlDs4wmZ%-jCSvZ9`94AMcpf?ao4^NFImGdUl56 zlbtL4@2EDai%pMdf#d~CGAM)?@NQ>xE%@I4rsc_xX5?5{QGp^h6?=?XUMo<|2~gPlIO?J z3!2{m$GEhA!y1oX&G)pQ0R5qHk^Uuia67!TCv;CRpX%`-eaz=4vVV$swB}2G&zB$U zCnEZM)zBU3OKAQi^CL6g0#~G_slPdyCxzlol0Rhj|2Qo)zalk?88+cDaVaS`8!b0Y z`;!Mcw_5s<{B_Z{L#5(VCG_O)jU0imslCqiX@}AENeE=o?0~6p!cjp#8zilw*)ntC#`P7pACBJZ0 z2p-?x;C-vTGQSPIZ}(T|8N6R5ejJz4{pR^C`As~p?-c>-@YUa1VqvyA7bbj0U z6yZac=eM1MCF$le-2!-gzXG^LH{;JyT!qIK-zB8^Z3ldyBQ)L?9|V4#%s&}k%Y2OX zaSxyxJzvV|_6~B)zk79^@sqrT@$Z^v{5zxg z&3?|R=h@ahaM`o#gqO~-hUk$!D~h*fezfSF)#sM##xK_VH~WNnZvX0e#((ZS<9}il zKlsqtVOcL;tJ8D*erZ;huiJRq{G!`8Z}|J8^r$z#yT6!c{6E*@wMpV}ZuEXSu{X8o z`x5aP84vg+9EXAazl!V&>}n)!^3AjJvM9WBhn2oOn)cs&R#E=5xxVK{^Eq&|CXuk}8E#E)b_2rWO z1Xa}@g2(z3A-LsFWO+P8aN7?fzjIXxUM>Cs;-Ap_Hhzwehv3!XUsnNtjqNXr*E2qh zS552JU0<2&`gP|gv|srx?&p_E@`3a-fXCA@fLnY(Y)JD_Jb7I|`{W9At#RC3`#u}9 zPI9{F`iQ3MZ!6GM`WeuzR=V>2ULk(B<)KD-Ry;4mD2hJ8BuMKQ(JM$w+^`GlaRtm5 z+&lewvh0^K`*KrC_UZR&y+7CU;IEPWW7E7Jzw4`W<#TG!@woYm?hmaihx8-qPu82+ z3+8$J$Y0?3Gsoe5dS;(epF&XY#%X@F{wrvbYb9 z`%CdGq|xA|5+}pH7}86#e*S9CchbCX+|~Qar|G;q;q}+Gb$lzcNbJ`KIqrc$pkdU4$2t<*>*_S$hcUfG4cF2t7-|LOWWZ>B_iN%U_3kJl3c+}6Lg{YWEl2g#_ZA`aRG``gJ zwrNeCqIE6O8wsbH_!9V1 z$Cs>oJGvl)%!eFb3h{y6FPo3z`xWRVi*9~=DT#LP#dWKnDiK#={z3mRzI8b_Rbn0x zzfKE&x{de=bdcwl_46zG`Bi!9_66&-S>%{?Op2dV9G&Ey;)CGRmHRZGD)-eGzdXM$ zcG29Yq3t5pGig5q=?n4SPt{KHK8}_9=V~Xr3!1;o{Qx<~W4$MKA(&4LMe@O{($4HA z$W?yj-jZ_1auI^Z@=pkE@lSSh1^jFmL+@9KU!^cqkSpv1o~HGh?iZjtq@RoT0Z*qc zB)v}ULGLllWJf~lEoJrrgAd*-dYn+`V(m!)Q zpXq-$&e0agUwVwzUAl8+^giMNU^iZ$rtvvW<73_52`N0a@ez61H)nZyg|46HPb;sj z!1n<>o-YHq#rGs$#9u3Me#D{vzLw=6C~xa&-ft0V&#BZ`OWb8S+DHD9+4sclMY=?s zCuaQADaluret*5oLE6}3dY*2- zIaz1F+4#w}|BQ3g>>s;O`RJ#UOX~d_X8k;^{ps|e_Os=?HKqJ%qqkDzM?)`0{b;r~ zG521&#?ONqU_W~0QlkgMe&NayZEq8%ysSH}+*49c+3yI!;&Y z2wo+AUT@nA9;Cl+{Qpzk?}X;Rv{Q{g2t(J`tUkf`$ZtVnX-ErmSkbfA`M<^M4K1|MGgxX=Z zle*d-f>+y4ywCGRC2_27=zjxH?U8$-J+x>dcdSi-OGKBUKm z_>%09S&ujSHF%vI`8|nd85hjc!{c)K9LGf|xo;Tp4)K#^AKS{U{&?{D&Xv0~zN8)x z*>8yk=s1SLxtT8^i6`ItkxDhoeU~^NLu=Ct_UL5-(;D1iTPnPFC{oHTL0UzJXp1lb8@+)6bQeUEFkf#71 zFHZs7mV4TVF|cyl$8W=_9cKeB?L1<&kLFkGdgI>)CHqJ9eYH^JkS7XI@Odb6UdA)~ z^Rm}*e8_Xf&Ofr~W* zQt#vZjZ!}AEi~t`r2OqVKj-H^mCN6dGVh0Q|WMSQE&-IPvy$(tz+>&o%29_Yn9 z=?yQ%`Raizmrtt&3}30^1W4=lF3hriQFkto{kIFhm|9Ed8`rVEc(>25uak1gmr{Pu zWupI`6G@?yzfTTu&=>s5`{r;CtY6xjoFuxM^ItvB^Ur_j_xwu0JqNTs@z2rDv7RHko?Q8QRB(>1x_-P;;~z@se)#9@jtZT0 zTJC)Y-4hdk_C@x*neiv_Vg_f0HX0k+$je>!?U0E zQ})~;?ZWpEl^$QQe<|#XBk@}C zuV4c({=FpMVSe#w+;NUT@*OqXPVuYw^Hx0{621_>u;;TS>Bjr)Lh$&01@BvQ^UqtQ z9PtbFc`Llj;?F*{&iG6C?eXy; z=Iw_@H8 zKfuF$>Bt2d;~h4V1EL1koY_NWAP&--}n(jG9N;D_9wD~dLIFe z$AIrwU~t)gkmq(HE(RQYVXfnWTmY>?KHVQW&g~>VqPIQg^~#SoWw!xUh@a?MNWACY zr(Lve%IhN`{;8V3P#^fhyHMNbTe$vPO7b)5kyTy*kFPI)+x#r=mzEdun+8JtvEOIE zhv*)Fu%iLa-#7s%qJ+m;oV@yTkA3UPCLb` zRJy8r_`DYyy#fM}etWI&_sTp2a(P=i`0=-{05xy!WHr8I{Z7gB6PizjrsvlisU@ z_akgkbo>eL`QKTmHk``eN&J<3FZs$B-~QkhhOu447Z)b4@pczR_6@@jmirqH1M#(!yZ`$2cRl>o z=X^=+`Ox<9OCGrX6Zc*5ibu{Ie3A3I1EXjD=;t@Jh09m|?NI+cQ*QF`{N{?ortBP_kpJLsGk4gV8uKQHr@YbO>%FTBQ#-F&=LJPd z{z^VPlPd`X0Pvv-@EHU%PWcaP0UxO7FT#_nem?R3q7vmZBEuihXYAnc#KZ__KX(E> z?)>SpRXy(fq0fDFvvcF4XPp0<7r*Gk|NKyL_WSCi+rM!1tS7(VH~*M=-e254UiST? z=MPnYPnUxyJGRV}h4(El4}W-OcIwdJ6b121{S6-)-g#guA~KPpI}c1u43AE2Iy64K zb82|kjze2_?*=FOWu^{oEKC)wOdpD+fJ5Fc6!6CQHE(3n8yVd>2An$u$0nq9jg0Qm z1wwBY{fzKU5j2`Hm$GqXit_ySQ7@u(aLR{Ij_esNOdXi8Na@3O7j{mKO&s1hJU$sl zgS|Cn|MrcQXE7iDc;WE=0(8;DC8Og9g7NX;6T_3k69(tM0D=|MuwE=-I>j$EOZ^@g3MbF}5Ep zU+7OWQEePa9Y)D)>F zvb@J%h>m5E#kn2--!M`0I43F7&{2Vw`)*% zXmDa==P))Y@ZX-oWm264*UJu)##TIAyV_KUCDx_R^V zO*=ww1wS|DcjT|yvgy)`c3d1}hJL}3I!z>@G!x)viyy2FI zqdC!3*ggT%meo%OuHn%=a9Osj*)q1LD_XoL6{G)i;X((mEzR3h?iqSQ4e8z;H}~JN zdL1~A#^@q=Qcv+PP!UBwS=bG&y=$E}J~jpJ7%A+#j7u9bl!9ZCnE!TOd!7Cj|A1dK zHaUWskq1u(1RnGDjfGYESoz^shboN!b;AeaE7rMNwf#A3(xVA5nJ8|>H6wdiX&Sra zQ3eKW>YBo6m`MA|=vJy?@|yDDi>dLEaCeK^IvGqgieQv+-SyX%6@bDdwyl-o19|VPuj!77L?H^q=e>$P-V1Nz%!roJ%NWT|XI+-6NwT z=tk7Vf-gF<`|$RNO$j$9urIN%t9NhvK-{qTD8l+}%9}d0bz)@CNXT!yc5itB-o0zL zk1OuS6>q-GAIms+P`_v~yNu*sGI|lT8|H@OnjaV$omzXYE*ORvYd;)iwGmqB#a7x* zF0wPMbpQAN=2KQyrDR0Dg8q}I<87C4>IMm?0uwDDp6Xw+uX$)$g_qM6;LjM{J34m# zC^*BLIy_!1-COe8cU-mkvQ3+=+P-D$jta;uF#Hd%M10NH;gjXVFRCzER(+~MdG}h4 zS1?e1{K%i^M?2xe_ZJRf;yE@kGIeww>4W~ensWkMwzvmGzlq~ug@F&gB(MWHcrq_PCTOWGV{osSo+IaLWe}C)~ z3n#YkZQpj|*87iN+H%$BC*C#ql7Sfe(&xX7A8XJ1K}?OnkDDs& zAD4(KO?FnR7rx~yzqH>8r*-?s1x*NtyskRJg=2n)>gTw6xbB$Zk*upNEvQJTaf#T^N}NM&6f9 zc>(x?;2pC@w7~YM!UPA90z((6>61<0XpUr9iHNeaV3ZvF?mv4m*?!je#PHd=>VRo| zX!#%BpZ(1bX@g6-KPpoWzT=P=^c>4%`^WbUhn=K-h4S{b9PW4C)bStX;K`Tw-Ipy_ z05B?3u1IS+AYe@u;AIE5!n^46NW}a)I8}cBcyNFD{)PBwbsT?|FzbFx$gPMN zY#$;&VAWYY!@q;?5^?>xfPoiVetAEbe~e5`4(}@(%Mxyh-wG(l163<#{r2i6W^~7y)`6llt|Mi@go8NKITc5uDIdS>O^GtqZd}8FA#%G;h+PoD!r^d=bm3sEm zwm<9A4OeZ*@7QqhRhMqcUxuGswgm4Vc|luQ{ekGr)Yfr?f2Jn9-U~1*9v#L+extu; zeeFnj`PsR*yo!KBCiXqNP!=?=?62>)9$Z=QB`v;ah4}gJyz4dvMU)%bYukCxm R58nUH7k})kkFNdI{{?{ba|HkZ literal 0 HcmV?d00001 diff --git a/etc/multivm_bootloaders/vm_bitcoin/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_bitcoin/proved_batch.yul/proved_batch.yul.zbin new file mode 100644 index 0000000000000000000000000000000000000000..20d52844b5c91a02800b8566da918ebe80b5962d GIT binary patch literal 72928 zcmeHw34B~fegC|@-jgj`vTRG1b@++c1h)iilLVB5?8bITzz{ih5{^=9W3L^>wj@ik zV{=tDfe=VbI6^o=F=@i_=L&@$P-tutAStxvz7L0ltCWUv1VU;3|NefznRm>--PLMW z4j(=U;c(X_y(TrTlzUftjdP1~@MLZJa{TK! zzH^gOt@D*Sem?GxIVy8L*LPGO?vJMF9`!SF%`<#C)nvHO_dUTq9%r6}e++z@;mSRh zYFD=^wWw98!-P*|)6_5bcxnwlU&hbVT$AA`M?FJzP)Tm*u}T%`x#P5}SEAl0oOX;u z-95Cf-QnJ(d^Jdg)2mPqf7#Sg!vBfX5S3GEU_gBx_#D-)&R1!A0=z_-4CC*0hSVPP zZ>7+|{Z|a3z@^$VXDKy3ANPX_y#$6nuGOBofaqz;rBr4K-KTvT518Og6ZT_{kC7|) z-_YMr15XMp8tk~e|EFlUjmjnRM=3wEM%_s84ATksYMREkBAa(!jcYcOPfg(ZG))(k zQ#_iiJ522<D^MI&SPt=% z@jEG&$3>S&KitoO-$c)s$i1_Y`9OG>FYf0x{e9enAIc~C;<^$PqkBh}-@x!LJV`PC zb_m@49Lg8)^g3OB8SYo({&szTkH-5TI6?T13O*+z&mG7MKd1hK|KN8!^ZN^$-#O{e zw7Wq1MWRP?p)&fK)mP#l=l;=+^fe^nI_s-y!!imgg_)@y)04b==YaBkniZ9Vfj7{{nA%Tjg;; zPgsA=couEd-l%&Ikk&&%iQnc*GARjp5W^u_kO;T zg%CTk4CRSFs>8{g$##z9fjGi??S7B&b==bb0FOtx_r%*%Tt5Q;qy^8S{$K?DsW{wy zpay>CN2Gq8_=)anH%7A@a)xov!#G%<4c}GDVLj_{H65JON$*?l*Y;lxxDmQ2MZC?vEh#(9;Eg947lQ45=kORH+oT2RPfs);lzOn&D6it&gVM zk9D~Z>T*Z99K42A?myCk?@hYgu{5{q9?oZNr>R0Q>b-5EQx?kBA4Ig6o zmjw=~B{+y<@T3LLk8by z3Tz_0qQr=h4|&`{;M31H>4B#2|A>FrX%^QMESyFk*kuS zQ;zBAJ_J6J9^S0^lFbbh{}tgo2hab+$dM=gP`RtC(PzQg8h?-OSDyRTS*2er7Yp_U z{StXv(IRp_67WyUIaHSAeBL`P{=HK8=e<+<2YM3SAipB#-gI2fy_;y9j`F63e=QoX zcZ2ZHd!z6V`Y(FL`j0s22Ie1lNOBd(`2ggV%V{|VO!M#RIR8B1Zy@LBC-H9>{TNix z9_6V%{HwHH_2N0;xIakaTJT~+Cr{gh79N-LSB6gW2oLx--_Yr!aXQU^fzZi)kI<>6 zJ#))fKDyf3!UcQ#Qj(93mGnS zLM1hy=;A)?-pT&{*XR$)?S)Fc9XQkqSC1RdZ^U!-^)Nl}6+05xjd73R&Lf6DIhWc= zJx|lmft^Nu3cIP_DwW~;_FoF!@7@f519bbKDYl3qX#;UR!)1y2mOeyismftShyK7jgduh)1~YAcU- zqx2_`=TH28$uqQ2^mCT-oPuvC5Z$yqr=IZW%5&;W&3|ndz>Q>izFU`Tjmyd1L&DFt z&B9OR#^He+Z_)MtQ1#&hHRSl7-!nNr)Sw*0w#Vf7`bSxg|8j$l5o1~nf8~K44-G-Ct*8U^GSIHl? zU#HU=rz+NH`7Uo~-&3`Nx`9M!n`y8J@$k@2u!hc}XTyf(C7=y+4b zd=lqnBJkw#hV`v{Qce8rXn*w_;-~S=CH{pC;-~Q!zzwJd$Ll5!X5x0H51=b`K9t9U z`wjY@^8Sb;)ee2n{lWcp`W|eq7WaFLVtLZn>O3isn!I<$k^DI_$|NN1&M%k%V#wD=t#=BzxgRRC zlIkN-cczA~7rUj`2Ot)C>aUZ@(>$s55iFG{R%{nRA!p!GVHK_3* zoe#agU)L+sGsE}Pg~CsxXNYGA5Aq(OXQ|6rPxQJ5mXFuK6T2vpW`Dgr&G8cQqMWby zdeXx*E)RLjqXo5)*U#R9(hI;B)=N+9h;nrP)6Gfyu9pY>QYRgbr$T);^|bv_PC?4+ zdlS#8^k&g#=QKT@wIZLO3-JYEiRiPebB6j1IQL829~GyE`%s$s)Eek>z^4w~&Op_6 zibkKUc6y;V((XEqhu3S=3Qd35KRuqAwG-&G)s9Lv2mc{G4vL$R&u$yn^5;r>UN8Dx z0G%bCBa6rJ94@C5ecE0GHIa1~%FDI_PU{dzqT# zzu2v?e|7d>(Rwk-Tf5`aev7s*Fh7(xK<(mrcOZ|PhgCUkA6m6P&Vp5_pDAg+KYL&e z^GU5+i~Su+JsbQ7U)mN3pS;r`CuH9=-ZtpqVY2_L&<|=47DnfB*YG<2LfyZWczywa z(-)~r=$hJY>z6;s&-FYbt&Vl`{DSQf?DLSihT!QAsSkT#%}1oZr|v7+1x-$QsZ-$S@1x52&) z*`GlAru9+{F#RchB)Ks0U0|26;s>6Y=V@bSGsbT?1+q_R1#bYplf5p`_?Bos>UCu_ zSIPcdSeJc+EF35NUDfe>xpZK!2dI4Zl-cY0##6t&t`GkqrdOBpA!~@g7UDmWKOKLC zcEsLiA@NrTPnNe3ZpoV`@mC19@pE2&_IA?n{}jhxZz_wwVB3hEtRLqpS}zuTUR^_< zW&EMOCet^B+w}bt#y@BD_5PIb)3`9tJ`4YHe{s#sY~CI0x0C%z<@QlwqYm2@J^vnd zhEj+n%swl7-o0>C(;4xbBD>G>$@>^!#}MDba?5@`-Urx=5@O%T&td+#@abZgyeGu@ zqQuU1LOa$dteKbXH{v{E#4gv#Cq?--wyPP5cZ2vhYvNzo_Xn{ddSstzZgrT>)Gf3_^yj=l?lhT?duuGZcXEF_;c@4L?%vvXdrjx7 z_-`7g==(Zuud+TiYEPe31HZ^=*nYB{hH%TCs7|DEAgA7$&d(@bYr9RyX=mZSK+Kf= zwHPkP;jORH{1-aRGjs^{Kbkm>Dgd_N4eJcyt8Z2uTlOyxd#3Q=N%+wh!>$;BySk!{cP`A&Ai%sN{#j9be-5ayu5E4>%Oh<8S3!ZAZ@( zJ1X+qzDLKAS&erd@QzSPud%?W4MV(x*!RS2G$9?fWABhj}kMuBw%<=lpwE-#ZuMFHrkB59@)?gCX43 zBeQ z^j61D(`FyMiJzDcfUcZbJms1B<~;C=@_<+`oXI}*)|)kb$-aRfEnm_1JfEcQ>HWyv zjxTasE{9RMr{$UB6z?w9dK1j=FwaI@&?fuKP(b9m=@*-zIm<>JM>EQU&%aIne|PXPqqTU@sYPYiP&KDdx$!tdttxc+e-4LS}IJyP|}b5G4YTJe5?Xx>x% zr7-WAHvD}u>%)sk&K3Cw$}3U6hw_~eD$aM#$Cd0EghTs}`tqI#+N561yk~=XL$6le zQ`Vuw_#s&@L%5}vp3iz8!fkupVEm#?Jlf{)JjLWa!}%GnBZP4*#Y3#G{9MOfh>!n_ z`U$F&T_-thPfOfj@?rB+d5KRPy)K6Gq~EarKFhVqH>M~)A^x%bIQwD54X#GHKGGwZZ*AlDD*JDdmk^%ZUI@3_Gw*THItT2( zHw+ampmhv)R{7G@AM>T+=X5?IT;KZrwDT(^zIE?HUK{h_aDCUwOp`uSexJ0@>|@AF ze%ULUIKbicTT)Nip8`7pJh+$o$AWw`mzyR(GKf5u#C0f_PI_-xsl4oSfMUvfsrmT6 zbob3hkCEc1epc9*-V(h3lKft(`&#x}!G2!%-5PKBKB~NTs`sn6_?f);ZCCHNaP@nq zu6_>{?`OfTgzu;3uF&tN>i1c*`(<6c!uzS(PPKtPMT#f$uuC_>{2~K(9QQ5oAJO-w zy;}LvM(6u>ew6W{Unah1hJ}+VLhi z%aQaipttvE=kXeh)6BjU87xH^_7h;kNupz9od$iC@88V!R|LBDXKmc?z>W(e2ciH|)Uv zlaDYy$?J8j%d6iKa>*aI!RL_Q@pkdJD$iR)9z%HYxI(x^H`R-{faW1IZ=q`!^b@%g z;$wmQAdOqrd*XRP3y*g-_cM&IZTiCw#`0;&{S50{__f~X{3QA%b~V)7T6VQTI(fC$ zM{GZqJiaP?0DVAz?<~;2K;x@mM~xjb`K~st&mB7c?`6C8?Pb4XyB5I%MnXTm&xpRd z-$XrbM=fSQ+3CQq~ z2zrgkdKLM(0n*2rtyhI|T9se(zS?zp-2W(JPnJ5Ok0J+zZ$RN)G4C44Ni{zy;|~2` zvK)r+xSlN~HRW})IG&{}8Q_1}Iw$8lBYxX%uhDh02Knecnduekoo$z-{~_G&f30<^ z-Hbo9TQ+_oXmlMR8Gl$m&JX47A^fCo63*k`TCayJdL;E8~0PS@+4^G8+ zo`!k}`Jp8!Y4R;q^E=jj;!QJMA809QKem^~5sBk1I?1>q@MJoLe6r}I?Gceh-ouQ) zhZfp31wz0M&ReJBmVj=c*KS36#{PZY*)cm8#%s0wOoM))rk|nrJXSYAC$7(Sth%3p z+#s)@?HJm-pX0e+E1nDIbrwIB#B(7$nV%ut;-`-1Lb#2;(RruDb6~dUN6SCxc+Tug z>_)!y8WM&XiVy_k<4}=XKp+T|UM8=-Y>3 zCM3RCtJkerUt4~u^;M6@nTDMkBs`Mu^PYDeq+r#~a8Lkg+)cJjn z^N8i^!>Ydb+!nr5^Ha;myuTCqaKCNFq24BfVd<$H~)tTlL^Q6S9lJ{!JtQ*e`@}v|kKE0=ww`80Bxp z{dtmiQ}fftp6Y!~&>!Lp)|85DM+eT-`;+AT36$MxQuf(iBpp*Lj*b4bmz5iA%!al&_`Bm2a8r_Fei|-QuSLUm+_rd!D zV((!NDR2GSAm3%n0}&p4@+MHOfE#1yB68~7 zL@(q#$>rznd|YsIx=38SJIbuTr!9Y*3X>J-c4GM#4g=Y_TB~Lxd?s&Kkrwt?c=n0 zPr%qmx+nW>*~gj6ooC`J(;r!<#bB%3NwJS8MehaDxx>&udQYKjUu6)FqNCa`iobN| z+>G$tW7kPKHv^VR;(F`cjOD@e__-P6Z+RZz#m~(kz2&@xKG!0Yb6al2E{E_s^`s_# z&dWvQw%PdEj?N)|nP1PIKD3@z05^=^G4lb^BYH2=%5TfNs(eF<7sbCmo}(Y$o2=&)#}9VgR>{tKZx(!DljJuxNW71Dj`7obXR=Sn zNllZKBkv>ocd+l~R=$_#$5M3ufeQ8kDM!w0cuQ;^-mrXjTo(8_nLnZ98H(p1kCdNr z??rpaqqz4;y8v*U;r@#rC*nl57n)w!Z7TPaUn4%Q()Qq2QhpJ}h?Y&4>2qb1@!Rrq#T?^* zZgu?L3&cLOeLq>hy$h?u>$WenUp%6pIOVyy^1<%`x%pQZ6d`S61nof`MEl#h(y_imh9{O*4?8NcPny_Yu`zio$K+GPAG;EU4#NF0An z`KSEo>WF^SDWBe7P_frpfp%y>frnWc-$0aDN)ZPxI^y=KJJlB(F^63mtzQ%=;`o z(EA-ic(NXZaLdnlweZXS=dgaW@smGa9T{J<@l!n20DfDay~XkQXt0lUh2zWj)A0Vw z1h|Lu0g*pa3;x^8bJH@<&1PhNt+E%%`K;M2znA9V9L~E?&wR(sNz-{J_{;Eqjs-u4 z81VcR0*XB9!ZjMNIsd6A?NfUyt>53F_evOFM!&b2St8%z$SjffQ}F$vb7^$Q6Wl=U zq!-I`XR(ySd%TT>GZtg<{I`PgeU7)0B?Vc;I-*qbDpI4Bed;GuJ0Xca2{s%J5{b^d~Ab&u5C;s5^%(#ksY>z6Wj5ZpUV1NXFkZ6hYU|zQ)!Uz`T?qJQ(`{>$@!S2U_6ng~ zG;B94xpV(Fjz5sIpUhIuYU%m2;_cNv9vi=vC-I&+$M`oj8NZcB@}AKkep??X4vOTF zye-x7doQZ4kKPO8agh6U!Poy=tZQTLY}*a*s<_?2x%g}J_t)1@{-EtQCQib86PSCd zY;K6x<&|5Eeixm-yRP#F2YCO0gYTr%xKwT<+FcVTneVSV`n(H$ zZby)Z$m;Vhva2K?kX@zo1H3QIQ7K>Y2F`$fKA`gkn|0n`3H8U!TivhWy%wyYQi6i_ z9}GL32LYYp=p4T^E z-)wte+t2gj^l7;Nw!OKw$@s|+NA>k!gZORw*z2NCZ!&(H{+BcvzqKCcozozGTRu4t z4D~hoHP&SOq<<0qx+j~A-(L6lU6b)!{r6Op@!S3|)nxp3|4Cj8<@Trjlkxb+zMu8J zE!!W{K9+>`XN}(;AKqVVDt^oUx&PB-{8sSfqlKR z=C5u4-qvLNv=2E-pTCabr~E9R-|OB@&nvH6%l_sFJUPw?_jOothWqIn_(_i%Sa-+v z(Z={-&!av={SEENtodujNAADJ@OD#Rsrn#4U!mubeYf^{Dapy|2t1ko;r@1;{d|nZpH*Dq47vWr>qU1y4dGp?Ep4SD{%+?tf9RT?VPj80TFDYK9dBmc> zGV=y=zF&GJ&qL;Dz0u4YR5#X5VHeDLR~dck-5*SLD5}T%NM11Bje5WEXXRecN4kt$ z>2>l@E^N6Hy$j)W%2iGL4a#jz{0+)&P5czU)S(xuTh@ch-X}s_6Jq^Cea->Gs!P> zY<`sKe(Ncw`&(y7_wgpt{pt#IpFXv85B#zI9@DJ-F|TjKtD1EYD{gncNc=SMV#jOx ze<1IbcF6nIsza}1cHli(yqA4*8T`#MKkYcGuea$da*qz;8afXg^=^&V!~UdLJFuVe z``fJh+pYUM%soctWS+>UmQl)g5$;o}FFfDQeouUw;_cv^LzK?wIOHy&1LuwL9y;FN zGUqHy{`8o`@5{!|$LiWL)AzBwBE58C)gBe-a((tB|H_*_Xgy8S?9Yv9-Cdn$Y%ocG_B%|GZnggE0ypUd7F@I&vDZOOylksJ;a zefj$+qGw8-#`5BG{rPr1lxMu&9YnA2`xz+5?*%(2a4!5He-}~fwSLc6Ih$Euz!;Ld z;5)X^v*`DIQYW!`cq2Yv^{|{Tm{MqOP$8Pu@)UgUD0P|Oi+#@k9teWnhksS7uJ0Pq zF^9*A9{L;~WDk6_+d_ymKH8s**@5KG@Hp1K`966k^!qU33F3R4S4?(7rOM7>%9DN3 z=jwN22VSiGJhzYCv$6Jx%A#i~75iR%@V)XSm^YFh;(NdKeAl=0u~z%T+&)%et@bOm zTW@>oV(q12AAI#%@D5_d=jxzYdhc5;*5k=wpE=}W@s~uOVYf;CAV@F;7%#pLF(m7@ z+J37{HcxcV>-FOuV!zzGvgZBr^fbZAezfDNWFI;3nD|BD$4nl{>0o=x-`xuQ3H8@^ zUdO$5(w9RvYT2a}1~?e;pO&3a8NheL{vOtL%dG#A{l)k@@6dF^IXIFpgFc;$IN_Zb z1!Bj}cL?08ZlA$bv_o>TQsOwMCE0=Cyt|qD*&22l2yK6>);MpC_+2Ca@0Rg;??OMS z#UIj7C;@2R7olUay{sIE5FXYOwnr3ah`m~5^v9v|!rpng?hn2yDg5V?3}m2?l}dqr%d(_1ZDxH(ILWH{U}i|1d!PnXP}I^ChF>2d=GsSe}}xpO|VnO{sS&{UbmA;`()>q=sbS?c0M;ub_{lYSo}dw+xhIU*!k>6 zvg5GxaX)Y@@B`Qv1iOOySC#KO8oMucbSC!v`&zHqensq-W&fL|SMT|wUWpveFz)(8 z)vHBuy;_QOv*Toc6#U#;xCQ8%!}p}8r$8=0_(!??!;;ICvG--)$4RjF{QU%p?~UEp z@s^J7mp)VMWM#Xb6?>k~$Uf5@DVnE|y^qK3n7@dfzZ84!Mc*)9%zMqg0`Egseja`yy^Hh`p)K?h^EsV&N^{<6Y01Q8S@Ea!@3TFN z{PEJ~>v#zJXNhhUh|u#c%=C&Jmmn`D^P#n}KB(!4_k3mlZZ=KhK)u=Sx8?7tPI9=i!$HZO9K z+bsQ)?+Ip=*~hI)lJ5-UipRC|J-U6BVL4m+iRyBeRcX#=VI*44GAs4_;45diuiLy2 zF5m5`KHpxp%HDmClVu|FqwP?<|s>1>a?z+xJwu&>qRP_hC&3?CeOA zbMGoEzR2l$zzQe+K6_U7FLmzIslBGq z<8@7<$EzM)dIb9+v>)l(RDnM45P9he3m4@ z`%#{cnEX4=Ap{pzOK$tvln-y*r&ey{B#T z(EEVg!^6lq3uW(XHYg|c?K4IVCHib0YSS4f@@#GvjuF^px?QBEM_w=*->^ zMIP-3n8CCmK9=iNYu}X%LJ}$AYoWP+Iuq67=ic9uJ}-Nu z`aYcq{F7*+fZAp~2J44vFao#o&`Rh1y{yA|m9C>gfA?R-jsTDOp2qC<<>2!}X#cmt z`jvvgq_|^vcKdR=USZ@6^Iwi%++mrodi!L)>UnxTowzTj>#&ip9Pi8NdV|Jys`uqM zup?L>>B3s>aWj9Rb#SG>+o=5#?m50Pd|Gxy`deY&9!VLWJ8tY8>oM?FT4xOQPw{tN zz^5OPJfm?mjCF4Cslq((F6p;?=VjS%D#_tOKhRft?%>dgaz?c&E?{qD$o=cS0}tU82{w7=M-}JF0JH-BYheE_<@J z2PPl00eLF$7wd>DFUUWyk+>n9nWlE~I*+;|H%xSitVarbI9QK7OY+lcvmPn%W6|}< zGW`quKqWn-{*wLh_#C!nzpkW*iq5TB9f2q7VOZbRL#ZF?={=Bp(I5Fv1nplLjOcm1 zK9m-Jee@6OGYaEJANq4Y+nZoNpZ64i3de?n&A(*2h4n4E zVc&`LJB5Bz|6SB+ZEv}0D52bKX894$1N0>td7Jb$^8lI+x_ACXbufhe$n=a zFq^ZBSLVnMYW)l8n>^kSZjV>fx9guVU}L`;$#>fGR-I2>_KPOruaHljGyFQA+BEz& zeRMvxY4~mW=zMC^@Z0^@`P8Q2x89R6=X)f-w+cJY^CS2Nxjv$=ztz|Ok*n6{C-Qz= z3SD7zpvip@{`kB}x!(k+K;=0;YoQ+~msY;w?=@n!+AeX5jvMe^u*8j+Ex=Dh%H_L6 zS@ypk9(15S42i?vcV6BucC8z+XH?&?jLLRT<-{H?$Nr_`q>olTY_CpX#Sa^^$xM%@?WEn#={bYCBNryO=>dpF#fy zdmgXjc|ucT-h~A!if8<+ybqDZx;xefyU*5si@HegI^TonejeKN6?es17fIn1y;EWcONDOeB9nt1@PN00zWT$_o_1D1bD`se)< z;%3D8%P%wjIFse|`xQB!FLb|9)BS=>UfOk6I^!sheL_XzkIG!h_?0^)aWq7e`0cp5 zJ$Ib=xBQ5vM>@yzZbu>Ry+O*!cyqgC9XEHtA$j%PygbKyEKFa((XMKNJb}L5z(?&b zzXnZlKXUwCcY1yFu=Hyq_ro{+&TZxX>H0m`XIY?f)9A+_uFB>8h|51_=qc;t%l};W zy9Fvm`Z#RXvvZuET>fxSUg)OMX9+#BTZA5{$Mnc*dWbwPzg^S+V=^xw`VVlwF~5SI z2km0vNcfQ!J$Rqthv`RZmBkOe??0Q7ex&sG?m-ytM@shtmM+E@`CeLZ9vZ?>p?~T$ z;S2VMGGEd>KZae<>+gVrFWn!u_%VR?SdOuu0OKLP$oNuQxgUPk7rLidPBlMTKw&!JacL`$+a!?Co%+{8R-y`Awrov$T`YW0qrMCx5K*Jz91WdUYIf z?EN#@wVtO`oR7hds_qCpF|Likt+-a^tvzQ|#Lx4V2s{~oSl_}gad)Ksr1{=p1a8;2 z{6shC;*fq*d_{Hy@`mxB+20Ba+D7+0zl9LsM_j+f`R5qR== z!}?Z#Wquo}Z;w~#8P=~8ze)xEkKUW0xJju#=&^aPFvzDk^~`U9N6&A)`24n~SIZ&K zZ+o6lk!}?Kua3Zz#}(GM=w{+MgoQry)sy+{@*(4gtUP28*EMN>%QEzz{Fm8(au4nc zu(z;%EN>)Njm-D@E&LyEGJg9!uwOJ8zcrt6e>KPWe;LPb_H)*~uc#AvqI}iw{}{f` z8ZW&M9>x2Scz@XrH6kw-y}jd2#&6Gmk2M*;-T%Ai82_i{82=~Z_|5sxuoyEtm*1wx zy>Wa^mzPh^G5$}?G5(j$G5+fWe{#MATy50eSIEzZ-9cRP1Bq995X(5{!*9m!;dl7C zx%RAy!+X|Q_h-iMgL+Rcd;Sz|@0|Gap7X5x^UXaG0_T@dJVl`vh{o|bf-c-4?oh{4 zI-kRNAWYKuIVQ^}OK{8^WPZZ=9vznmKZN zI}RC__3PgERg?o6X9!QGV+gn8fW(mIqqxd>GrX^&3SArJn|+=Q<2!|P{e-3~pJ!8r zt}@P$ZjI9Q-{w}I70=7SMX@KC1Zn$X^2kc^hCM%$dAs*in5Y8rUGaA~g84-T_mqEG zS>HYl@3FFfY?}Au_ue^UIY)m;&TTm~ICvf z$d7rSPwV&3fQQNWx#t9aZ1-Bv+w(J=T1;UGN)-R@`lXX5##-uG0bC(IQ17Q&P1 z8NzLP45EG^Qr{jw+sO#LPW+@#+AhS-<>*BYx=3~`!}NzVIrZe1AeTD7WS!g5`&KQ7 zoL`E_fjur;j*`a}+AWK2f&EXT-^AayRLCo_{9v5mZ&TizsxS{oo_9c=en9dBI>`0? z`uYKVy;H8be^}e|zRL3OiHhk_b=ydFx5%=-q-zA_(Gc)g=#AKOvi^V$AAxZozfD(7poPT_rRp7A4Z z=lzD6dE!Tp%@=#A)JOTbn)fa$uU5|2epbDQpKp-zE&hD7Z&AwMuAk?F=TGPI*Wnxs zw(sgpzTbg$61o2n-DmyuO?01C8TJc(H=ui@FMfuft9x3wd{)h4c<)1^Pq^3po!`QC zUA=dntW(ebOa^PeIQZopTBqs#iN>eWua|P^m(ugTn?-+|6KSDSu$}}s`3ZfG{gP{> zzv)S$tJx>ncQn{1sp|*(B(IbDW&0$jWZ&P+_AmB@`y{L4cOPoueUg2%+$Y(0kI*5N zhu>$uG(SZ6PixzG@RF~Ng4Pa`?>PePe;}d`@Y5aVSF*y z?!&(-^+lv`^7x%mD^ z9jD;Aj;m6cX=(@K)bR?R$A$e4YhwE@kI6bGIwa?HsZ>^V_y5LP&jTK_j;H86Di{-v zQ}Az&;v5jejF?;r~XH z`CC`q3VY4*pHltvN$+4!;`g3)KhL_KZ|>PHJW<=n6v8QTnDV}sWzBHl^`c_uruIs#9Y=divl&r&~>cRQ}({7Ym! zc6~D+cEER%_rKHe3i;JYUY#i0l=(89=M?o@4-$XS?%$#Tmh%SvImIPW{NHIZe%tQr zcx2A{|A6#AIiCQoSn-edJ<%%w^qf z{g0sCC!k*NU1Dy#%0DOZR}q~4%a`2#scDF0rN5SC&zd+|5l*=2@2cWt>7r7p5|XOV z)At_DS1SPca1Hp;jn5w1xPI%#4cjg(Y}vT&qKzBv3ewGr|1Pr2Tle1GhmKm0Vz+wy z{>bR|vC+wq$*I!lRIEVxO^jI2{N96Cmlvt}WMve(t2A|4@!IucJ4zQ9C$IK*7Dx7! zc0>x`bmI@b^X5D6{lfG9UG4hdmhnsOx%ML;yYf{Jt{Qr=^ZNaxtA707H+Dse&)}y+ z?fa(S4(`C=14<2*g@F%};k@NCjpLX7BU-II= z{nn?`$G)%re#^fcIsM!h{`PB`=fCWBtou~?J96G|6{u22s<)qBzUgSS`stNRtHbX- zdTi?8(9}c~B&CC;?fa)cf6o_`#WBcM3oRnMZ*oi z@1DHvt{U*~jE;?-QQA8`b;wU1K(+ehJ!`<7fNYRUe|KqOw6w>c94~G+Yz*K`Rv+E* zUr?GrT3`R|oEY0%p(>X!y1HP^X{7DtyPb*IP*`{&Q`+EjH!G3f2lyK?^whMF!Bqr`t1K&K7XQG<;*=Ft_DU}|Imq%vC!5g6`ne{ zb!@7*2Wq%!Wba6M*@@D={UZ~l9hV*`OPawb^nR_VEIOl(vldy9mcJ2)kvhp_)pY-98FRy z{Q9MU3B=zfSKRMGCRX-$ZHW{?Q$e0~wR4 zoIl=H)x;i}tnQn3k5`wEXxEZ>Rcms%1=`{71wV?rN~|ArQhVg@3ir+TMs8>FGiJl0 z{s%2>TKi12RT|xekYv-kO=G)yYhX;U@A+tz1J_iReJXdkp3p-3%jVVu-?a7|NG9>{ zX^51b>VuInLp@pC39G#09DjU_QUfE!J(qE5L#9gbb%Y#$+ppOtKPvo-xMgf|1T!li zkqQ_v=I( zzzC7{RI$C(!sOM}(+5-IBhlfO^>s3ws+7U#!MFx5J#~0QHFf zLAMGQUXqAsWRg3c2&0D>ANfBFKY4(YWRuA_S1`)DeR3c>M@C1`&6s(qKEM0f$L~U{ zIkNN6mYC0pb~f}siRjh4HorfKZ2^j?eVg*94qiGjvTGy~mtC{Fx&rUqu`|Gx^yA7m zT^8^%2_CjDR?IH5=KG)hxc#igeN28s{1j>UTO?h$Uebj?L<@bh{Y$TGAC_KUGWs-F zU(8KuYOsG~bn5IgHPR@&+&bgyi8UHuQUi{c+^ha!?|0R|Y*i@y&*<*av1>;m8UECv z@pA3nRM@h0+eMdc+_-Jarc1ZhKxTmvpZFE>bAb(?te(D6#mTDXQx&UEztwmR2NmR> zf8$5;q=&#~iyx5WuIx zoQ}aw*8on5o+v>7zH7yUe!}D6QK&zZ|3)YMahg5{@LNCqYwrV}dd`L;Z~4;oADKU~ zWq0@HmtT6<@n>~xyKmwhLw_-t;9ph-mGR^3vwnefv&w%kt9xKIDa9}~f;exgxOZGK zvNRc5t6ub$&;O!wZKZVo#|2FUhg4Vi*hI4@jazzkhG^*-M?1DecO%8|En52{mPXeYpGTMFe+26 zNM|)5U~M(vRhe6(?)QGN?16nX;$OE04(vs!`lmA!FfWkwsj8t;8J_Rny7Y!veT1KO zp-tPD{LFq9z1LwXB3G@SQDBYVzxu(OpH{WVk#nj$$0O$quZKh;voT2lDn&?=WXDp9 zUg9E&CHU9`gUcqNwDy7(Fj@VjMd)y8jJtMl-?dc(!~<8Akt{Z((zVs+p9iL@2MA_N zfghwP>Qy7b`oV$3tXSBE15?;`UFGk9 z*JksJ_zkg1EVSnW243#jrG7ZS7@3+Z?J47Bg|H*&1&rVRx(%7I&)D*uXRY71zOZ%u#oL~>v2YoF zZrWsOW9Q=wyQ=CxvL{oQjw3xYHQ^7Ok6G(z2@~xN!J70nBh}@9`|j#0j(|!0Z*-w4 z>|WJh-|sxoUko%QxoC~`vHwl3)$$_qJlZWQwaP_0Ou-7*Vh!OUb>CYYJp{wW>({){ yRsmPi<85m``l6v{JmvXkU3|@d9R9O?H+4O5&QD+TvRCieb?yfaO?@!;&i@axGb+6R literal 0 HcmV?d00001 From 5f818aa12188c81fd120ade7a5fb1bb50d94eb26 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:05:10 +0100 Subject: [PATCH 012/212] feat: start celestia node from the last block height --- docker-compose-via.yml | 4 ++-- infrastructure/via/src/celestia.ts | 13 +++++++++++++ infrastructure/via/src/config.ts | 20 +++++++++++++++++++- infrastructure/via/src/helpers.ts | 16 ++++++++++++++++ infrastructure/via/src/init.ts | 5 ++++- infrastructure/via/src/up.ts | 5 +++-- 6 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 infrastructure/via/src/helpers.ts diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 38ba99fb4..6a9e479b3 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -113,8 +113,8 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia - command: celestia light start --core.ip validator-2.celestia-arabica-11.com --p2p.network arabica + target: /home/celestia:rw + command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip validator-2.celestia-arabica-11.com --p2p.network arabica ports: - '26658:26658' environment: diff --git a/infrastructure/via/src/celestia.ts b/infrastructure/via/src/celestia.ts index 04d7386a3..1464c62c4 100644 --- a/infrastructure/via/src/celestia.ts +++ b/infrastructure/via/src/celestia.ts @@ -118,6 +118,19 @@ async function fix_celestia_config() { return line; }); + // Get the celestia block height where start the node + const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/l2-inits/${process.env.VIA_ENV}.init.env`); + const envs = (await fs.readFile(envFilePath, 'utf-8')).split('\n'); + let height = '1'; + for (let i = 0; i < envs.length; i++) { + if (envs[i].startsWith('VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HEIGHT')) { + height = envs[i].split('=')[1]; + break; + } + } + + await runCommand(`docker exec celestia-node sed -i 's/ SampleFrom = 1/ SampleFrom = ${height}/' config.toml`); + // Join the updated lines back into a single string const updatedConfigFileContent = updatedLines.join('\n'); diff --git a/infrastructure/via/src/config.ts b/infrastructure/via/src/config.ts index ce3d16528..adfb99b14 100644 --- a/infrastructure/via/src/config.ts +++ b/infrastructure/via/src/config.ts @@ -6,6 +6,7 @@ import * as env from './env'; import path from 'path'; import dotenv from 'dotenv'; import { unpackStringSemVer } from 'utils'; +import { updateEnvVariable } from './helpers'; function loadConfigFile(configPath: string, stack: string[] = []) { if (stack.includes(configPath)) { @@ -125,7 +126,7 @@ export function compileConfig(environment?: string) { console.log(`Configs compiled for ${environment}`); } -export function pushConfig(environment?: string, diff?: string) { +export async function pushConfig(environment?: string, diff?: string) { environment ??= process.env.VIA_ENV!; const l2InitFile = `etc/env/l2-inits/${environment}.init.env`; const difference: number = parseInt(diff ? diff : '0'); @@ -180,8 +181,24 @@ export function pushConfig(environment?: string, diff?: string) { env.modify('DATABASE_MERKLE_TREE_BACKUP_PATH', `./db/${environment}/backups`, l2InitFile, false); env.reload(); + await fetchCelestiaTrustedHash(); } +const fetchCelestiaTrustedHash = async () => { + let environment = process.env.VIA_ENV!; + const l2InitFile = `etc/env/l2-inits/${environment}.init.env`; + + const response = await (await fetch('https://rpc.celestia-arabica-11.com/header')).json(); + const { last_block_id, height } = response.result.header; + + const envFilePath1 = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); + + env.modify('VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HEIGHT', height, l2InitFile, false); + env.modify('VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH', last_block_id.hash, l2InitFile, false); + await updateEnvVariable(envFilePath1, 'VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HEIGHT', height); + await updateEnvVariable(envFilePath1, 'VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH', last_block_id.hash); +}; + // used to increase chainId for easy deployment of next hyperchain on shared bridge // export function bumpChainId() { // // note we bump in the .toml file directly @@ -207,3 +224,4 @@ command diff = diff ? diff : '0'; pushConfig(environment, diff); }); +// .action(fetchCelestiaTrustedHash); diff --git a/infrastructure/via/src/helpers.ts b/infrastructure/via/src/helpers.ts new file mode 100644 index 000000000..a0f36907a --- /dev/null +++ b/infrastructure/via/src/helpers.ts @@ -0,0 +1,16 @@ +import * as fs from 'fs/promises'; +import * as dotenv from 'dotenv'; + +export async function updateEnvVariable(envFilePath: string, variableName: string, newValue: string) { + const envFileContent = await fs.readFile(envFilePath, 'utf-8'); + const envConfig = dotenv.parse(envFileContent); + + envConfig[variableName] = newValue; + + let newEnvContent = ''; + for (const key in envConfig) { + newEnvContent += `${key}=${envConfig[key]}\n`; + } + + await fs.writeFile(envFilePath, newEnvContent, 'utf-8'); +} diff --git a/infrastructure/via/src/init.ts b/infrastructure/via/src/init.ts index fe5b6a0c6..f64df3b1f 100644 --- a/infrastructure/via/src/init.ts +++ b/infrastructure/via/src/init.ts @@ -13,6 +13,7 @@ import * as config from './config'; import * as run from './run'; // import * as server from './server'; import { createVolumes, up } from './up'; +import path from 'path'; // Checks if all required tools are installed with the correct versions const checkEnv = async (): Promise => { @@ -56,7 +57,9 @@ const initSetup = async ({ await announced('Checking environment', checkEnv()); await announced('Checking git hooks', env.gitHooks()); await announced('Create volumes', createVolumes()); - await announced('Setting up containers', up(docker.VIA_DOCKER_COMPOSE)); + const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/l2-inits/${process.env.VIA_ENV}.init.env`); + + await announced('Setting up containers', up(docker.VIA_DOCKER_COMPOSE, envFilePath)); } await announced('Compiling JS packages', run.yarn()); diff --git a/infrastructure/via/src/up.ts b/infrastructure/via/src/up.ts index 602d149fc..0c1835767 100644 --- a/infrastructure/via/src/up.ts +++ b/infrastructure/via/src/up.ts @@ -23,9 +23,10 @@ export function createVolumes() { }); } -export async function up(composeFile?: string) { +export async function up(composeFile?: string, envFilePath?: string) { if (composeFile) { - await utils.spawn(`docker compose -f ${composeFile} up -d`); + const envFile = envFilePath ? `--env-file ${envFilePath}` : ''; + await utils.spawn(`docker compose ${envFile} -f ${composeFile} up -d`); } else { await utils.spawn('docker compose up -d'); } From 0ed7b5a747bf642b6bd1b99a857e56ac68d33523 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:07:05 +0100 Subject: [PATCH 013/212] feat(dal): add function to fetch the da data by block number --- ...e380dd27b78499c7cef2a267147c7328263fb.json | 40 +++++++++++++++++++ core/lib/dal/src/via_data_availability_dal.rs | 31 ++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 core/lib/dal/.sqlx/query-2108acea7492e6704849a80b866e380dd27b78499c7cef2a267147c7328263fb.json diff --git a/core/lib/dal/.sqlx/query-2108acea7492e6704849a80b866e380dd27b78499c7cef2a267147c7328263fb.json b/core/lib/dal/.sqlx/query-2108acea7492e6704849a80b866e380dd27b78499c7cef2a267147c7328263fb.json new file mode 100644 index 000000000..666dd19ff --- /dev/null +++ b/core/lib/dal/.sqlx/query-2108acea7492e6704849a80b866e380dd27b78499c7cef2a267147c7328263fb.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n blob_id,\n inclusion_data,\n sent_at\n FROM\n via_data_availability\n WHERE\n inclusion_data IS NOT NULL\n AND is_proof = FALSE\n AND l1_batch_number = $1\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "blob_id", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "inclusion_data", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "sent_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + false + ] + }, + "hash": "2108acea7492e6704849a80b866e380dd27b78499c7cef2a267147c7328263fb" +} diff --git a/core/lib/dal/src/via_data_availability_dal.rs b/core/lib/dal/src/via_data_availability_dal.rs index c297ca18a..c88dba05b 100644 --- a/core/lib/dal/src/via_data_availability_dal.rs +++ b/core/lib/dal/src/via_data_availability_dal.rs @@ -453,4 +453,35 @@ impl ViaDataAvailabilityDal<'_, '_> { }) .collect()) } + + /// Returns the data availability blob of the block. + pub async fn get_da_blob( + &mut self, + l1_batch_number: L1BatchNumber, + ) -> DalResult> { + let result = sqlx::query_as!( + StorageDABlob, + r#" + SELECT + l1_batch_number, + blob_id, + inclusion_data, + sent_at + FROM + via_data_availability + WHERE + inclusion_data IS NOT NULL + AND is_proof = FALSE + AND l1_batch_number = $1 + LIMIT + 1 + "#, + l1_batch_number.0 as i64 + ) + .instrument("get_da_blob") + .fetch_optional(self.storage) + .await?; + + Ok(result.map(DataAvailabilityBlob::from)) + } } From 682d348ad25f1fc250c2275fc1c85891c8e4619e Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:08:40 +0100 Subject: [PATCH 014/212] feat: implement the via withdrawal client lib --- Cargo.lock | 61 ++++-- Cargo.toml | 4 +- core/lib/via_withdrawal_client/Cargo.toml | 34 +++ core/lib/via_withdrawal_client/src/client.rs | 148 +++++++++++++ core/lib/via_withdrawal_client/src/lib.rs | 4 + core/lib/via_withdrawal_client/src/pubdata.rs | 207 ++++++++++++++++++ core/lib/via_withdrawal_client/src/types.rs | 114 ++++++++++ .../lib/via_withdrawal_client/src/withdraw.rs | 76 +++++++ 8 files changed, 633 insertions(+), 15 deletions(-) create mode 100644 core/lib/via_withdrawal_client/Cargo.toml create mode 100644 core/lib/via_withdrawal_client/src/client.rs create mode 100644 core/lib/via_withdrawal_client/src/lib.rs create mode 100644 core/lib/via_withdrawal_client/src/pubdata.rs create mode 100644 core/lib/via_withdrawal_client/src/types.rs create mode 100644 core/lib/via_withdrawal_client/src/withdraw.rs diff --git a/Cargo.lock b/Cargo.lock index 071f8d160..318cf40a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,9 +109,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "arrayvec 0.7.6", "bytes", @@ -2296,6 +2296,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dotenvy" version = "0.15.7" @@ -3217,7 +3223,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3236,7 +3242,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3286,6 +3292,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hashlink" version = "0.9.1" @@ -3692,12 +3704,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] @@ -4228,7 +4240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -5318,7 +5330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] @@ -6860,7 +6872,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -7220,7 +7232,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "ipnetwork", "log", "memchr", @@ -7962,7 +7974,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "toml_datetime", "winnow 0.5.40", ] @@ -7973,7 +7985,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -8596,6 +8608,27 @@ dependencies = [ "zksync_vm_utils", ] +[[package]] +name = "via_withdrawal_client" +version = "0.1.0" +dependencies = [ + "anyhow", + "bitcoin", + "byteorder", + "dotenv", + "hex", + "rand 0.8.5", + "tokio", + "tracing", + "via_da_clients", + "zksync_basic_types", + "zksync_config", + "zksync_da_client", + "zksync_dal", + "zksync_types", + "zksync_utils", +] + [[package]] name = "vise" version = "0.2.0" @@ -8853,7 +8886,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ffc0077d5..db2249155 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ members = [ "core/node/via_btc_sender", "core/node/via_fee_model", "core/node/via_state_keeper", + "core/lib/via_withdrawal_client", ] @@ -315,9 +316,10 @@ zksync_logs_bloom_backfill = { version = "0.1.0", path = "core/node/logs_bloom_b # VIA Protocol Related Components via_btc_client= { version = "0.1.0", path = "core/lib/via_btc_client" } +via_withdrawal_client = { version = "0.1.0", path = "core/lib/via_withdrawal_client" } via_da_clients = { version = "0.1.0", path = "core/lib/via_da_clients" } via_btc_watch = { version = "0.1.0", path = "core/node/via_btc_watch" } via_da_dispatcher = { version = "0.1.0", path = "core/node/via_da_dispatcher" } via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } -via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } +via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } \ No newline at end of file diff --git a/core/lib/via_withdrawal_client/Cargo.toml b/core/lib/via_withdrawal_client/Cargo.toml new file mode 100644 index 000000000..df41d2014 --- /dev/null +++ b/core/lib/via_withdrawal_client/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "via_withdrawal_client" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +hex.workspace = true +anyhow.workspace = true +zksync_basic_types.workspace = true +zksync_da_client.workspace = true +zksync_config.workspace = true +zksync_types.workspace = true +zksync_utils.workspace = true +tokio.workspace = true +tracing.workspace = true +via_da_clients.workspace = true + +bitcoin = { version = "0.32.2", features = ["serde"] } +byteorder = "1.4" + +[dev-dependencies] +rand = "0.8" +zksync_dal.workspace = true +dotenv = "0.15" + +[[example]] +name = "withdraw" +path = "examples/withdraw.rs" diff --git a/core/lib/via_withdrawal_client/src/client.rs b/core/lib/via_withdrawal_client/src/client.rs new file mode 100644 index 000000000..3591d3b94 --- /dev/null +++ b/core/lib/via_withdrawal_client/src/client.rs @@ -0,0 +1,148 @@ +use std::{collections::HashMap, str::FromStr}; + +use zksync_da_client::DataAvailabilityClient; +use zksync_types::{web3::keccak256, H160, H256}; + +use crate::{ + pubdata::Pubdata, + types::{L2BridgeLogMetadata, WithdrawalRequest, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR}, + withdraw::parse_l2_withdrawal_message, +}; + +#[derive(Debug)] +pub struct WithdrawalClient { + client: Box, +} + +impl WithdrawalClient { + pub fn new(client: Box) -> Self { + Self { client } + } + + pub async fn get_withdrawals(&self, blob_id: &str) -> anyhow::Result> { + let pubdata_bytes = self._fetch_pubdata(blob_id).await?; + let pubdata = Pubdata::decode_pubdata(pubdata_bytes)?; + let l2_bridge_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); + let withdrawals = WithdrawalClient::_get_valid_withdrawals(l2_bridge_metadata); + Ok(withdrawals) + } + + async fn _fetch_pubdata(&self, blob_id: &str) -> anyhow::Result> { + let response = self.client.get_inclusion_data(blob_id).await?; + if let Some(inclusion_data) = response { + return Ok(inclusion_data.data); + }; + Ok(Vec::new()) + } + + fn _l2_to_l1_messages_hashmap(pubdata: &Pubdata) -> HashMap> { + let mut hashes: HashMap> = HashMap::new(); + for message in &pubdata.l2_to_l1_messages { + let hash = H256::from(keccak256(&message)); + hashes.insert(hash, message.clone()); + } + hashes + } + + fn _list_l2_bridge_metadata(pubdata: &Pubdata) -> Vec { + let mut withdrawals: Vec = Vec::new(); + let l2_bridges_hash = + H256::from(H160::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap()); + let l2_to_l1_messages_hashmap = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + for log in pubdata.user_logs.clone() { + // Ignore the logs if not from emitted from the L2 bridge contract + if log.key != l2_bridges_hash { + continue; + }; + + if log.key != l2_bridges_hash { + continue; + }; + withdrawals.push(L2BridgeLogMetadata { + message: l2_to_l1_messages_hashmap[&log.value].clone(), + log, + }); + } + withdrawals + } + + fn _get_valid_withdrawals( + l2_bridge_logs_metadata: Vec, + ) -> Vec { + let mut withdrawal_requests: Vec = Vec::new(); + for l2_bridge_log_metadata in l2_bridge_logs_metadata { + let withdrawal_request = parse_l2_withdrawal_message(l2_bridge_log_metadata.message); + + match withdrawal_request { + Ok(req) => withdrawal_requests.push(req), + Err(_) => (), + } + } + withdrawal_requests + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use bitcoin::Address; + use zksync_types::{H256, U256}; + + use super::*; + + #[test] + fn test_l2_to_l1_messages_hashmap() { + let input = "00000001000100000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000000800aa1fd131a17718668a78581197d19972abd907b7b343b9694e02246d18c3801c500000001000000506c0960f962637274317178326c6b30756e756b6d3830716d65706a703439687766397a36786e7a307337336b396a35360000000000000000000000000000000000000000000000000000000005f5e10000000000010001280400032c1818e4770f08c05b28829d7d5f9d401d492c7432c166dfecf4af04238ea323009d7042e8fb0f249338d18505e5ba1d4a546e9d21f47c847ca725ff53ac29f740ca1bbc31cc849a8092a36f9a321e17412dee200b956038af1c2dc83430a0e8b000d3e2c6760d91078e517a2cb882cd3c9551de3ab5f30d554d51b17e3744cf92b0cf368ce957aed709b985423cd3ba11615de01ecafa15eb9a11bc6cdef4f6327900436ef22b96a07224eb06f0eecfecc184033da7db2a5fb58f867f17298b896b55000000420901000000362205f5e1000000003721032b8b14000000382209216c140000003a8901000000000000000000000000000000170000003b8902000000000000000000000000000000170000003e890200000000000000000000000000000017"; + let encoded_pubdata = hex::decode(input).unwrap(); + let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hash = H256::from(pubdata.user_logs[0].value); + assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); + } + + #[test] + fn test_list_l2_bridge_metadata() { + let input = "00000001000100000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000000800aa1fd131a17718668a78581197d19972abd907b7b343b9694e02246d18c3801c500000001000000506c0960f962637274317178326c6b30756e756b6d3830716d65706a703439687766397a36786e7a307337336b396a35360000000000000000000000000000000000000000000000000000000005f5e10000000000010001280400032c1818e4770f08c05b28829d7d5f9d401d492c7432c166dfecf4af04238ea323009d7042e8fb0f249338d18505e5ba1d4a546e9d21f47c847ca725ff53ac29f740ca1bbc31cc849a8092a36f9a321e17412dee200b956038af1c2dc83430a0e8b000d3e2c6760d91078e517a2cb882cd3c9551de3ab5f30d554d51b17e3744cf92b0cf368ce957aed709b985423cd3ba11615de01ecafa15eb9a11bc6cdef4f6327900436ef22b96a07224eb06f0eecfecc184033da7db2a5fb58f867f17298b896b55000000420901000000362205f5e1000000003721032b8b14000000382209216c140000003a8901000000000000000000000000000000170000003b8902000000000000000000000000000000170000003e890200000000000000000000000000000017"; + let encoded_pubdata = hex::decode(input).unwrap(); + let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hash = H256::from(pubdata.user_logs[0].value); + assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); + + let l2_bridge_logs_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); + assert_eq!(l2_bridge_logs_metadata.len(), 1); + assert_eq!( + l2_bridge_logs_metadata[0].message, + pubdata.clone().l2_to_l1_messages[0] + ); + assert_eq!( + l2_bridge_logs_metadata[0].log.value, + pubdata.user_logs[0].value + ); + } + + #[test] + fn test_get_valid_withdrawals() { + let input = "00000001000100000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000000800aa1fd131a17718668a78581197d19972abd907b7b343b9694e02246d18c3801c500000001000000506c0960f962637274317178326c6b30756e756b6d3830716d65706a703439687766397a36786e7a307337336b396a35360000000000000000000000000000000000000000000000000000000005f5e10000000000010001280400032c1818e4770f08c05b28829d7d5f9d401d492c7432c166dfecf4af04238ea323009d7042e8fb0f249338d18505e5ba1d4a546e9d21f47c847ca725ff53ac29f740ca1bbc31cc849a8092a36f9a321e17412dee200b956038af1c2dc83430a0e8b000d3e2c6760d91078e517a2cb882cd3c9551de3ab5f30d554d51b17e3744cf92b0cf368ce957aed709b985423cd3ba11615de01ecafa15eb9a11bc6cdef4f6327900436ef22b96a07224eb06f0eecfecc184033da7db2a5fb58f867f17298b896b55000000420901000000362205f5e1000000003721032b8b14000000382209216c140000003a8901000000000000000000000000000000170000003b8902000000000000000000000000000000170000003e890200000000000000000000000000000017"; + let encoded_pubdata = hex::decode(input).unwrap(); + let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hash = H256::from(pubdata.user_logs[0].value); + assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); + + let l2_bridge_logs_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); + let withdrawals = WithdrawalClient::_get_valid_withdrawals(l2_bridge_logs_metadata); + let expected_user_address = + Address::from_str("bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56").unwrap(); + assert_eq!(withdrawals.len(), 1); + assert_eq!(withdrawals[0].clone().address, expected_user_address); + assert_eq!( + withdrawals[0].clone().amount, + U256::from_dec_str("100000000").unwrap() + ); + } +} diff --git a/core/lib/via_withdrawal_client/src/lib.rs b/core/lib/via_withdrawal_client/src/lib.rs new file mode 100644 index 000000000..32c497ef9 --- /dev/null +++ b/core/lib/via_withdrawal_client/src/lib.rs @@ -0,0 +1,4 @@ +pub mod client; +mod pubdata; +mod types; +mod withdraw; diff --git a/core/lib/via_withdrawal_client/src/pubdata.rs b/core/lib/via_withdrawal_client/src/pubdata.rs new file mode 100644 index 000000000..41dd35519 --- /dev/null +++ b/core/lib/via_withdrawal_client/src/pubdata.rs @@ -0,0 +1,207 @@ +use std::io::{Cursor, Read}; + +use anyhow::Context; +use byteorder::{BigEndian, ReadBytesExt}; + +use crate::types::L1MessengerL2ToL1Log; + +#[derive(Debug, Clone, Default)] +pub struct Pubdata { + pub user_logs: Vec, + pub l2_to_l1_messages: Vec>, +} + +impl Pubdata { + pub fn _encode_pubdata(self) -> Vec { + let mut l1_messenger_pubdata = vec![]; + + // Encoding user L2->L1 logs. + // Format: `[(numberOfL2ToL1Logs as u32) || l2tol1logs[1] || ... || l2tol1logs[n]]` + l1_messenger_pubdata.extend((self.user_logs.len() as u32).to_be_bytes()); + for l2tol1log in self.user_logs { + l1_messenger_pubdata.extend(l2tol1log.encode_packed()); + } + + // Encoding L2->L1 messages + // Format: `[(numberOfMessages as u32) || (messages[1].len() as u32) || messages[1] || ... || (messages[n].len() as u32) || messages[n]]` + l1_messenger_pubdata.extend((self.l2_to_l1_messages.len() as u32).to_be_bytes()); + for message in self.l2_to_l1_messages { + l1_messenger_pubdata.extend((message.len() as u32).to_be_bytes()); + l1_messenger_pubdata.extend(message); + } + + l1_messenger_pubdata + } + + pub fn decode_pubdata(pubdata: Vec) -> anyhow::Result { + let mut cursor = Cursor::new(pubdata); + let mut user_logs = Vec::new(); + let mut l2_to_l1_messages = Vec::new(); + + // Decode user L2->L1 logs + let num_user_logs = cursor + .read_u32::() + .context("Failed to decode num user logs")? as usize; + for _ in 0..num_user_logs { + let log = L1MessengerL2ToL1Log::decode_packed(&mut cursor)?; + user_logs.push(log); + } + + // Decode L2->L1 messages + let num_messages = cursor.read_u32::()? as usize; + for _ in 0..num_messages { + let message_len = cursor.read_u32::()? as usize; + let mut message = vec![0u8; message_len]; + cursor + .read_exact(&mut message) + .context("Read l2 to l1 message")?; + l2_to_l1_messages.push(message); + } + + Ok(Pubdata { + user_logs, + l2_to_l1_messages, + }) + } +} + +/// Helper function to read a specific number of bytes +fn _read_bytes(reader: &mut R, num_bytes: usize) -> anyhow::Result> { + let mut buffer = vec![0u8; num_bytes]; + reader.read_exact(&mut buffer)?; + Ok(buffer) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use hex::encode; + use rand; + use zksync_types::{web3::keccak256, Address, H256}; + + use super::*; + use crate::types::L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR; + + fn generate_random_hex(len: usize) -> String { + // Generate random bytes + let random_bytes: Vec = (0..len).map(|_| rand::random::()).collect(); + + // Convert bytes to hex and return it + encode(random_bytes) + } + + #[test] + fn test_decode_l1_messager_l2_to_l1_log() { + let message = L1MessengerL2ToL1Log { + l2_shard_id: 0, + is_service: true, + tx_number_in_block: 5, + sender: Address::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap(), + key: H256::random(), + value: H256::random(), + }; + let encoded_messages = message.encode_packed(); + + let mut cursor = Cursor::new(encoded_messages); + let decoded = L1MessengerL2ToL1Log::decode_packed(&mut cursor).unwrap(); + assert_eq!(message.l2_shard_id, decoded.l2_shard_id); + assert_eq!(message.is_service, decoded.is_service); + assert_eq!(message.tx_number_in_block, decoded.tx_number_in_block); + assert_eq!(message.sender, decoded.sender); + assert_eq!(message.key, decoded.key); + assert_eq!(message.value, decoded.value); + } + + #[test] + fn test_decode_pubdata_with_single_l1_messager_l2_to_l1_log() { + let message = L1MessengerL2ToL1Log { + l2_shard_id: 0, + is_service: true, + tx_number_in_block: 5, + sender: Address::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap(), + key: H256::random(), + value: H256::random(), + }; + + let pubdata = Pubdata { + user_logs: vec![message.clone()], + l2_to_l1_messages: vec![hex::decode("deadbeef").unwrap()], + }; + + let encoded_pubdata = pubdata._encode_pubdata(); + let pubdata_input = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let decoded_message = pubdata_input.user_logs[0].clone(); + assert_eq!(pubdata_input.user_logs.len(), 1); + assert_eq!(decoded_message.l2_shard_id, message.clone().l2_shard_id); + assert_eq!(decoded_message.is_service, message.clone().is_service); + assert_eq!( + decoded_message.tx_number_in_block, + message.clone().tx_number_in_block + ); + assert_eq!(decoded_message.sender, message.clone().sender); + assert_eq!(decoded_message.key, message.clone().key); + assert_eq!(decoded_message.value, message.clone().value); + } + + #[test] + fn test_decode_pubdata_with_many_l1_messager_l2_to_l1_log() { + let len: usize = 5; + let mut user_logs: Vec = Vec::new(); + let mut l2_to_l1_messages: Vec> = Vec::new(); + for _ in 0..len { + let log = L1MessengerL2ToL1Log { + l2_shard_id: 0, + is_service: true, + tx_number_in_block: 5, + sender: Address::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap(), + key: H256::from_str(&generate_random_hex(32)).unwrap(), + value: H256::from_str(&generate_random_hex(32)).unwrap(), + }; + user_logs.push(log.clone()); + l2_to_l1_messages.push(hex::decode("deadbeef").unwrap()); + } + + let pubdata = Pubdata { + user_logs: user_logs.clone(), + l2_to_l1_messages: l2_to_l1_messages, + }; + + let encoded_pubdata = pubdata._encode_pubdata(); + let pubdata_input = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let decoded_logs = pubdata_input.user_logs.clone(); + let decoded_messages = pubdata_input.l2_to_l1_messages.clone(); + assert_eq!(pubdata_input.user_logs.len(), len); + assert_eq!(pubdata_input.l2_to_l1_messages.len(), len); + for i in 0..len { + let decoded_log = decoded_logs[i].clone(); + let msg_log = user_logs[i].clone(); + + assert_eq!(decoded_log.l2_shard_id, msg_log.clone().l2_shard_id); + assert_eq!(decoded_log.is_service, msg_log.clone().is_service); + assert_eq!( + decoded_log.tx_number_in_block, + msg_log.clone().tx_number_in_block + ); + assert_eq!(decoded_log.sender, msg_log.clone().sender); + assert_eq!(decoded_log.key, msg_log.clone().key); + assert_eq!(decoded_log.value, msg_log.clone().value); + + // l2 to l1 message + let decoded_message = decoded_messages[i].clone(); + assert_eq!(decoded_message, hex::decode("deadbeef").unwrap()); + } + } + + #[test] + fn test_decode_pubdata_with_single_real_l1_messager_l2_to_l1_log() { + let input = "00000001000100000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000000800aa1fd131a17718668a78581197d19972abd907b7b343b9694e02246d18c3801c500000001000000506c0960f962637274317178326c6b30756e756b6d3830716d65706a703439687766397a36786e7a307337336b396a35360000000000000000000000000000000000000000000000000000000005f5e10000000000010001280400032c1818e4770f08c05b28829d7d5f9d401d492c7432c166dfecf4af04238ea323009d7042e8fb0f249338d18505e5ba1d4a546e9d21f47c847ca725ff53ac29f740ca1bbc31cc849a8092a36f9a321e17412dee200b956038af1c2dc83430a0e8b000d3e2c6760d91078e517a2cb882cd3c9551de3ab5f30d554d51b17e3744cf92b0cf368ce957aed709b985423cd3ba11615de01ecafa15eb9a11bc6cdef4f6327900436ef22b96a07224eb06f0eecfecc184033da7db2a5fb58f867f17298b896b55000000420901000000362205f5e1000000003721032b8b14000000382209216c140000003a8901000000000000000000000000000000170000003b8902000000000000000000000000000000170000003e890200000000000000000000000000000017"; + let encoded_pubdata = hex::decode(input).unwrap(); + let pubdata_input = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); + + let hash = keccak256(&pubdata_input.l2_to_l1_messages[0].clone()); + assert_eq!(H256::from(hash), pubdata_input.user_logs[0].value); + } +} diff --git a/core/lib/via_withdrawal_client/src/types.rs b/core/lib/via_withdrawal_client/src/types.rs new file mode 100644 index 000000000..514980156 --- /dev/null +++ b/core/lib/via_withdrawal_client/src/types.rs @@ -0,0 +1,114 @@ +use std::io::Read; + +use anyhow::Context; +use bitcoin::{address::NetworkUnchecked, Address as BitcoinAddress}; +use byteorder::{BigEndian, ReadBytesExt}; +use zksync_types::{Address, H160, H256, U256}; +use zksync_utils::{u256_to_bytes_be, u256_to_h256}; + +/// The function selector used in L2 to compute the message. +pub const WITHDRAW_FUNC_SIG: &str = "finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[])"; + +/// The L2 system bridge address. +pub const L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR: &str = "000000000000000000000000000000000000800a"; + +#[derive(Clone, Debug, Default)] +pub struct L2BridgeLogMetadata { + pub log: L1MessengerL2ToL1Log, + pub message: Vec, +} + +#[derive(Clone, Debug)] +pub struct WithdrawalRequest { + /// The receiver l1 address. + pub address: BitcoinAddress, + /// The amount user will receive. + pub amount: U256, +} + +/// Corresponds to the following solidity event: +/// ```solidity +/// struct L2ToL1Log { +/// uint8 l2ShardId; +/// bool isService; +/// uint16 txNumberInBlock; +/// address sender; +/// bytes32 key; +/// bytes32 value; +/// } +/// ``` +#[derive(Clone, Debug, Default)] +pub struct L1MessengerL2ToL1Log { + /// l2ShardId The shard identifier, 0 - rollup, 1 - porter + /// All other values are not used but are reserved for the future + pub l2_shard_id: u8, + /// isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address. + /// This field is required formally but does not have any special meaning + pub is_service: bool, + /// txNumberInBatch The L2 transaction number in a Batch, in which the log was sent + pub tx_number_in_block: u16, + /// sender The L2 address which sent the log + pub sender: H160, + /// key The 32 bytes of information that was sent in the log + pub key: H256, + /// value The 32 bytes of information that was sent in the log + pub value: H256, +} + +impl L1MessengerL2ToL1Log { + pub fn encode_packed(&self) -> Vec { + let mut res: Vec = vec![]; + res.push(self.l2_shard_id); + res.push(self.is_service as u8); + res.extend_from_slice(&self.tx_number_in_block.to_be_bytes()); + res.extend_from_slice(self.sender.as_bytes()); + res.extend(u256_to_bytes_be(&U256::from_big_endian(&self.key.0))); + res.extend(u256_to_bytes_be(&U256::from_big_endian(&self.value.0))); + res + } + + pub fn decode_packed(reader: &mut R) -> anyhow::Result { + // Read `l2_shard_id` (1 byte) + let l2_shard_id = reader.read_u8().context("Failed to read l2_shard_id")?; + + // Read `is_service` (1 byte, a boolean stored as 0 or 1) + let is_service_byte = reader.read_u8().context("Failed to read is_service byte")?; + let is_service = is_service_byte != 0; // 0 -> false, non-zero -> true + + // Read `tx_number_in_block` (2 bytes, u16) + let tx_number_in_block = reader + .read_u16::() + .context("Failed to read tx_number_in_block")?; + + // Read `sender` (address is 20 bytes) + let mut sender_bytes = [0u8; 20]; + reader + .read_exact(&mut sender_bytes) + .context("Failed to read sender address")?; + let sender = Address::from(sender_bytes); + + // Read `key` (U256 is 32 bytes) + let key_bytes = _read_bytes(reader, 32).context("Failed to read key bytes")?; + let key = u256_to_h256(U256::from_big_endian(&key_bytes)); + + // Read `value` (U256 is 32 bytes) + let value_bytes = _read_bytes(reader, 32).context("Failed to read value bytes")?; + let value = u256_to_h256(U256::from_big_endian(&value_bytes)); + + Ok(L1MessengerL2ToL1Log { + l2_shard_id, + is_service, + tx_number_in_block, + sender, + key, + value, + }) + } +} + +/// Helper function to read a specific number of bytes +fn _read_bytes(reader: &mut R, num_bytes: usize) -> anyhow::Result> { + let mut buffer = vec![0u8; num_bytes]; + reader.read_exact(&mut buffer)?; + Ok(buffer) +} diff --git a/core/lib/via_withdrawal_client/src/withdraw.rs b/core/lib/via_withdrawal_client/src/withdraw.rs new file mode 100644 index 000000000..420927ac0 --- /dev/null +++ b/core/lib/via_withdrawal_client/src/withdraw.rs @@ -0,0 +1,76 @@ +use std::str::FromStr; + +use anyhow::Context; +use bitcoin::Address as BitcoinAddress; +use zksync_basic_types::{web3::keccak256, U256}; + +use crate::types::{WithdrawalRequest, WITHDRAW_FUNC_SIG}; + +pub fn parse_l2_withdrawal_message(l2_to_l1_message: Vec) -> anyhow::Result { + // We check that the message is long enough to read the data. + // Please note that there are two versions of the message: + // The message that is sent by `withdraw(address _l1Receiver)` + // It should be equal to the length of the bytes4 function signature + bytes l1Receiver + uint256 amount = 4 + X + 32. + let message_len = l2_to_l1_message.len(); + let address_size = message_len - 36; + if message_len <= 36 { + return Err(anyhow::format_err!("Invalid message length.")); + } + + let func_selector_bytes = &l2_to_l1_message[0..4]; + if func_selector_bytes != _get_withdraw_function_selector() { + return Err(anyhow::format_err!("Invalid message function selector.")); + } + + // The address bytes represent the l1 receiver + let address_bytes = &l2_to_l1_message[4..4 + address_size]; + let address_str = + String::from_utf8(address_bytes.to_vec()).context("Parse address to string")?; + let address = BitcoinAddress::from_str(&address_str).context("parse bitcoin address")?; + + // The last 32 bytes represent the amount (uint256) + let amount_bytes = &l2_to_l1_message[address_size + 4..]; + let amount = U256::from_big_endian(amount_bytes); + + return Ok(WithdrawalRequest { address, amount }); +} + +/// Get the withdrawal function selector. +fn _get_withdraw_function_selector() -> Vec { + let hash = keccak256(WITHDRAW_FUNC_SIG.as_bytes()); + hash[0..4].to_vec() +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use super::*; + + #[test] + fn test_parse_l2_withdrawal_message_when_address_bech32m() { + // Example transaction: https://etherscan.io/tx/0x70afe07734e9b0c2d8393ab2a51fda5ac2cfccc80a01cc4a5cf587eaea3c4610 + let l2_to_l1_message = hex::decode("6c0960f96263317179383267617732687466643573736c706c70676d7a346b74663979336b37706163323232366b30776c6a6c6d7733617466773571776d346176340000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); + let expected_receiver = BitcoinAddress::from_str( + &"bc1qy82gaw2htfd5sslplpgmz4ktf9y3k7pac2226k0wljlmw3atfw5qwm4av4", + ) + .unwrap(); + let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); + let res = parse_l2_withdrawal_message(l2_to_l1_message).unwrap(); + + assert_eq!(res.address, expected_receiver); + assert_eq!(res.amount, expected_amount); + } + + #[test] + fn test_parse_l2_withdrawal_message_when_address_p2pkh() { + let l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); + let expected_receiver = + BitcoinAddress::from_str(&"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap(); + let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); + let res = parse_l2_withdrawal_message(l2_to_l1_message).unwrap(); + + assert_eq!(res.address, expected_receiver); + assert_eq!(res.amount, expected_amount); + } +} From aba1ba2ce15b89b2c7a0d6163014c756e14d5da9 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:10:29 +0100 Subject: [PATCH 015/212] feat: add cmd to via cli to withdraw tokens --- infrastructure/via/package.json | 2 + infrastructure/via/src/index.ts | 2 + infrastructure/via/src/withdraw.ts | 74 ++++++++++++++++++++++ yarn.lock | 98 +++++++++++++++--------------- 4 files changed, 126 insertions(+), 50 deletions(-) create mode 100644 infrastructure/via/src/withdraw.ts diff --git a/infrastructure/via/package.json b/infrastructure/via/package.json index 3674fc535..a211bf9ea 100644 --- a/infrastructure/via/package.json +++ b/infrastructure/via/package.json @@ -13,6 +13,8 @@ "devDependencies": { "typescript": "^4.4.4", "@types/node": "^16.11.7", + "zksync-ethers": "^6.13.1", + "ethers": "^6.13.4", "eslint": "^7.32.0", "@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0" diff --git a/infrastructure/via/src/index.ts b/infrastructure/via/src/index.ts index eb1db3717..8fbd6acea 100644 --- a/infrastructure/via/src/index.ts +++ b/infrastructure/via/src/index.ts @@ -18,6 +18,7 @@ import { command as bootstrap } from './bootstrap'; import { command as verifier } from './verifier'; import { command as celestia } from './celestia'; import { command as btc_explorer } from './btc_explorer'; +import { command as withdraw } from './withdraw'; const COMMANDS = [ server, @@ -35,6 +36,7 @@ const COMMANDS = [ verifier, celestia, btc_explorer, + withdraw, completion(program as Command) ]; diff --git a/infrastructure/via/src/withdraw.ts b/infrastructure/via/src/withdraw.ts new file mode 100644 index 000000000..408a60f14 --- /dev/null +++ b/infrastructure/via/src/withdraw.ts @@ -0,0 +1,74 @@ +import * as fs from 'fs'; +import { Command } from 'commander'; +import { Wallet, Provider, Contract } from 'zksync-ethers'; +import { ethers } from 'ethers'; + +// 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 +const DEFAULT_L2_PRIVATE_KEY = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; +const DEFAULT_L2_RPC_URL = 'http://0.0.0.0:3050'; +const L2_BASE_TOKEN = '0x000000000000000000000000000000000000800a'; + +async function withdraw(amount: number, receiverL1Address: string, userL2PrivateKey: string, rpcUrl: string) { + if (isNaN(amount)) { + console.error('Error: Invalid withdraw amount. Please provide a valid number.'); + return; + } + + const abi = [ + { + inputs: [ + { + internalType: 'uint256', + name: '_account', + type: 'uint256' + } + ], + name: 'balanceOf', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { + internalType: 'bytes', + name: '_l1Receiver', + type: 'bytes' + } + ], + name: 'withdraw', + outputs: [], + stateMutability: 'payable', + type: 'function' + } + ]; + + const provider = new Provider(rpcUrl); + const wallet = new Wallet(userL2PrivateKey, provider); + const btcAddress = ethers.toUtf8Bytes(receiverL1Address); + const contract = new Contract(L2_BASE_TOKEN, abi, wallet) as any; + + let balance = await contract.balanceOf(wallet.address); + console.log('Balance before withdraw', ethers.formatUnits(balance, 8)); + const tx = await contract.connect(wallet).withdraw(btcAddress, { value: ethers.parseUnits(String(amount), 8) }); + await tx.wait(); + balance = await contract.balanceOf(wallet.address); + console.log('Balance after withdraw', ethers.formatUnits(balance, 8)); +} + +export const command = new Command('token').description('Bridge BTC L2>L1'); + +command + .command('withdraw') + .description('withdraw BTC to l1') + .requiredOption('--amount ', 'amount of BTC to withdraw', parseFloat) + .requiredOption('--receiver-l1-address ', 'receiver l1 address') + .option('--user-private-key ', 'user private key', DEFAULT_L2_PRIVATE_KEY) + .option('--rpc-url ', 'RPC URL', DEFAULT_L2_RPC_URL) + .action((cmd: Command) => withdraw(cmd.amount, cmd.receiverL1Address, cmd.userPrivateKey, cmd.rpcUrl)); diff --git a/yarn.lock b/yarn.lock index 9da6ab7d3..c80c9142e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -466,11 +466,6 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint-community/regexpp@^4.6.1": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" - integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== - "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -2559,6 +2554,14 @@ dependencies: ethers "^5.0.2" +"@typechain/ethers-v6@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz#42fe214a19a8b687086c93189b301e2b878797ea" + integrity sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + "@types/abstract-leveldown@*": version "7.2.5" resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.5.tgz#db2cf364c159fb1f12be6cd3549f56387eaf8d73" @@ -2789,6 +2792,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -5379,6 +5389,19 @@ ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.13.4: + version "6.13.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" + integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" + ethers@^6.7.1: version "6.12.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" @@ -5786,15 +5809,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - fp-ts@1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" @@ -7612,13 +7626,6 @@ linkify-it@^4.0.1: dependencies: uc.micro "^1.0.1" -linkify-it@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" - integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw== - dependencies: - uc.micro "^1.0.1" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -8522,23 +8529,6 @@ ordinal@^1.0.3: resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== -optionator@^0.9.3: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.5" - -ordinal@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" - integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== - os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9547,13 +9537,6 @@ serialize-javascript@^6.0.2: dependencies: randombytes "^2.1.0" -serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" @@ -10476,16 +10459,16 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@2.7.0, tslib@^2.6.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.6.2: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== - tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -10687,6 +10670,11 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + undici@^5.14.0: version "5.28.4" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" @@ -10972,6 +10960,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + ws@8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" @@ -11097,6 +11090,11 @@ zksync-ethers@^5.9.0: dependencies: ethers "~5.7.0" +zksync-ethers@^6.13.1: + version "6.15.2" + resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-6.15.2.tgz#bff003ed346aa4ef9a4c714dd21944c3cfed6673" + integrity sha512-eqFeKVYXyfHYW1Tw0CkCk255zeuFltDbfZfraxpe/Z/idVR1WxeBlKvLLzIM884KVVeghRkConSRlOibhtm6xw== + zksync-ethers@^6.9.0: version "6.9.0" resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-6.9.0.tgz#efaff1d59e2cff837eeda84c4ba59fdca4972a91" From 8342a64e6bada0a3195ccd0ffc1b7538a9a542e7 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:13:47 +0100 Subject: [PATCH 016/212] feat: add example to list the withdrawals from pubdata --- .../examples/withdraw.rs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 core/lib/via_withdrawal_client/examples/withdraw.rs diff --git a/core/lib/via_withdrawal_client/examples/withdraw.rs b/core/lib/via_withdrawal_client/examples/withdraw.rs new file mode 100644 index 000000000..caded66f6 --- /dev/null +++ b/core/lib/via_withdrawal_client/examples/withdraw.rs @@ -0,0 +1,68 @@ +use std::{env, str::FromStr}; + +use anyhow::{Context, Result}; +use dotenv; +use tracing::info; +use via_da_clients::celestia::client::CelestiaClient; +use via_withdrawal_client::client::WithdrawalClient; +use zksync_config::ViaCelestiaConfig; +use zksync_da_client::DataAvailabilityClient; +use zksync_dal::{ConnectionPool, Core, CoreDal}; +use zksync_types::{url::SensitiveUrl, L1BatchNumber}; + +const DEFAULT_DATABASE_URL: &str = "postgres://postgres:notsecurepassword@0.0.0.0:5432/via"; +const DEFAULT_CELESTIA: &str = "http://0.0.0.0:26658"; + +#[tokio::main] +async fn main() -> Result<()> { + let home = env::var("VIA_HOME").context("VIA HOME not set")?; + let _ = dotenv::from_path(home.clone() + "/etc/env/target/via.env"); + + let celestia_auth_token = env::var("VIA_CELESTIA_CLIENT_AUTH_TOKEN")?; + + let args: Vec = env::args().collect(); + let block_number = args[1].parse::().unwrap(); + info!("Fetch withdrawals in block {}", block_number); + + // Connect to db + let url = SensitiveUrl::from_str(DEFAULT_DATABASE_URL).unwrap(); + let connection_pool = ConnectionPool::::builder(url, 100) + .build() + .await + .unwrap(); + let l1_batch_number = L1BatchNumber::from(block_number); + let mut storage = connection_pool.connection().await.unwrap(); + + let header_res = storage + .via_data_availability_dal() + .get_da_blob(l1_batch_number) + .await + .unwrap(); + if header_res.is_none() { + info!("DA for block not exists yet"); + return Ok(()); + } + + let header = header_res.unwrap(); + + let da_config = ViaCelestiaConfig { + api_node_url: String::from(DEFAULT_CELESTIA), + auth_token: String::from(celestia_auth_token), + blob_size_limit: 1973786, + }; + + // Connect to withdrawl client + let client = CelestiaClient::new(da_config).await?; + let da_client: Box = Box::new(client); + let withdrawal_client = WithdrawalClient::new(da_client); + + let withdrawals = withdrawal_client + .get_withdrawals(header.blob_id.as_str()) + .await?; + + info!("--------------------------------------------------------"); + info!("Withdrawals {:?}", withdrawals); + info!("--------------------------------------------------------"); + + Ok(()) +} From 44e05a53072510ea91379c19c9af9ad2bac3e780 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:34:48 +0100 Subject: [PATCH 017/212] clean: config file --- infrastructure/via/src/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/infrastructure/via/src/config.ts b/infrastructure/via/src/config.ts index adfb99b14..2364ea389 100644 --- a/infrastructure/via/src/config.ts +++ b/infrastructure/via/src/config.ts @@ -224,4 +224,3 @@ command diff = diff ? diff : '0'; pushConfig(environment, diff); }); -// .action(fetchCelestiaTrustedHash); From b861b301aee7c042e2a0a3f316e0c43a65e1538a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:18:45 +0100 Subject: [PATCH 018/212] fix: remove underscore prefix from the private functions --- core/lib/via_withdrawal_client/src/client.rs | 28 +++++++++---------- core/lib/via_withdrawal_client/src/pubdata.rs | 8 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/lib/via_withdrawal_client/src/client.rs b/core/lib/via_withdrawal_client/src/client.rs index 3591d3b94..926299b16 100644 --- a/core/lib/via_withdrawal_client/src/client.rs +++ b/core/lib/via_withdrawal_client/src/client.rs @@ -20,14 +20,14 @@ impl WithdrawalClient { } pub async fn get_withdrawals(&self, blob_id: &str) -> anyhow::Result> { - let pubdata_bytes = self._fetch_pubdata(blob_id).await?; + let pubdata_bytes = self.fetch_pubdata(blob_id).await?; let pubdata = Pubdata::decode_pubdata(pubdata_bytes)?; - let l2_bridge_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); - let withdrawals = WithdrawalClient::_get_valid_withdrawals(l2_bridge_metadata); + let l2_bridge_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); + let withdrawals = WithdrawalClient::get_valid_withdrawals(l2_bridge_metadata); Ok(withdrawals) } - async fn _fetch_pubdata(&self, blob_id: &str) -> anyhow::Result> { + async fn fetch_pubdata(&self, blob_id: &str) -> anyhow::Result> { let response = self.client.get_inclusion_data(blob_id).await?; if let Some(inclusion_data) = response { return Ok(inclusion_data.data); @@ -35,7 +35,7 @@ impl WithdrawalClient { Ok(Vec::new()) } - fn _l2_to_l1_messages_hashmap(pubdata: &Pubdata) -> HashMap> { + fn l2_to_l1_messages_hashmap(pubdata: &Pubdata) -> HashMap> { let mut hashes: HashMap> = HashMap::new(); for message in &pubdata.l2_to_l1_messages { let hash = H256::from(keccak256(&message)); @@ -44,11 +44,11 @@ impl WithdrawalClient { hashes } - fn _list_l2_bridge_metadata(pubdata: &Pubdata) -> Vec { + fn list_l2_bridge_metadata(pubdata: &Pubdata) -> Vec { let mut withdrawals: Vec = Vec::new(); let l2_bridges_hash = H256::from(H160::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap()); - let l2_to_l1_messages_hashmap = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let l2_to_l1_messages_hashmap = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); for log in pubdata.user_logs.clone() { // Ignore the logs if not from emitted from the L2 bridge contract if log.key != l2_bridges_hash { @@ -66,7 +66,7 @@ impl WithdrawalClient { withdrawals } - fn _get_valid_withdrawals( + fn get_valid_withdrawals( l2_bridge_logs_metadata: Vec, ) -> Vec { let mut withdrawal_requests: Vec = Vec::new(); @@ -97,7 +97,7 @@ mod tests { let encoded_pubdata = hex::decode(input).unwrap(); let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); - let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); let hash = H256::from(pubdata.user_logs[0].value); assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); } @@ -108,11 +108,11 @@ mod tests { let encoded_pubdata = hex::decode(input).unwrap(); let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); - let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); let hash = H256::from(pubdata.user_logs[0].value); assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); - let l2_bridge_logs_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); + let l2_bridge_logs_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); assert_eq!(l2_bridge_logs_metadata.len(), 1); assert_eq!( l2_bridge_logs_metadata[0].message, @@ -130,12 +130,12 @@ mod tests { let encoded_pubdata = hex::decode(input).unwrap(); let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); - let hashes = WithdrawalClient::_l2_to_l1_messages_hashmap(&pubdata); + let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); let hash = H256::from(pubdata.user_logs[0].value); assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); - let l2_bridge_logs_metadata = WithdrawalClient::_list_l2_bridge_metadata(&pubdata); - let withdrawals = WithdrawalClient::_get_valid_withdrawals(l2_bridge_logs_metadata); + let l2_bridge_logs_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); + let withdrawals = WithdrawalClient::get_valid_withdrawals(l2_bridge_logs_metadata); let expected_user_address = Address::from_str("bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56").unwrap(); assert_eq!(withdrawals.len(), 1); diff --git a/core/lib/via_withdrawal_client/src/pubdata.rs b/core/lib/via_withdrawal_client/src/pubdata.rs index 41dd35519..edca0e48e 100644 --- a/core/lib/via_withdrawal_client/src/pubdata.rs +++ b/core/lib/via_withdrawal_client/src/pubdata.rs @@ -12,7 +12,7 @@ pub struct Pubdata { } impl Pubdata { - pub fn _encode_pubdata(self) -> Vec { + pub fn encode_pubdata(self) -> Vec { let mut l1_messenger_pubdata = vec![]; // Encoding user L2->L1 logs. @@ -66,7 +66,7 @@ impl Pubdata { } /// Helper function to read a specific number of bytes -fn _read_bytes(reader: &mut R, num_bytes: usize) -> anyhow::Result> { +fn read_bytes(reader: &mut R, num_bytes: usize) -> anyhow::Result> { let mut buffer = vec![0u8; num_bytes]; reader.read_exact(&mut buffer)?; Ok(buffer) @@ -129,7 +129,7 @@ mod tests { l2_to_l1_messages: vec![hex::decode("deadbeef").unwrap()], }; - let encoded_pubdata = pubdata._encode_pubdata(); + let encoded_pubdata = pubdata.encode_pubdata(); let pubdata_input = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); let decoded_message = pubdata_input.user_logs[0].clone(); @@ -168,7 +168,7 @@ mod tests { l2_to_l1_messages: l2_to_l1_messages, }; - let encoded_pubdata = pubdata._encode_pubdata(); + let encoded_pubdata = pubdata.encode_pubdata(); let pubdata_input = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); let decoded_logs = pubdata_input.user_logs.clone(); From 9c02f452415d74b28d5e7de4c28a2ccb0847fa81 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:19:34 +0100 Subject: [PATCH 019/212] fix: delete duplicate code --- core/lib/via_withdrawal_client/src/client.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/lib/via_withdrawal_client/src/client.rs b/core/lib/via_withdrawal_client/src/client.rs index 926299b16..bb7faf95c 100644 --- a/core/lib/via_withdrawal_client/src/client.rs +++ b/core/lib/via_withdrawal_client/src/client.rs @@ -55,9 +55,6 @@ impl WithdrawalClient { continue; }; - if log.key != l2_bridges_hash { - continue; - }; withdrawals.push(L2BridgeLogMetadata { message: l2_to_l1_messages_hashmap[&log.value].clone(), log, From 9c008306268b2cb5260675239bee662870ed5fce Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:18:07 +0100 Subject: [PATCH 020/212] fix: clean code --- docker-compose-via.yml | 2 +- infrastructure/via/src/celestia.ts | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 6a9e479b3..977e5d751 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -113,7 +113,7 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia:rw + target: /home/celestia command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip validator-2.celestia-arabica-11.com --p2p.network arabica ports: - '26658:26658' diff --git a/infrastructure/via/src/celestia.ts b/infrastructure/via/src/celestia.ts index 1464c62c4..af15166a8 100644 --- a/infrastructure/via/src/celestia.ts +++ b/infrastructure/via/src/celestia.ts @@ -4,6 +4,7 @@ import * as fs from 'fs/promises'; import * as path from 'path'; import * as dotenv from 'dotenv'; import { exec } from 'child_process'; +import { updateEnvVariable } from './helpers'; // Function to execute a shell command and return it as a Promise function runCommand(command: string): Promise { @@ -26,20 +27,6 @@ const get_auth_node_command = 'docker exec $(docker ps -q -f name=celestia-node) celestia light auth admin --p2p.network arabica'; const restart_celestia_container_command = 'docker restart celestia-node'; -async function updateEnvVariable(envFilePath: string, variableName: string, newValue: string) { - const envFileContent = await fs.readFile(envFilePath, 'utf-8'); - const envConfig = dotenv.parse(envFileContent); - - envConfig[variableName] = newValue; - - let newEnvContent = ''; - for (const key in envConfig) { - newEnvContent += `${key}=${envConfig[key]}\n`; - } - - await fs.writeFile(envFilePath, newEnvContent, 'utf-8'); -} - async function updateEnvironment(auth_token: string) { const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); From 5042016b430c23bcd2a038f06c48dad5959d50fc Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:25:52 +0100 Subject: [PATCH 021/212] fix: clean code --- docker-compose-via.yml | 2 +- infrastructure/via/src/celestia.ts | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 6a9e479b3..977e5d751 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -113,7 +113,7 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia:rw + target: /home/celestia command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip validator-2.celestia-arabica-11.com --p2p.network arabica ports: - '26658:26658' diff --git a/infrastructure/via/src/celestia.ts b/infrastructure/via/src/celestia.ts index 1464c62c4..af15166a8 100644 --- a/infrastructure/via/src/celestia.ts +++ b/infrastructure/via/src/celestia.ts @@ -4,6 +4,7 @@ import * as fs from 'fs/promises'; import * as path from 'path'; import * as dotenv from 'dotenv'; import { exec } from 'child_process'; +import { updateEnvVariable } from './helpers'; // Function to execute a shell command and return it as a Promise function runCommand(command: string): Promise { @@ -26,20 +27,6 @@ const get_auth_node_command = 'docker exec $(docker ps -q -f name=celestia-node) celestia light auth admin --p2p.network arabica'; const restart_celestia_container_command = 'docker restart celestia-node'; -async function updateEnvVariable(envFilePath: string, variableName: string, newValue: string) { - const envFileContent = await fs.readFile(envFilePath, 'utf-8'); - const envConfig = dotenv.parse(envFileContent); - - envConfig[variableName] = newValue; - - let newEnvContent = ''; - for (const key in envConfig) { - newEnvContent += `${key}=${envConfig[key]}\n`; - } - - await fs.writeFile(envFilePath, newEnvContent, 'utf-8'); -} - async function updateEnvironment(auth_token: string) { const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); From 9bc559e5a76acb175c6b999ad2947e4ff6d34c07 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:08:40 +0100 Subject: [PATCH 022/212] fix: add tracing_subscriber to the example --- Cargo.lock | 1 + core/lib/via_withdrawal_client/Cargo.toml | 1 + core/lib/via_withdrawal_client/examples/withdraw.rs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 318cf40a1..4d7bd0154 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8620,6 +8620,7 @@ dependencies = [ "rand 0.8.5", "tokio", "tracing", + "tracing-subscriber", "via_da_clients", "zksync_basic_types", "zksync_config", diff --git a/core/lib/via_withdrawal_client/Cargo.toml b/core/lib/via_withdrawal_client/Cargo.toml index df41d2014..d76034a99 100644 --- a/core/lib/via_withdrawal_client/Cargo.toml +++ b/core/lib/via_withdrawal_client/Cargo.toml @@ -20,6 +20,7 @@ zksync_utils.workspace = true tokio.workspace = true tracing.workspace = true via_da_clients.workspace = true +tracing-subscriber.workspace = true bitcoin = { version = "0.32.2", features = ["serde"] } byteorder = "1.4" diff --git a/core/lib/via_withdrawal_client/examples/withdraw.rs b/core/lib/via_withdrawal_client/examples/withdraw.rs index caded66f6..4971eceba 100644 --- a/core/lib/via_withdrawal_client/examples/withdraw.rs +++ b/core/lib/via_withdrawal_client/examples/withdraw.rs @@ -15,6 +15,9 @@ const DEFAULT_CELESTIA: &str = "http://0.0.0.0:26658"; #[tokio::main] async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); let home = env::var("VIA_HOME").context("VIA HOME not set")?; let _ = dotenv::from_path(home.clone() + "/etc/env/target/via.env"); From 41846f7d309886ade7d24f7fa40c7dcba2b8c65a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:19:46 +0100 Subject: [PATCH 023/212] fix: genesis version --- etc/env/file_based/genesis.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index 8950256bc..ddac8123f 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -1,9 +1,9 @@ genesis_root: 0xa8ba1e76b4d8560bee8c039c91d88b4860cae79b05d4b2d656f0d38d7856a2dd genesis_rollup_leaf_index: 54 genesis_batch_commitment: 0x53de9f8fb086c1cc78e337800264fd9beb7a35fc56dd4a7afce5b3e9f2475251 -genesis_protocol_semantic_version: '0.24.1' +genesis_protocol_semantic_version: '0.26.0' # deprecated -genesis_protocol_version: 24 +genesis_protocol_version: 26 default_aa_hash: 0x01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f bootloader_hash: 0x010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491 l1_chain_id: 9 From 13db627536ad4d634886c4d69dbbad9f1f179835 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:20:44 +0100 Subject: [PATCH 024/212] chore: update crates --- Cargo.lock | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a80ccec8d..8b21a4a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3831,14 +3831,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hashers" version = "1.0.1" From 3fb7ec0cce8864b3776109d9e50fc980423b2d8a Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Mon, 9 Dec 2024 17:16:41 +0100 Subject: [PATCH 025/212] feat: new tables for voting, updated --- ...c0355f5ff8c0b7918d961df7348f7e3236a17.json | 15 +++ ...25bdc5ac79944550cfe2acca1e80a76caf720.json | 16 +++ ...4b47eec44c39bc907fe4d6edacca4b6f797f8.json | 14 ++ ...61c010316e5cc31cafee6227c5240e72fc988.json | 28 ++++ ...54a75405d056b8945fe00ba9a848886328525.json | 22 ++++ .../20241209150000_create_via_votes.down.sql | 2 + .../20241209150000_create_via_votes.up.sql | 16 +++ core/lib/dal/src/lib.rs | 9 +- core/lib/dal/src/via_votes_dal.rs | 124 ++++++++++++++++++ core/node/via_btc_watch/src/lib.rs | 21 +-- .../src/message_processors/mod.rs | 2 + .../src/message_processors/votable.rs | 88 +++++++++++++ 12 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json create mode 100644 core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json create mode 100644 core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json create mode 100644 core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json create mode 100644 core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json create mode 100644 core/lib/dal/migrations/20241209150000_create_via_votes.down.sql create mode 100644 core/lib/dal/migrations/20241209150000_create_via_votes.up.sql create mode 100644 core/lib/dal/src/via_votes_dal.rs create mode 100644 core/node/via_btc_watch/src/message_processors/votable.rs diff --git a/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json b/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json new file mode 100644 index 000000000..d61ceb1c4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO via_votable_transactions (tx_id, transaction_type)\n VALUES ($1, $2)\n ON CONFLICT (tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Text" + ] + }, + "nullable": [] + }, + "hash": "180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17" +} diff --git a/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json b/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json new file mode 100644 index 000000000..43fea07d4 --- /dev/null +++ b/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO via_votes (tx_id, verifier_address, vote)\n VALUES ($1, $2, $3)\n ON CONFLICT (tx_id, verifier_address) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720" +} diff --git a/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json b/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json new file mode 100644 index 000000000..8a4ae7302 --- /dev/null +++ b/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET is_finalized = TRUE, updated_at = NOW()\n WHERE tx_id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8" +} diff --git a/core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json b/core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json new file mode 100644 index 000000000..741fbd96d --- /dev/null +++ b/core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) FILTER (WHERE vote = TRUE) AS ok_votes,\n COUNT(*) AS total_votes\n FROM via_votes\n WHERE tx_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "ok_votes", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "total_votes", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988" +} diff --git a/core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json b/core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json new file mode 100644 index 000000000..388e8b8d3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT is_finalized\n FROM via_votable_transactions\n WHERE tx_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_finalized", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525" +} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.down.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.down.sql new file mode 100644 index 000000000..9bce83ce9 --- /dev/null +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS via_votes; +DROP TABLE IF EXISTS via_votable_transactions; diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql new file mode 100644 index 000000000..65770c88a --- /dev/null +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS via_votable_transactions ( + tx_id BYTEA PRIMARY KEY, + transaction_type TEXT NOT NULL, + is_finalized BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS via_votes ( + tx_id BYTEA NOT NULL REFERENCES via_votable_transactions(tx_id) ON DELETE CASCADE, + verifier_address TEXT NOT NULL, + vote BOOLEAN NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + + PRIMARY KEY (tx_id, verifier_address) +); diff --git a/core/lib/dal/src/lib.rs b/core/lib/dal/src/lib.rs index 5fe900c0c..7d914fa53 100644 --- a/core/lib/dal/src/lib.rs +++ b/core/lib/dal/src/lib.rs @@ -27,7 +27,7 @@ use crate::{ tokens_web3_dal::TokensWeb3Dal, transactions_dal::TransactionsDal, transactions_web3_dal::TransactionsWeb3Dal, via_blocks_dal::ViaBlocksDal, via_data_availability_dal::ViaDataAvailabilityDal, via_transactions_dal::ViaTransactionsDal, - vm_runner_dal::VmRunnerDal, + via_votes_dal::ViaVotesDal, vm_runner_dal::VmRunnerDal, }; pub mod base_token_dal; @@ -66,6 +66,7 @@ pub mod transactions_web3_dal; pub mod via_blocks_dal; pub mod via_data_availability_dal; pub mod via_transactions_dal; +pub mod via_votes_dal; pub mod vm_runner_dal; #[cfg(test)] @@ -86,6 +87,8 @@ where fn via_transactions_dal(&mut self) -> ViaTransactionsDal<'_, 'a>; + fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a>; + fn transactions_web3_dal(&mut self) -> TransactionsWeb3Dal<'_, 'a>; fn tee_verifier_input_producer_dal(&mut self) -> TeeVerifierInputProducerDal<'_, 'a>; @@ -165,6 +168,10 @@ impl<'a> CoreDal<'a> for Connection<'a, Core> { ViaTransactionsDal { storage: self } } + fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a> { + ViaVotesDal { storage: self } + } + fn transactions_web3_dal(&mut self) -> TransactionsWeb3Dal<'_, 'a> { TransactionsWeb3Dal { storage: self } } diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs new file mode 100644 index 000000000..c122ddd62 --- /dev/null +++ b/core/lib/dal/src/via_votes_dal.rs @@ -0,0 +1,124 @@ +use zksync_db_connection::{connection::Connection, error::DalResult, instrument::InstrumentExt}; +use zksync_types::{Address, H256}; + +use crate::Core; + +pub struct ViaVotesDal<'c, 'a> { + pub(crate) storage: &'c mut Connection<'a, Core>, +} + +impl ViaVotesDal<'_, '_> { + pub async fn insert_votable_transaction( + &mut self, + tx_id: H256, + tx_type: &str, + ) -> DalResult<()> { + sqlx::query!( + r#" + INSERT INTO + via_votable_transactions (tx_id, transaction_type) + VALUES + ($1, $2) + ON CONFLICT (tx_id) DO NOTHING + "#, + tx_id.as_bytes(), + tx_type + ) + .instrument("insert_votable_transaction") + .fetch_optional(self.storage) + .await?; + Ok(()) + } + + pub async fn insert_vote( + &mut self, + tx_id: H256, + verifier_address: &str, + vote: bool, + ) -> DalResult<()> { + sqlx::query!( + r#" + INSERT INTO + via_votes (tx_id, verifier_address, vote) + VALUES + ($1, $2, $3) + ON CONFLICT (tx_id, verifier_address) DO NOTHING + "#, + tx_id.as_bytes(), + verifier_address, + vote + ) + .instrument("insert_vote") + .fetch_optional(self.storage) + .await?; + Ok(()) + } + + pub async fn get_vote_count(&mut self, tx_id: H256) -> DalResult<(i64, i64)> { + let row = sqlx::query!( + r#" + SELECT + COUNT(*) FILTER ( + WHERE + vote = TRUE + ) AS ok_votes, + COUNT(*) AS total_votes + FROM + via_votes + WHERE + tx_id = $1 + "#, + tx_id.as_bytes() + ) + .instrument("get_vote_count") + .fetch_one(self.storage) + .await?; + + let ok_votes = row.ok_votes.unwrap_or(0); + let total_votes = row.total_votes.unwrap_or(0); + Ok((ok_votes, total_votes)) + } + + pub async fn finalize_transaction_if_needed( + &mut self, + tx_id: H256, + threshold: f64, + ) -> DalResult<()> { + let (ok_votes, total_votes) = self.get_vote_count(tx_id).await?; + if total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + is_finalized = TRUE, + updated_at = NOW() + WHERE + tx_id = $1 + "#, + tx_id.as_bytes() + ) + .instrument("finalize_transaction_if_needed") + .execute(self.storage) + .await?; + } + Ok(()) + } + + pub async fn is_transaction_finalized(&mut self, tx_id: H256) -> DalResult { + let row = sqlx::query!( + r#" + SELECT + is_finalized + FROM + via_votable_transactions + WHERE + tx_id = $1 + "#, + tx_id.as_bytes() + ) + .instrument("is_transaction_finalized") + .fetch_optional(self.storage) + .await?; + Ok(row.map(|r| r.is_finalized).unwrap_or(false)) + } +} diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index faaaaa8bb..1ec22bc2d 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -15,7 +15,9 @@ use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_types::PriorityOpId; use self::{ - message_processors::{L1ToL2MessageProcessor, MessageProcessor, MessageProcessorError}, + message_processors::{ + L1ToL2MessageProcessor, MessageProcessor, MessageProcessorError, VotableMessageProcessor, + }, metrics::METRICS, }; use crate::metrics::ErrorType; @@ -57,12 +59,13 @@ impl BtcWatch { tracing::info!("initialized state: {state:?}"); drop(storage); - // TODO: add other message processors if needed - let message_processors: Vec> = - vec![Box::new(L1ToL2MessageProcessor::new( + let message_processors: Vec> = vec![ + Box::new(L1ToL2MessageProcessor::new( state.bridge_address.clone(), state.next_expected_priority_id, - ))]; + )), + Box::new(VotableMessageProcessor::new(3)), + ]; let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); @@ -173,9 +176,11 @@ impl BtcWatch { .await .map_err(|e| MessageProcessorError::Internal(e.into()))?; - // temporary use only one processor to avoid cloning - if let Some(processor) = self.message_processors.first_mut() { - processor.process_messages(storage, messages).await?; + for processor in self.message_processors.iter_mut() { + processor + .process_messages(storage, messages.clone()) + .await + .map_err(|e| MessageProcessorError::Internal(e.into()))?; } self.last_processed_bitcoin_block = to_block; diff --git a/core/node/via_btc_watch/src/message_processors/mod.rs b/core/node/via_btc_watch/src/message_processors/mod.rs index f6b4eaefc..cc1d1f88a 100644 --- a/core/node/via_btc_watch/src/message_processors/mod.rs +++ b/core/node/via_btc_watch/src/message_processors/mod.rs @@ -1,8 +1,10 @@ pub(crate) use l1_to_l2::L1ToL2MessageProcessor; use via_btc_client::types::FullInscriptionMessage; +pub(crate) use votable::VotableMessageProcessor; use zksync_dal::{Connection, Core}; mod l1_to_l2; +mod votable; #[derive(Debug, thiserror::Error)] pub(super) enum MessageProcessorError { diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs new file mode 100644 index 000000000..4bc80c692 --- /dev/null +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -0,0 +1,88 @@ +use via_btc_client::types::{BitcoinTxid, FullInscriptionMessage}; +use zksync_dal::{Connection, Core, CoreDal}; +use zksync_types::H256; + +use super::{MessageProcessor, MessageProcessorError}; + +#[derive(Debug)] +pub struct VotableMessageProcessor { + verifier_count: usize, + threshold: f64, +} + +impl VotableMessageProcessor { + pub fn new(verifier_count: usize) -> Self { + Self { + verifier_count, + threshold: 0.5, + } + } +} + +#[async_trait::async_trait] +impl MessageProcessor for VotableMessageProcessor { + async fn process_messages( + &mut self, + storage: &mut Connection<'_, Core>, + msgs: Vec, + ) -> Result<(), MessageProcessorError> { + let mut votes_dal = storage.via_votes_dal(); + + for msg in msgs { + match msg { + FullInscriptionMessage::L1BatchDAReference(da_msg) => { + let tx_id = convert_txid_to_h256(da_msg.common.tx_id); + votes_dal + .insert_votable_transaction(tx_id, "L1BatchDAReference") + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + } + FullInscriptionMessage::ProofDAReference(proof_msg) => { + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + votes_dal + .insert_votable_transaction(tx_id, "ProofDAReference") + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + } + FullInscriptionMessage::ValidatorAttestation(attestation_msg) => { + let reference_txid = convert_txid_to_h256(attestation_msg.input.reference_txid); + // Vote = true if attestation_msg.input.attestation == Vote::Ok + let is_ok = matches!( + attestation_msg.input.attestation, + via_btc_client::types::Vote::Ok + ); + votes_dal + .insert_vote( + reference_txid, + &attestation_msg.common.p2wpkh_address.to_string(), + is_ok, + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + // Check finalization + votes_dal + .finalize_transaction_if_needed(reference_txid, self.threshold) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + } + // bootstrapping phase is already covered + FullInscriptionMessage::ProposeSequencer(_) => { + continue; + } + // Non-votable messages like SystemBootstrapping or L1ToL2Message are ignored by this processor + FullInscriptionMessage::SystemBootstrapping(_) + | FullInscriptionMessage::L1ToL2Message(_) => { + // do nothing + } + } + } + Ok(()) + } +} + +fn convert_txid_to_h256(txid: BitcoinTxid) -> H256 { + let mut tx_id_bytes = txid.as_raw_hash()[..].to_vec(); + tx_id_bytes.reverse(); + H256::from_slice(&tx_id_bytes) +} From 98ff2a5d4fdeb9ee175dbb87c750a087e5c7eba8 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 12 Dec 2024 13:58:07 +0330 Subject: [PATCH 026/212] complete withdrawal example --- Cargo.lock | 44 +++- core/lib/via_btc_client/Cargo.toml | 10 + .../lib/via_btc_client/examples/withdrawal.rs | 220 ++++++++++++++++++ core/lib/via_btc_client/src/lib.rs | 2 +- 4 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 core/lib/via_btc_client/examples/withdrawal.rs diff --git a/Cargo.lock b/Cargo.lock index 071f8d160..a2c32b66f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4228,7 +4228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4665,6 +4665,21 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "musig2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaa74fd6a0747bd589b36abce26cd4cd1cd2abedb2fcba26c4eed694dd85487" +dependencies = [ + "base16ct 0.2.0", + "hmac", + "once_cell", + "secp", + "secp256k1 0.30.0", + "sha2 0.10.8", + "subtle", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -6518,6 +6533,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ed54b1141d8cec428d8a4abf01282755ba4e4c8a621dd23fa2e0ed761814c2" +dependencies = [ + "base16ct 0.2.0", + "once_cell", + "secp256k1 0.30.0", + "subtle", +] + [[package]] name = "secp256k1" version = "0.27.0" @@ -6539,6 +6566,17 @@ dependencies = [ "serde", ] +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys 0.10.0", +] + [[package]] name = "secp256k1-sys" version = "0.8.1" @@ -8424,9 +8462,11 @@ dependencies = [ "inquire", "lazy_static", "mockall", + "musig2", "rand 0.8.5", "reqwest 0.12.7", "secp256k1 0.29.0", + "secp256k1 0.30.0", "serde", "serde_json", "thiserror", @@ -8853,7 +8893,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/core/lib/via_btc_client/Cargo.toml b/core/lib/via_btc_client/Cargo.toml index 71ea11391..6f686d24f 100644 --- a/core/lib/via_btc_client/Cargo.toml +++ b/core/lib/via_btc_client/Cargo.toml @@ -26,6 +26,7 @@ bitcoincore-rpc = "0.19.0" rand.workspace = true hex.workspace = true secp256k1 = "0.29.0" +secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} reqwest = "0.12.5" serde_json.workspace = true inquire = { version = "0.7.5", optional = true } @@ -34,6 +35,8 @@ serde.workspace = true tracing.workspace = true tracing-subscriber.workspace = true bincode = "1.3" +musig2 = "0.2.0" + [dev-dependencies] mockall = "0.13.0" @@ -62,3 +65,10 @@ path = "examples/bootstrap.rs" [[example]] name = "verify_batch" path = "examples/verify_batch.rs" + + +[[example]] +name = "withdrawal" +path = "examples/withdrawal.rs" + + diff --git a/core/lib/via_btc_client/examples/withdrawal.rs b/core/lib/via_btc_client/examples/withdrawal.rs new file mode 100644 index 000000000..108609ac6 --- /dev/null +++ b/core/lib/via_btc_client/examples/withdrawal.rs @@ -0,0 +1,220 @@ +use bitcoin::{ + absolute, + hashes::Hash, + sighash::{Prevouts, SighashCache}, + taproot::TaprootSpendInfo, + Address as BitcoinAddress, Amount, Network, OutPoint, TapSighashType, Transaction, TxIn, TxOut, + Witness, XOnlyPublicKey, +}; +// use bitcoincore_rpc::Auth; +use musig2::{ + verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, SecNonceSpices, +}; +use rand::{rngs::OsRng, Rng}; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // ------------------------------------------- + // Setup: Create secret and public keys for three participants + // ------------------------------------------- + let mut rng = OsRng; + let secret_key_1 = SecretKey::new(&mut rng); + let secret_key_2 = SecretKey::new(&mut rng); + let secret_key_3 = SecretKey::new(&mut rng); + + let secp = Secp256k1::new(); + let public_key_1 = PublicKey::from_secret_key(&secp, &secret_key_1); + let public_key_2 = PublicKey::from_secret_key(&secp, &secret_key_2); + let public_key_3 = PublicKey::from_secret_key(&secp, &secret_key_3); + + // ------------------------------------------- + // Key aggregation (MuSig2) + // ------------------------------------------- + let pubkeys = vec![public_key_1, public_key_2, public_key_3]; + let key_agg_ctx = KeyAggContext::new(pubkeys)?; + let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); + + // Convert to x-only pubkey for Taproot address + let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); + let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + // Create a P2TR address from the aggregated x-only public key + let secp_btc = bitcoin::secp256k1::Secp256k1::new(); + let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); + let tweaked_key = tap_info.output_key(); + let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); + println!("Aggregated taproot address: {}", address); + + // ------------------------------------------- + // Connect to Bitcoin node (adjust RPC credentials and URL) + // ------------------------------------------- + // NOTE: Update these with real RPC credentials and URL + let _rpc_url = "http://127.0.0.1:18443"; + let _rpc_user = "user"; + let _rpc_pass = "pass"; + + // let client = BitcoinClient::new(rpc_url, Network::Regtest, Auth::UserPass(rpc_user.into(), rpc_pass.into()))?; + + // ------------------------------------------- + // Instead of fetching UTXOs from node, use a fake constant UTXO for demonstration + // Comment out real fetching code + // ------------------------------------------- + // let utxos = client.fetch_utxos(&address).await?; + // if utxos.is_empty() { + // eprintln!("No UTXOs found for this address. Please fund it first."); + // return Ok(()); + // } + + // We'll use a fake UTXO here + let fake_utxo_txid = bitcoin::Txid::from_slice(&[0x11; 32]).unwrap(); // just a dummy 32-byte txid + let fake_vout = 0; + let fake_utxo_amount = Amount::from_btc(1.0).unwrap(); // 1 BTC in the fake utxo + let fake_utxo = (fake_utxo_txid, fake_vout, fake_utxo_amount); + + // ------------------------------------------- + // Create a transaction spending this fake UTXO + // ------------------------------------------- + let send_amount = Amount::from_btc(0.1).unwrap(); // amount to send + let fee_amount = Amount::from_btc(0.0001).unwrap(); + let change_amount = fake_utxo_amount - send_amount - fee_amount; + + // The recipient address - for demonstration let's send to the same aggregated address + // or another regtest address. + let recipient_address = address.clone(); + let change_address = address.clone(); + + let txin = TxIn { + previous_output: OutPoint { + txid: fake_utxo.0, + vout: fake_utxo.1, + }, + sequence: bitcoin::Sequence(0xFFFFFFFF), + witness: Witness::new(), + script_sig: bitcoin::Script::new().into(), + }; + + let txout_recipient = TxOut { + value: send_amount, + script_pubkey: recipient_address.script_pubkey(), + }; + + let txout_change = TxOut { + value: change_amount, + script_pubkey: change_address.script_pubkey(), + }; + + let mut unsigned_tx = Transaction { + version: bitcoin::transaction::Version(2), + lock_time: absolute::LockTime::ZERO, + input: vec![txin], + output: vec![txout_recipient, txout_change], + }; + + // ------------------------------------------- + // Compute the BIP341 sighash for signing + // ------------------------------------------- + let mut sighash_cache = SighashCache::new(&unsigned_tx); + let sighash_type = TapSighashType::All; + + // For taproot key spend (no script): + let sighash = sighash_cache.taproot_key_spend_signature_hash( + 0, + &Prevouts::All(&[TxOut { + value: fake_utxo_amount, + script_pubkey: recipient_address.script_pubkey(), + }]), + sighash_type, + )?; + + let message = sighash; // This 32-byte hash is what we will sign using MuSig2 + + // ------------------------------------------- + // MuSig2 Nonce Exchange and Partial Signatures + // ------------------------------------------- + // First round: generate public nonces + let mut first_round_1 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 0, + SecNonceSpices::new() + .with_seckey(secret_key_1) + .with_message(&message), + )?; + + let mut first_round_2 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 1, + SecNonceSpices::new() + .with_seckey(secret_key_2) + .with_message(&message), + )?; + + let mut first_round_3 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 2, + SecNonceSpices::new() + .with_seckey(secret_key_3) + .with_message(&message), + )?; + + // Get public nonces + let pub_nonce_1 = first_round_1.our_public_nonce(); + let pub_nonce_2 = first_round_2.our_public_nonce(); + let pub_nonce_3 = first_round_3.our_public_nonce(); + + // Exchange nonces between participants + first_round_1.receive_nonce(1, pub_nonce_2.clone())?; + first_round_1.receive_nonce(2, pub_nonce_3.clone())?; + + first_round_2.receive_nonce(0, pub_nonce_1.clone())?; + first_round_2.receive_nonce(2, pub_nonce_3.clone())?; + + first_round_3.receive_nonce(0, pub_nonce_1.clone())?; + first_round_3.receive_nonce(1, pub_nonce_2.clone())?; + + // Second round: Create partial signatures + let mut second_round_1 = first_round_1.finalize(secret_key_1, &message)?; + let second_round_2 = first_round_2.finalize(secret_key_2, &message)?; + let second_round_3 = first_round_3.finalize(secret_key_3, &message)?; + + // Get partial signatures + let _partial_sig_1: PartialSignature = second_round_1.our_signature(); + let partial_sig_2: PartialSignature = second_round_2.our_signature(); + let partial_sig_3: PartialSignature = second_round_3.our_signature(); + + // One participant collects all partial signatures + second_round_1.receive_signature(1, partial_sig_2)?; + second_round_1.receive_signature(2, partial_sig_3)?; + + // Final aggregate MuSig2 signature + let final_signature: CompactSignature = second_round_1.finalize()?; + + // Verify the signature (optional sanity check) + match verify_single(aggregated_pubkey, final_signature, message) { + Ok(_) => println!("MuSig2 signature verified successfully!"), + Err(e) => println!("MuSig2 signature verification failed: {:?}", e), + } + + // ------------------------------------------- + // Insert the final signature into the transaction witness + // ------------------------------------------- + let mut final_sig_with_hashtype = final_signature.serialize().to_vec(); + final_sig_with_hashtype.push(sighash_type as u8); // For SIGHASH_DEFAULT this is 0x00 + + // For a key-path spend in taproot, the witness is just the signature + unsigned_tx.input[0].witness = Witness::from(vec![final_sig_with_hashtype]); + + // ------------------------------------------- + // Print the signed raw transaction (in hex) + // ------------------------------------------- + let signed_raw_tx = bitcoin::consensus::encode::serialize_hex(&unsigned_tx); + println!("Signed raw transaction (hex): {}", signed_raw_tx); + + // NOTE: In real scenario, you could broadcast this transaction using the Bitcoin node RPC: + // client.broadcast_raw_tx(&signed_raw_tx).await?; + // Here we just printed it. + + Ok(()) +} diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index 9a86fee97..caa009cc0 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -1,7 +1,7 @@ pub mod traits; pub mod types; -pub(crate) mod client; +pub mod client; pub mod indexer; pub mod inscriber; #[cfg(feature = "regtest")] From 9dccd2e48ba94fbccbff9dbf4cb60ab330624b6f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:05:15 +0100 Subject: [PATCH 027/212] chore: update gitmodule --- .gitmodules | 1 + contracts | 2 +- etc/env/base/contracts.toml | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8ec15bfcb..3c352b775 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/vianetwork/era-contracts.git +branch = devnet-2 diff --git a/contracts b/contracts index 4fde2cb06..cd3c930a1 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 4fde2cb06d1d1c4ac0e5fac230f12305dd42e59c +Subproject commit cd3c930a1d6bbe37f7a3bf39589703898654fe38 diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index 5d947b95b..b5cc2a796 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0xa8ba1e76b4d8560bee8c039c91d88b4860cae79b05d4b2d656f0d38d7856a2dd" -GENESIS_BATCH_COMMITMENT = "0x53de9f8fb086c1cc78e337800264fd9beb7a35fc56dd4a7afce5b3e9f2475251" +GENESIS_ROOT = "0x55cc43e53c79bfdc738ca7aa7a7677ed0c50d07ae3d72181da42ac897af8bdd5" +GENESIS_BATCH_COMMITMENT = "0x9ad49644e4f8c9a3642db6033df1bb89b5f7d4e156ba9e48296d323d453f69f1" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" From 14c87284efb920a8608fd9ff435916882e92d09f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:24:53 +0100 Subject: [PATCH 028/212] chore: update genesis config --- etc/env/file_based/genesis.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index ddac8123f..50ee75852 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -1,6 +1,6 @@ -genesis_root: 0xa8ba1e76b4d8560bee8c039c91d88b4860cae79b05d4b2d656f0d38d7856a2dd +genesis_root: 0x55cc43e53c79bfdc738ca7aa7a7677ed0c50d07ae3d72181da42ac897af8bdd5 genesis_rollup_leaf_index: 54 -genesis_batch_commitment: 0x53de9f8fb086c1cc78e337800264fd9beb7a35fc56dd4a7afce5b3e9f2475251 +genesis_batch_commitment: 0x9ad49644e4f8c9a3642db6033df1bb89b5f7d4e156ba9e48296d323d453f69f1 genesis_protocol_semantic_version: '0.26.0' # deprecated genesis_protocol_version: 26 From ebde8c8f2b8981713bbfbf3a5ee96555ba1ce831 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:12:52 +0100 Subject: [PATCH 029/212] feat(via_btc_client): add bitcoin block fee history --- Cargo.lock | 1 + core/lib/via_btc_client/Cargo.toml | 5 ++ .../via_btc_client/examples/fee_history.rs | 49 ++++++++++++++++ core/lib/via_btc_client/src/client/mod.rs | 42 +++++++++++++- .../via_btc_client/src/client/rpc_client.rs | 13 ++++- core/lib/via_btc_client/src/indexer/mod.rs | 7 +++ core/lib/via_btc_client/src/inscriber/mod.rs | 7 +++ .../src/inscriber/test_utils.rs | 58 ++++++++++++++++++- core/lib/via_btc_client/src/traits.rs | 9 ++- core/lib/via_btc_client/src/types.rs | 2 +- 10 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 core/lib/via_btc_client/examples/fee_history.rs diff --git a/Cargo.lock b/Cargo.lock index 8b21a4a8a..1a6948bea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9382,6 +9382,7 @@ dependencies = [ "bincode", "bitcoin", "bitcoincore-rpc", + "futures 0.3.30", "hex", "inquire", "lazy_static", diff --git a/core/lib/via_btc_client/Cargo.toml b/core/lib/via_btc_client/Cargo.toml index 71ea11391..79292c7b4 100644 --- a/core/lib/via_btc_client/Cargo.toml +++ b/core/lib/via_btc_client/Cargo.toml @@ -21,6 +21,7 @@ thiserror.workspace = true async-trait.workspace = true lazy_static.workspace = true tokio.workspace = true +futures.workspace = true bitcoin = { version = "0.32.2", features = ["serde"] } bitcoincore-rpc = "0.19.0" rand.workspace = true @@ -62,3 +63,7 @@ path = "examples/bootstrap.rs" [[example]] name = "verify_batch" path = "examples/verify_batch.rs" + +[[example]] +name = "fee_history" +path = "examples/fee_history.rs" \ No newline at end of file diff --git a/core/lib/via_btc_client/examples/fee_history.rs b/core/lib/via_btc_client/examples/fee_history.rs new file mode 100644 index 000000000..fbbc6acdd --- /dev/null +++ b/core/lib/via_btc_client/examples/fee_history.rs @@ -0,0 +1,49 @@ +use std::{env, str::FromStr}; + +use anyhow::{Context, Result}; +use tracing::info; +use via_btc_client::{ + inscriber::Inscriber, + types::{BitcoinNetwork, NodeAuth}, +}; + +const RPC_URL: &str = "http://0.0.0.0:18443"; +const RPC_USERNAME: &str = "rpcuser"; +const RPC_PASSWORD: &str = "rpcpassword"; +const NETWORK: BitcoinNetwork = BitcoinNetwork::Regtest; +const PK: &str = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm"; + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); + + let args: Vec = env::args().collect(); + let number_blocks = usize::from_str(&args[1].to_string())?; + + let inscriber = Inscriber::new( + RPC_URL, + NETWORK, + NodeAuth::UserPass(RPC_USERNAME.to_string(), RPC_PASSWORD.to_string()), + PK, + None, + ) + .await + .context("Failed to Inscriber")?; + + let client = inscriber.get_client().await; + + let to_block = client.fetch_block_height().await? as usize; + let from_block = to_block - number_blocks; + info!( + "Fetch blocks fee history from block {} to {}", + from_block, to_block + ); + + let fee_history = client.get_fee_history(from_block, to_block).await?; + + info!("Fee history {:?}", fee_history); + + Ok(()) +} diff --git a/core/lib/via_btc_client/src/client/mod.rs b/core/lib/via_btc_client/src/client/mod.rs index f4d512eef..8ecacb82c 100644 --- a/core/lib/via_btc_client/src/client/mod.rs +++ b/core/lib/via_btc_client/src/client/mod.rs @@ -1,8 +1,9 @@ -use std::sync::Arc; +use std::{sync::Arc, u64}; use async_trait::async_trait; use bitcoin::{Address, Block, BlockHash, Network, OutPoint, Transaction, TxOut, Txid}; -use bitcoincore_rpc::json::EstimateMode; +use bitcoincore_rpc::json::{EstimateMode, GetBlockStatsResult}; +use futures::future::join_all; use tracing::{debug, error, instrument}; mod rpc_client; @@ -156,6 +157,42 @@ impl BitcoinOps for BitcoinClient { debug!("Fetching block by hash"); self.rpc.get_block_by_hash(block_hash).await } + + #[instrument(skip(self), target = "bitcoin_client")] + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult { + debug!("Fetching block by hash"); + self.rpc.get_block_stats(height).await + } + + /// Retrieve the "fee_history" for the Bitcoin blockchain between provided blocks 'from_block_height' and 'to_block_height'. + #[instrument(skip(self), target = "bitcoin_client")] + async fn get_fee_history( + &self, + from_block_height: usize, + to_block_height: usize, + ) -> BitcoinClientResult> { + debug!("Fetching blocks fee history"); + + let mut fetch_blocks_futures = Vec::new(); + for block_height in from_block_height..to_block_height { + fetch_blocks_futures.push(self.get_block_stats(block_height as u64)); + } + + let blocks = join_all(fetch_blocks_futures).await; + let mut fee_history: Vec = Vec::new(); + + for block_result in blocks { + match block_result { + Ok(block) => { + fee_history.push(std::cmp::max(block.min_fee_rate.to_sat(), 1)); + } + Err(err) => { + return BitcoinClientResult::Err(err.clone()); + } + } + } + Ok(fee_history) + } } impl Clone for BitcoinClient { @@ -198,6 +235,7 @@ mod tests { async fn get_raw_transaction_info(&self, txid: &Txid) -> BitcoinClientResult; async fn estimate_smart_fee(&self, conf_target: u16, estimate_mode: Option) -> BitcoinClientResult; async fn get_blockchain_info(&self) -> BitcoinRpcResult; + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult; } } diff --git a/core/lib/via_btc_client/src/client/rpc_client.rs b/core/lib/via_btc_client/src/client/rpc_client.rs index 517cb7f7a..8f9ee7d9f 100644 --- a/core/lib/via_btc_client/src/client/rpc_client.rs +++ b/core/lib/via_btc_client/src/client/rpc_client.rs @@ -4,7 +4,9 @@ use async_trait::async_trait; use bitcoin::{Address, Block, BlockHash, OutPoint, Transaction, Txid}; use bitcoincore_rpc::{ bitcoincore_rpc_json::EstimateMode, - json::{EstimateSmartFeeResult, GetBlockchainInfoResult, ScanTxOutRequest}, + json::{ + EstimateSmartFeeResult, GetBlockStatsResult, GetBlockchainInfoResult, ScanTxOutRequest, + }, Client, RpcApi, }; use tracing::{debug, instrument}; @@ -221,6 +223,15 @@ impl BitcoinRpc for BitcoinRpcClient { }) .await } + + #[instrument(skip(self), target = "bitcoin_client::rpc_client")] + async fn get_block_stats(&self, height: u64) -> BitcoinRpcResult { + Self::retry_rpc(|| { + debug!("Getting block stats"); + self.client.get_block_stats(height).map_err(|e| e.into()) + }) + .await + } } impl Clone for BitcoinRpcClient { diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 10cbf6d66..fbe86c05e 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -336,6 +336,7 @@ mod tests { block::Header, hashes::Hash, Amount, Block, OutPoint, ScriptBuf, Transaction, TxMerkleNode, TxOut, }; + use bitcoincore_rpc::json::GetBlockStatsResult; use mockall::{mock, predicate::*}; use super::*; @@ -355,6 +356,12 @@ mod tests { async fn fetch_block_height(&self) -> BitcoinClientResult; async fn get_fee_rate(&self, conf_target: u16) -> BitcoinClientResult; fn get_network(&self) -> Network; + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult; + async fn get_fee_history( + &self, + from_block_height: usize, + to_block_height: usize, + ) -> BitcoinClientResult>; } } diff --git a/core/lib/via_btc_client/src/inscriber/mod.rs b/core/lib/via_btc_client/src/inscriber/mod.rs index 473cb8fab..cc5434000 100644 --- a/core/lib/via_btc_client/src/inscriber/mod.rs +++ b/core/lib/via_btc_client/src/inscriber/mod.rs @@ -808,6 +808,7 @@ mod tests { Block, BlockHash, CompressedPublicKey, OutPoint, PrivateKey, ScriptBuf, Transaction, TxOut, Txid, }; + use bitcoincore_rpc::json::GetBlockStatsResult; use mockall::{mock, predicate::*}; use super::*; @@ -829,6 +830,12 @@ mod tests { async fn fetch_block_height(&self) -> BitcoinClientResult; async fn get_fee_rate(&self, conf_target: u16) -> BitcoinClientResult; fn get_network(&self) -> BitcoinNetwork; + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult; + async fn get_fee_history( + &self, + from_block_height: usize, + to_block_height: usize, + ) -> BitcoinClientResult>; } } diff --git a/core/lib/via_btc_client/src/inscriber/test_utils.rs b/core/lib/via_btc_client/src/inscriber/test_utils.rs index fa5509b1c..3b922da91 100644 --- a/core/lib/via_btc_client/src/inscriber/test_utils.rs +++ b/core/lib/via_btc_client/src/inscriber/test_utils.rs @@ -8,9 +8,10 @@ use bitcoin::{ ecdsa::Signature as ECDSASignature, schnorr::Signature as SchnorrSignature, All, Keypair, Message, PublicKey, Secp256k1, }, - Address, Block, BlockHash, CompressedPublicKey, Network, OutPoint, PrivateKey, ScriptBuf, - Transaction, TxOut, Txid, + Address, Amount, Block, BlockHash, CompressedPublicKey, Network, OutPoint, PrivateKey, + ScriptBuf, Transaction, TxOut, Txid, }; +use bitcoincore_rpc::json::{FeeRatePercentiles, GetBlockStatsResult}; use super::Inscriber; use crate::{ @@ -27,6 +28,7 @@ pub struct MockBitcoinOpsConfig { pub tx_confirmation: bool, pub transaction: Option, pub block: Option, + pub fee_history: Vec, } impl MockBitcoinOpsConfig { @@ -37,9 +39,13 @@ impl MockBitcoinOpsConfig { pub fn set_tx_confirmation(&mut self, tx_confirmation: bool) { self.tx_confirmation = tx_confirmation; } + + pub fn set_fee_history(&mut self, fees: Vec) { + self.fee_history = fees; + } } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct MockBitcoinOps { pub balance: u128, pub utxos: Vec<(OutPoint, TxOut)>, @@ -48,6 +54,7 @@ pub struct MockBitcoinOps { pub tx_confirmation: bool, pub transaction: Option, pub block: Option, + pub fee_history: Vec, } impl MockBitcoinOps { @@ -60,6 +67,7 @@ impl MockBitcoinOps { tx_confirmation: config.tx_confirmation, transaction: config.transaction, block: config.block, + fee_history: config.fee_history, } } } @@ -112,6 +120,50 @@ impl BitcoinOps for MockBitcoinOps { async fn fetch_block_by_hash(&self, _block_hash: &BlockHash) -> BitcoinClientResult { BitcoinClientResult::Ok(self.block.clone().expect("No block found")) } + + async fn get_fee_history(&self, _: usize, _: usize) -> BitcoinClientResult> { + BitcoinClientResult::Ok(self.fee_history.clone()) + } + + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult { + BitcoinClientResult::Ok(GetBlockStatsResult { + avg_fee: Amount::ZERO, + avg_fee_rate: Amount::ZERO, + avg_tx_size: 0, + block_hash: BlockHash::all_zeros(), + fee_rate_percentiles: FeeRatePercentiles { + fr_10th: Amount::ZERO, + fr_25th: Amount::ZERO, + fr_50th: Amount::ZERO, + fr_75th: Amount::ZERO, + fr_90th: Amount::ZERO, + }, + height, + ins: 0, + max_fee: Amount::ZERO, + max_fee_rate: Amount::ZERO, + max_tx_size: 0, + median_fee: Amount::ZERO, + median_time: 0, + median_tx_size: 0, + min_fee: Amount::ZERO, + min_fee_rate: Amount::ZERO, + min_tx_size: 0, + outs: 0, + subsidy: Amount::ZERO, + sw_total_size: 0, + sw_total_weight: 0, + sw_txs: 0, + time: 0, + total_out: Amount::ZERO, + total_size: 0, + total_weight: 0, + total_fee: Amount::ZERO, + txs: 0, + utxo_increase: 0, + utxo_size_inc: 0, + }) + } } #[derive(Debug, Clone)] diff --git a/core/lib/via_btc_client/src/traits.rs b/core/lib/via_btc_client/src/traits.rs index e2b38f2f8..35ee9542c 100644 --- a/core/lib/via_btc_client/src/traits.rs +++ b/core/lib/via_btc_client/src/traits.rs @@ -6,7 +6,7 @@ use bitcoin::{ secp256k1::{All, Secp256k1}, Address, Block, BlockHash, Network, OutPoint, ScriptBuf, Transaction, TxOut, Txid, }; -use bitcoincore_rpc::bitcoincore_rpc_json::GetBlockchainInfoResult; +use bitcoincore_rpc::{bitcoincore_rpc_json::GetBlockchainInfoResult, json::GetBlockStatsResult}; use secp256k1::{ ecdsa::Signature as ECDSASignature, schnorr::Signature as SchnorrSignature, Message, PublicKey, }; @@ -37,6 +37,12 @@ pub trait BitcoinOps: Send + Sync { async fn get_transaction(&self, txid: &Txid) -> BitcoinClientResult; async fn fetch_block_by_hash(&self, block_hash: &BlockHash) -> BitcoinClientResult; + async fn get_block_stats(&self, height: u64) -> BitcoinClientResult; + async fn get_fee_history( + &self, + from_block_height: usize, + to_block_height: usize, + ) -> BitcoinClientResult>; } impl std::fmt::Debug for dyn BitcoinOps + 'static { @@ -61,6 +67,7 @@ pub trait BitcoinRpc: Send + Sync { async fn get_block_by_hash(&self, block_hash: &BlockHash) -> BitcoinRpcResult; async fn get_best_block_hash(&self) -> BitcoinRpcResult; + async fn get_block_stats(&self, height: u64) -> BitcoinRpcResult; async fn get_raw_transaction_info( &self, txid: &Txid, diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index ff92e5544..eb440f424 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -246,7 +246,7 @@ pub struct InscriberOutput { pub is_broadcasted: bool, } -#[derive(Debug, Error)] +#[derive(Debug, Error, Clone)] pub enum BitcoinError { #[error("RPC error: {0}")] Rpc(String), From ea33b1dda855429eaad11ccc25b0e1c93cb542f5 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:15:06 +0100 Subject: [PATCH 030/212] feat(via_fee_model): implement the new via fee model logic - update the node logic - add gas adjuster ressource - update the via_l1_gas layer --- Cargo.lock | 3 + .../src/implementations/layers/mod.rs | 1 + .../layers/via_gas_adjuster.rs | 109 +++++++++ .../src/implementations/layers/via_l1_gas.rs | 27 ++- .../src/implementations/resources/mod.rs | 1 + .../resources/via_gas_adjuster.rs | 21 ++ .../src/message_processors/l1_to_l2.rs | 6 +- core/node/via_fee_model/Cargo.toml | 2 + .../src/l1_gas_price/gas_adjuster/mod.rs | 213 ++++++++++++++++++ .../via_fee_model/src/l1_gas_price/mod.rs | 1 + core/node/via_fee_model/src/lib.rs | 155 +++++++++++-- core/node/via_state_keeper/Cargo.toml | 1 + .../via_state_keeper/src/io/tests/tester.rs | 30 ++- 13 files changed, 528 insertions(+), 42 deletions(-) create mode 100644 core/node/node_framework/src/implementations/layers/via_gas_adjuster.rs create mode 100644 core/node/node_framework/src/implementations/resources/via_gas_adjuster.rs create mode 100644 core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs create mode 100644 core/node/via_fee_model/src/l1_gas_price/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1a6948bea..60191959e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9493,8 +9493,10 @@ dependencies = [ "async-trait", "tokio", "tracing", + "via_btc_client", "vise", "zksync_config", + "zksync_dal", "zksync_node_fee_model", "zksync_types", "zksync_utils", @@ -9539,6 +9541,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "via_btc_client", "via_fee_model", "vise", "zksync_config", diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index 980dff48c..cd8534b04 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -38,6 +38,7 @@ pub mod validate_chain_ids; pub mod via_btc_sender; pub mod via_btc_watch; pub mod via_da_dispatcher; +pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; pub mod vm_runner; diff --git a/core/node/node_framework/src/implementations/layers/via_gas_adjuster.rs b/core/node/node_framework/src/implementations/layers/via_gas_adjuster.rs new file mode 100644 index 000000000..a35cbb9eb --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_gas_adjuster.rs @@ -0,0 +1,109 @@ +use std::sync::Arc; + +use anyhow::Context; +use via_btc_client::{inscriber::Inscriber, types::NodeAuth}; +use via_btc_watch::BitcoinNetwork; +use via_fee_model::ViaGasAdjuster; +use zksync_config::{GasAdjusterConfig, ViaBtcSenderConfig}; + +use crate::{ + implementations::resources::via_gas_adjuster::ViaGasAdjusterResource, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for sequencer L1 gas interfaces. +/// Adds several resources that depend on L1 gas price. +#[derive(Debug)] +pub struct ViaGasAdjusterLayer { + gas_adjuster_config: GasAdjusterConfig, + config: ViaBtcSenderConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input {} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + pub gas_adjuster: ViaGasAdjusterResource, + /// Only runs if someone uses the resources listed above. + #[context(task)] + pub gas_adjuster_task: ViaGasAdjusterTask, +} + +impl ViaGasAdjusterLayer { + pub fn new(gas_adjuster_config: GasAdjusterConfig, config: ViaBtcSenderConfig) -> Self { + Self { + gas_adjuster_config, + config, + } + } +} + +#[async_trait::async_trait] +impl WiringLayer for ViaGasAdjusterLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "via_gas_adjuster_layer" + } + + async fn wire(self, _: Self::Input) -> Result { + let network = BitcoinNetwork::from_core_arg(self.config.network()) + .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; + + let inscriber = Inscriber::new( + self.config.rpc_url(), + network, + NodeAuth::UserPass( + self.config.rpc_user().to_string(), + self.config.rpc_password().to_string(), + ), + self.config.private_key(), + None, + ) + .await + .context("Init inscriber")?; + + let adjuster = ViaGasAdjuster::new(self.gas_adjuster_config, inscriber) + .await + .context("GasAdjuster::new()")?; + let gas_adjuster = Arc::new(adjuster); + + Ok(Output { + gas_adjuster: gas_adjuster.clone().into(), + gas_adjuster_task: ViaGasAdjusterTask { gas_adjuster }, + }) + } +} + +#[derive(Debug)] +pub struct ViaGasAdjusterTask { + gas_adjuster: Arc, +} + +#[async_trait::async_trait] +impl Task for ViaGasAdjusterTask { + fn id(&self) -> TaskId { + "via_gas_adjuster".into() + } + + async fn run(self: Box, mut stop_receiver: StopReceiver) -> anyhow::Result<()> { + // Gas adjuster layer is added to provide a resource for anyone to use, but it comes with + // a support task. If nobody has used the resource, we don't need to run the support task. + if Arc::strong_count(&self.gas_adjuster) == 1 { + tracing::info!( + "Via gas adjuster is not used by any other task, not running the support task" + ); + stop_receiver.0.changed().await?; + return Ok(()); + } + + self.gas_adjuster.run(stop_receiver.0).await + } +} diff --git a/core/node/node_framework/src/implementations/layers/via_l1_gas.rs b/core/node/node_framework/src/implementations/layers/via_l1_gas.rs index 914c083bd..22f878989 100644 --- a/core/node/node_framework/src/implementations/layers/via_l1_gas.rs +++ b/core/node/node_framework/src/implementations/layers/via_l1_gas.rs @@ -2,10 +2,15 @@ use std::sync::Arc; use via_fee_model::{ViaApiFeeInputProvider, ViaMainNodeFeeInputProvider}; use zksync_config::configs::chain::StateKeeperConfig; +use zksync_node_framework_derive::FromContext; use zksync_types::fee_model::FeeModelConfig; use crate::{ - implementations::resources::fee_input::{ApiFeeInputResource, SequencerFeeInputResource}, + implementations::resources::{ + fee_input::{ApiFeeInputResource, SequencerFeeInputResource}, + pools::{MasterPool, PoolResource}, + via_gas_adjuster::ViaGasAdjusterResource, + }, wiring_layer::{WiringError, WiringLayer}, IntoContext, }; @@ -17,6 +22,13 @@ pub struct ViaL1GasLayer { state_keeper_config: StateKeeperConfig, } +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, + pub gas_adjuster: ViaGasAdjusterResource, +} + #[derive(Debug, IntoContext)] #[context(crate = crate)] pub struct Output { @@ -34,20 +46,25 @@ impl ViaL1GasLayer { #[async_trait::async_trait] impl WiringLayer for ViaL1GasLayer { - type Input = (); + type Input = Input; type Output = Output; fn layer_name(&self) -> &'static str { "via_l1_gas_layer" } - async fn wire(self, _input: Self::Input) -> Result { + async fn wire(self, input: Self::Input) -> Result { let main_fee_input_provider = Arc::new(ViaMainNodeFeeInputProvider::new( + input.gas_adjuster.0.clone(), FeeModelConfig::from_state_keeper_config(&self.state_keeper_config), )?); - let api_fee_input_provider = - Arc::new(ViaApiFeeInputProvider::new(main_fee_input_provider.clone())); + let main_pool = input.master_pool.get().await?; + + let api_fee_input_provider = Arc::new(ViaApiFeeInputProvider::new( + main_fee_input_provider.clone(), + main_pool, + )); Ok(Output { sequencer_fee_input: main_fee_input_provider.into(), diff --git a/core/node/node_framework/src/implementations/resources/mod.rs b/core/node/node_framework/src/implementations/resources/mod.rs index 374c470d2..e65731499 100644 --- a/core/node/node_framework/src/implementations/resources/mod.rs +++ b/core/node/node_framework/src/implementations/resources/mod.rs @@ -15,5 +15,6 @@ pub mod reverter; pub mod state_keeper; pub mod sync_state; pub mod via_btc_indexer; +pub mod via_gas_adjuster; pub mod via_state_keeper; pub mod web3_api; diff --git a/core/node/node_framework/src/implementations/resources/via_gas_adjuster.rs b/core/node/node_framework/src/implementations/resources/via_gas_adjuster.rs new file mode 100644 index 000000000..5d9ea43d7 --- /dev/null +++ b/core/node/node_framework/src/implementations/resources/via_gas_adjuster.rs @@ -0,0 +1,21 @@ +use std::sync::Arc; + +use via_fee_model::ViaGasAdjuster; + +use crate::resource::Resource; + +/// A resource that provides [`GasAdjuster`] to the service. +#[derive(Debug, Clone)] +pub struct ViaGasAdjusterResource(pub Arc); + +impl Resource for ViaGasAdjusterResource { + fn name() -> String { + "common/via_gas_adjuster".into() + } +} + +impl From> for ViaGasAdjusterResource { + fn from(gas_adjuster: Arc) -> Self { + Self(gas_adjuster) + } +} diff --git a/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs b/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs index 9e47b3b93..431ac4a5d 100644 --- a/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs +++ b/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs @@ -96,9 +96,9 @@ impl L1ToL2MessageProcessor { let eth_address_l2 = msg.input.receiver_l2_address; let calldata = msg.input.call_data.clone(); - let value = U256::from(amount); - let mantissa = U256::from(10_000_000_000u64); // scale down the cost Eth 18 decimals - BTC 8 decimals - let max_fee_per_gas = U256::from(100_000_000_000u64) / mantissa; + let mantissa = U256::from(10_000_000_000u64); // Eth 18 decimals - BTC 8 decimals + let value = U256::from(amount) * mantissa; + let max_fee_per_gas = U256::from(100_000_000u64); let gas_limit = U256::from(1_000_000u64); let gas_per_pubdata_limit = U256::from(800u64); diff --git a/core/node/via_fee_model/Cargo.toml b/core/node/via_fee_model/Cargo.toml index 8ee41ed97..9ae96d73c 100644 --- a/core/node/via_fee_model/Cargo.toml +++ b/core/node/via_fee_model/Cargo.toml @@ -14,8 +14,10 @@ categories.workspace = true vise.workspace = true zksync_types.workspace = true zksync_config.workspace = true +zksync_dal.workspace = true zksync_utils.workspace = true zksync_node_fee_model.workspace = true +via_btc_client.workspace = true tokio = { workspace = true, features = ["time"] } anyhow.workspace = true diff --git a/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs b/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs new file mode 100644 index 000000000..cd51b8876 --- /dev/null +++ b/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs @@ -0,0 +1,213 @@ +//! This module determines the fees to pay in txs containing blocks submitted to the L1. + +use std::{ + collections::VecDeque, + sync::{Arc, RwLock}, +}; + +use tokio::sync::watch; +use via_btc_client::inscriber::Inscriber; +use zksync_config::GasAdjusterConfig; + +/// This component keeps track of the median `base_fee` from the last `max_base_fee_samples` blocks +/// and of the median `blob_base_fee` from the last `max_blob_base_fee_sample` blocks. +/// It is used to adjust the base_fee of transactions sent to L1. +#[derive(Debug)] +pub struct ViaGasAdjuster { + pub(super) base_fee_statistics: GasStatistics, + pub(super) config: GasAdjusterConfig, + pub(super) inscriber: Inscriber, +} + +impl ViaGasAdjuster { + pub async fn new(config: GasAdjusterConfig, inscriber: Inscriber) -> anyhow::Result { + // Subtracting 1 from the "latest" block number to prevent errors in case + // the info about the latest block is not yet present on the node. + // This sometimes happens on Infura. + let current_block = inscriber + .get_client() + .await + .fetch_block_height() + .await? + .saturating_sub(1) as usize; + + let fee_history = inscriber + .get_client() + .await + .get_fee_history( + current_block as usize - config.max_base_fee_samples, + current_block, + ) + .await?; + + let base_fee_statistics = + GasStatistics::new(config.max_base_fee_samples, current_block, fee_history); + + Ok(Self { + base_fee_statistics, + config, + inscriber, + }) + } + + /// Performs an actualization routine for `GasAdjuster`. + /// This method is intended to be invoked periodically. + pub async fn keep_updated(&self) -> anyhow::Result<()> { + let current_block = self + .inscriber + .get_client() + .await + .fetch_block_height() + .await? + .saturating_sub(1) as usize; + let last_processed_block = self.base_fee_statistics.last_processed_block(); + + if current_block > last_processed_block { + let n_blocks = current_block - last_processed_block; + let fee_history = self + .inscriber + .get_client() + .await + .get_fee_history(current_block - n_blocks, current_block) + .await?; + + self.base_fee_statistics.add_samples(fee_history); + } + Ok(()) + } + + fn bound_gas_price(&self, gas_price: u64) -> u64 { + let max_l1_gas_price = self.config.max_l1_gas_price(); + if gas_price > max_l1_gas_price { + tracing::warn!( + "Effective gas price is too high: {gas_price}, using max allowed: {}", + max_l1_gas_price + ); + return max_l1_gas_price; + } + gas_price + } + + pub async fn run(self: Arc, stop_receiver: watch::Receiver) -> anyhow::Result<()> { + loop { + if *stop_receiver.borrow() { + tracing::info!("Stop signal received, gas_adjuster is shutting down"); + break; + } + + if let Err(err) = self.keep_updated().await { + tracing::warn!("Cannot add the base fee to gas statistics: {}", err); + } + + tokio::time::sleep(self.config.poll_period()).await; + } + Ok(()) + } + + /// Returns the sum of base and priority fee, in wei, not considering time in mempool. + /// Can be used to get an estimate of current gas price. + pub(crate) fn estimate_effective_gas_price(&self) -> u64 { + if let Some(price) = self.config.internal_enforced_l1_gas_price { + return price; + } + + let effective_gas_price = self.get_base_fee() + self.get_priority_fee(); + + let calculated_price = + (self.config.internal_l1_pricing_multiplier * effective_gas_price as f64) as u64; + + // Bound the price if it's too high. + self.bound_gas_price(calculated_price) + } + + // Todo: investigate the DA layer gas cost + pub(crate) fn estimate_effective_pubdata_price(&self) -> u64 { + if let Some(price) = self.config.internal_enforced_pubdata_price { + return price; + } + 0 + } + + fn get_base_fee(&self) -> u64 { + let median = self.base_fee_statistics.median(); + median + } + + fn get_priority_fee(&self) -> u64 { + self.config.default_priority_fee_per_gas + } +} + +/// Helper structure responsible for collecting the data about recent transactions, +/// calculating the median base fee. +#[derive(Debug, Clone, Default)] +pub(super) struct GasStatisticsInner { + samples: VecDeque, + median_cached: T, + max_samples: usize, + last_processed_block: usize, +} + +impl GasStatisticsInner { + fn new(max_samples: usize, block: usize, fee_history: impl IntoIterator) -> Self { + let mut statistics = Self { + max_samples, + samples: VecDeque::with_capacity(max_samples), + median_cached: T::default(), + last_processed_block: 0, + }; + + statistics.add_samples(fee_history); + + Self { + last_processed_block: block, + ..statistics + } + } + + fn median(&self) -> T { + self.median_cached + } + + fn add_samples(&mut self, fees: impl IntoIterator) { + let old_len = self.samples.len(); + self.samples.extend(fees); + let processed_blocks = self.samples.len() - old_len; + self.last_processed_block += processed_blocks; + + let extra = self.samples.len().saturating_sub(self.max_samples); + self.samples.drain(..extra); + + let mut samples: Vec<_> = self.samples.iter().cloned().collect(); + + if !self.samples.is_empty() { + let (_, &mut median, _) = samples.select_nth_unstable(self.samples.len() / 2); + self.median_cached = median; + } + } +} + +#[derive(Debug, Default)] +pub(super) struct GasStatistics(RwLock>); + +impl GasStatistics { + pub fn new(max_samples: usize, block: usize, fee_history: impl IntoIterator) -> Self { + Self(RwLock::new(GasStatisticsInner::new( + max_samples, + block, + fee_history, + ))) + } + + pub fn median(&self) -> T { + self.0.read().unwrap().median() + } + + pub fn add_samples(&self, fees: impl IntoIterator) { + self.0.write().unwrap().add_samples(fees) + } + + pub fn last_processed_block(&self) -> usize { + self.0.read().unwrap().last_processed_block + } +} diff --git a/core/node/via_fee_model/src/l1_gas_price/mod.rs b/core/node/via_fee_model/src/l1_gas_price/mod.rs new file mode 100644 index 000000000..2239c1621 --- /dev/null +++ b/core/node/via_fee_model/src/l1_gas_price/mod.rs @@ -0,0 +1 @@ +pub mod gas_adjuster; diff --git a/core/node/via_fee_model/src/lib.rs b/core/node/via_fee_model/src/lib.rs index 8243f951b..7b06e7917 100644 --- a/core/node/via_fee_model/src/lib.rs +++ b/core/node/via_fee_model/src/lib.rs @@ -1,21 +1,44 @@ use std::{fmt::Debug, sync::Arc}; +use anyhow::Context; use async_trait::async_trait; +pub use l1_gas_price::gas_adjuster::ViaGasAdjuster; +use zksync_dal::{ConnectionPool, Core, CoreDal}; +use zksync_node_fee_model::BaseTokenRatioProvider; pub use zksync_node_fee_model::BatchFeeModelInputProvider; -use zksync_types::fee_model::{ - BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, - FeeParamsV2, +use zksync_types::{ + fee_model::{ + BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, + FeeParamsV2, PubdataIndependentBatchFeeModelInput, + }, + U256, }; +use zksync_utils::ceil_div_u256; + +mod l1_gas_price; + +#[async_trait] +pub trait ViaBaseTokenRatioProvider: Debug + Send + Sync + 'static { + fn get_conversion_ratio_by_timestamp( + &self, + from_timestamp: u64, + to_timestamp: u64, + ) -> BaseTokenConversionRatio; +} #[derive(Debug)] pub struct ViaMainNodeFeeInputProvider { + provider: Arc, fee_model_config: FeeModelConfigV2, } impl ViaMainNodeFeeInputProvider { - pub fn new(config: FeeModelConfig) -> anyhow::Result { + pub fn new(provider: Arc, config: FeeModelConfig) -> anyhow::Result { match config { - FeeModelConfig::V2(fee_model_config) => Ok(Self { fee_model_config }), + FeeModelConfig::V2(fee_model_config) => Ok(Self { + provider, + fee_model_config, + }), FeeModelConfig::V1(_) => Err(anyhow::anyhow!("Via fee model must be inited using V2")), } } @@ -28,18 +51,22 @@ impl BatchFeeModelInputProvider for ViaMainNodeFeeInputProvider { _l1_gas_price_scale_factor: f64, _l1_pubdata_price_scale_factor: f64, ) -> anyhow::Result { - Ok(BatchFeeInput::pubdata_independent( - self.fee_model_config.minimal_l2_gas_price, - self.fee_model_config.minimal_l2_gas_price, - self.fee_model_config.max_pubdata_per_batch, - )) + if let FeeParams::V2(params_v2) = self.get_fee_model_params() { + let fee = clip_batch_fee_model_input(compute_batch_fee_model_input( + params_v2, + _l1_gas_price_scale_factor, + _l1_pubdata_price_scale_factor, + )); + return Ok(BatchFeeInput::PubdataIndependent(fee)); + } + Err(anyhow::Error::msg("Via batch fee must be v2")) } fn get_fee_model_params(&self) -> FeeParams { FeeParams::V2(FeeParamsV2::new( self.fee_model_config, - self.fee_model_config.minimal_l2_gas_price, - self.fee_model_config.max_pubdata_per_batch, + self.provider.estimate_effective_gas_price(), + self.provider.estimate_effective_pubdata_price(), BaseTokenConversionRatio::default(), )) } @@ -48,11 +75,18 @@ impl BatchFeeModelInputProvider for ViaMainNodeFeeInputProvider { #[derive(Debug)] pub struct ViaApiFeeInputProvider { inner: Arc, + connection_pool: ConnectionPool, } impl ViaApiFeeInputProvider { - pub fn new(inner: Arc) -> Self { - Self { inner } + pub fn new( + inner: Arc, + connection_pool: ConnectionPool, + ) -> Self { + Self { + inner, + connection_pool, + } } } @@ -60,17 +94,25 @@ impl ViaApiFeeInputProvider { impl BatchFeeModelInputProvider for ViaApiFeeInputProvider { async fn get_batch_fee_input_scaled( &self, - _l1_gas_price_scale_factor: f64, - _l1_pubdata_price_scale_factor: f64, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, ) -> anyhow::Result { - if let FeeParams::V2(params_v2) = self.inner.get_fee_model_params() { - return Ok(BatchFeeInput::pubdata_independent( - params_v2.l1_gas_price(), - params_v2.l1_gas_price(), - params_v2.l1_pubdata_price(), - )); - } - Err(anyhow::Error::msg("Via batch fee must be v2")) + let inner_input = self + .inner + .get_batch_fee_input_scaled(l1_gas_price_scale_factor, l1_pubdata_price_scale_factor) + .await + .context("cannot get batch fee input from base provider")?; + let last_l2_block_params = self + .connection_pool + .connection_tagged("via_api_fee_input_provider") + .await? + .blocks_dal() + .get_last_sealed_l2_block_header() + .await?; + + Ok(last_l2_block_params + .map(|header| inner_input.stricter(header.batch_fee_input)) + .unwrap_or(inner_input)) } fn get_fee_model_params(&self) -> FeeParams { @@ -78,6 +120,71 @@ impl BatchFeeModelInputProvider for ViaApiFeeInputProvider { } } +/// Calculates the batch fee input based on the main node parameters. +fn compute_batch_fee_model_input( + params: FeeParamsV2, + l1_gas_price_scale_factor: f64, + l1_pubdata_price_scale_factor: f64, +) -> PubdataIndependentBatchFeeModelInput { + let config = params.config(); + let l1_gas_price = params.l1_gas_price(); + let l1_pubdata_price = params.l1_pubdata_price(); + + // Firstly, we scale the gas price and pubdata price in case it is needed. + let l1_gas_price = (l1_gas_price as f64 * l1_gas_price_scale_factor) as u64; + let l1_pubdata_price = (l1_pubdata_price as f64 * l1_pubdata_price_scale_factor) as u64; + + // Todo: rename "batch_overhead_l1_gas" to "total_inscription_gas_vbyte" + let inscriptions_cost_satoshi = (config.batch_overhead_l1_gas * l1_gas_price) as u64; + // Scale the inscriptions_cost_satoshi to 18 decimals + let gas_price_satoshi = inscriptions_cost_satoshi * 10_000_000_000 / config.max_gas_per_batch; + // The "minimal_l2_gas_price" calculated from the operational cost to publish and verify block. + let fair_l2_gas_price = gas_price_satoshi + config.minimal_l2_gas_price; + + PubdataIndependentBatchFeeModelInput { + l1_gas_price, + fair_l2_gas_price: fair_l2_gas_price, + fair_pubdata_price: l1_pubdata_price, + } +} + +/// Bootloader places limitations on fair_l2_gas_price and fair_pubdata_price. +/// (MAX_ALLOWED_FAIR_L2_GAS_PRICE and MAX_ALLOWED_FAIR_PUBDATA_PRICE in bootloader code respectively) +/// Server needs to clip this prices in order to allow chain continues operation at a loss. The alternative +/// would be to stop accepting the transactions until the conditions improve. +/// TODO (PE-153): to be removed when bootloader limitation is removed +fn clip_batch_fee_model_input( + fee_model: PubdataIndependentBatchFeeModelInput, +) -> PubdataIndependentBatchFeeModelInput { + /// MAX_ALLOWED_FAIR_L2_GAS_PRICE + const MAXIMUM_L2_GAS_PRICE: u64 = 10_000_000_000_000; + /// MAX_ALLOWED_FAIR_PUBDATA_PRICE + const MAXIMUM_PUBDATA_PRICE: u64 = 1_000_000_000_000_000; + PubdataIndependentBatchFeeModelInput { + l1_gas_price: fee_model.l1_gas_price, + fair_l2_gas_price: if fee_model.fair_l2_gas_price < MAXIMUM_L2_GAS_PRICE { + fee_model.fair_l2_gas_price + } else { + tracing::warn!( + "Fair l2 gas price {} exceeds maximum. Limitting to {}", + fee_model.fair_l2_gas_price, + MAXIMUM_L2_GAS_PRICE + ); + MAXIMUM_L2_GAS_PRICE + }, + fair_pubdata_price: if fee_model.fair_pubdata_price < MAXIMUM_PUBDATA_PRICE { + fee_model.fair_pubdata_price + } else { + tracing::warn!( + "Fair pubdata price {} exceeds maximum. Limitting to {}", + fee_model.fair_pubdata_price, + MAXIMUM_PUBDATA_PRICE + ); + MAXIMUM_PUBDATA_PRICE + }, + } +} + /// Mock [`BatchFeeModelInputProvider`] implementation that returns a constant value. /// Intended to be used in tests only. #[derive(Debug)] diff --git a/core/node/via_state_keeper/Cargo.toml b/core/node/via_state_keeper/Cargo.toml index 0e6066cb5..1930ddf22 100644 --- a/core/node/via_state_keeper/Cargo.toml +++ b/core/node/via_state_keeper/Cargo.toml @@ -46,5 +46,6 @@ assert_matches.workspace = true tempfile.workspace = true test-casing.workspace = true futures.workspace = true +via_btc_client.workspace = true zksync_system_constants.workspace = true diff --git a/core/node/via_state_keeper/src/io/tests/tester.rs b/core/node/via_state_keeper/src/io/tests/tester.rs index 88da7929f..c08e93bc5 100644 --- a/core/node/via_state_keeper/src/io/tests/tester.rs +++ b/core/node/via_state_keeper/src/io/tests/tester.rs @@ -2,8 +2,14 @@ use std::{slice, sync::Arc, time::Duration}; -use via_fee_model::ViaMainNodeFeeInputProvider; -use zksync_config::configs::{chain::StateKeeperConfig, wallets::Wallets}; +use via_btc_client::inscriber::test_utils::{ + get_mock_inscriber_and_conditions, MockBitcoinOpsConfig, +}; +use via_fee_model::{ViaGasAdjuster, ViaMainNodeFeeInputProvider}; +use zksync_config::{ + configs::{chain::StateKeeperConfig, wallets::Wallets}, + GasAdjusterConfig, +}; use zksync_contracts::BaseSystemContracts; use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_multivm::{ @@ -44,9 +50,17 @@ impl Tester { } pub(super) async fn create_batch_fee_input_provider(&self) -> ViaMainNodeFeeInputProvider { - ViaMainNodeFeeInputProvider::new(FeeModelConfig::V1(FeeModelConfigV1 { - minimal_l2_gas_price: self.minimal_l2_gas_price(), - })) + let inscriber = get_mock_inscriber_and_conditions(MockBitcoinOpsConfig::default()); + ViaMainNodeFeeInputProvider::new( + Arc::new( + ViaGasAdjuster::new(GasAdjusterConfig::default(), inscriber) + .await + .unwrap(), + ), + FeeModelConfig::V1(FeeModelConfigV1 { + minimal_l2_gas_price: self.minimal_l2_gas_price(), + }), + ) .unwrap() } @@ -59,11 +73,7 @@ impl Tester { &self, pool: ConnectionPool, ) -> (MempoolIO, MempoolGuard) { - let batch_fee_input_provider = - ViaMainNodeFeeInputProvider::new(FeeModelConfig::V1(FeeModelConfigV1 { - minimal_l2_gas_price: self.minimal_l2_gas_price(), - })) - .unwrap(); + let batch_fee_input_provider = self.create_batch_fee_input_provider().await; let mempool = MempoolGuard::new(PriorityOpId(0), 100); let config = StateKeeperConfig { From 9db2d47eb32153dabb6229bfbaacd3bc44e958d6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:21:47 +0100 Subject: [PATCH 031/212] feat(via_server): add the viagas adjuster layer and update configs --- core/bin/via_server/src/config.rs | 8 ++++---- core/bin/via_server/src/node_builder.rs | 12 ++++++++++++ etc/env/base/chain.toml | 6 +++--- etc/env/base/eth_sender.toml | 6 +++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/core/bin/via_server/src/config.rs b/core/bin/via_server/src/config.rs index 60a948842..427373973 100644 --- a/core/bin/via_server/src/config.rs +++ b/core/bin/via_server/src/config.rs @@ -10,8 +10,8 @@ use zksync_config::{ FriWitnessGeneratorConfig, ObservabilityConfig, PrometheusConfig, ProtectiveReadsWriterConfig, }, - ApiConfig, DADispatcherConfig, DBConfig, ObjectStoreConfig, PostgresConfig, ViaBtcSenderConfig, - ViaBtcWatchConfig, ViaCelestiaConfig, + ApiConfig, DADispatcherConfig, DBConfig, EthConfig, GasAdjusterConfig, ObjectStoreConfig, + PostgresConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, }; use zksync_core_leftovers::temp_config_store::{decode_yaml_repr, TempConfigStore}; use zksync_env_config::FromEnv; @@ -63,9 +63,9 @@ pub(crate) fn load_env_config() -> anyhow::Result { proof_data_handler_config: None, api_config: ApiConfig::from_env().ok(), db_config: DBConfig::from_env().ok(), - eth_sender_config: None, + eth_sender_config: EthConfig::from_env().ok(), eth_watch_config: None, - gas_adjuster_config: None, + gas_adjuster_config: GasAdjusterConfig::from_env().ok(), observability: ObservabilityConfig::from_env().ok(), snapshot_creator: None, da_dispatcher_config: DADispatcherConfig::from_env().ok(), diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 231016e0b..5cc6c10c0 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -30,6 +30,7 @@ use zksync_node_framework::{ }, via_btc_watch::BtcWatchLayer, via_da_dispatcher::DataAvailabilityDispatcherLayer, + via_gas_adjuster::ViaGasAdjusterLayer, via_l1_gas::ViaL1GasLayer, via_state_keeper::{ main_batch_executor::MainBatchExecutorLayer, mempool_io::MempoolIOLayer, @@ -190,6 +191,16 @@ impl ViaNodeBuilder { Ok(self) } + fn add_gas_adjuster_layer(mut self) -> anyhow::Result { + let gas_adjuster_config = try_load_config!(self.configs.eth) + .gas_adjuster + .context("Via gas adjuster")?; + let btc_sender_config = try_load_config!(self.configs.via_btc_sender_config); + let gas_adjuster_layer = ViaGasAdjusterLayer::new(gas_adjuster_config, btc_sender_config); + self.node.add_layer(gas_adjuster_layer); + Ok(self) + } + fn add_l1_gas_layer(mut self) -> anyhow::Result { let state_keeper_config = try_load_config!(self.configs.state_keeper_config); let l1_gas_layer = ViaL1GasLayer::new(state_keeper_config); @@ -422,6 +433,7 @@ impl ViaNodeBuilder { // VIA layers .add_btc_watcher_layer()? .add_btc_sender_layer()? + .add_gas_adjuster_layer()? .add_l1_gas_layer()? .add_tx_sender_layer()? .add_api_caches_layer()? diff --git a/etc/env/base/chain.toml b/etc/env/base/chain.toml index 29c9312f1..265a6d6d8 100644 --- a/etc/env/base/chain.toml +++ b/etc/env/base/chain.toml @@ -53,7 +53,7 @@ reject_tx_at_gas_percentage = 0.95 # The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well # as potentially premium for congestion. -minimal_l2_gas_price = 100 +minimal_l2_gas_price = 10000000 # The constant that represents the possibility that a batch can be sealed because of overuse of computation resources. # It has range from 0 to 1. If it is 0, the compute will not depend on the cost for closing the batch. @@ -65,8 +65,8 @@ compute_overhead_part = 0.0 # If it is 1, the pubdata limit per batch will have to cover the entire cost of closing the batch. pubdata_overhead_part = 1.0 -# The constant amount of L1 gas that is used as the overhead for the batch. It includes the price for batch verification, etc. -batch_overhead_l1_gas = 800000 +# The constant L1 gas unit in vbyte required to finilize the L1 Batch. This cost includes the Pubdata, proof and verification inscriptions. +batch_overhead_l1_gas = 5000 # The maximum amount of gas that can be used by the batch. This value is derived from the circuits limitation per batch. max_gas_per_batch = 200000000 diff --git a/etc/env/base/eth_sender.toml b/etc/env/base/eth_sender.toml index 31fe626c8..819dfceec 100644 --- a/etc/env/base/eth_sender.toml +++ b/etc/env/base/eth_sender.toml @@ -49,10 +49,10 @@ max_acceptable_priority_fee_in_gwei = 100000000000 pubdata_sending_mode = "Blobs" [eth_sender.gas_adjuster] -# Priority fee to be used by GasAdjuster (in wei). -default_priority_fee_per_gas = 1_000_000_000 +# Priority fee to be used by GasAdjuster (in satoshi). +default_priority_fee_per_gas = 1 # Max number of base fees from previous blocks to be used to correctly price transactions. -max_base_fee_samples = 10_000 +max_base_fee_samples = 10 # These two are parameters of the base_fee_per_gas formula in GasAdjuster. # The possible formulas are: # 1. base_fee_median * (A + B * time_in_mempool) From 304ed19dad6db48f32ffc4ff1ab4052efd981eb6 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Mon, 16 Dec 2024 11:06:09 +0100 Subject: [PATCH 032/212] feat: simulate eth finalization --- Cargo.lock | 1 + core/bin/via_server/src/node_builder.rs | 4 +- ...2b3f7eafbb32d4fcc30ba411f537f83a81046.json | 16 +++++ ...5bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json} | 4 +- ...c0355f5ff8c0b7918d961df7348f7e3236a17.json | 15 ---- ...25bdc5ac79944550cfe2acca1e80a76caf720.json | 16 ----- ...4b47eec44c39bc907fe4d6edacca4b6f797f8.json | 14 ---- ...b27b9b83f2025bd9d8785c530cd18c4e8cd75.json | 15 ++++ ...0bb4fc567b47885e4263e604ad9c2bce35ed.json} | 4 +- ...49b437da96558b91e8a6c24878604440a9a68.json | 14 ++++ core/lib/dal/src/via_votes_dal.rs | 9 +-- core/node/via_btc_watch/Cargo.toml | 1 + core/node/via_btc_watch/src/lib.rs | 2 +- .../src/message_processors/votable.rs | 69 ++++++++++++++++--- 14 files changed, 118 insertions(+), 66 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json rename core/lib/dal/.sqlx/{query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json => query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json} (51%) delete mode 100644 core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json delete mode 100644 core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json delete mode 100644 core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json create mode 100644 core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json rename core/lib/dal/.sqlx/{query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json => query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json} (57%) create mode 100644 core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json diff --git a/Cargo.lock b/Cargo.lock index 0c8381ec1..9b7c3967f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9419,6 +9419,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "sqlx", "thiserror", "tokio", "tracing", diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 231016e0b..1536f8680 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -434,8 +434,8 @@ impl ViaNodeBuilder { .add_logs_bloom_backfill_layer()? .add_metadata_calculator_layer(true)? .add_commitment_generator_layer()? - .add_via_celestia_da_client_layer()? - .add_da_dispatcher_layer()? + // .add_via_celestia_da_client_layer()? + // .add_da_dispatcher_layer()? .node .build()) } diff --git a/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json b/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json new file mode 100644 index 000000000..33fbca1f8 --- /dev/null +++ b/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votes (tx_id, verifier_address, vote)\n VALUES\n ($1, $2, $3)\n ON CONFLICT (tx_id, verifier_address) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046" +} diff --git a/core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json b/core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json similarity index 51% rename from core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json rename to core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json index 388e8b8d3..fff85f446 100644 --- a/core/lib/dal/.sqlx/query-963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525.json +++ b/core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT is_finalized\n FROM via_votable_transactions\n WHERE tx_id = $1\n ", + "query": "\n SELECT\n is_finalized\n FROM\n via_votable_transactions\n WHERE\n tx_id = $1\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ false ] }, - "hash": "963ad4c7c26246791c7f0c962a654a75405d056b8945fe00ba9a848886328525" + "hash": "15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f" } diff --git a/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json b/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json deleted file mode 100644 index d61ceb1c4..000000000 --- a/core/lib/dal/.sqlx/query-180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO via_votable_transactions (tx_id, transaction_type)\n VALUES ($1, $2)\n ON CONFLICT (tx_id) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Text" - ] - }, - "nullable": [] - }, - "hash": "180b6307cd4a831e2dc478822dcc0355f5ff8c0b7918d961df7348f7e3236a17" -} diff --git a/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json b/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json deleted file mode 100644 index 43fea07d4..000000000 --- a/core/lib/dal/.sqlx/query-3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO via_votes (tx_id, verifier_address, vote)\n VALUES ($1, $2, $3)\n ON CONFLICT (tx_id, verifier_address) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "3d53477adf17418255b7bfdcdb125bdc5ac79944550cfe2acca1e80a76caf720" -} diff --git a/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json b/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json deleted file mode 100644 index 8a4ae7302..000000000 --- a/core/lib/dal/.sqlx/query-4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE via_votable_transactions\n SET is_finalized = TRUE, updated_at = NOW()\n WHERE tx_id = $1\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "4626efe6dfcec2aaca55f9fd9ad4b47eec44c39bc907fe4d6edacca4b6f797f8" -} diff --git a/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json b/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json new file mode 100644 index 000000000..44559b668 --- /dev/null +++ b/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votable_transactions (tx_id, transaction_type)\n VALUES\n ($1, $2)\n ON CONFLICT (tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Text" + ] + }, + "nullable": [] + }, + "hash": "88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75" +} diff --git a/core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json b/core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json similarity index 57% rename from core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json rename to core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json index 741fbd96d..f5baa12d0 100644 --- a/core/lib/dal/.sqlx/query-74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988.json +++ b/core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n COUNT(*) FILTER (WHERE vote = TRUE) AS ok_votes,\n COUNT(*) AS total_votes\n FROM via_votes\n WHERE tx_id = $1\n ", + "query": "\n SELECT\n COUNT(*) FILTER (\n WHERE\n vote = TRUE\n ) AS ok_votes,\n COUNT(*) AS total_votes\n FROM\n via_votes\n WHERE\n tx_id = $1\n ", "describe": { "columns": [ { @@ -24,5 +24,5 @@ null ] }, - "hash": "74aac4b1d27a51aba030d184ae861c010316e5cc31cafee6227c5240e72fc988" + "hash": "b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed" } diff --git a/core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json b/core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json new file mode 100644 index 000000000..a456eece3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n is_finalized = TRUE,\n updated_at = NOW()\n WHERE\n tx_id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68" +} diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index c122ddd62..049749b8c 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -1,5 +1,5 @@ use zksync_db_connection::{connection::Connection, error::DalResult, instrument::InstrumentExt}; -use zksync_types::{Address, H256}; +use zksync_types::H256; use crate::Core; @@ -83,9 +83,10 @@ impl ViaVotesDal<'_, '_> { &mut self, tx_id: H256, threshold: f64, - ) -> DalResult<()> { + ) -> DalResult { let (ok_votes, total_votes) = self.get_vote_count(tx_id).await?; - if total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold { + let finalized = total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold; + if finalized { sqlx::query!( r#" UPDATE via_votable_transactions @@ -101,7 +102,7 @@ impl ViaVotesDal<'_, '_> { .execute(self.storage) .await?; } - Ok(()) + Ok(finalized) } pub async fn is_transaction_finalized(&mut self, tx_id: H256) -> DalResult { diff --git a/core/node/via_btc_watch/Cargo.toml b/core/node/via_btc_watch/Cargo.toml index 333ab9faa..5b58de68f 100644 --- a/core/node/via_btc_watch/Cargo.toml +++ b/core/node/via_btc_watch/Cargo.toml @@ -22,5 +22,6 @@ anyhow.workspace = true thiserror.workspace = true async-trait.workspace = true tracing.workspace = true +sqlx.workspace = true [dev-dependencies] diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index 1ec22bc2d..91e7a8732 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -64,7 +64,7 @@ impl BtcWatch { state.bridge_address.clone(), state.next_expected_priority_id, )), - Box::new(VotableMessageProcessor::new(3)), + Box::new(VotableMessageProcessor::new()), ]; let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 4bc80c692..0055694d6 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -1,20 +1,21 @@ +use sqlx::types::chrono::{DateTime, Utc}; use via_btc_client::types::{BitcoinTxid, FullInscriptionMessage}; use zksync_dal::{Connection, Core, CoreDal}; -use zksync_types::H256; +use zksync_types::{aggregated_operations::AggregatedActionType, L1BatchNumber, H256}; use super::{MessageProcessor, MessageProcessorError}; +const DEFAULT_THRESHOLD: f64 = 0.5; + #[derive(Debug)] pub struct VotableMessageProcessor { - verifier_count: usize, threshold: f64, } impl VotableMessageProcessor { - pub fn new(verifier_count: usize) -> Self { + pub fn new() -> Self { Self { - verifier_count, - threshold: 0.5, + threshold: DEFAULT_THRESHOLD, } } } @@ -26,26 +27,61 @@ impl MessageProcessor for VotableMessageProcessor { storage: &mut Connection<'_, Core>, msgs: Vec, ) -> Result<(), MessageProcessorError> { - let mut votes_dal = storage.via_votes_dal(); + // Get the current timestamp + let dt = Utc::now(); + let naive_utc = dt.naive_utc(); + let offset = dt.offset().clone(); + let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); for msg in msgs { match msg { FullInscriptionMessage::L1BatchDAReference(da_msg) => { + let mut votes_dal = storage.via_votes_dal(); + let tx_id = convert_txid_to_h256(da_msg.common.tx_id); votes_dal - .insert_votable_transaction(tx_id, "L1BatchDAReference") + .insert_votable_transaction(tx_id.clone(), "L1BatchDAReference") .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + let mut eth_sender_dal = storage.eth_sender_dal(); + + eth_sender_dal + .insert_bogus_confirmed_eth_tx( + da_msg.input.l1_batch_index, + AggregatedActionType::Commit, + tx_id, + dt, + ) + .await?; } FullInscriptionMessage::ProofDAReference(proof_msg) => { let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + let mut votes_dal = storage.via_votes_dal(); + votes_dal .insert_votable_transaction(tx_id, "ProofDAReference") .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + let mut eth_sender_dal = storage.eth_sender_dal(); + + // todo: insert proper l1_batch number + eth_sender_dal + .insert_bogus_confirmed_eth_tx( + L1BatchNumber(1), + AggregatedActionType::PublishProofOnchain, + tx_id, + dt, + ) + .await?; } FullInscriptionMessage::ValidatorAttestation(attestation_msg) => { + let mut votes_dal = storage.via_votes_dal(); + let reference_txid = convert_txid_to_h256(attestation_msg.input.reference_txid); + let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); + // Vote = true if attestation_msg.input.attestation == Vote::Ok let is_ok = matches!( attestation_msg.input.attestation, @@ -61,14 +97,27 @@ impl MessageProcessor for VotableMessageProcessor { .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; // Check finalization - votes_dal + if votes_dal .finalize_transaction_if_needed(reference_txid, self.threshold) .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + { + let mut eth_sender_dal = storage.eth_sender_dal(); + + // todo: insert proper l1_batch number + eth_sender_dal + .insert_bogus_confirmed_eth_tx( + L1BatchNumber(1), + AggregatedActionType::Execute, + tx_id, + dt, + ) + .await?; + } } // bootstrapping phase is already covered FullInscriptionMessage::ProposeSequencer(_) => { - continue; + // do nothing } // Non-votable messages like SystemBootstrapping or L1ToL2Message are ignored by this processor FullInscriptionMessage::SystemBootstrapping(_) From ac779d1368a32b8d8f9fbc39d90b188e0ef9cdd4 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:59:48 +0100 Subject: [PATCH 033/212] feat: via verifier base orchestration layer --- Cargo.lock | 23 ++++ Cargo.toml | 3 +- core/bin/via_verifier/Cargo.toml | 33 ++++++ core/bin/via_verifier/src/config.rs | 97 ++++++++++++++++ core/bin/via_verifier/src/main.rs | 129 ++++++++++++++++++++++ core/bin/via_verifier/src/node_builder.rs | 82 ++++++++++++++ 6 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 core/bin/via_verifier/Cargo.toml create mode 100644 core/bin/via_verifier/src/config.rs create mode 100644 core/bin/via_verifier/src/main.rs create mode 100644 core/bin/via_verifier/src/node_builder.rs diff --git a/Cargo.lock b/Cargo.lock index 8b21a4a8a..cbe2e453c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9558,6 +9558,29 @@ dependencies = [ "zksync_vm_utils", ] +[[package]] +name = "via_verifier" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.16", + "tikv-jemallocator", + "tokio", + "tracing", + "via_da_clients", + "zksync_config", + "zksync_core_leftovers", + "zksync_env_config", + "zksync_metadata_calculator", + "zksync_node_api_server", + "zksync_node_framework", + "zksync_protobuf_config", + "zksync_storage", + "zksync_types", + "zksync_utils", + "zksync_vlog", +] + [[package]] name = "via_withdrawal_client" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e92474e86..f8ae9639f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,7 @@ members = [ "core/node/via_fee_model", "core/node/via_state_keeper", "core/lib/via_withdrawal_client", + "core/bin/via_verifier", ] @@ -324,4 +325,4 @@ via_btc_watch = { version = "0.1.0", path = "core/node/via_btc_watch" } via_da_dispatcher = { version = "0.1.0", path = "core/node/via_da_dispatcher" } via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } -via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } \ No newline at end of file +via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } diff --git a/core/bin/via_verifier/Cargo.toml b/core/bin/via_verifier/Cargo.toml new file mode 100644 index 000000000..0d618795b --- /dev/null +++ b/core/bin/via_verifier/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "via_verifier" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +zksync_config = { workspace = true, features = ["observability_ext"] } +zksync_env_config.workspace = true +zksync_storage.workspace = true +zksync_utils.workspace = true +zksync_types.workspace = true +zksync_node_framework.workspace = true +zksync_vlog.workspace = true +zksync_core_leftovers.workspace = true +zksync_protobuf_config.workspace = true +zksync_node_api_server.workspace = true +zksync_metadata_calculator.workspace = true +via_da_clients.workspace = true + + +anyhow.workspace = true +clap = { workspace = true, features = ["derive"] } +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true + +[target.'cfg(not(target_env = "msvc"))'.dependencies] +tikv-jemallocator.workspace = true diff --git a/core/bin/via_verifier/src/config.rs b/core/bin/via_verifier/src/config.rs new file mode 100644 index 000000000..60a948842 --- /dev/null +++ b/core/bin/via_verifier/src/config.rs @@ -0,0 +1,97 @@ +use anyhow::Context as _; +use zksync_config::{ + configs::{ + api::MerkleTreeApiConfig, + chain::{CircuitBreakerConfig, MempoolConfig, OperationsManagerConfig, StateKeeperConfig}, + consensus::ConsensusSecrets, + fri_prover_group::FriProverGroupConfig, + house_keeper::HouseKeeperConfig, + BasicWitnessInputProducerConfig, FriProofCompressorConfig, FriProverConfig, + FriWitnessGeneratorConfig, ObservabilityConfig, PrometheusConfig, + ProtectiveReadsWriterConfig, + }, + ApiConfig, DADispatcherConfig, DBConfig, ObjectStoreConfig, PostgresConfig, ViaBtcSenderConfig, + ViaBtcWatchConfig, ViaCelestiaConfig, +}; +use zksync_core_leftovers::temp_config_store::{decode_yaml_repr, TempConfigStore}; +use zksync_env_config::FromEnv; +use zksync_protobuf_config::proto; + +pub(crate) fn read_consensus_secrets() -> anyhow::Result> { + // Read public config. + let Ok(path) = std::env::var("CONSENSUS_SECRETS_PATH") else { + return Ok(None); + }; + let secrets = std::fs::read_to_string(&path).context(path)?; + Ok(Some( + decode_yaml_repr::(&secrets) + .context("failed decoding YAML")?, + )) +} +// +// pub(crate) fn read_consensus_config() -> anyhow::Result> { +// // Read public config. +// let Ok(path) = std::env::var("CONSENSUS_CONFIG_PATH") else { +// return Ok(None); +// }; +// let cfg = std::fs::read_to_string(&path).context(path)?; +// Ok(Some( +// decode_yaml_repr::(&cfg).context("failed decoding YAML")?, +// )) +// } + +pub(crate) fn load_env_config() -> anyhow::Result { + Ok(TempConfigStore { + postgres_config: PostgresConfig::from_env().ok(), + health_check_config: None, + merkle_tree_api_config: MerkleTreeApiConfig::from_env().ok(), + web3_json_rpc_config: None, + circuit_breaker_config: CircuitBreakerConfig::from_env().ok(), + mempool_config: MempoolConfig::from_env().ok(), + network_config: None, + contract_verifier: None, + operations_manager_config: OperationsManagerConfig::from_env().ok(), + state_keeper_config: StateKeeperConfig::from_env().ok(), + house_keeper_config: HouseKeeperConfig::from_env().ok(), + fri_proof_compressor_config: FriProofCompressorConfig::from_env().ok(), + fri_prover_config: FriProverConfig::from_env().ok(), + fri_prover_group_config: FriProverGroupConfig::from_env().ok(), + fri_prover_gateway_config: None, + fri_witness_vector_generator: None, + fri_witness_generator_config: FriWitnessGeneratorConfig::from_env().ok(), + prometheus_config: PrometheusConfig::from_env().ok(), + proof_data_handler_config: None, + api_config: ApiConfig::from_env().ok(), + db_config: DBConfig::from_env().ok(), + eth_sender_config: None, + eth_watch_config: None, + gas_adjuster_config: None, + observability: ObservabilityConfig::from_env().ok(), + snapshot_creator: None, + da_dispatcher_config: DADispatcherConfig::from_env().ok(), + protective_reads_writer_config: ProtectiveReadsWriterConfig::from_env().ok(), + basic_witness_input_producer_config: BasicWitnessInputProducerConfig::from_env().ok(), + core_object_store: ObjectStoreConfig::from_env().ok(), + base_token_adjuster_config: None, + commitment_generator: None, + pruning: None, + snapshot_recovery: None, + external_price_api_client_config: None, + external_proof_integration_api_config: None, + experimental_vm_config: None, + prover_job_monitor_config: None, + }) +} + +// TODO: temporary solution, should be removed after the config is refactored +pub(crate) fn via_load_env_config( +) -> anyhow::Result<(ViaBtcWatchConfig, ViaBtcSenderConfig, ViaCelestiaConfig)> { + let btc_watch_config = + ViaBtcWatchConfig::from_env().context("Failed to load BTC watch config")?; + let btc_sender_config = + ViaBtcSenderConfig::from_env().context("Failed to load BTC sender config")?; + let celestia_config = + ViaCelestiaConfig::from_env().context("Failed to load celestia config")?; + + Ok((btc_watch_config, btc_sender_config, celestia_config)) +} diff --git a/core/bin/via_verifier/src/main.rs b/core/bin/via_verifier/src/main.rs new file mode 100644 index 000000000..f76dc9544 --- /dev/null +++ b/core/bin/via_verifier/src/main.rs @@ -0,0 +1,129 @@ +use anyhow::Context as _; +use clap::Parser; +use zksync_config::{ + configs::{DatabaseSecrets, L1Secrets, Secrets}, + ContractsConfig, GenesisConfig, ViaGeneralConfig, +}; +use zksync_env_config::FromEnv; + +mod config; +mod node_builder; + +#[cfg(not(target_env = "msvc"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +#[derive(Debug, Parser)] +#[command(author = "Via verifer", version, about = "Via verifer node", long_about = None)] +struct Cli { + /// Run the verifier node as coordinator. + #[arg(long)] + coordinator: bool, + + /// Path to the YAML config. If set, it will be used instead of env vars. + #[arg(long)] + config_path: Option, + + /// Path to the YAML with secrets. If set, it will be used instead of env vars. + #[arg(long)] + secrets_path: Option, + + /// Path to the yaml with contracts. If set, it will be used instead of env vars. + #[arg(long)] + contracts_config_path: Option, + + /// Path to the wallets config. If set, it will be used instead of env vars. + #[arg(long)] + wallets_path: Option, + + /// Path to the YAML with genesis configuration. If set, it will be used instead of env vars. + #[arg(long)] + genesis_path: Option, +} + +fn main() -> anyhow::Result<()> { + let opt = Cli::parse(); + + // Load env config + let tmp_config = config::load_env_config()?; + + // Load configurations + let configs = match opt.config_path { + Some(_path) => { + todo!("Load config from file") + } + None => { + let general = tmp_config.general(); + let mut via_general = ViaGeneralConfig::from(general); + + // Load the rest of the configs + let via_configs = config::via_load_env_config()?; + via_general.via_btc_watch_config = Some(via_configs.0); + via_general.via_btc_sender_config = Some(via_configs.1); + via_general.via_celestia_config = Some(via_configs.2); + via_general + } + }; + + let secrets = match opt.secrets_path { + Some(_path) => { + todo!("Load secrets from file") + } + None => Secrets { + consensus: config::read_consensus_secrets().context("read_verifier_secrets()")?, + database: DatabaseSecrets::from_env().ok(), + l1: L1Secrets::from_env().ok(), + }, + }; + + let genesis = match opt.genesis_path { + Some(_path) => { + todo!("Load genesis from file") + } + None => GenesisConfig::from_env().context("Failed to load genesis from env")?, + }; + + let wallets = match opt.wallets_path { + Some(_path) => { + todo!("Load config from file"); + } + None => tmp_config.wallets(), + }; + + let mut contracts_config = match opt.contracts_config_path { + Some(_path) => { + todo!("Load contracts from file") + } + None => ContractsConfig::from_env().context("contracts_config")?, + }; + + // Disable ecosystem contracts for now + contracts_config.ecosystem_contracts = None; + + let observability_config = configs + .observability + .clone() + .context("Observability config missing")?; + + let node_builder = node_builder::ViaNodeBuilder::new( + opt.coordinator, + configs, + wallets, + secrets, + genesis, + contracts_config, + )?; + + let observability_guard = { + // Observability initialization should be performed within tokio context. + let _context_guard = node_builder.runtime_handle().enter(); + observability_config.install()? + }; + + // Build the node + + let node = node_builder.build()?; + node.run(observability_guard)?; + + Ok(()) +} diff --git a/core/bin/via_verifier/src/node_builder.rs b/core/bin/via_verifier/src/node_builder.rs new file mode 100644 index 000000000..d35115cab --- /dev/null +++ b/core/bin/via_verifier/src/node_builder.rs @@ -0,0 +1,82 @@ +use anyhow::Context; +use zksync_config::{ + configs::{wallets::Wallets, Secrets}, + ContractsConfig, GenesisConfig, ViaGeneralConfig, +}; +use zksync_node_framework::{ + implementations::layers::{ + circuit_breaker_checker::CircuitBreakerCheckerLayer, healtcheck_server::HealthCheckLayer, + sigint::SigintHandlerLayer, + }, + service::{ZkStackService, ZkStackServiceBuilder}, +}; + +/// Macro that looks into a path to fetch an optional config, +/// and clones it into a variable. +macro_rules! try_load_config { + ($path:expr) => { + $path.as_ref().context(stringify!($path))?.clone() + }; +} + +pub struct ViaNodeBuilder { + coordinator: bool, + node: ZkStackServiceBuilder, + configs: ViaGeneralConfig, + wallets: Wallets, + genesis_config: GenesisConfig, + contracts_config: ContractsConfig, + secrets: Secrets, +} + +impl ViaNodeBuilder { + pub fn new( + coordinator: bool, + via_general_config: ViaGeneralConfig, + wallets: Wallets, + secrets: Secrets, + genesis_config: GenesisConfig, + contracts_config: ContractsConfig, + ) -> anyhow::Result { + Ok(Self { + coordinator, + node: ZkStackServiceBuilder::new().context("Cannot create ZkStackServiceBuilder")?, + configs: via_general_config, + wallets, + genesis_config, + contracts_config, + secrets, + }) + } + + pub fn runtime_handle(&self) -> tokio::runtime::Handle { + self.node.runtime_handle() + } + + fn add_sigint_handler_layer(mut self) -> anyhow::Result { + self.node.add_layer(SigintHandlerLayer); + Ok(self) + } + + fn add_healthcheck_layer(mut self) -> anyhow::Result { + let healthcheck_config = try_load_config!(self.configs.api_config).healthcheck; + self.node.add_layer(HealthCheckLayer(healthcheck_config)); + Ok(self) + } + + fn add_circuit_breaker_checker_layer(mut self) -> anyhow::Result { + let circuit_breaker_config = try_load_config!(self.configs.circuit_breaker_config); + self.node + .add_layer(CircuitBreakerCheckerLayer(circuit_breaker_config)); + Ok(self) + } + + pub fn build(self) -> anyhow::Result { + Ok(self + .add_sigint_handler_layer()? + .add_healthcheck_layer()? + .add_circuit_breaker_checker_layer()? + .node + .build()) + } +} From 6b3eb21dca0bec8f82792057c909c1e7b2a5998c Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:18:49 +0100 Subject: [PATCH 034/212] feat: update via cli to start the verifier and the coordinator --- Makefile | 16 ++++ infrastructure/via/src/index.ts | 6 +- .../via/src/{withdraw.ts => token.ts} | 50 ++++++++++++- infrastructure/via/src/verifier.ts | 75 ++++--------------- via-playground/README.md | 2 +- 5 files changed, 83 insertions(+), 66 deletions(-) rename infrastructure/via/src/{withdraw.ts => token.ts} (60%) diff --git a/Makefile b/Makefile index de12e5278..ba62d86c6 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,22 @@ server: @echo "------------------------------------------------------------------------------------" @$(CLI_TOOL) server +# Run 'via verifier' +.PHONY: verifier +verifier: + @echo "------------------------------------------------------------------------------------" + @echo "$(YELLOW)Running the verifier software...$(RESET)" + @echo "------------------------------------------------------------------------------------" + @$(CLI_TOOL) verifier + +# Run 'via verifier --coordinator' +.PHONY: coordinator +coordinator: + @echo "------------------------------------------------------------------------------------" + @echo "$(YELLOW)Running the coordinator software...$(RESET)" + @echo "------------------------------------------------------------------------------------" + @$(CLI_TOOL) verifier --coordinator + # Run 'via clean' .PHONY: clean clean: diff --git a/infrastructure/via/src/index.ts b/infrastructure/via/src/index.ts index 8fbd6acea..0cb1bba61 100644 --- a/infrastructure/via/src/index.ts +++ b/infrastructure/via/src/index.ts @@ -15,10 +15,10 @@ import { command as db } from './database'; import * as env from './env'; import { command as transactions } from './transactions'; import { command as bootstrap } from './bootstrap'; -import { command as verifier } from './verifier'; +import { verifierCommand as verifier } from './verifier'; import { command as celestia } from './celestia'; import { command as btc_explorer } from './btc_explorer'; -import { command as withdraw } from './withdraw'; +import { command as token } from './token'; const COMMANDS = [ server, @@ -36,7 +36,7 @@ const COMMANDS = [ verifier, celestia, btc_explorer, - withdraw, + token, completion(program as Command) ]; diff --git a/infrastructure/via/src/withdraw.ts b/infrastructure/via/src/token.ts similarity index 60% rename from infrastructure/via/src/withdraw.ts rename to infrastructure/via/src/token.ts index 408a60f14..6f2bd3c81 100644 --- a/infrastructure/via/src/withdraw.ts +++ b/infrastructure/via/src/token.ts @@ -1,13 +1,38 @@ -import * as fs from 'fs'; import { Command } from 'commander'; import { Wallet, Provider, Contract } from 'zksync-ethers'; import { ethers } from 'ethers'; +import * as utils from 'utils'; + +const DEFAULT_DEPOSITOR_PRIVATE_KEY = 'cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R'; +const DEFAULT_NETWORK = 'regtest'; +const DEFAULT_RPC_URL = 'http://0.0.0.0:18443'; +const DEFAULT_RPC_USERNAME = 'rpcuser'; +const DEFAULT_RPC_PASSWORD = 'rpcpassword'; // 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 const DEFAULT_L2_PRIVATE_KEY = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; const DEFAULT_L2_RPC_URL = 'http://0.0.0.0:3050'; const L2_BASE_TOKEN = '0x000000000000000000000000000000000000800a'; +async function deposit( + amount: number, + receiverL2Address: string, + senderPrivateKey: string, + network: String, + rcpUrl: string, + rpcUsername: string, + rpcPassword: string +) { + if (isNaN(amount)) { + console.error('Error: Invalid deposit amount. Please provide a valid number.'); + return; + } + process.chdir(`${process.env.VIA_HOME}`); + await utils.spawn( + `cargo run --example deposit -- ${amount} ${receiverL2Address} ${senderPrivateKey} ${network} ${rcpUrl} ${rpcUsername} ${rpcPassword}` + ); +} + async function withdraw(amount: number, receiverL1Address: string, userL2PrivateKey: string, rpcUrl: string) { if (isNaN(amount)) { console.error('Error: Invalid withdraw amount. Please provide a valid number.'); @@ -62,7 +87,28 @@ async function withdraw(amount: number, receiverL1Address: string, userL2Private console.log('Balance after withdraw', ethers.formatUnits(balance, 8)); } -export const command = new Command('token').description('Bridge BTC L2>L1'); +export const command = new Command('token').description('Bridge BTC L2<>L1'); +command + .command('deposit') + .description('deposit BTC to l2') + .requiredOption('--amount ', 'amount of BTC to deposit', parseFloat) + .requiredOption('--receiver-l2-address ', 'receiver l2 address') + .option('--sender-private-key ', 'sender private key', DEFAULT_DEPOSITOR_PRIVATE_KEY) + .option('--network ', 'network', DEFAULT_NETWORK) + .option('--rpc-url ', 'RPC URL', DEFAULT_RPC_URL) + .option('--rpc-username ', 'RPC username', DEFAULT_RPC_USERNAME) + .option('--rpc-password ', 'RPC password', DEFAULT_RPC_PASSWORD) + .action((cmd: Command) => + deposit( + cmd.amount, + cmd.receiverL2Address, + cmd.senderPrivateKey, + cmd.network, + cmd.rpcUrl, + cmd.rpcUsername, + cmd.rpcPassword + ) + ); command .command('withdraw') diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index f376af7d8..3aad834dd 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -1,65 +1,20 @@ -import * as utils from 'utils'; import { Command } from 'commander'; +import * as utils from 'utils'; +import * as env from './env'; -const DEFAULT_DEPOSITOR_PRIVATE_KEY = 'cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R'; -const DEFAULT_NETWORK = 'regtest'; -const DEFAULT_RPC_URL = 'http://0.0.0.0:18443'; -const DEFAULT_RPC_USERNAME = 'rpcuser'; -const DEFAULT_RPC_PASSWORD = 'rpcpassword'; - -async function verifyBatch(batchProofRefRevealTxId: string) { - process.chdir(`${process.env.VIA_HOME}`); - await utils.spawn(`cargo run --example verify_batch -- ${batchProofRefRevealTxId}`); -} - -async function deposit( - amount: number, - receiverL2Address: string, - senderPrivateKey: string, - network: String, - rcpUrl: string, - rpcUsername: string, - rpcPassword: string -) { - if (isNaN(amount)) { - console.error('Error: Invalid deposit amount. Please provide a valid number.'); - return; +export async function verifier(isCoordinator: boolean) { + let options = ''; + console.log(isCoordinator); + if (isCoordinator) { + options += '--coordinator'; } - process.chdir(`${process.env.VIA_HOME}`); - await utils.spawn( - `cargo run --example deposit -- ${amount} ${receiverL2Address} ${senderPrivateKey} ${network} ${rcpUrl} ${rpcUsername} ${rpcPassword}` - ); + await utils.spawn(`cargo run --bin via_verifier -- ${options}`); } -export const command = new Command('verifier').description('verifier network mock'); - -command - .command('verify-batch') - .description('verify batch by batch da ref reveal tx id') - .requiredOption( - '--batch-proof-ref-reveal-tx-id ', - 'reveal tx id for the l1 batch proof to verify' - ) - .action((cmd: Command) => verifyBatch(cmd.batchProofRefRevealTxId)); - -command - .command('deposit') - .description('deposit BTC to l2') - .requiredOption('--amount ', 'amount of BTC to deposit', parseFloat) - .requiredOption('--receiver-l2-address ', 'receiver l2 address') - .option('--sender-private-key ', 'sender private key', DEFAULT_DEPOSITOR_PRIVATE_KEY) - .option('--network ', 'network', DEFAULT_NETWORK) - .option('--rpc-url ', 'RPC URL', DEFAULT_RPC_URL) - .option('--rpc-username ', 'RPC username', DEFAULT_RPC_USERNAME) - .option('--rpc-password ', 'RPC password', DEFAULT_RPC_PASSWORD) - .action((cmd: Command) => - deposit( - cmd.amount, - cmd.receiverL2Address, - cmd.senderPrivateKey, - cmd.network, - cmd.rpcUrl, - cmd.rpcUsername, - cmd.rpcPassword - ) - ); +export const verifierCommand = new Command('verifier') + .description('start via verifier node') + .option('--coordinator', 'start the verifier node as coordinator', false) + .action(async (cmd: Command) => { + cmd.chainName ? env.reload(cmd.chainName) : env.load(); + await verifier(cmd.coordinator); + }); diff --git a/via-playground/README.md b/via-playground/README.md index 06799ec7b..f8a674603 100644 --- a/via-playground/README.md +++ b/via-playground/README.md @@ -21,7 +21,7 @@ and replace it in `hardhat.config.ts`. 3. Run the following command to bridge BTC to L2: ```shell - via verifier deposit \ + via token deposit \ --amount 100 \ --receiver-l2-address 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 \ --sender-private-key \ From 0219dc53b655f6a5cbe8b46f10b71a07a9fa01d8 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 17 Dec 2024 19:17:27 +0100 Subject: [PATCH 035/212] feat: db schema upd, fixed l1_batch_number --- core/bin/via_server/src/node_builder.rs | 4 +- ...2b3f7eafbb32d4fcc30ba411f537f83a81046.json | 16 -- ...05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json | 22 --- ...073159cb97bf34ebf2740e3f40b863515cce.json} | 5 +- ...d2e238e3263394702c9a4dafb1043aa3fb2c3.json | 15 ++ ...b27b9b83f2025bd9d8785c530cd18c4e8cd75.json | 15 -- ...6d91830eac4268a83112781a6d9c521c5be9.json} | 5 +- ...510b32864e18832c7f6d4bd54c14783f54cca.json | 17 ++ .../20241209150000_create_via_votes.up.sql | 15 +- core/lib/dal/src/via_votes_dal.rs | 70 ++++---- core/lib/via_btc_client/DEV.md | 2 +- core/lib/via_btc_client/src/indexer/mod.rs | 52 ++++++ core/node/via_btc_watch/src/lib.rs | 2 +- .../src/message_processors/l1_to_l2.rs | 6 +- .../src/message_processors/mod.rs | 3 +- .../src/message_processors/votable.rs | 152 +++++++++--------- 16 files changed, 221 insertions(+), 180 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json delete mode 100644 core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json rename core/lib/dal/.sqlx/{query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json => query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json} (76%) create mode 100644 core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json delete mode 100644 core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json rename core/lib/dal/.sqlx/{query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json => query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json} (65%) create mode 100644 core/lib/dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 1536f8680..231016e0b 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -434,8 +434,8 @@ impl ViaNodeBuilder { .add_logs_bloom_backfill_layer()? .add_metadata_calculator_layer(true)? .add_commitment_generator_layer()? - // .add_via_celestia_da_client_layer()? - // .add_da_dispatcher_layer()? + .add_via_celestia_da_client_layer()? + .add_da_dispatcher_layer()? .node .build()) } diff --git a/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json b/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json deleted file mode 100644 index 33fbca1f8..000000000 --- a/core/lib/dal/.sqlx/query-10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votes (tx_id, verifier_address, vote)\n VALUES\n ($1, $2, $3)\n ON CONFLICT (tx_id, verifier_address) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "10a8f2acc8fa47a344d985d95a92b3f7eafbb32d4fcc30ba411f537f83a81046" -} diff --git a/core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json b/core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json deleted file mode 100644 index fff85f446..000000000 --- a/core/lib/dal/.sqlx/query-15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n is_finalized\n FROM\n via_votable_transactions\n WHERE\n tx_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "is_finalized", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Bytea" - ] - }, - "nullable": [ - false - ] - }, - "hash": "15ee57dfbde199ac5e9ea30488c05bcd619f87b5444dc1b2d1c7e77ae3c47c8f" -} diff --git a/core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json b/core/lib/dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json similarity index 76% rename from core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json rename to core/lib/dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json index f5baa12d0..2dedade5f 100644 --- a/core/lib/dal/.sqlx/query-b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed.json +++ b/core/lib/dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n COUNT(*) FILTER (\n WHERE\n vote = TRUE\n ) AS ok_votes,\n COUNT(*) AS total_votes\n FROM\n via_votes\n WHERE\n tx_id = $1\n ", + "query": "\n SELECT\n COUNT(*) FILTER (\n WHERE\n vote = TRUE\n ) AS ok_votes,\n COUNT(*) AS total_votes\n FROM\n via_votes\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", "describe": { "columns": [ { @@ -16,6 +16,7 @@ ], "parameters": { "Left": [ + "Int8", "Bytea" ] }, @@ -24,5 +25,5 @@ null ] }, - "hash": "b38342a659048118ba377392d0320bb4fc567b47885e4263e604ad9c2bce35ed" + "hash": "42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce" } diff --git a/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json b/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json new file mode 100644 index 000000000..dc1fa1f4a --- /dev/null +++ b/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id)\n VALUES\n ($1, $2)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3" +} diff --git a/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json b/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json deleted file mode 100644 index 44559b668..000000000 --- a/core/lib/dal/.sqlx/query-88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (tx_id, transaction_type)\n VALUES\n ($1, $2)\n ON CONFLICT (tx_id) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Text" - ] - }, - "nullable": [] - }, - "hash": "88a90fb59c1649513c9c0a7960bb27b9b83f2025bd9d8785c530cd18c4e8cd75" -} diff --git a/core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json b/core/lib/dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json similarity index 65% rename from core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json rename to core/lib/dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json index a456eece3..5a7d4a2de 100644 --- a/core/lib/dal/.sqlx/query-cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68.json +++ b/core/lib/dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json @@ -1,14 +1,15 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE via_votable_transactions\n SET\n is_finalized = TRUE,\n updated_at = NOW()\n WHERE\n tx_id = $1\n ", + "query": "\n UPDATE via_votable_transactions\n SET\n is_finalized = TRUE,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", "describe": { "columns": [], "parameters": { "Left": [ + "Int8", "Bytea" ] }, "nullable": [] }, - "hash": "cbdfeea9dd4c13468f4023d532249b437da96558b91e8a6c24878604440a9a68" + "hash": "ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9" } diff --git a/core/lib/dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json b/core/lib/dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json new file mode 100644 index 000000000..9133c893a --- /dev/null +++ b/core/lib/dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votes (l1_batch_number, tx_id, verifier_address, vote)\n VALUES\n ($1, $2, $3, $4)\n ON CONFLICT (l1_batch_number, tx_id, verifier_address) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca" +} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index 65770c88a..d15858eed 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -1,16 +1,19 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( - tx_id BYTEA PRIMARY KEY, - transaction_type TEXT NOT NULL, + l1_batch_number BIGINT NOT NULL REFERENCES l1_batches (number) ON DELETE CASCADE, + tx_id BYTEA, is_finalized BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP NOT NULL DEFAULT NOW(), - updated_at TIMESTAMP NOT NULL DEFAULT NOW() + updated_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (l1_batch_number, tx_id) ); CREATE TABLE IF NOT EXISTS via_votes ( - tx_id BYTEA NOT NULL REFERENCES via_votable_transactions(tx_id) ON DELETE CASCADE, + l1_batch_number BIGINT NOT NULL, + tx_id BYTEA NOT NULL, verifier_address TEXT NOT NULL, vote BOOLEAN NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (l1_batch_number, tx_id, verifier_address), + FOREIGN KEY (l1_batch_number, tx_id) REFERENCES via_votable_transactions (l1_batch_number, tx_id) ON DELETE CASCADE + ); - PRIMARY KEY (tx_id, verifier_address) -); diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 049749b8c..bf9eb08a2 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -8,30 +8,36 @@ pub struct ViaVotesDal<'c, 'a> { } impl ViaVotesDal<'_, '_> { + /// Inserts a new row in `via_votable_transactions`. + /// Notice we haven’t changed this since the PK is still (l1_batch_number, tx_id). pub async fn insert_votable_transaction( &mut self, + l1_batch_number: u32, tx_id: H256, - tx_type: &str, ) -> DalResult<()> { sqlx::query!( r#" INSERT INTO - via_votable_transactions (tx_id, transaction_type) + via_votable_transactions (l1_batch_number, tx_id) VALUES ($1, $2) - ON CONFLICT (tx_id) DO NOTHING + ON CONFLICT (l1_batch_number, tx_id) DO NOTHING "#, - tx_id.as_bytes(), - tx_type + l1_batch_number as i64, + tx_id.as_bytes() ) .instrument("insert_votable_transaction") .fetch_optional(self.storage) .await?; + Ok(()) } + /// Inserts a new vote row in `via_votes`. + /// Now requires `l1_batch_number` as part of the primary key / FK. pub async fn insert_vote( &mut self, + l1_batch_number: u32, tx_id: H256, verifier_address: &str, vote: bool, @@ -39,11 +45,12 @@ impl ViaVotesDal<'_, '_> { sqlx::query!( r#" INSERT INTO - via_votes (tx_id, verifier_address, vote) + via_votes (l1_batch_number, tx_id, verifier_address, vote) VALUES - ($1, $2, $3) - ON CONFLICT (tx_id, verifier_address) DO NOTHING + ($1, $2, $3, $4) + ON CONFLICT (l1_batch_number, tx_id, verifier_address) DO NOTHING "#, + l1_batch_number as i32, tx_id.as_bytes(), verifier_address, vote @@ -51,10 +58,17 @@ impl ViaVotesDal<'_, '_> { .instrument("insert_vote") .fetch_optional(self.storage) .await?; + Ok(()) } - pub async fn get_vote_count(&mut self, tx_id: H256) -> DalResult<(i64, i64)> { + /// Returns (ok_votes, total_votes) for the given `(l1_batch_number, tx_id)`. + /// Must also filter on `l1_batch_number`. + pub async fn get_vote_count( + &mut self, + l1_batch_number: u32, + tx_id: H256, + ) -> DalResult<(i64, i64)> { let row = sqlx::query!( r#" SELECT @@ -66,8 +80,10 @@ impl ViaVotesDal<'_, '_> { FROM via_votes WHERE - tx_id = $1 + l1_batch_number = $1 + AND tx_id = $2 "#, + l1_batch_number as i32, tx_id.as_bytes() ) .instrument("get_vote_count") @@ -79,14 +95,19 @@ impl ViaVotesDal<'_, '_> { Ok((ok_votes, total_votes)) } + /// Marks the transaction as finalized if #ok_votes / #total_votes > threshold. + /// Must use `(l1_batch_number, tx_id)` in both vote counting and the UPDATE statement. pub async fn finalize_transaction_if_needed( &mut self, + l1_batch_number: u32, tx_id: H256, threshold: f64, ) -> DalResult { - let (ok_votes, total_votes) = self.get_vote_count(tx_id).await?; - let finalized = total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold; - if finalized { + let (ok_votes, total_votes) = self.get_vote_count(l1_batch_number, tx_id).await?; + let is_above_threshold = + total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold; + + if is_above_threshold { sqlx::query!( r#" UPDATE via_votable_transactions @@ -94,32 +115,17 @@ impl ViaVotesDal<'_, '_> { is_finalized = TRUE, updated_at = NOW() WHERE - tx_id = $1 + l1_batch_number = $1 + AND tx_id = $2 "#, + l1_batch_number as i64, tx_id.as_bytes() ) .instrument("finalize_transaction_if_needed") .execute(self.storage) .await?; } - Ok(finalized) - } - pub async fn is_transaction_finalized(&mut self, tx_id: H256) -> DalResult { - let row = sqlx::query!( - r#" - SELECT - is_finalized - FROM - via_votable_transactions - WHERE - tx_id = $1 - "#, - tx_id.as_bytes() - ) - .instrument("is_transaction_finalized") - .fetch_optional(self.storage) - .await?; - Ok(row.map(|r| r.is_finalized).unwrap_or(false)) + Ok(is_above_threshold) } } diff --git a/core/lib/via_btc_client/DEV.md b/core/lib/via_btc_client/DEV.md index 87a707dde..238dd25d1 100644 --- a/core/lib/via_btc_client/DEV.md +++ b/core/lib/via_btc_client/DEV.md @@ -144,7 +144,7 @@ Votable: No (4) L1BatchDAReference -Votable: Yes +Votable: No Sender Validation: only valid sequencer |----------------------------------------------------------| | Schnorr Signature | diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 10cbf6d66..23227a0d2 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -7,6 +7,7 @@ use tracing::{debug, error, info, instrument, warn}; mod parser; pub use parser::get_eth_address; use parser::MessageParser; +use zksync_basic_types::L1BatchNumber; use zksync_types::H256; use crate::{ @@ -184,6 +185,23 @@ impl BitcoinInscriptionIndexer { self.starting_block_number, ) } + + pub async fn get_l1_batch_number( + &mut self, + msg: &FullInscriptionMessage, + ) -> Option { + match msg { + FullInscriptionMessage::ProofDAReference(proof_msg) => self + .get_l1_batch_number_from_proof_tx_id(&proof_msg.input.l1_batch_reveal_txid) + .await + .ok(), + FullInscriptionMessage::ValidatorAttestation(va_msg) => self + .get_l1_batch_number_from_validation_tx_id(&va_msg.input.reference_txid) + .await + .ok(), + _ => None, + } + } } impl BitcoinInscriptionIndexer { @@ -325,6 +343,40 @@ impl BitcoinInscriptionIndexer { debug!("L1ToL2Message transfer validity: {}", is_valid); is_valid } + + async fn get_l1_batch_number_from_proof_tx_id( + &mut self, + txid: &Txid, + ) -> anyhow::Result { + let a = self.client.get_transaction(txid).await?; + let b = self.parser.parse_transaction(&a, 0); + let msg = b + .first() + .ok_or_else(|| anyhow::anyhow!("No message found"))?; + + match msg { + FullInscriptionMessage::L1BatchDAReference(da_msg) => Ok(da_msg.input.l1_batch_index), + _ => Err(anyhow::anyhow!("Invalid message type")), + } + } + + async fn get_l1_batch_number_from_validation_tx_id( + &mut self, + txid: &Txid, + ) -> anyhow::Result { + let a = self.client.get_transaction(txid).await?; + let b = self.parser.parse_transaction(&a, 0); + let msg = b + .first() + .ok_or_else(|| anyhow::anyhow!("No message found"))?; + + match msg { + FullInscriptionMessage::ProofDAReference(da_msg) => Ok(self + .get_l1_batch_number_from_proof_tx_id(&da_msg.input.l1_batch_reveal_txid) + .await?), + _ => Err(anyhow::anyhow!("Invalid message type")), + } + } } #[cfg(test)] diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index 91e7a8732..b893f4fdc 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -178,7 +178,7 @@ impl BtcWatch { for processor in self.message_processors.iter_mut() { processor - .process_messages(storage, messages.clone()) + .process_messages(storage, messages.clone(), &mut self.indexer) .await .map_err(|e| MessageProcessorError::Internal(e.into()))?; } diff --git a/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs b/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs index 9e47b3b93..6fc8cf381 100644 --- a/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs +++ b/core/node/via_btc_watch/src/message_processors/l1_to_l2.rs @@ -1,4 +1,7 @@ -use via_btc_client::types::{BitcoinAddress, FullInscriptionMessage, L1ToL2Message}; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinAddress, FullInscriptionMessage, L1ToL2Message}, +}; use zksync_dal::{Connection, Core, CoreDal}; use zksync_types::{ abi::L2CanonicalTransaction, @@ -33,6 +36,7 @@ impl MessageProcessor for L1ToL2MessageProcessor { &mut self, storage: &mut Connection<'_, Core>, msgs: Vec, + _: &mut BitcoinInscriptionIndexer, ) -> Result<(), MessageProcessorError> { let mut priority_ops = Vec::new(); for msg in msgs { diff --git a/core/node/via_btc_watch/src/message_processors/mod.rs b/core/node/via_btc_watch/src/message_processors/mod.rs index cc1d1f88a..af783ecfe 100644 --- a/core/node/via_btc_watch/src/message_processors/mod.rs +++ b/core/node/via_btc_watch/src/message_processors/mod.rs @@ -1,5 +1,5 @@ pub(crate) use l1_to_l2::L1ToL2MessageProcessor; -use via_btc_client::types::FullInscriptionMessage; +use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; pub(crate) use votable::VotableMessageProcessor; use zksync_dal::{Connection, Core}; @@ -20,5 +20,6 @@ pub(super) trait MessageProcessor: 'static + std::fmt::Debug + Send + Sync { &mut self, storage: &mut Connection<'_, Core>, msgs: Vec, + indexer: &mut BitcoinInscriptionIndexer, ) -> Result<(), MessageProcessorError>; } diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 0055694d6..75c14bd02 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -1,5 +1,8 @@ use sqlx::types::chrono::{DateTime, Utc}; -use via_btc_client::types::{BitcoinTxid, FullInscriptionMessage}; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinTxid, FullInscriptionMessage}, +}; use zksync_dal::{Connection, Core, CoreDal}; use zksync_types::{aggregated_operations::AggregatedActionType, L1BatchNumber, H256}; @@ -26,6 +29,7 @@ impl MessageProcessor for VotableMessageProcessor { &mut self, storage: &mut Connection<'_, Core>, msgs: Vec, + indexer: &mut BitcoinInscriptionIndexer, ) -> Result<(), MessageProcessorError> { // Get the current timestamp let dt = Utc::now(); @@ -34,96 +38,86 @@ impl MessageProcessor for VotableMessageProcessor { let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); for msg in msgs { - match msg { - FullInscriptionMessage::L1BatchDAReference(da_msg) => { - let mut votes_dal = storage.via_votes_dal(); + if let Some(l1_batch_number) = indexer.get_l1_batch_number(&msg).await { + match msg { + FullInscriptionMessage::ProofDAReference(proof_msg) => { + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + let mut votes_dal = storage.via_votes_dal(); - let tx_id = convert_txid_to_h256(da_msg.common.tx_id); - votes_dal - .insert_votable_transaction(tx_id.clone(), "L1BatchDAReference") - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + votes_dal + .insert_votable_transaction(l1_batch_number.0, tx_id) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; - let mut eth_sender_dal = storage.eth_sender_dal(); - - eth_sender_dal - .insert_bogus_confirmed_eth_tx( - da_msg.input.l1_batch_index, - AggregatedActionType::Commit, - tx_id, - dt, - ) - .await?; - } - FullInscriptionMessage::ProofDAReference(proof_msg) => { - let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); - let mut votes_dal = storage.via_votes_dal(); - - votes_dal - .insert_votable_transaction(tx_id, "ProofDAReference") - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; - - let mut eth_sender_dal = storage.eth_sender_dal(); - - // todo: insert proper l1_batch number - eth_sender_dal - .insert_bogus_confirmed_eth_tx( - L1BatchNumber(1), - AggregatedActionType::PublishProofOnchain, - tx_id, - dt, - ) - .await?; - } - FullInscriptionMessage::ValidatorAttestation(attestation_msg) => { - let mut votes_dal = storage.via_votes_dal(); - - let reference_txid = convert_txid_to_h256(attestation_msg.input.reference_txid); - let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); - - // Vote = true if attestation_msg.input.attestation == Vote::Ok - let is_ok = matches!( - attestation_msg.input.attestation, - via_btc_client::types::Vote::Ok - ); - votes_dal - .insert_vote( - reference_txid, - &attestation_msg.common.p2wpkh_address.to_string(), - is_ok, - ) - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; - - // Check finalization - if votes_dal - .finalize_transaction_if_needed(reference_txid, self.threshold) - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? - { let mut eth_sender_dal = storage.eth_sender_dal(); - // todo: insert proper l1_batch number eth_sender_dal .insert_bogus_confirmed_eth_tx( - L1BatchNumber(1), - AggregatedActionType::Execute, + l1_batch_number, + AggregatedActionType::PublishProofOnchain, tx_id, dt, ) .await?; } + FullInscriptionMessage::ValidatorAttestation(attestation_msg) => { + let mut votes_dal = storage.via_votes_dal(); + + let reference_txid = + convert_txid_to_h256(attestation_msg.input.reference_txid); + let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); + + // Vote = true if attestation_msg.input.attestation == Vote::Ok + let is_ok = matches!( + attestation_msg.input.attestation, + via_btc_client::types::Vote::Ok + ); + votes_dal + .insert_vote( + l1_batch_number.0, + reference_txid, + &attestation_msg.common.p2wpkh_address.to_string(), + is_ok, + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + // Check finalization + if votes_dal + .finalize_transaction_if_needed( + l1_batch_number.0, + reference_txid, + self.threshold, + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + { + let mut eth_sender_dal = storage.eth_sender_dal(); + + eth_sender_dal + .insert_bogus_confirmed_eth_tx( + l1_batch_number, + AggregatedActionType::Execute, + tx_id, + dt, + ) + .await?; + } + } + // bootstrapping phase is already covered + FullInscriptionMessage::ProposeSequencer(_) + | FullInscriptionMessage::SystemBootstrapping(_) => { + // do nothing + } + // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor + FullInscriptionMessage::L1ToL2Message(_) + | FullInscriptionMessage::L1BatchDAReference(_) => { + // do nothing + } } - // bootstrapping phase is already covered - FullInscriptionMessage::ProposeSequencer(_) => { - // do nothing - } - // Non-votable messages like SystemBootstrapping or L1ToL2Message are ignored by this processor - FullInscriptionMessage::SystemBootstrapping(_) - | FullInscriptionMessage::L1ToL2Message(_) => { - // do nothing - } + } else { + tracing::warn!("L1 batch number is not found for message: {:?}", msg); + continue; } } Ok(()) From 6e897414e90566e52870bb36bdfcd9aab02dede9 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:06:10 +0100 Subject: [PATCH 036/212] feat: add verifer and coordinator envs configs --- .gitignore | 1 + Makefile | 26 +++++++++- etc/env/configs/via.toml | 74 +--------------------------- etc/env/configs/via_base.toml | 71 ++++++++++++++++++++++++++ etc/env/configs/via_coordinator.toml | 1 + etc/env/configs/via_verifier.toml | 1 + 6 files changed, 99 insertions(+), 75 deletions(-) create mode 100644 etc/env/configs/via_base.toml create mode 100644 etc/env/configs/via_coordinator.toml create mode 100644 etc/env/configs/via_verifier.toml diff --git a/.gitignore b/.gitignore index a05869d89..733a66811 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ Cargo.lock /etc/env/.current /etc/env/configs/* !/etc/env/configs/dev.toml +!/etc/env/configs/via*.toml !/etc/env/configs/dev_validium.toml !/etc/env/configs/dev_validium_docker.toml !/etc/env/configs/ext-node.toml diff --git a/Makefile b/Makefile index ba62d86c6..76e6fca89 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,20 @@ RESET = \033[0m # CLI tool CLI_TOOL = via + +CMD := $(firstword $(MAKECMDGOALS)) +VIA_ENV ?= via +DIFF ?= 0 + +# Select the via env +ifeq ($(CMD), via-verifier) + VIA_ENV := via_verifier + DIFF := 1 +else ifeq ($(CMD), via-coordinator) + VIA_ENV := via_coordinator + DIFF := 2 +endif + # Default target: Show help message .PHONY: help help: @@ -46,13 +60,21 @@ via: env config init transactions celestia bootstrap server-genesis server .PHONY: all all: env config init transactions celestia btc-explorer bootstrap server-genesis server +# Run the basic setup workflow in verifier +.PHONY: via-verifier +via-verifier: env config verifier + +# Run the basic setup workflow in coordinator +.PHONY: via-verifier +via-coordinator: env config coordinator + # Run 'via env via' .PHONY: env env: @echo "------------------------------------------------------------------------------------" @echo "$(YELLOW)Setting the environment...$(RESET)" @echo "------------------------------------------------------------------------------------" - @$(CLI_TOOL) env via + @$(CLI_TOOL) env ${VIA_ENV} # Run 'via config compile' .PHONY: config @@ -60,7 +82,7 @@ config: @echo "------------------------------------------------------------------------------------" @echo "$(YELLOW)Creating environment configuration file...$(RESET)" @echo "------------------------------------------------------------------------------------" - @$(CLI_TOOL) config compile + @$(CLI_TOOL) config compile ${VIA_ENV} ${DIFF} # Run 'via init' .PHONY: init diff --git a/etc/env/configs/via.toml b/etc/env/configs/via.toml index 91ba6a400..fbf3053cf 100644 --- a/etc/env/configs/via.toml +++ b/etc/env/configs/via.toml @@ -1,73 +1 @@ -__imports__ = [ "base", "l2-inits/via.init.env" ] - -[via_btc_watch] -confirmations_for_btc_msg = 0 -btc_node_poll_interval = 1000 -rpc_url = "http://0.0.0.0:18443" -rpc_user = "rpcuser" -rpc_password = "rpcpassword" -network = "regtest" -bootstrap_txids = [] -actor_role = "Sequencer" -# Number of blocks that we should wait before processing the new blocks. -# For local regtest we should wait for 0 blocks. -# But for mainnet we should wait for 3 blocks. -btc_blocks_lag = 0 - -[via_btc_sender] -poll_interval = 1000 -private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" -max_aggregated_blocks_to_commit = 1 -max_aggregated_proofs_to_commit = 1 -max_txs_in_flight = 1 -rpc_url = "http://0.0.0.0:18443" -rpc_user = "rpcuser" -rpc_password = "rpcpassword" -network = "regtest" -actor_role = "Sequencer" -da_identifier = "da_identifier_celestia" -proof_sending_mode= "SkipEveryProof" -block_confirmations = 0 - -[via_celestia_client] -api_node_url = "http://0.0.0.0:26658" -auth_token = "" -blob_size_limit = 1973786 - -[rust] -log = """\ -warn,\ -zksync_node_framework=info,\ -zksync_node_consensus=info,\ -zksync_consensus_bft=info,\ -zksync_consensus_network=info,\ -zksync_consensus_storage=info,\ -zksync_commitment_generator=info,\ -zksync_core=debug,\ -zksync_dal=info,\ -zksync_db_connection=info,\ -zksync_health_check=debug,\ -zksync_eth_client=info,\ -zksync_state_keeper=info,\ -zksync_node_sync=info,\ -zksync_storage=info,\ -zksync_metadata_calculator=info,\ -zksync_merkle_tree=info,\ -zksync_node_api_server=info,\ -zksync_node_db_pruner=info,\ -zksync_reorg_detector=info,\ -zksync_consistency_checker=info,\ -zksync_state=debug,\ -zksync_utils=debug,\ -zksync_types=info,\ -zksync_web3_decl=debug,\ -loadnext=info,\ -vm=info,\ -zksync_external_node=info,\ -zksync_snapshots_applier=debug,\ -via_btc_watch=debug,\ -via_state_keeper=debug,\ -via_btc_sender=debug,\ -via_da_dispatcher=debug,\ -via_da_clients=debug,\ -""" +__imports__ = ["base", "l2-inits/via.init.env", "configs/via_base.toml"] diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml new file mode 100644 index 000000000..843dc00ad --- /dev/null +++ b/etc/env/configs/via_base.toml @@ -0,0 +1,71 @@ +[via_btc_watch] +confirmations_for_btc_msg = 0 +btc_node_poll_interval = 1000 +rpc_url = "http://0.0.0.0:18443" +rpc_user = "rpcuser" +rpc_password = "rpcpassword" +network = "regtest" +bootstrap_txids = [] +actor_role = "Sequencer" +# Number of blocks that we should wait before processing the new blocks. +# For local regtest we should wait for 0 blocks. +# But for mainnet we should wait for 3 blocks. +btc_blocks_lag = 0 + +[via_btc_sender] +poll_interval = 1000 +private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" +max_aggregated_blocks_to_commit = 1 +max_aggregated_proofs_to_commit = 1 +max_txs_in_flight = 1 +rpc_url = "http://0.0.0.0:18443" +rpc_user = "rpcuser" +rpc_password = "rpcpassword" +network = "regtest" +actor_role = "Sequencer" +da_identifier = "da_identifier_celestia" +proof_sending_mode= "SkipEveryProof" +block_confirmations = 0 + +[via_celestia_client] +api_node_url = "http://0.0.0.0:26658" +auth_token = "" +blob_size_limit = 1973786 + +[rust] +log = """\ +warn,\ +zksync_node_framework=info,\ +zksync_node_consensus=info,\ +zksync_consensus_bft=info,\ +zksync_consensus_network=info,\ +zksync_consensus_storage=info,\ +zksync_commitment_generator=info,\ +zksync_core=debug,\ +zksync_dal=info,\ +zksync_db_connection=info,\ +zksync_health_check=debug,\ +zksync_eth_client=info,\ +zksync_state_keeper=info,\ +zksync_node_sync=info,\ +zksync_storage=info,\ +zksync_metadata_calculator=info,\ +zksync_merkle_tree=info,\ +zksync_node_api_server=info,\ +zksync_node_db_pruner=info,\ +zksync_reorg_detector=info,\ +zksync_consistency_checker=info,\ +zksync_state=debug,\ +zksync_utils=debug,\ +zksync_types=info,\ +zksync_web3_decl=debug,\ +loadnext=info,\ +vm=info,\ +zksync_external_node=info,\ +zksync_snapshots_applier=debug,\ +via_btc_watch=debug,\ +via_state_keeper=debug,\ +via_btc_sender=debug,\ +via_da_dispatcher=debug,\ +via_da_clients=debug,\ +""" diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml new file mode 100644 index 000000000..16ed64eb1 --- /dev/null +++ b/etc/env/configs/via_coordinator.toml @@ -0,0 +1 @@ +__imports__ = [ "base", "l2-inits/via_coordinator.init.env", "configs/via_base.toml" ] diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml new file mode 100644 index 000000000..ce2ed419f --- /dev/null +++ b/etc/env/configs/via_verifier.toml @@ -0,0 +1 @@ +__imports__ = [ "base", "l2-inits/via_verifier.init.env", "configs/via_base.toml" ] From 0eb79e451b4aaa9c31ca89f85d1ff11a1034d950 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 09:49:19 +0330 Subject: [PATCH 037/212] fix withdrawal test --- core/lib/via_btc_client/src/withdrawal/mod.rs | 120 ++++++++++++++---- 1 file changed, 93 insertions(+), 27 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index 0469fbb22..d5879fa08 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -230,48 +230,114 @@ impl WithdrawalBuilder { #[cfg(test)] mod tests { use std::str::FromStr; - + use async_trait::async_trait; use bitcoin::Network; - use super::*; + use mockall::{mock, predicate::*}; + use crate::types::BitcoinError; + + mock! { + BitcoinOps {} + #[async_trait] + impl BitcoinOps for BitcoinOps { + async fn fetch_utxos(&self, _address: &Address) -> Result, BitcoinError> { + // Mock implementation + let txid = Txid::from_str( + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ).unwrap(); + let outpoint = OutPoint::new(txid, 0); + let txout = TxOut { + value: Amount::from_btc(1.0).unwrap(), + script_pubkey: ScriptBuf::new(), + }; + Ok(vec![(outpoint, txout)]) + } + + async fn get_fee_rate(&self, _target_blocks: u16) -> Result { + Ok(2) + } + + async fn broadcast_signed_transaction(&self, _tx_hex: &str) -> Result { + Ok(Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap()) + } + + async fn check_tx_confirmation(&self, _txid: &Txid, _min_confirmations: u32) -> Result { + Ok(true) + } + + async fn fetch_block_height(&self) -> Result { + Ok(100000) + } + + async fn get_balance(&self, _address: &Address) -> Result { + Ok(100000000) // 1 BTC in sats + } + fn get_network(&self) -> bitcoin::Network { + Network::Regtest + } + + async fn fetch_block(&self, _height: u128) -> Result { + Ok(bitcoin::Block::default()) + } + + async fn get_transaction(&self, _txid: &Txid) -> Result { + Ok(Transaction::default()) + } + + async fn fetch_block_by_hash(&self, _hash: &bitcoin::BlockHash) -> Result { + Ok(bitcoin::Block::default()) + } + } + } #[tokio::test] - #[ignore] // Remove this to run against a local Bitcoin node async fn test_withdrawal_builder() -> Result<()> { let network = Network::Regtest; - let bridge_address = Address::from_str("bcrt1q6rhpng9evgu7ul6k0kr8f8sdre3hy9ym8t7g5h")? + let bridge_address = Address::from_str("bcrt1pxqkh0g270lucjafgngmwv7vtgc8mk9j5y4j8fnrxm77yunuh398qfv8tqp")? .require_network(network)?; - let builder = WithdrawalBuilder::new( - "http://localhost:18443", - BitcoinNetwork::Regtest, - bitcoincore_rpc::Auth::None, + // Create mock and set expectations + let mut mock_ops = MockBitcoinOps::new(); + mock_ops + .expect_fetch_utxos() + .returning(|_| { + let txid = Txid::from_str( + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ).unwrap(); + let outpoint = OutPoint::new(txid, 0); + let txout = TxOut { + value: Amount::from_btc(1.0).unwrap(), + script_pubkey: ScriptBuf::new(), + }; + Ok(vec![(outpoint, txout)]) + }); + + mock_ops + .expect_get_fee_rate() + .returning(|_| Ok(2)); + + // Use mock client + let builder = WithdrawalBuilder { + client: Arc::new(mock_ops), bridge_address, - ) - .await?; - - let withdrawals = vec![ - WithdrawalRequest { - address: Address::from_str("bcrt1qg3y8889zzz0qvg3xhm4e9j8z9wp7524fn0qxya")? - .require_network(network)?, - amount: Amount::from_btc(0.1)?, - }, - WithdrawalRequest { - address: Address::from_str("bcrt1qf6em9yq7h8zmmwl9q8ue73x34dj9ql9xl7t4ph")? - .require_network(network)?, - amount: Amount::from_btc(0.2)?, - }, - ]; - - let proof_txid = - Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")?; + }; + + let withdrawal_address = "bcrt1pv6dtdf0vrrj6ntas926v8vw9u0j3mga29vmfnxh39zfxya83p89qz9ze3l"; + let withdrawal_amount = Amount::from_btc(0.1)?; + + let withdrawals = vec![WithdrawalRequest { + address: Address::from_str(withdrawal_address)?.require_network(network)?, + amount: withdrawal_amount, + }]; + + let proof_txid = Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")?; let withdrawal_tx = builder .create_unsigned_withdrawal_tx(withdrawals, proof_txid) .await?; assert!(!withdrawal_tx.utxos.is_empty()); - // Verify OP_RETURN output exists and contains our data + // Verify OP_RETURN output let op_return_output = withdrawal_tx .tx .output From 704d792b4500f20865a67319d779c5746c8f9aa6 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 09:50:08 +0330 Subject: [PATCH 038/212] remove unrelated file from via_btc_client --- core/lib/via_btc_client/Cargo.toml | 6 - .../lib/via_btc_client/examples/withdrawal.rs | 220 ------------------ core/lib/via_btc_client/src/withdrawal/fee.rs | 0 core/lib/via_btc_client/src/withdrawal/mod.rs | 44 ++-- .../lib/via_btc_client/src/withdrawal/utxo.rs | 0 5 files changed, 21 insertions(+), 249 deletions(-) delete mode 100644 core/lib/via_btc_client/examples/withdrawal.rs delete mode 100644 core/lib/via_btc_client/src/withdrawal/fee.rs delete mode 100644 core/lib/via_btc_client/src/withdrawal/utxo.rs diff --git a/core/lib/via_btc_client/Cargo.toml b/core/lib/via_btc_client/Cargo.toml index 6f686d24f..1ac488dbc 100644 --- a/core/lib/via_btc_client/Cargo.toml +++ b/core/lib/via_btc_client/Cargo.toml @@ -26,7 +26,6 @@ bitcoincore-rpc = "0.19.0" rand.workspace = true hex.workspace = true secp256k1 = "0.29.0" -secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} reqwest = "0.12.5" serde_json.workspace = true inquire = { version = "0.7.5", optional = true } @@ -67,8 +66,3 @@ name = "verify_batch" path = "examples/verify_batch.rs" -[[example]] -name = "withdrawal" -path = "examples/withdrawal.rs" - - diff --git a/core/lib/via_btc_client/examples/withdrawal.rs b/core/lib/via_btc_client/examples/withdrawal.rs deleted file mode 100644 index 108609ac6..000000000 --- a/core/lib/via_btc_client/examples/withdrawal.rs +++ /dev/null @@ -1,220 +0,0 @@ -use bitcoin::{ - absolute, - hashes::Hash, - sighash::{Prevouts, SighashCache}, - taproot::TaprootSpendInfo, - Address as BitcoinAddress, Amount, Network, OutPoint, TapSighashType, Transaction, TxIn, TxOut, - Witness, XOnlyPublicKey, -}; -// use bitcoincore_rpc::Auth; -use musig2::{ - verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, SecNonceSpices, -}; -use rand::{rngs::OsRng, Rng}; -use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; - -#[tokio::main] -async fn main() -> Result<(), Box> { - // ------------------------------------------- - // Setup: Create secret and public keys for three participants - // ------------------------------------------- - let mut rng = OsRng; - let secret_key_1 = SecretKey::new(&mut rng); - let secret_key_2 = SecretKey::new(&mut rng); - let secret_key_3 = SecretKey::new(&mut rng); - - let secp = Secp256k1::new(); - let public_key_1 = PublicKey::from_secret_key(&secp, &secret_key_1); - let public_key_2 = PublicKey::from_secret_key(&secp, &secret_key_2); - let public_key_3 = PublicKey::from_secret_key(&secp, &secret_key_3); - - // ------------------------------------------- - // Key aggregation (MuSig2) - // ------------------------------------------- - let pubkeys = vec![public_key_1, public_key_2, public_key_3]; - let key_agg_ctx = KeyAggContext::new(pubkeys)?; - let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); - - // Convert to x-only pubkey for Taproot address - let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); - let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; - // Create a P2TR address from the aggregated x-only public key - let secp_btc = bitcoin::secp256k1::Secp256k1::new(); - let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); - let tweaked_key = tap_info.output_key(); - let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); - println!("Aggregated taproot address: {}", address); - - // ------------------------------------------- - // Connect to Bitcoin node (adjust RPC credentials and URL) - // ------------------------------------------- - // NOTE: Update these with real RPC credentials and URL - let _rpc_url = "http://127.0.0.1:18443"; - let _rpc_user = "user"; - let _rpc_pass = "pass"; - - // let client = BitcoinClient::new(rpc_url, Network::Regtest, Auth::UserPass(rpc_user.into(), rpc_pass.into()))?; - - // ------------------------------------------- - // Instead of fetching UTXOs from node, use a fake constant UTXO for demonstration - // Comment out real fetching code - // ------------------------------------------- - // let utxos = client.fetch_utxos(&address).await?; - // if utxos.is_empty() { - // eprintln!("No UTXOs found for this address. Please fund it first."); - // return Ok(()); - // } - - // We'll use a fake UTXO here - let fake_utxo_txid = bitcoin::Txid::from_slice(&[0x11; 32]).unwrap(); // just a dummy 32-byte txid - let fake_vout = 0; - let fake_utxo_amount = Amount::from_btc(1.0).unwrap(); // 1 BTC in the fake utxo - let fake_utxo = (fake_utxo_txid, fake_vout, fake_utxo_amount); - - // ------------------------------------------- - // Create a transaction spending this fake UTXO - // ------------------------------------------- - let send_amount = Amount::from_btc(0.1).unwrap(); // amount to send - let fee_amount = Amount::from_btc(0.0001).unwrap(); - let change_amount = fake_utxo_amount - send_amount - fee_amount; - - // The recipient address - for demonstration let's send to the same aggregated address - // or another regtest address. - let recipient_address = address.clone(); - let change_address = address.clone(); - - let txin = TxIn { - previous_output: OutPoint { - txid: fake_utxo.0, - vout: fake_utxo.1, - }, - sequence: bitcoin::Sequence(0xFFFFFFFF), - witness: Witness::new(), - script_sig: bitcoin::Script::new().into(), - }; - - let txout_recipient = TxOut { - value: send_amount, - script_pubkey: recipient_address.script_pubkey(), - }; - - let txout_change = TxOut { - value: change_amount, - script_pubkey: change_address.script_pubkey(), - }; - - let mut unsigned_tx = Transaction { - version: bitcoin::transaction::Version(2), - lock_time: absolute::LockTime::ZERO, - input: vec![txin], - output: vec![txout_recipient, txout_change], - }; - - // ------------------------------------------- - // Compute the BIP341 sighash for signing - // ------------------------------------------- - let mut sighash_cache = SighashCache::new(&unsigned_tx); - let sighash_type = TapSighashType::All; - - // For taproot key spend (no script): - let sighash = sighash_cache.taproot_key_spend_signature_hash( - 0, - &Prevouts::All(&[TxOut { - value: fake_utxo_amount, - script_pubkey: recipient_address.script_pubkey(), - }]), - sighash_type, - )?; - - let message = sighash; // This 32-byte hash is what we will sign using MuSig2 - - // ------------------------------------------- - // MuSig2 Nonce Exchange and Partial Signatures - // ------------------------------------------- - // First round: generate public nonces - let mut first_round_1 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), - 0, - SecNonceSpices::new() - .with_seckey(secret_key_1) - .with_message(&message), - )?; - - let mut first_round_2 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), - 1, - SecNonceSpices::new() - .with_seckey(secret_key_2) - .with_message(&message), - )?; - - let mut first_round_3 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), - 2, - SecNonceSpices::new() - .with_seckey(secret_key_3) - .with_message(&message), - )?; - - // Get public nonces - let pub_nonce_1 = first_round_1.our_public_nonce(); - let pub_nonce_2 = first_round_2.our_public_nonce(); - let pub_nonce_3 = first_round_3.our_public_nonce(); - - // Exchange nonces between participants - first_round_1.receive_nonce(1, pub_nonce_2.clone())?; - first_round_1.receive_nonce(2, pub_nonce_3.clone())?; - - first_round_2.receive_nonce(0, pub_nonce_1.clone())?; - first_round_2.receive_nonce(2, pub_nonce_3.clone())?; - - first_round_3.receive_nonce(0, pub_nonce_1.clone())?; - first_round_3.receive_nonce(1, pub_nonce_2.clone())?; - - // Second round: Create partial signatures - let mut second_round_1 = first_round_1.finalize(secret_key_1, &message)?; - let second_round_2 = first_round_2.finalize(secret_key_2, &message)?; - let second_round_3 = first_round_3.finalize(secret_key_3, &message)?; - - // Get partial signatures - let _partial_sig_1: PartialSignature = second_round_1.our_signature(); - let partial_sig_2: PartialSignature = second_round_2.our_signature(); - let partial_sig_3: PartialSignature = second_round_3.our_signature(); - - // One participant collects all partial signatures - second_round_1.receive_signature(1, partial_sig_2)?; - second_round_1.receive_signature(2, partial_sig_3)?; - - // Final aggregate MuSig2 signature - let final_signature: CompactSignature = second_round_1.finalize()?; - - // Verify the signature (optional sanity check) - match verify_single(aggregated_pubkey, final_signature, message) { - Ok(_) => println!("MuSig2 signature verified successfully!"), - Err(e) => println!("MuSig2 signature verification failed: {:?}", e), - } - - // ------------------------------------------- - // Insert the final signature into the transaction witness - // ------------------------------------------- - let mut final_sig_with_hashtype = final_signature.serialize().to_vec(); - final_sig_with_hashtype.push(sighash_type as u8); // For SIGHASH_DEFAULT this is 0x00 - - // For a key-path spend in taproot, the witness is just the signature - unsigned_tx.input[0].witness = Witness::from(vec![final_sig_with_hashtype]); - - // ------------------------------------------- - // Print the signed raw transaction (in hex) - // ------------------------------------------- - let signed_raw_tx = bitcoin::consensus::encode::serialize_hex(&unsigned_tx); - println!("Signed raw transaction (hex): {}", signed_raw_tx); - - // NOTE: In real scenario, you could broadcast this transaction using the Bitcoin node RPC: - // client.broadcast_raw_tx(&signed_raw_tx).await?; - // Here we just printed it. - - Ok(()) -} diff --git a/core/lib/via_btc_client/src/withdrawal/fee.rs b/core/lib/via_btc_client/src/withdrawal/fee.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index d5879fa08..c64d584de 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -229,12 +229,12 @@ impl WithdrawalBuilder { #[cfg(test)] mod tests { - use std::str::FromStr; + use super::*; + use crate::types::BitcoinError; use async_trait::async_trait; use bitcoin::Network; - use super::*; use mockall::{mock, predicate::*}; - use crate::types::BitcoinError; + use std::str::FromStr; mock! { BitcoinOps {} @@ -293,28 +293,25 @@ mod tests { #[tokio::test] async fn test_withdrawal_builder() -> Result<()> { let network = Network::Regtest; - let bridge_address = Address::from_str("bcrt1pxqkh0g270lucjafgngmwv7vtgc8mk9j5y4j8fnrxm77yunuh398qfv8tqp")? - .require_network(network)?; + let bridge_address = + Address::from_str("bcrt1pxqkh0g270lucjafgngmwv7vtgc8mk9j5y4j8fnrxm77yunuh398qfv8tqp")? + .require_network(network)?; // Create mock and set expectations let mut mock_ops = MockBitcoinOps::new(); - mock_ops - .expect_fetch_utxos() - .returning(|_| { - let txid = Txid::from_str( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" - ).unwrap(); - let outpoint = OutPoint::new(txid, 0); - let txout = TxOut { - value: Amount::from_btc(1.0).unwrap(), - script_pubkey: ScriptBuf::new(), - }; - Ok(vec![(outpoint, txout)]) - }); - - mock_ops - .expect_get_fee_rate() - .returning(|_| Ok(2)); + mock_ops.expect_fetch_utxos().returning(|_| { + let txid = + Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") + .unwrap(); + let outpoint = OutPoint::new(txid, 0); + let txout = TxOut { + value: Amount::from_btc(1.0).unwrap(), + script_pubkey: ScriptBuf::new(), + }; + Ok(vec![(outpoint, txout)]) + }); + + mock_ops.expect_get_fee_rate().returning(|_| Ok(2)); // Use mock client let builder = WithdrawalBuilder { @@ -330,7 +327,8 @@ mod tests { amount: withdrawal_amount, }]; - let proof_txid = Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")?; + let proof_txid = + Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")?; let withdrawal_tx = builder .create_unsigned_withdrawal_tx(withdrawals, proof_txid) diff --git a/core/lib/via_btc_client/src/withdrawal/utxo.rs b/core/lib/via_btc_client/src/withdrawal/utxo.rs deleted file mode 100644 index e69de29bb..000000000 From a220ad564b46ee0452c7d27518a7a857a3d55511 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 09:50:35 +0330 Subject: [PATCH 039/212] init via_musig2 --- Cargo.lock | 13 +- Cargo.toml | 3 + core/lib/via_musig2/Cargo.toml | 34 +++ core/lib/via_musig2/examples/coordinator.rs | 1 + .../examples/key_generation_setup.rs | 1 + core/lib/via_musig2/examples/withdrawal.rs | 220 ++++++++++++++++++ core/lib/via_musig2/src/lib.rs | 1 + 7 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 core/lib/via_musig2/Cargo.toml create mode 100644 core/lib/via_musig2/examples/coordinator.rs create mode 100644 core/lib/via_musig2/examples/key_generation_setup.rs create mode 100644 core/lib/via_musig2/examples/withdrawal.rs create mode 100644 core/lib/via_musig2/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a2c32b66f..dc8ec7ba1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8466,7 +8466,6 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.7", "secp256k1 0.29.0", - "secp256k1 0.30.0", "serde", "serde_json", "thiserror", @@ -8577,6 +8576,18 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "via_musig2" +version = "0.1.0" +dependencies = [ + "bitcoin", + "hex", + "musig2", + "rand 0.8.5", + "secp256k1 0.30.0", + "tokio", +] + [[package]] name = "via_server" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index ffc0077d5..44d68bb83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,8 @@ members = [ "core/node/via_btc_sender", "core/node/via_fee_model", "core/node/via_state_keeper", + "core/lib/via_da_clients", + "core/lib/via_musig2", ] @@ -321,3 +323,4 @@ via_da_dispatcher = { version = "0.1.0", path = "core/node/via_da_dispatcher" } via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } +via_musig2 = { version = "0.1.0", path = "core/lib/via_musig2" } diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml new file mode 100644 index 000000000..87e9d3fb7 --- /dev/null +++ b/core/lib/via_musig2/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "via_musig2" +description = "Via Network Musig2 Wrapper" +version.workspace = true +edition.workspace = true +authors = ["Via Network"] +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +rand.workspace = true +hex.workspace = true +bitcoin = { version = "0.32.2", features = ["serde"] } +musig2 = "0.2.0" +secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} +tokio = { version = "1.0", features = ["full"] } + + + + + +[[example]] +name = "key_generation_setup" +path = "examples/key_generation_setup.rs" + + +[[example]] +name = "withdrawal" +path = "examples/withdrawal.rs" + + diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs new file mode 100644 index 000000000..f328e4d9d --- /dev/null +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/core/lib/via_musig2/examples/key_generation_setup.rs b/core/lib/via_musig2/examples/key_generation_setup.rs new file mode 100644 index 000000000..f328e4d9d --- /dev/null +++ b/core/lib/via_musig2/examples/key_generation_setup.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/core/lib/via_musig2/examples/withdrawal.rs b/core/lib/via_musig2/examples/withdrawal.rs new file mode 100644 index 000000000..108609ac6 --- /dev/null +++ b/core/lib/via_musig2/examples/withdrawal.rs @@ -0,0 +1,220 @@ +use bitcoin::{ + absolute, + hashes::Hash, + sighash::{Prevouts, SighashCache}, + taproot::TaprootSpendInfo, + Address as BitcoinAddress, Amount, Network, OutPoint, TapSighashType, Transaction, TxIn, TxOut, + Witness, XOnlyPublicKey, +}; +// use bitcoincore_rpc::Auth; +use musig2::{ + verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, SecNonceSpices, +}; +use rand::{rngs::OsRng, Rng}; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // ------------------------------------------- + // Setup: Create secret and public keys for three participants + // ------------------------------------------- + let mut rng = OsRng; + let secret_key_1 = SecretKey::new(&mut rng); + let secret_key_2 = SecretKey::new(&mut rng); + let secret_key_3 = SecretKey::new(&mut rng); + + let secp = Secp256k1::new(); + let public_key_1 = PublicKey::from_secret_key(&secp, &secret_key_1); + let public_key_2 = PublicKey::from_secret_key(&secp, &secret_key_2); + let public_key_3 = PublicKey::from_secret_key(&secp, &secret_key_3); + + // ------------------------------------------- + // Key aggregation (MuSig2) + // ------------------------------------------- + let pubkeys = vec![public_key_1, public_key_2, public_key_3]; + let key_agg_ctx = KeyAggContext::new(pubkeys)?; + let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); + + // Convert to x-only pubkey for Taproot address + let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); + let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + // Create a P2TR address from the aggregated x-only public key + let secp_btc = bitcoin::secp256k1::Secp256k1::new(); + let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); + let tweaked_key = tap_info.output_key(); + let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); + println!("Aggregated taproot address: {}", address); + + // ------------------------------------------- + // Connect to Bitcoin node (adjust RPC credentials and URL) + // ------------------------------------------- + // NOTE: Update these with real RPC credentials and URL + let _rpc_url = "http://127.0.0.1:18443"; + let _rpc_user = "user"; + let _rpc_pass = "pass"; + + // let client = BitcoinClient::new(rpc_url, Network::Regtest, Auth::UserPass(rpc_user.into(), rpc_pass.into()))?; + + // ------------------------------------------- + // Instead of fetching UTXOs from node, use a fake constant UTXO for demonstration + // Comment out real fetching code + // ------------------------------------------- + // let utxos = client.fetch_utxos(&address).await?; + // if utxos.is_empty() { + // eprintln!("No UTXOs found for this address. Please fund it first."); + // return Ok(()); + // } + + // We'll use a fake UTXO here + let fake_utxo_txid = bitcoin::Txid::from_slice(&[0x11; 32]).unwrap(); // just a dummy 32-byte txid + let fake_vout = 0; + let fake_utxo_amount = Amount::from_btc(1.0).unwrap(); // 1 BTC in the fake utxo + let fake_utxo = (fake_utxo_txid, fake_vout, fake_utxo_amount); + + // ------------------------------------------- + // Create a transaction spending this fake UTXO + // ------------------------------------------- + let send_amount = Amount::from_btc(0.1).unwrap(); // amount to send + let fee_amount = Amount::from_btc(0.0001).unwrap(); + let change_amount = fake_utxo_amount - send_amount - fee_amount; + + // The recipient address - for demonstration let's send to the same aggregated address + // or another regtest address. + let recipient_address = address.clone(); + let change_address = address.clone(); + + let txin = TxIn { + previous_output: OutPoint { + txid: fake_utxo.0, + vout: fake_utxo.1, + }, + sequence: bitcoin::Sequence(0xFFFFFFFF), + witness: Witness::new(), + script_sig: bitcoin::Script::new().into(), + }; + + let txout_recipient = TxOut { + value: send_amount, + script_pubkey: recipient_address.script_pubkey(), + }; + + let txout_change = TxOut { + value: change_amount, + script_pubkey: change_address.script_pubkey(), + }; + + let mut unsigned_tx = Transaction { + version: bitcoin::transaction::Version(2), + lock_time: absolute::LockTime::ZERO, + input: vec![txin], + output: vec![txout_recipient, txout_change], + }; + + // ------------------------------------------- + // Compute the BIP341 sighash for signing + // ------------------------------------------- + let mut sighash_cache = SighashCache::new(&unsigned_tx); + let sighash_type = TapSighashType::All; + + // For taproot key spend (no script): + let sighash = sighash_cache.taproot_key_spend_signature_hash( + 0, + &Prevouts::All(&[TxOut { + value: fake_utxo_amount, + script_pubkey: recipient_address.script_pubkey(), + }]), + sighash_type, + )?; + + let message = sighash; // This 32-byte hash is what we will sign using MuSig2 + + // ------------------------------------------- + // MuSig2 Nonce Exchange and Partial Signatures + // ------------------------------------------- + // First round: generate public nonces + let mut first_round_1 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 0, + SecNonceSpices::new() + .with_seckey(secret_key_1) + .with_message(&message), + )?; + + let mut first_round_2 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 1, + SecNonceSpices::new() + .with_seckey(secret_key_2) + .with_message(&message), + )?; + + let mut first_round_3 = FirstRound::new( + key_agg_ctx.clone(), + rand::thread_rng().gen::<[u8; 32]>(), + 2, + SecNonceSpices::new() + .with_seckey(secret_key_3) + .with_message(&message), + )?; + + // Get public nonces + let pub_nonce_1 = first_round_1.our_public_nonce(); + let pub_nonce_2 = first_round_2.our_public_nonce(); + let pub_nonce_3 = first_round_3.our_public_nonce(); + + // Exchange nonces between participants + first_round_1.receive_nonce(1, pub_nonce_2.clone())?; + first_round_1.receive_nonce(2, pub_nonce_3.clone())?; + + first_round_2.receive_nonce(0, pub_nonce_1.clone())?; + first_round_2.receive_nonce(2, pub_nonce_3.clone())?; + + first_round_3.receive_nonce(0, pub_nonce_1.clone())?; + first_round_3.receive_nonce(1, pub_nonce_2.clone())?; + + // Second round: Create partial signatures + let mut second_round_1 = first_round_1.finalize(secret_key_1, &message)?; + let second_round_2 = first_round_2.finalize(secret_key_2, &message)?; + let second_round_3 = first_round_3.finalize(secret_key_3, &message)?; + + // Get partial signatures + let _partial_sig_1: PartialSignature = second_round_1.our_signature(); + let partial_sig_2: PartialSignature = second_round_2.our_signature(); + let partial_sig_3: PartialSignature = second_round_3.our_signature(); + + // One participant collects all partial signatures + second_round_1.receive_signature(1, partial_sig_2)?; + second_round_1.receive_signature(2, partial_sig_3)?; + + // Final aggregate MuSig2 signature + let final_signature: CompactSignature = second_round_1.finalize()?; + + // Verify the signature (optional sanity check) + match verify_single(aggregated_pubkey, final_signature, message) { + Ok(_) => println!("MuSig2 signature verified successfully!"), + Err(e) => println!("MuSig2 signature verification failed: {:?}", e), + } + + // ------------------------------------------- + // Insert the final signature into the transaction witness + // ------------------------------------------- + let mut final_sig_with_hashtype = final_signature.serialize().to_vec(); + final_sig_with_hashtype.push(sighash_type as u8); // For SIGHASH_DEFAULT this is 0x00 + + // For a key-path spend in taproot, the witness is just the signature + unsigned_tx.input[0].witness = Witness::from(vec![final_sig_with_hashtype]); + + // ------------------------------------------- + // Print the signed raw transaction (in hex) + // ------------------------------------------- + let signed_raw_tx = bitcoin::consensus::encode::serialize_hex(&unsigned_tx); + println!("Signed raw transaction (hex): {}", signed_raw_tx); + + // NOTE: In real scenario, you could broadcast this transaction using the Bitcoin node RPC: + // client.broadcast_raw_tx(&signed_raw_tx).await?; + // Here we just printed it. + + Ok(()) +} diff --git a/core/lib/via_musig2/src/lib.rs b/core/lib/via_musig2/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/core/lib/via_musig2/src/lib.rs @@ -0,0 +1 @@ + From 36388febb69f8497399dd6216236ca7072926e9f Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 09:51:35 +0330 Subject: [PATCH 040/212] apply linter --- core/lib/via_btc_client/src/withdrawal/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index c64d584de..6c0082294 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -229,12 +229,14 @@ impl WithdrawalBuilder { #[cfg(test)] mod tests { - use super::*; - use crate::types::BitcoinError; + use std::str::FromStr; + use async_trait::async_trait; use bitcoin::Network; use mockall::{mock, predicate::*}; - use std::str::FromStr; + + use super::*; + use crate::types::BitcoinError; mock! { BitcoinOps {} From 35cff4940c2f93b32699bd1e67e2d954f88d34e3 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 11:02:54 +0330 Subject: [PATCH 041/212] add key_generation_setup core --- Cargo.lock | 1 + core/lib/via_musig2/Cargo.toml | 1 + core/lib/via_musig2/examples/coordinator.rs | 4 +- .../examples/key_generation_setup.rs | 101 +++++++++++++++++- 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc8ec7ba1..1360a7b4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8581,6 +8581,7 @@ name = "via_musig2" version = "0.1.0" dependencies = [ "bitcoin", + "clap 4.5.16", "hex", "musig2", "rand 0.8.5", diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml index 87e9d3fb7..cd7635412 100644 --- a/core/lib/via_musig2/Cargo.toml +++ b/core/lib/via_musig2/Cargo.toml @@ -17,6 +17,7 @@ bitcoin = { version = "0.32.2", features = ["serde"] } musig2 = "0.2.0" secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} tokio = { version = "1.0", features = ["full"] } +clap = { version = "4.0", features = ["derive"] } diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index f328e4d9d..e7a11a969 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -1 +1,3 @@ -fn main() {} +fn main() { + println!("Hello, world!"); +} diff --git a/core/lib/via_musig2/examples/key_generation_setup.rs b/core/lib/via_musig2/examples/key_generation_setup.rs index f328e4d9d..371ed44d5 100644 --- a/core/lib/via_musig2/examples/key_generation_setup.rs +++ b/core/lib/via_musig2/examples/key_generation_setup.rs @@ -1 +1,100 @@ -fn main() {} +use bitcoin::taproot::TaprootSpendInfo; +use bitcoin::{Address as BitcoinAddress, Network, XOnlyPublicKey}; +use musig2::KeyAggContext; +use rand::rngs::OsRng; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; +use std::{env, str::FromStr}; + +#[derive(Debug)] +#[allow(dead_code)] +struct ContributorOutput { + secret_key: Option, + public_key: PublicKey, +} + +#[derive(Debug)] +#[allow(dead_code)] +struct CoordinatorOutput { + participant_count: usize, + bridge_address: BitcoinAddress, +} + +// TODO: Add mechanism to validate generated address for bridge is valid and contain all contributors' pubkeys + +fn generate_keypair() -> (SecretKey, PublicKey) { + let mut rng = OsRng; + let secp = Secp256k1::new(); + let secret_key = SecretKey::new(&mut rng); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + (secret_key, public_key) +} + +fn create_bridge_address( + pubkeys: Vec, +) -> Result> { + let key_agg_ctx: KeyAggContext = KeyAggContext::new(pubkeys)?; + let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); + + let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); + let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + + let secp_btc = bitcoin::secp256k1::Secp256k1::new(); + let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); + let tweaked_key = tap_info.output_key(); + let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); + + Ok(address) +} + +fn main() -> Result<(), Box> { + let args: Vec = env::args().collect(); + + if args.len() < 2 { + return Err( + "Usage:\ncontributor [optional_public_key]\ncoordinator public_key1 public_key2 ..." + .into(), + ); + } + + match args[1].as_str() { + "contributor" => { + let output = if args.len() > 2 { + // Use provided public key + let public_key = PublicKey::from_str(&args[2])?; + ContributorOutput { + secret_key: None, + public_key, + } + } else { + // Generate new keypair + let (secret_key, public_key) = generate_keypair(); + ContributorOutput { + secret_key: Some(secret_key), + public_key, + } + }; + println!("{:?}", output); + Ok(()) + } + "coordinator" => { + if args.len() <= 2 { + return Err("Error: Coordinator needs at least one public key".into()); + } + + let mut pubkeys = Vec::new(); + for _i in 2..args.len() { + let (_, public_key) = generate_keypair(); + pubkeys.push(public_key); + } + + let bridge_address = create_bridge_address(pubkeys)?; + let output = CoordinatorOutput { + participant_count: args.len() - 2, + bridge_address, + }; + println!("{:?}", output); + Ok(()) + } + _ => Err("Invalid role. Use 'contributor' or 'coordinator'".into()), + } +} From df0ed114f7e4cde63c9db7fcd7cfaf57df8184e4 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 11:03:28 +0330 Subject: [PATCH 042/212] apply linter --- core/lib/via_musig2/examples/key_generation_setup.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/lib/via_musig2/examples/key_generation_setup.rs b/core/lib/via_musig2/examples/key_generation_setup.rs index 371ed44d5..52144424f 100644 --- a/core/lib/via_musig2/examples/key_generation_setup.rs +++ b/core/lib/via_musig2/examples/key_generation_setup.rs @@ -1,9 +1,9 @@ -use bitcoin::taproot::TaprootSpendInfo; -use bitcoin::{Address as BitcoinAddress, Network, XOnlyPublicKey}; +use std::{env, str::FromStr}; + +use bitcoin::{taproot::TaprootSpendInfo, Address as BitcoinAddress, Network, XOnlyPublicKey}; use musig2::KeyAggContext; use rand::rngs::OsRng; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; -use std::{env, str::FromStr}; #[derive(Debug)] #[allow(dead_code)] From 3903bb330e0deb3f7c5f1dab8e49490e6c2d531a Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 11:24:44 +0330 Subject: [PATCH 043/212] add calculate-bridge-address and contribute-musig2 command to via verifier --- Cargo.lock | 1 - core/lib/via_musig2/Cargo.toml | 1 - .../examples/key_generation_setup.rs | 2 +- infrastructure/via/src/verifier.ts | 40 +++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1360a7b4e..dc8ec7ba1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8581,7 +8581,6 @@ name = "via_musig2" version = "0.1.0" dependencies = [ "bitcoin", - "clap 4.5.16", "hex", "musig2", "rand 0.8.5", diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml index cd7635412..87e9d3fb7 100644 --- a/core/lib/via_musig2/Cargo.toml +++ b/core/lib/via_musig2/Cargo.toml @@ -17,7 +17,6 @@ bitcoin = { version = "0.32.2", features = ["serde"] } musig2 = "0.2.0" secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} tokio = { version = "1.0", features = ["full"] } -clap = { version = "4.0", features = ["derive"] } diff --git a/core/lib/via_musig2/examples/key_generation_setup.rs b/core/lib/via_musig2/examples/key_generation_setup.rs index 52144424f..8efd408dc 100644 --- a/core/lib/via_musig2/examples/key_generation_setup.rs +++ b/core/lib/via_musig2/examples/key_generation_setup.rs @@ -51,7 +51,7 @@ fn main() -> Result<(), Box> { if args.len() < 2 { return Err( - "Usage:\ncontributor [optional_public_key]\ncoordinator public_key1 public_key2 ..." + "Usage: contributor [optional_public_key] OR coordinator public_key1 public_key2 ..." .into(), ); } diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index f376af7d8..583135cf1 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -31,6 +31,34 @@ async function deposit( ); } +async function contributeMuSig2(secretKey?: string) { + process.chdir(`${process.env.VIA_HOME}`); + const args = secretKey ? ` contributor ${secretKey}` : ' contributor'; + await utils.spawn(`cargo run --example key_generation_setup --${args}`); + + console.log('\nInstructions:'); + console.log('1. Save your secret key securely - you will need it for signing transactions'); + console.log('2. Share your public key with:'); + console.log(' - The sequencer coordinator'); + console.log(' - Other verifier nodes'); + console.log(' - The verifier coordinator'); + // TODO: + console.log('\nNote: In future versions, this process will be authenticated using attestation addresses too'); +} + +async function calculateBridgeAddress(publicKeys: string[]) { + process.chdir(`${process.env.VIA_HOME}`); + const pubkeysArg = publicKeys.join(' '); + await utils.spawn(`cargo run --example key_generation_setup -- coordinator ${pubkeysArg}`); + + console.log('\nInstructions:'); + console.log('1. Save this bridge address - it will be used for all Via protocol transactions'); + // TODO: + console.log('2. In future versions:'); + console.log(' - This script will automatically update verifier and sequencer environments'); + console.log(' - Public keys will be authenticated via attestation addresses'); +} + export const command = new Command('verifier').description('verifier network mock'); command @@ -63,3 +91,15 @@ command cmd.rpcPassword ) ); + +command + .command('contribute-musig2') + .description('Generate or use existing MuSig2 keys for the verifier') + .option('--secret-key ', 'Optional: Use existing secret key instead of generating new ones') + .action((cmd: Command) => contributeMuSig2(cmd.secretKey)); + +command + .command('calculate-bridge-address') + .description('Calculate bridge address from multiple public keys') + .requiredOption('--public-keys ', 'List of public keys to create bridge address') + .action((cmd: Command) => calculateBridgeAddress(cmd.publicKeys)); From df4a07759d6c45ca329469a101dc199061c3e393 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 11:25:39 +0330 Subject: [PATCH 044/212] apply linter --- infrastructure/via/src/verifier.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index 583135cf1..ce7f16721 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -35,7 +35,7 @@ async function contributeMuSig2(secretKey?: string) { process.chdir(`${process.env.VIA_HOME}`); const args = secretKey ? ` contributor ${secretKey}` : ' contributor'; await utils.spawn(`cargo run --example key_generation_setup --${args}`); - + console.log('\nInstructions:'); console.log('1. Save your secret key securely - you will need it for signing transactions'); console.log('2. Share your public key with:'); @@ -50,7 +50,7 @@ async function calculateBridgeAddress(publicKeys: string[]) { process.chdir(`${process.env.VIA_HOME}`); const pubkeysArg = publicKeys.join(' '); await utils.spawn(`cargo run --example key_generation_setup -- coordinator ${pubkeysArg}`); - + console.log('\nInstructions:'); console.log('1. Save this bridge address - it will be used for all Via protocol transactions'); // TODO: From 99c1acf3176a7aebbfa4715133085e71930d129e Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 12:03:11 +0330 Subject: [PATCH 045/212] first iteration for musig2 wrapper --- core/lib/via_musig2/examples/coordinator.rs | 6 + core/lib/via_musig2/src/lib.rs | 225 ++++++++++++++++++++ 2 files changed, 231 insertions(+) diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index e7a11a969..3ca452a3b 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -1,3 +1,9 @@ fn main() { println!("Hello, world!"); } + +// create musig2 lib wrapper +// in this file we should write example for http server for coordinator and pooling for normal verifer from http server +// the struct should be design in a way to being able manage multiple request at the same time +// using btc_vlient withdrawal component to create fake withdrawal request for matter of example +// the struct also shopuld be act as temproary data base for managing nounce and diffrent data diff --git a/core/lib/via_musig2/src/lib.rs b/core/lib/via_musig2/src/lib.rs index 8b1378917..28f85227b 100644 --- a/core/lib/via_musig2/src/lib.rs +++ b/core/lib/via_musig2/src/lib.rs @@ -1 +1,226 @@ +use std::fmt; +use musig2::{ + verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, PubNonce, + SecNonceSpices, SecondRound, +}; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; + +#[derive(Debug)] +pub enum MusigError { + Musig2Error(String), + InvalidSignerIndex, + MissingNonces, + MissingPartialSignatures, + InvalidState(String), +} + +impl fmt::Display for MusigError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MusigError::Musig2Error(e) => write!(f, "MuSig2 error: {}", e), + MusigError::InvalidSignerIndex => write!(f, "Invalid signer index"), + MusigError::MissingNonces => write!(f, "Missing required nonces"), + MusigError::MissingPartialSignatures => { + write!(f, "Missing required partial signatures") + } + MusigError::InvalidState(s) => write!(f, "Invalid state: {}", s), + } + } +} + +impl std::error::Error for MusigError {} + +/// Represents a single signer in the MuSig2 protocol +pub struct Signer { + secret_key: SecretKey, + _public_key: PublicKey, + signer_index: usize, + key_agg_ctx: KeyAggContext, + first_round: Option, + second_round: Option>, + message: Vec, +} + +impl Signer { + /// Create a new signer with the given secret key and index + pub fn new( + secret_key: SecretKey, + signer_index: usize, + all_pubkeys: Vec, + ) -> Result { + let secp = Secp256k1::new(); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + let key_agg_ctx = + KeyAggContext::new(all_pubkeys).map_err(|e| MusigError::Musig2Error(e.to_string()))?; + + Ok(Self { + secret_key, + _public_key: public_key, + signer_index, + key_agg_ctx, + first_round: None, + second_round: None, + message: Vec::new(), + }) + } + + /// Get the aggregated public key for all signers + pub fn aggregated_pubkey(&self) -> PublicKey { + self.key_agg_ctx.aggregated_pubkey() + } + + /// Start the signing session with a message + pub fn start_signing_session(&mut self, message: Vec) -> Result { + if message.len() != 32 { + return Err(MusigError::Musig2Error("Message must be 32 bytes".into())); + } + self.message = message.clone(); + + let msg_array: [u8; 32] = message[..32] + .try_into() + .map_err(|_| MusigError::Musig2Error("Failed to convert message to array".into()))?; + + let first_round = FirstRound::new( + self.key_agg_ctx.clone(), + rand::random::<[u8; 32]>(), + self.signer_index, + SecNonceSpices::new() + .with_seckey(self.secret_key) + .with_message(&msg_array), + ) + .map_err(|e| MusigError::Musig2Error(e.to_string()))?; + + let nonce = first_round.our_public_nonce(); + self.first_round = Some(first_round); + Ok(nonce) + } + + /// Receive a nonce from another participant + pub fn receive_nonce( + &mut self, + signer_index: usize, + nonce: PubNonce, + ) -> Result<(), MusigError> { + let first_round = self + .first_round + .as_mut() + .ok_or_else(|| MusigError::InvalidState("First round not initialized".into()))?; + + first_round + .receive_nonce(signer_index, nonce) + .map_err(|e| MusigError::Musig2Error(e.to_string()))?; + Ok(()) + } + + /// Create partial signature + pub fn create_partial_signature(&mut self) -> Result { + let msg_array: [u8; 32] = self.message[..32] + .try_into() + .map_err(|_| MusigError::Musig2Error("Failed to convert message to array".into()))?; + + let first_round = self + .first_round + .take() + .ok_or_else(|| MusigError::InvalidState("First round not initialized".into()))?; + + let second_round = first_round + .finalize(self.secret_key, msg_array) + .map_err(|e| MusigError::Musig2Error(e.to_string()))?; + + let partial_sig = second_round.our_signature(); + self.second_round = Some(second_round); + Ok(partial_sig) + } + + /// Receive partial signature from another signer + pub fn receive_partial_signature( + &mut self, + signer_index: usize, + partial_sig: PartialSignature, + ) -> Result<(), MusigError> { + let second_round = self + .second_round + .as_mut() + .ok_or_else(|| MusigError::InvalidState("Second round not initialized".into()))?; + + second_round + .receive_signature(signer_index, partial_sig) + .map_err(|e| MusigError::Musig2Error(e.to_string()))?; + Ok(()) + } + + /// Create final signature + pub fn create_final_signature(&mut self) -> Result { + let second_round = self + .second_round + .take() + .ok_or_else(|| MusigError::InvalidState("Second round not initialized".into()))?; + + second_round + .finalize() + .map_err(|e| MusigError::Musig2Error(e.to_string())) + } +} + +/// Helper function to verify a complete signature +pub fn verify_signature( + pubkey: PublicKey, + signature: CompactSignature, + message: &[u8], +) -> Result<(), MusigError> { + verify_single(pubkey, signature, message).map_err(|e| MusigError::Musig2Error(e.to_string())) +} + +#[cfg(test)] +mod tests { + use rand::rngs::OsRng; + + use super::*; + + #[test] + fn test_signer_lifecycle() -> Result<(), MusigError> { + let mut rng = OsRng; + let secret_key_1 = SecretKey::new(&mut rng); + let secret_key_2 = SecretKey::new(&mut rng); + + let secp = Secp256k1::new(); + let public_key_1 = PublicKey::from_secret_key(&secp, &secret_key_1); + let public_key_2 = PublicKey::from_secret_key(&secp, &secret_key_2); + + let pubkeys = vec![public_key_1, public_key_2]; + + let mut signer1 = Signer::new(secret_key_1, 0, pubkeys.clone())?; + let mut signer2 = Signer::new(secret_key_2, 1, pubkeys)?; + + // Generate and exchange nonces + let message = b"test message".to_vec(); + let nonce1 = signer1.start_signing_session(message.clone())?; + let nonce2 = signer2.start_signing_session(message.clone())?; + + signer1.receive_nonce(1, nonce2)?; + signer2.receive_nonce(0, nonce1)?; + + // Create partial signatures + let partial_sig1 = signer1.create_partial_signature()?; + let partial_sig2 = signer2.create_partial_signature()?; + + // Exchange partial signatures + signer1.receive_partial_signature(1, partial_sig2)?; + signer2.receive_partial_signature(0, partial_sig1)?; + + // Create final signatures + let final_sig1 = signer1.create_final_signature()?; + let final_sig2 = signer2.create_final_signature()?; + + assert_eq!( + final_sig1.serialize(), + final_sig2.serialize(), + "Final signatures should match" + ); + // Verify the signature + verify_signature(signer1.aggregated_pubkey(), final_sig1, &message)?; + + Ok(()) + } +} From 3d38fef6d39fa7c2f1dac39736296af9afebb19b Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 12:18:12 +0330 Subject: [PATCH 046/212] add notice for key order in via verifer --- infrastructure/via/src/verifier.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index ce7f16721..bfe616ee9 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -36,18 +36,25 @@ async function contributeMuSig2(secretKey?: string) { const args = secretKey ? ` contributor ${secretKey}` : ' contributor'; await utils.spawn(`cargo run --example key_generation_setup --${args}`); - console.log('\nInstructions:'); + console.log('\nNOTICE: The order of public keys is critical for MuSig2 setup!'); + console.log('Make sure to keep track of the order in which public keys are shared and used.\n'); + + console.log('Instructions:'); console.log('1. Save your secret key securely - you will need it for signing transactions'); console.log('2. Share your public key with:'); console.log(' - The sequencer coordinator'); console.log(' - Other verifier nodes'); console.log(' - The verifier coordinator'); + console.log('3. Remember the position/order of your public key in the final set'); // TODO: console.log('\nNote: In future versions, this process will be authenticated using attestation addresses too'); } async function calculateBridgeAddress(publicKeys: string[]) { process.chdir(`${process.env.VIA_HOME}`); + console.log('\nNOTICE: Public key order is critical! Make sure the keys are provided in the same order'); + console.log('as they were originally shared. Using a different order will result in an invalid bridge address!\n'); + const pubkeysArg = publicKeys.join(' '); await utils.spawn(`cargo run --example key_generation_setup -- coordinator ${pubkeysArg}`); @@ -55,6 +62,7 @@ async function calculateBridgeAddress(publicKeys: string[]) { console.log('1. Save this bridge address - it will be used for all Via protocol transactions'); // TODO: console.log('2. In future versions:'); + console.log(' - Verify that all participants used the same public key order'); console.log(' - This script will automatically update verifier and sequencer environments'); console.log(' - Public keys will be authenticated via attestation addresses'); } From adc0a0198e61bc9be2b2b57044cb41299407ac39 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 12:30:35 +0330 Subject: [PATCH 047/212] fix musig2 wrapper test --- core/lib/via_musig2/src/lib.rs | 13 +++---------- infrastructure/via/src/verifier.ts | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/core/lib/via_musig2/src/lib.rs b/core/lib/via_musig2/src/lib.rs index 28f85227b..cc32353d1 100644 --- a/core/lib/via_musig2/src/lib.rs +++ b/core/lib/via_musig2/src/lib.rs @@ -38,7 +38,7 @@ pub struct Signer { signer_index: usize, key_agg_ctx: KeyAggContext, first_round: Option, - second_round: Option>, + second_round: Option>>, message: Vec, } @@ -72,14 +72,9 @@ impl Signer { /// Start the signing session with a message pub fn start_signing_session(&mut self, message: Vec) -> Result { - if message.len() != 32 { - return Err(MusigError::Musig2Error("Message must be 32 bytes".into())); - } self.message = message.clone(); - let msg_array: [u8; 32] = message[..32] - .try_into() - .map_err(|_| MusigError::Musig2Error("Failed to convert message to array".into()))?; + let msg_array = message.as_slice(); let first_round = FirstRound::new( self.key_agg_ctx.clone(), @@ -115,9 +110,7 @@ impl Signer { /// Create partial signature pub fn create_partial_signature(&mut self) -> Result { - let msg_array: [u8; 32] = self.message[..32] - .try_into() - .map_err(|_| MusigError::Musig2Error("Failed to convert message to array".into()))?; + let msg_array = self.message.clone(); let first_round = self .first_round diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index bfe616ee9..3f4ee8f5f 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -38,7 +38,7 @@ async function contributeMuSig2(secretKey?: string) { console.log('\nNOTICE: The order of public keys is critical for MuSig2 setup!'); console.log('Make sure to keep track of the order in which public keys are shared and used.\n'); - + console.log('Instructions:'); console.log('1. Save your secret key securely - you will need it for signing transactions'); console.log('2. Share your public key with:'); @@ -54,7 +54,7 @@ async function calculateBridgeAddress(publicKeys: string[]) { process.chdir(`${process.env.VIA_HOME}`); console.log('\nNOTICE: Public key order is critical! Make sure the keys are provided in the same order'); console.log('as they were originally shared. Using a different order will result in an invalid bridge address!\n'); - + const pubkeysArg = publicKeys.join(' '); await utils.spawn(`cargo run --example key_generation_setup -- coordinator ${pubkeysArg}`); From a9a6a9a03a304549499f47fd07e29d2594dc9031 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 12:47:24 +0330 Subject: [PATCH 048/212] add coordinator base --- Cargo.lock | 48 +++-- core/lib/via_musig2/Cargo.toml | 12 +- core/lib/via_musig2/examples/coordinator.rs | 204 +++++++++++++++++++- 3 files changed, 242 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc8ec7ba1..4ba616149 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,9 +485,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", @@ -511,7 +511,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -532,7 +532,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -3572,7 +3572,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] @@ -3987,7 +3987,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] @@ -4012,7 +4012,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] @@ -4067,7 +4067,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] @@ -8042,7 +8042,7 @@ dependencies = [ "socket2", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -8068,6 +8068,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.1", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-http" version = "0.5.2" @@ -8580,12 +8596,18 @@ dependencies = [ name = "via_musig2" version = "0.1.0" dependencies = [ + "anyhow", + "axum", "bitcoin", "hex", "musig2", "rand 0.8.5", "secp256k1 0.30.0", + "serde", + "serde_json", "tokio", + "uuid", + "via_btc_client", ] [[package]] @@ -10374,7 +10396,7 @@ dependencies = [ "thiserror", "thread_local", "tokio", - "tower", + "tower 0.4.13", "tower-http", "tracing", "vise", @@ -10686,7 +10708,7 @@ dependencies = [ "hyper 1.4.1", "serde_json", "tokio", - "tower", + "tower 0.4.13", "tracing", "vise", "zksync_basic_types", diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml index 87e9d3fb7..0c540f0fe 100644 --- a/core/lib/via_musig2/Cargo.toml +++ b/core/lib/via_musig2/Cargo.toml @@ -13,12 +13,16 @@ categories.workspace = true [dependencies] rand.workspace = true hex.workspace = true +via_btc_client.workspace = true +anyhow.workspace = true bitcoin = { version = "0.32.2", features = ["serde"] } musig2 = "0.2.0" secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} tokio = { version = "1.0", features = ["full"] } - - +axum = "0.7.9" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +uuid = "1.3" @@ -32,3 +36,7 @@ name = "withdrawal" path = "examples/withdrawal.rs" +[[example]] +name = "coordinator" +path = "examples/coordinator.rs" + diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index 3ca452a3b..1947c0f38 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -1,9 +1,199 @@ -fn main() { - println!("Hello, world!"); +use std::{collections::HashMap, sync::Arc}; + +use axum::{ + extract::{Path, State}, + http::StatusCode, + routing::{get, post}, + Json, Router, +}; +use bitcoin::{Address, Amount, Network, Txid}; +use musig2::{CompactSignature, PartialSignature, PubNonce}; +use secp256k1_musig2::{PublicKey, SecretKey}; +use serde::{Deserialize, Serialize}; +use tokio::sync::RwLock; +use via_btc_client::{ + types::BitcoinNetwork, + withdrawal::{UnsignedWithdrawalTx, WithdrawalBuilder, WithdrawalRequest}, +}; + +// Shared state for managing signing sessions +struct AppState { + signer: via_musig2::Signer, + signing_sessions: HashMap, + unsigned_txs: HashMap, + bridge_address: Address, +} + +#[derive(Debug, Clone)] +struct SigningSession { + session_id: String, + tx_id: String, + received_nonces: HashMap, + received_sigs: HashMap, + final_signature: Option, +} + +#[derive(Serialize, Deserialize)] +struct NoncePair { + signer_index: usize, + nonce: String, // Base64 encoded } -// create musig2 lib wrapper -// in this file we should write example for http server for coordinator and pooling for normal verifer from http server -// the struct should be design in a way to being able manage multiple request at the same time -// using btc_vlient withdrawal component to create fake withdrawal request for matter of example -// the struct also shopuld be act as temproary data base for managing nounce and diffrent data +#[derive(Serialize, Deserialize)] +struct PartialSignaturePair { + signer_index: usize, + signature: String, // Base64 encoded +} + +#[derive(Serialize, Deserialize)] +struct SigningSessionResponse { + session_id: String, + message_to_sign: String, + aggregated_pubkey: String, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Initialize coordinator's signer (also acts as a verifier) + let mut rng = rand::thread_rng(); + let secret_key = SecretKey::new(&mut rng); + + // For demo, we'll use 3 verifiers (including coordinator) + let secp = bitcoin::secp256k1::Secp256k1::new(); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + let all_pubkeys = vec![ + public_key.clone(), + // Add other verifiers' public keys + // These would normally come from configuration + PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)), + PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)), + ]; + + let signer = via_musig2::Signer::new(secret_key, 0, all_pubkeys)?; + + // Create test bridge address + let bridge_address = + Address::from_str("bcrt1pxqkh0g270lucjafgngmwv7vtgc8mk9j5y4j8fnrxm77yunuh398qfv8tqp")? + .require_network(Network::Regtest)?; + + // Initialize shared state + let state = Arc::new(RwLock::new(AppState { + signer, + signing_sessions: HashMap::new(), + unsigned_txs: HashMap::new(), + bridge_address, + })); + + // Build router + let app = Router::new() + .route("/session/:id", get(get_session)) + .route("/session/:id/nonce", post(submit_nonce)) + .route("/session/:id/partial", post(submit_partial_signature)) + .route("/session/:id/signature", get(get_final_signature)) + .with_state(state); + + // Start server + println!("Starting coordinator server on 0.0.0.0:3000"); + axum::Server::bind(&"0.0.0.0:3000".parse()?) + .serve(app.into_make_service()) + .await?; + + Ok(()) +} + +// Create new signing session for a withdrawal transaction +async fn create_signing_session( + state: &RwLock, +) -> anyhow::Result { + let mut state = state.write().await; + + // Create test withdrawal transaction + let withdrawal_builder = create_test_withdrawal_builder().await?; + let withdrawals = create_test_withdrawal_requests()?; + let proof_txid = Txid::from_slice(&[0x42; 32])?; + + let unsigned_tx = withdrawal_builder + .create_unsigned_withdrawal_tx(withdrawals, proof_txid) + .await?; + + // Create unique session ID + let session_id = uuid::Uuid::new_v4().to_string(); + let tx_id = unsigned_tx.txid.to_string(); + + // Store unsigned transaction + state + .unsigned_txs + .insert(tx_id.clone(), unsigned_tx.clone()); + + // Initialize signing session + let session = SigningSession { + session_id: session_id.clone(), + tx_id, + received_nonces: HashMap::new(), + received_sigs: HashMap::new(), + final_signature: None, + }; + + state.signing_sessions.insert(session_id.clone(), session); + + // Start signing session with message (transaction hash) + let message = unsigned_tx.tx.compute_txid().as_raw_hash().to_vec(); + let nonce = state.signer.start_signing_session(message.clone())?; + + // Store coordinator's own nonce + if let Some(session) = state.signing_sessions.get_mut(&session_id) { + session.received_nonces.insert(0, nonce); + } + + Ok(SigningSessionResponse { + session_id, + message_to_sign: hex::encode(message), + aggregated_pubkey: hex::encode(state.signer.aggregated_pubkey().serialize()), + }) +} + +// Handler implementations +async fn get_session( + State(state): State>>, + Path(session_id): Path, +) -> Result, StatusCode> { + // Implementation + todo!() +} + +async fn submit_nonce( + State(state): State>>, + Path(session_id): Path, + Json(nonce_pair): Json, +) -> Result { + // Implementation + todo!() +} + +async fn submit_partial_signature( + State(state): State>>, + Path(session_id): Path, + Json(sig_pair): Json, +) -> Result { + // Implementation + todo!() +} + +async fn get_final_signature( + State(state): State>>, + Path(session_id): Path, +) -> Result, StatusCode> { + // Implementation + todo!() +} + +// Helper functions +async fn create_test_withdrawal_builder() -> anyhow::Result { + // Similar to withdrawal_builder test setup + todo!() +} + +fn create_test_withdrawal_requests() -> anyhow::Result> { + // Similar to withdrawal_builder test setup + todo!() +} From b40c7c07d0ca40cd51a308c9cfd1b5c9896ff62c Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 13:21:00 +0330 Subject: [PATCH 049/212] add coordinator logic --- Cargo.lock | 72 ++- core/lib/via_btc_client/src/withdrawal/mod.rs | 2 +- core/lib/via_musig2/Cargo.toml | 14 +- core/lib/via_musig2/examples/coordinator.rs | 511 ++++++++++++++---- core/lib/via_musig2/src/lib.rs | 34 ++ 5 files changed, 527 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ba616149..c63b4b7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,6 +483,38 @@ dependencies = [ "paste", ] +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "tokio", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + [[package]] name = "axum" version = "0.7.9" @@ -490,7 +522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.5", "bytes", "futures-util", "http 1.1.0", @@ -517,6 +549,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -8026,7 +8075,7 @@ checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.7.9", "base64 0.22.1", "bytes", "h2 0.4.6", @@ -8425,6 +8474,7 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ + "getrandom", "serde", ] @@ -8597,15 +8647,21 @@ name = "via_musig2" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.6.20", + "base64 0.21.7", "bitcoin", + "bitcoincore-rpc", "hex", + "hyper 0.14.30", "musig2", "rand 0.8.5", + "reqwest 0.12.7", "secp256k1 0.30.0", "serde", "serde_json", "tokio", + "tracing", + "tracing-subscriber", "uuid", "via_btc_client", ] @@ -9785,7 +9841,7 @@ name = "zksync_contract_verification_server" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "serde", "serde_json", "tokio", @@ -10164,7 +10220,7 @@ name = "zksync_external_proof_integration_api" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "bincode", "tokio", "tracing", @@ -10298,7 +10354,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum", + "axum 0.7.9", "futures 0.3.30", "itertools 0.10.5", "once_cell", @@ -10378,7 +10434,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum", + "axum 0.7.9", "chrono", "futures 0.3.30", "governor", @@ -10703,7 +10759,7 @@ name = "zksync_proof_data_handler" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "chrono", "hyper 1.4.1", "serde_json", diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal/mod.rs index 6c0082294..0df1cbd18 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal/mod.rs @@ -27,7 +27,7 @@ pub struct WithdrawalRequest { pub amount: Amount, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct UnsignedWithdrawalTx { pub tx: Transaction, pub txid: Txid, diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml index 0c540f0fe..deed99b2d 100644 --- a/core/lib/via_musig2/Cargo.toml +++ b/core/lib/via_musig2/Cargo.toml @@ -15,14 +15,20 @@ rand.workspace = true hex.workspace = true via_btc_client.workspace = true anyhow.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +serde_json.workspace = true +serde.workspace = true +reqwest.workspace = true +bitcoincore-rpc = "0.19.0" bitcoin = { version = "0.32.2", features = ["serde"] } musig2 = "0.2.0" secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} tokio = { version = "1.0", features = ["full"] } -axum = "0.7.9" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -uuid = "1.3" +axum = "0.6" +uuid = { version = "1.3", features = ["v4"] } +hyper = { version = "0.14", features = ["full"] } +base64 = "0.21" diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index 1947c0f38..c637609d5 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, str::FromStr, sync::Arc, time::Duration}; use axum::{ extract::{Path, State}, @@ -6,22 +6,30 @@ use axum::{ routing::{get, post}, Json, Router, }; -use bitcoin::{Address, Amount, Network, Txid}; -use musig2::{CompactSignature, PartialSignature, PubNonce}; -use secp256k1_musig2::{PublicKey, SecretKey}; +use base64::Engine; +use bitcoin::{hashes::Hash, Address, Amount, Network, Txid}; +use hyper::Server; +use musig2::{BinaryEncoding, Clone, CompactSignature, PartialSignature, PubNonce, ToBytes}; +use rand::thread_rng; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; +use tracing::{info, instrument}; +use uuid::Uuid; use via_btc_client::{ types::BitcoinNetwork, withdrawal::{UnsignedWithdrawalTx, WithdrawalBuilder, WithdrawalRequest}, }; +use via_musig2::{verify_signature, Signer}; -// Shared state for managing signing sessions +#[derive(Clone)] struct AppState { - signer: via_musig2::Signer, - signing_sessions: HashMap, - unsigned_txs: HashMap, + signer: Arc>, + signing_sessions: Arc>>, + unsigned_txs: Arc>>, bridge_address: Address, + all_pubkeys: Vec, + num_signers: usize, } #[derive(Debug, Clone)] @@ -31,169 +39,486 @@ struct SigningSession { received_nonces: HashMap, received_sigs: HashMap, final_signature: Option, + message: Vec, } -#[derive(Serialize, Deserialize)] +/// Data posted by other signers to submit their nonce +#[derive(Serialize, Deserialize, Debug)] struct NoncePair { signer_index: usize, nonce: String, // Base64 encoded } -#[derive(Serialize, Deserialize)] +/// Data posted by other signers to submit their partial signature +#[derive(Serialize, Deserialize, Debug)] struct PartialSignaturePair { signer_index: usize, signature: String, // Base64 encoded } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] struct SigningSessionResponse { session_id: String, - message_to_sign: String, - aggregated_pubkey: String, + message_to_sign: String, // hex-encoded message (txid) + aggregated_pubkey: String, // hex-encoded aggregated pubkey + required_signers: usize, + received_nonces: usize, + received_partial_signatures: usize, + final_signature: Option, // hex-encoded final signature if present } #[tokio::main] async fn main() -> anyhow::Result<()> { - // Initialize coordinator's signer (also acts as a verifier) - let mut rng = rand::thread_rng(); + tracing_subscriber::fmt::init(); + + // Setup coordinator keys and signers + let mut rng = thread_rng(); let secret_key = SecretKey::new(&mut rng); - // For demo, we'll use 3 verifiers (including coordinator) - let secp = bitcoin::secp256k1::Secp256k1::new(); + let secp = Secp256k1::new(); let public_key = PublicKey::from_secret_key(&secp, &secret_key); - let all_pubkeys = vec![ - public_key.clone(), - // Add other verifiers' public keys - // These would normally come from configuration - PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)), - PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)), - ]; + let other_pubkey_1 = PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)); + let other_pubkey_2 = PublicKey::from_secret_key(&secp, &SecretKey::new(&mut rng)); - let signer = via_musig2::Signer::new(secret_key, 0, all_pubkeys)?; + let all_pubkeys = vec![public_key, other_pubkey_1, other_pubkey_2]; + let coordinator_signer = Signer::new(secret_key, 0, all_pubkeys.clone())?; // Create test bridge address let bridge_address = Address::from_str("bcrt1pxqkh0g270lucjafgngmwv7vtgc8mk9j5y4j8fnrxm77yunuh398qfv8tqp")? .require_network(Network::Regtest)?; - // Initialize shared state - let state = Arc::new(RwLock::new(AppState { - signer, - signing_sessions: HashMap::new(), - unsigned_txs: HashMap::new(), + let state = AppState { + signer: Arc::new(RwLock::new(coordinator_signer)), + signing_sessions: Arc::new(RwLock::new(HashMap::new())), + unsigned_txs: Arc::new(RwLock::new(HashMap::new())), bridge_address, - })); + all_pubkeys: all_pubkeys.clone(), + num_signers: 3, + }; + + // Start coordinator server in one task + let server_state = state.clone(); + let server_task = tokio::spawn(async move { + run_coordinator_server(server_state).await.unwrap(); + }); + + // Wait a bit for the server to start + tokio::time::sleep(Duration::from_secs(1)).await; + + // Create one signing session for demonstration + let session_id = create_signing_session(&state).await?; - // Build router + // Now simulate other verifiers (signer_index = 1 and 2) + // Each verifier has their own keys: + let mut rng = thread_rng(); + let verifier1_sk = SecretKey::new(&mut rng); + let verifier1_signer = Signer::new(verifier1_sk, 1, all_pubkeys.clone())?; + + let mut rng = thread_rng(); + let verifier2_sk = SecretKey::new(&mut rng); + let verifier2_signer = Signer::new(verifier2_sk, 2, all_pubkeys)?; + + // Spawn tasks for verifier polling + let verifier1_task = tokio::spawn(run_verifier_polling( + "http://0.0.0.0:3000".to_string(), + session_id.session_id.clone(), + verifier1_signer, + )); + + let verifier2_task = tokio::spawn(run_verifier_polling( + "http://0.0.0.0:3000".to_string(), + session_id.session_id.clone(), + verifier2_signer, + )); + + // Run all concurrently + let _ = tokio::join!(server_task, verifier1_task, verifier2_task); + + Ok(()) +} + +async fn run_coordinator_server(state: AppState) -> anyhow::Result<()> { let app = Router::new() + .route("/session/new", post(create_session_handler)) .route("/session/:id", get(get_session)) .route("/session/:id/nonce", post(submit_nonce)) .route("/session/:id/partial", post(submit_partial_signature)) .route("/session/:id/signature", get(get_final_signature)) + .route("/session/:id/nonces", get(get_nonces)) .with_state(state); - // Start server - println!("Starting coordinator server on 0.0.0.0:3000"); - axum::Server::bind(&"0.0.0.0:3000".parse()?) + info!("Starting coordinator server on 0.0.0.0:3000"); + Server::bind(&"0.0.0.0:3000".parse()?) .serve(app.into_make_service()) .await?; Ok(()) } -// Create new signing session for a withdrawal transaction -async fn create_signing_session( - state: &RwLock, -) -> anyhow::Result { - let mut state = state.write().await; +async fn run_verifier_polling( + base_url: String, + session_id: String, + mut signer: Signer, +) -> anyhow::Result<()> { + use reqwest::Client; - // Create test withdrawal transaction - let withdrawal_builder = create_test_withdrawal_builder().await?; - let withdrawals = create_test_withdrawal_requests()?; - let proof_txid = Txid::from_slice(&[0x42; 32])?; + let client = Client::new(); - let unsigned_tx = withdrawal_builder - .create_unsigned_withdrawal_tx(withdrawals, proof_txid) - .await?; + loop { + // Fetch session info + let url = format!("{}/session/{}", base_url, session_id); + let resp = client.get(&url).send().await?; + if resp.status().as_u16() == StatusCode::NOT_FOUND.as_u16() { + // Session might not exist yet, wait and retry + tokio::time::sleep(Duration::from_secs(2)).await; + continue; + } + if !resp.status().is_success() { + println!( + "Verifier polling: Error fetching session info: {:?}", + resp.text().await? + ); + tokio::time::sleep(Duration::from_secs(2)).await; + continue; + } - // Create unique session ID - let session_id = uuid::Uuid::new_v4().to_string(); - let tx_id = unsigned_tx.txid.to_string(); + let session_info: SigningSessionResponse = resp.json().await?; + if session_info.final_signature.is_some() { + println!( + "Verifier {}: Final signature obtained! {:?}", + signer.signer_index(), + session_info.final_signature + ); + break; + } - // Store unsigned transaction - state - .unsigned_txs - .insert(tx_id.clone(), unsigned_tx.clone()); + // We need to see if we have submitted our nonce and partial signature + // If we have not submitted nonce and partial sig yet, we do so if needed: + if session_info.received_nonces < session_info.required_signers { + // We need to submit nonce if not already submitted + // Start signing session if not started: + let message = hex::decode(&session_info.message_to_sign)?; + if signer.has_not_started() { + signer.start_signing_session(message)?; + } - // Initialize signing session - let session = SigningSession { - session_id: session_id.clone(), - tx_id, - received_nonces: HashMap::new(), - received_sigs: HashMap::new(), - final_signature: None, - }; + if !signer.has_submitted_nonce() { + // Submit our nonce + let nonce = signer + .our_nonce() + .ok_or_else(|| anyhow::anyhow!("No nonce available"))?; + let nonce_b64 = base64::engine::general_purpose::STANDARD.encode(nonce.to_bytes()); + let nonce_pair = NoncePair { + signer_index: signer.signer_index(), + nonce: nonce_b64, + }; + let nonce_url = format!("{}/session/{}/nonce", base_url, session_id); + let resp = client.post(&nonce_url).json(&nonce_pair).send().await?; + if !resp.status().is_success() { + println!( + "Verifier {}: Error submitting nonce: {:?}", + signer.signer_index(), + resp.text().await? + ); + } else { + signer.mark_nonce_submitted(); + } + } + } else if session_info.received_partial_signatures < session_info.required_signers { + // All nonces are in, we can finalize first round and create partial signature if not done + if !signer.has_created_partial_sig() { + // We need to fetch all nonces from the coordinator + let nonces_url = format!("{}/session/{}/nonces", base_url, session_id); + let resp = client.get(&nonces_url).send().await?; + let nonces: HashMap = resp.json().await?; - state.signing_sessions.insert(session_id.clone(), session); + // Process each nonce + for (idx, nonce_b64) in nonces { + if idx != signer.signer_index() { + let nonce_bytes = + base64::engine::general_purpose::STANDARD.decode(nonce_b64)?; + let nonce = PubNonce::from_bytes(&nonce_bytes)?; + signer + .receive_nonce(idx, nonce.clone()) + .map_err(|e| anyhow::anyhow!("Failed to receive nonce: {}", e))?; + } + } - // Start signing session with message (transaction hash) - let message = unsigned_tx.tx.compute_txid().as_raw_hash().to_vec(); - let nonce = state.signer.start_signing_session(message.clone())?; + let partial_sig = signer.create_partial_signature()?; + let sig_b64 = + base64::engine::general_purpose::STANDARD.encode(partial_sig.serialize()); + let sig_pair = PartialSignaturePair { + signer_index: signer.signer_index(), + signature: sig_b64, + }; + let partial_url = format!("{}/session/{}/partial", base_url, session_id); + let resp = client.post(&partial_url).json(&sig_pair).send().await?; + if !resp.status().is_success() { + println!( + "Verifier {}: Error submitting partial signature: {:?}", + signer.signer_index(), + resp.text().await? + ); + } else { + signer.mark_partial_sig_submitted(); + } + } + } else { + // waiting for final signature + } - // Store coordinator's own nonce - if let Some(session) = state.signing_sessions.get_mut(&session_id) { - session.received_nonces.insert(0, nonce); + tokio::time::sleep(Duration::from_secs(2)).await; } - Ok(SigningSessionResponse { - session_id, - message_to_sign: hex::encode(message), - aggregated_pubkey: hex::encode(state.signer.aggregated_pubkey().serialize()), - }) + Ok(()) +} + +// Handler to create a new signing session for a withdrawal transaction +#[instrument(skip(state))] +async fn create_session_handler( + State(state): State, +) -> Result, StatusCode> { + create_signing_session(&state) + .await + .map(Json) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) } -// Handler implementations +// GET /session/:id +#[instrument(skip(state))] async fn get_session( - State(state): State>>, + State(state): State, Path(session_id): Path, ) -> Result, StatusCode> { - // Implementation - todo!() + let sessions = state.signing_sessions.read().await; + let session = sessions.get(&session_id).ok_or(StatusCode::NOT_FOUND)?; + + let signer = state.signer.read().await; + let resp = SigningSessionResponse { + session_id: session.session_id.clone(), + message_to_sign: hex::encode(&session.message), + aggregated_pubkey: hex::encode(signer.aggregated_pubkey().serialize()), + required_signers: state.num_signers, + received_nonces: session.received_nonces.len(), + received_partial_signatures: session.received_sigs.len(), + final_signature: session + .final_signature + .as_ref() + .map(|sig| hex::encode(sig.serialize())), + }; + Ok(Json(resp)) } +// POST /session/:id/nonce +#[instrument(skip(state))] async fn submit_nonce( - State(state): State>>, + State(state): State, Path(session_id): Path, Json(nonce_pair): Json, ) -> Result { - // Implementation - todo!() + let decoded_nonce = base64::engine::general_purpose::STANDARD + .decode(&nonce_pair.nonce) + .map_err(|_| StatusCode::BAD_REQUEST)?; + let pub_nonce = PubNonce::from_bytes(&decoded_nonce).map_err(|_| StatusCode::BAD_REQUEST)?; + + { + let mut sessions = state.signing_sessions.write().await; + let session = sessions.get_mut(&session_id).ok_or(StatusCode::NOT_FOUND)?; + + session + .received_nonces + .insert(nonce_pair.signer_index, pub_nonce); + + // If all nonces are collected, coordinator finalizes and create partial sig + if session.received_nonces.len() == state.num_signers { + let mut signer = state.signer.write().await; + for (&i, nonce) in &session.received_nonces { + if i != 0 { + signer + .receive_nonce(i, nonce.clone()) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + } + } + let partial_sig = signer + .create_partial_signature() + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + session.received_sigs.insert(0, partial_sig); + } + } + + Ok(StatusCode::OK) } +// POST /session/:id/partial +#[instrument(skip(state))] async fn submit_partial_signature( - State(state): State>>, + State(state): State, Path(session_id): Path, Json(sig_pair): Json, ) -> Result { - // Implementation - todo!() + let decoded_sig = base64::decode(&sig_pair.signature).map_err(|_| StatusCode::BAD_REQUEST)?; + let partial_sig = + PartialSignature::from_slice(&decoded_sig).map_err(|_| StatusCode::BAD_REQUEST)?; + + { + let mut sessions = state.signing_sessions.write().await; + let session = sessions.get_mut(&session_id).ok_or(StatusCode::NOT_FOUND)?; + + session + .received_sigs + .insert(sig_pair.signer_index, partial_sig); + + if session.received_sigs.len() == state.num_signers { + let mut signer = state.signer.write().await; + for (&i, psig) in &session.received_sigs { + if i != 0 { + signer + .receive_partial_signature(i, *psig) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + } + } + + let final_sig = signer + .create_final_signature() + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + session.final_signature = Some(final_sig); + + // Verify final sig + let agg_pub = signer.aggregated_pubkey(); + verify_signature(agg_pub, final_sig, &session.message) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + } + } + + Ok(StatusCode::OK) } +// GET /session/:id/signature +#[instrument(skip(state))] async fn get_final_signature( - State(state): State>>, + State(state): State, Path(session_id): Path, ) -> Result, StatusCode> { - // Implementation - todo!() + let sessions = state.signing_sessions.read().await; + let session = sessions.get(&session_id).ok_or(StatusCode::NOT_FOUND)?; + + if let Some(final_sig) = &session.final_signature { + Ok(Json(hex::encode(final_sig.serialize()))) + } else { + Err(StatusCode::NOT_FOUND) + } } -// Helper functions -async fn create_test_withdrawal_builder() -> anyhow::Result { - // Similar to withdrawal_builder test setup - todo!() +async fn create_signing_session(state: &AppState) -> anyhow::Result { + let unsigned_tx = { + let withdrawal_builder = create_test_withdrawal_builder(&state.bridge_address).await?; + let withdrawals = create_test_withdrawal_requests()?; + let proof_txid = Txid::hash(&[0x42; 32]); + + withdrawal_builder + .create_unsigned_withdrawal_tx(withdrawals, proof_txid) + .await? + }; + + // Create unique session ID + let session_id = Uuid::new_v4().to_string(); + let tx_id = unsigned_tx.txid.to_string(); + + { + let mut utxos = state.unsigned_txs.write().await; + utxos.insert(tx_id.clone(), unsigned_tx.clone()); + } + + // Start signing session with message (transaction hash) + let message = unsigned_tx.tx.compute_txid().as_raw_hash().to_vec(); + { + let mut signer = state.signer.write().await; + signer.start_signing_session(message.clone())?; + } + + let session = SigningSession { + session_id: session_id.clone(), + tx_id, + received_nonces: HashMap::new(), + received_sigs: HashMap::new(), + final_signature: None, + message: message.clone(), + }; + + { + let mut sessions = state.signing_sessions.write().await; + sessions.insert(session_id.clone(), session); + } + + // Coordinator is signer_index 0, so insert coordinator's nonce: + { + let mut signer = state.signer.write().await; + let coordinator_nonce = signer.our_nonce().expect("nonce should be generated"); + let mut sessions = state.signing_sessions.write().await; + let session = sessions.get_mut(&session_id).unwrap(); + session.received_nonces.insert(0, coordinator_nonce); + } + + let signer = state.signer.read().await; + Ok(SigningSessionResponse { + session_id, + message_to_sign: hex::encode(message), + aggregated_pubkey: hex::encode(signer.aggregated_pubkey().serialize()), + required_signers: state.num_signers, + received_nonces: 1, + received_partial_signatures: 0, + final_signature: None, + }) } +// Mock a WithdrawalBuilder +async fn create_test_withdrawal_builder( + bridge_address: &Address, +) -> anyhow::Result { + let rpc_url = "http://localhost:18443"; + let network = BitcoinNetwork::Regtest; + let auth = bitcoincore_rpc::Auth::None; + let builder = WithdrawalBuilder::new(rpc_url, network, auth, bridge_address.clone()).await?; + Ok(builder) +} + +// Mock withdrawal requests fn create_test_withdrawal_requests() -> anyhow::Result> { - // Similar to withdrawal_builder test setup - todo!() + // Just create two withdrawal requests for demonstration + let addr1 = + Address::from_str("bcrt1pv6dtdf0vrrj6ntas926v8vw9u0j3mga29vmfnxh39zfxya83p89qz9ze3l")? + .require_network(Network::Regtest)?; + let addr2 = Address::from_str("bcrt1qxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz0abcd")? + .require_network(Network::Regtest)?; + + let requests = vec![ + WithdrawalRequest { + address: addr1, + amount: Amount::from_btc(0.1)?, + }, + WithdrawalRequest { + address: addr2, + amount: Amount::from_btc(0.05)?, + }, + ]; + Ok(requests) +} + +async fn get_nonces( + State(state): State, + Path(session_id): Path, +) -> Result>, StatusCode> { + let sessions = state.signing_sessions.read().await; + let session = sessions.get(&session_id).ok_or(StatusCode::NOT_FOUND)?; + + let mut nonces = HashMap::new(); + for (&idx, nonce) in &session.received_nonces { + nonces.insert( + idx, + base64::engine::general_purpose::STANDARD.encode(nonce.to_bytes()), + ); + } + + Ok(Json(nonces)) } diff --git a/core/lib/via_musig2/src/lib.rs b/core/lib/via_musig2/src/lib.rs index cc32353d1..54cee1c07 100644 --- a/core/lib/via_musig2/src/lib.rs +++ b/core/lib/via_musig2/src/lib.rs @@ -40,6 +40,8 @@ pub struct Signer { first_round: Option, second_round: Option>>, message: Vec, + nonce_submitted: bool, + partial_sig_submitted: bool, } impl Signer { @@ -62,6 +64,8 @@ impl Signer { first_round: None, second_round: None, message: Vec::new(), + nonce_submitted: false, + partial_sig_submitted: false, }) } @@ -154,6 +158,36 @@ impl Signer { .finalize() .map_err(|e| MusigError::Musig2Error(e.to_string())) } + + pub fn signer_index(&self) -> usize { + self.signer_index + } + + pub fn has_not_started(&self) -> bool { + self.first_round.is_none() + } + + pub fn has_submitted_nonce(&self) -> bool { + self.nonce_submitted + } + + pub fn mark_nonce_submitted(&mut self) { + self.nonce_submitted = true; + } + + pub fn our_nonce(&self) -> Option { + self.first_round + .as_ref() + .map(|round| round.our_public_nonce()) + } + + pub fn has_created_partial_sig(&self) -> bool { + self.second_round.is_some() + } + + pub fn mark_partial_sig_submitted(&mut self) { + self.partial_sig_submitted = true; + } } /// Helper function to verify a complete signature From 4c39a2b9e6c6e92a8b869889f4bf71303a335fc4 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 18 Dec 2024 13:28:55 +0330 Subject: [PATCH 050/212] add coordinator logic --- core/lib/via_musig2/examples/coordinator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index c637609d5..cee578a53 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, str::FromStr, sync::Arc, time::Duration}; +use std::{clone::Clone, collections::HashMap, str::FromStr, sync::Arc, time::Duration}; use axum::{ extract::{Path, State}, @@ -9,7 +9,7 @@ use axum::{ use base64::Engine; use bitcoin::{hashes::Hash, Address, Amount, Network, Txid}; use hyper::Server; -use musig2::{BinaryEncoding, Clone, CompactSignature, PartialSignature, PubNonce, ToBytes}; +use musig2::{BinaryEncoding, CompactSignature, PartialSignature, PubNonce}; use rand::thread_rng; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; use serde::{Deserialize, Serialize}; @@ -430,8 +430,8 @@ async fn create_signing_session(state: &AppState) -> anyhow::Result Date: Wed, 18 Dec 2024 13:45:52 +0330 Subject: [PATCH 051/212] fix warnings --- core/lib/via_musig2/examples/coordinator.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index cee578a53..6be70f802 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -23,6 +23,7 @@ use via_btc_client::{ use via_musig2::{verify_signature, Signer}; #[derive(Clone)] +#[allow(dead_code)] struct AppState { signer: Arc>, signing_sessions: Arc>>, @@ -33,6 +34,7 @@ struct AppState { } #[derive(Debug, Clone)] +#[allow(dead_code)] struct SigningSession { session_id: String, tx_id: String, @@ -357,7 +359,9 @@ async fn submit_partial_signature( Path(session_id): Path, Json(sig_pair): Json, ) -> Result { - let decoded_sig = base64::decode(&sig_pair.signature).map_err(|_| StatusCode::BAD_REQUEST)?; + let decoded_sig = base64::engine::general_purpose::STANDARD + .decode(&sig_pair.signature) + .map_err(|_| StatusCode::BAD_REQUEST)?; let partial_sig = PartialSignature::from_slice(&decoded_sig).map_err(|_| StatusCode::BAD_REQUEST)?; @@ -453,6 +457,7 @@ async fn create_signing_session(state: &AppState) -> anyhow::Result Date: Thu, 19 Dec 2024 13:40:00 +0330 Subject: [PATCH 052/212] fix review comments --- core/lib/via_btc_client/src/lib.rs | 2 +- .../{withdrawal => withdrawal_builder}/mod.rs | 92 ++++++++++++++----- core/lib/via_musig2/examples/coordinator.rs | 2 +- core/lib/via_musig2/src/lib.rs | 11 +++ 4 files changed, 84 insertions(+), 23 deletions(-) rename core/lib/via_btc_client/src/{withdrawal => withdrawal_builder}/mod.rs (79%) diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index caa009cc0..02b64c37f 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -8,4 +8,4 @@ pub mod inscriber; pub mod regtest; pub(crate) mod signer; pub(crate) mod utils; -pub mod withdrawal; +pub mod withdrawal_builder; diff --git a/core/lib/via_btc_client/src/withdrawal/mod.rs b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs similarity index 79% rename from core/lib/via_btc_client/src/withdrawal/mod.rs rename to core/lib/via_btc_client/src/withdrawal_builder/mod.rs index 0df1cbd18..9d5b34e59 100644 --- a/core/lib/via_btc_client/src/withdrawal/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs @@ -4,7 +4,7 @@ // and now we know the number of input and output we can estimate the fee and perform final utxo selection // create a unsigned transaction and return it to the caller -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use anyhow::Result; use bitcoin::{ @@ -62,17 +62,45 @@ impl WithdrawalBuilder { ) -> Result { debug!("Creating unsigned withdrawal transaction"); - // Calculate total amount needed - let total_amount: Amount = withdrawals - .iter() - .try_fold(Amount::ZERO, |acc, w| acc.checked_add(w.amount)) + // Group withdrawals by address and sum amounts + let mut grouped_withdrawals: HashMap = HashMap::new(); + for w in withdrawals { + *grouped_withdrawals.entry(w.address).or_insert(Amount::ZERO) = grouped_withdrawals + .get(&w.address) + .unwrap_or(&Amount::ZERO) + .checked_add(w.amount) + .ok_or_else(|| anyhow::anyhow!("Withdrawal amount overflow when grouping"))?; + } + + // Calculate total withdrawal amount from grouped withdrawals + let total_withdrawal_amount: Amount = grouped_withdrawals + .values() + .try_fold(Amount::ZERO, |acc, amount| acc.checked_add(*amount)) .ok_or_else(|| anyhow::anyhow!("Withdrawal amount overflow"))?; - // Get available UTXOs from bridge address - let utxos = self.get_available_utxos().await?; + // Get available UTXOs first to estimate number of inputs + let available_utxos = self.get_available_utxos().await?; + + // Get fee rate + let fee_rate = self.client.get_fee_rate(1).await?; + + // Estimate initial fee with approximate input count + // We'll estimate high initially to avoid underestimating + let estimated_input_count = + self.estimate_input_count(&available_utxos, total_withdrawal_amount)?; + let initial_fee = self.estimate_fee( + estimated_input_count, + grouped_withdrawals.len() as u32 + 2, // +1 for OP_RETURN, +1 for potential change + fee_rate, + )?; + + // Calculate total amount needed including estimated fee + let total_needed = total_withdrawal_amount + .checked_add(initial_fee) + .ok_or_else(|| anyhow::anyhow!("Total amount overflow"))?; - // Select UTXOs for the withdrawal - let selected_utxos = self.select_utxos(&utxos, total_amount).await?; + // Select UTXOs for the total amount including fee + let selected_utxos = self.select_utxos(&available_utxos, total_needed).await?; // Calculate total input amount let total_input_amount: Amount = selected_utxos @@ -87,17 +115,16 @@ impl WithdrawalBuilder { script_pubkey: op_return_data, }; - // Estimate fee (including OP_RETURN output) - let fee_rate = self.client.get_fee_rate(1).await?; - let fee_amount = self.estimate_fee( + // Calculate actual fee with real input count + let actual_fee = self.estimate_fee( selected_utxos.len() as u32, - withdrawals.len() as u32 + 1, // +1 for OP_RETURN output + grouped_withdrawals.len() as u32 + 1, // +1 for OP_RETURN output fee_rate, )?; - // Verify we have enough funds - let total_needed = total_amount - .checked_add(fee_amount) + // Verify we have enough funds with actual fee + let total_needed = total_withdrawal_amount + .checked_add(actual_fee) .ok_or_else(|| anyhow::anyhow!("Total amount overflow"))?; if total_input_amount < total_needed { @@ -119,12 +146,12 @@ impl WithdrawalBuilder { }) .collect(); - // Create outputs for withdrawals - let mut outputs: Vec = withdrawals + // Create outputs for grouped withdrawals + let mut outputs: Vec = grouped_withdrawals .into_iter() - .map(|w| TxOut { - value: w.amount, - script_pubkey: w.address.script_pubkey(), + .map(|(address, amount)| TxOut { + value: amount, + script_pubkey: address.script_pubkey(), }) .collect(); @@ -225,6 +252,29 @@ impl WithdrawalBuilder { Ok(ScriptBuf::new_op_return(encoded_data)) } + + #[instrument(skip(self, utxos), target = "bitcoin_withdrawal")] + fn estimate_input_count( + &self, + utxos: &[(OutPoint, TxOut)], + target_amount: Amount, + ) -> Result { + let mut count: u32 = 0; + let mut total = Amount::ZERO; + + for utxo in utxos { + count += 1; + total = total + .checked_add(utxo.1.value) + .ok_or_else(|| anyhow::anyhow!("Amount overflow during input count estimation"))?; + + if total >= target_amount { + break; + } + } + // Add one more to our estimate to be safe + Ok(count.saturating_add(1)) + } } #[cfg(test)] diff --git a/core/lib/via_musig2/examples/coordinator.rs b/core/lib/via_musig2/examples/coordinator.rs index 6be70f802..90e466fec 100644 --- a/core/lib/via_musig2/examples/coordinator.rs +++ b/core/lib/via_musig2/examples/coordinator.rs @@ -18,7 +18,7 @@ use tracing::{info, instrument}; use uuid::Uuid; use via_btc_client::{ types::BitcoinNetwork, - withdrawal::{UnsignedWithdrawalTx, WithdrawalBuilder, WithdrawalRequest}, + withdrawal_builder::{UnsignedWithdrawalTx, WithdrawalBuilder, WithdrawalRequest}, }; use via_musig2::{verify_signature, Signer}; diff --git a/core/lib/via_musig2/src/lib.rs b/core/lib/via_musig2/src/lib.rs index 54cee1c07..ddb316d92 100644 --- a/core/lib/via_musig2/src/lib.rs +++ b/core/lib/via_musig2/src/lib.rs @@ -53,6 +53,17 @@ impl Signer { ) -> Result { let secp = Secp256k1::new(); let public_key = PublicKey::from_secret_key(&secp, &secret_key); + + // Verify that signer_index is valid and matches the public key + if signer_index >= all_pubkeys.len() { + return Err(MusigError::InvalidSignerIndex); + } + if all_pubkeys[signer_index] != public_key { + return Err(MusigError::Musig2Error( + "Public key at signer_index does not match derived public key".into(), + )); + } + let key_agg_ctx = KeyAggContext::new(all_pubkeys).map_err(|e| MusigError::Musig2Error(e.to_string()))?; From 588e8ee5e223d61bacfa75c3c9d1ab660f157131 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 19 Dec 2024 13:43:38 +0330 Subject: [PATCH 053/212] update cargo lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8ee5b446b..2a0be2984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9624,7 +9624,7 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", - "uuid", + "uuid 1.10.0", "via_btc_client", ] From 1c2e1eaf49ae46cf3b597b3cbc5a9cb7c3503e81 Mon Sep 17 00:00:00 2001 From: Miroslav Pavlovic Date: Thu, 19 Dec 2024 14:02:02 +0100 Subject: [PATCH 054/212] fix: inscribe correct reveal_tx_id --- core/lib/dal/src/models/storage_btc_block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/dal/src/models/storage_btc_block.rs b/core/lib/dal/src/models/storage_btc_block.rs index 5726e7e3f..525e06384 100644 --- a/core/lib/dal/src/models/storage_btc_block.rs +++ b/core/lib/dal/src/models/storage_btc_block.rs @@ -21,7 +21,7 @@ impl From for ViaBtcL1BlockDetails { hash: details.hash, commit_tx_id: Txid::from_str(&details.commit_tx_id.clone().unwrap_or_default()) .unwrap_or(Txid::all_zeros()), - reveal_tx_id: Txid::from_str(&details.commit_tx_id.clone().unwrap_or_default()) + reveal_tx_id: Txid::from_str(&details.reveal_tx_id.clone().unwrap_or_default()) .unwrap_or(Txid::all_zeros()), blob_id: details.blob_id.unwrap_or_default(), } From ce86f4a52b4bb849a48a3595c4a4ca96cdbca93e Mon Sep 17 00:00:00 2001 From: Miroslav Pavlovic Date: Thu, 19 Dec 2024 16:14:10 +0100 Subject: [PATCH 055/212] fix: use correct bootloader version for eth_call --- core/node/api_server/src/tx_sender/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/node/api_server/src/tx_sender/mod.rs b/core/node/api_server/src/tx_sender/mod.rs index 3e40f7937..88aa9ae0b 100644 --- a/core/node/api_server/src/tx_sender/mod.rs +++ b/core/node/api_server/src/tx_sender/mod.rs @@ -198,7 +198,7 @@ impl ApiContracts { vm_1_5_0_small_memory: BaseSystemContracts::playground_1_5_0_small_memory(), vm_1_5_0_increased_memory: BaseSystemContracts::playground_post_1_5_0_increased_memory(), - vm_bitcoin: BaseSystemContracts::estimate_gas_bitcoin_1_0_0(), + vm_bitcoin: BaseSystemContracts::playground_bitcoin_1_0_0(), }, } } From b0fd407dcf38c9ea4dbfcbf502ab4663c2a6c1e6 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Thu, 19 Dec 2024 23:00:17 +0100 Subject: [PATCH 056/212] fix: review fixes, add logic for server restart --- ...d1a9f913563e6af55b0dd7293b30a7e210a61.json | 23 ++++++ ...6ffdbc61d4d836abe2f0a08876836ec83c6f0.json | 20 +++++ core/lib/dal/src/via_votes_dal.rs | 49 ++++++++++-- core/lib/via_btc_client/src/indexer/mod.rs | 4 + .../src/message_processors/votable.rs | 74 ++++++++++++++----- 5 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json create mode 100644 core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json diff --git a/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json b/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json new file mode 100644 index 000000000..17a3c47bf --- /dev/null +++ b/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT is_finalized\n FROM via_votable_transactions\n WHERE l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_finalized", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61" +} diff --git a/core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json b/core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json new file mode 100644 index 000000000..2990d3d58 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT MAX(l1_batch_number) AS max_batch_number\n FROM via_votable_transactions\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0" +} diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index bf9eb08a2..18a346544 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -95,19 +95,40 @@ impl ViaVotesDal<'_, '_> { Ok((ok_votes, total_votes)) } - /// Marks the transaction as finalized if #ok_votes / #total_votes > threshold. + /// Marks the transaction as finalized if #ok_votes / #total_votes >= threshold. /// Must use `(l1_batch_number, tx_id)` in both vote counting and the UPDATE statement. pub async fn finalize_transaction_if_needed( &mut self, l1_batch_number: u32, tx_id: H256, threshold: f64, + number_of_verifiers: usize, ) -> DalResult { - let (ok_votes, total_votes) = self.get_vote_count(l1_batch_number, tx_id).await?; - let is_above_threshold = - total_votes > 0 && (ok_votes as f64) / (total_votes as f64) > threshold; + let row = sqlx::query!( + r#" + SELECT + is_finalized + FROM + via_votable_transactions + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + l1_batch_number as i64, + tx_id.as_bytes() + ) + .instrument("check_if_already_finalized") + .fetch_one(self.storage) + .await?; - if is_above_threshold { + if row.is_finalized { + return Ok(false); + } + + let (ok_votes, _total_votes) = self.get_vote_count(l1_batch_number, tx_id).await?; + let is_threshold_reached = (ok_votes as f64) / (number_of_verifiers as f64) >= threshold; + + if is_threshold_reached { sqlx::query!( r#" UPDATE via_votable_transactions @@ -126,6 +147,22 @@ impl ViaVotesDal<'_, '_> { .await?; } - Ok(is_above_threshold) + Ok(is_threshold_reached) + } + + pub async fn get_last_inserted_block(&mut self) -> DalResult> { + let row = sqlx::query!( + r#" + SELECT + MAX(l1_batch_number) AS max_batch_number + FROM + via_votable_transactions + "# + ) + .instrument("get_last_inserted_block") + .fetch_one(self.storage) + .await?; + + Ok(row.max_batch_number.map(|n| n as u32)) } } diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 23227a0d2..eef55506a 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -202,6 +202,10 @@ impl BitcoinInscriptionIndexer { _ => None, } } + + pub fn get_number_of_verifiers(&self) -> usize { + self.verifier_addresses.len() + } } impl BitcoinInscriptionIndexer { diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 75c14bd02..1a0153762 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -4,7 +4,7 @@ use via_btc_client::{ types::{BitcoinTxid, FullInscriptionMessage}, }; use zksync_dal::{Connection, Core, CoreDal}; -use zksync_types::{aggregated_operations::AggregatedActionType, L1BatchNumber, H256}; +use zksync_types::{aggregated_operations::AggregatedActionType, H256}; use super::{MessageProcessor, MessageProcessorError}; @@ -38,12 +38,29 @@ impl MessageProcessor for VotableMessageProcessor { let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); for msg in msgs { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(&msg).await { - match msg { - FullInscriptionMessage::ProofDAReference(proof_msg) => { - let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + match msg { + ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { let mut votes_dal = storage.via_votes_dal(); + let last_inserted_block = votes_dal + .get_last_inserted_block() + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + .unwrap_or(0); + + if l1_batch_number.0 <= last_inserted_block { + tracing::warn!( + "Skipping ProofDAReference message with l1_batch_number: {:?} because it is already processed", + l1_batch_number + ); + continue; + } + + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + let batch_tx_id = + convert_txid_to_h256(proof_msg.input.l1_batch_reveal_txid); + votes_dal .insert_votable_transaction(l1_batch_number.0, tx_id) .await @@ -51,6 +68,15 @@ impl MessageProcessor for VotableMessageProcessor { let mut eth_sender_dal = storage.eth_sender_dal(); + eth_sender_dal + .insert_bogus_confirmed_eth_tx( + l1_batch_number, + AggregatedActionType::Commit, + batch_tx_id, + dt, + ) + .await?; + eth_sender_dal .insert_bogus_confirmed_eth_tx( l1_batch_number, @@ -59,8 +85,15 @@ impl MessageProcessor for VotableMessageProcessor { dt, ) .await?; + } else { + tracing::warn!( + "L1BatchNumber not found for ProofDAReference message : {:?}", + proof_msg + ); } - FullInscriptionMessage::ValidatorAttestation(attestation_msg) => { + } + ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { let mut votes_dal = storage.via_votes_dal(); let reference_txid = @@ -88,12 +121,18 @@ impl MessageProcessor for VotableMessageProcessor { l1_batch_number.0, reference_txid, self.threshold, + indexer.get_number_of_verifiers(), ) .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? { let mut eth_sender_dal = storage.eth_sender_dal(); + tracing::error!( + "Finalizing transaction with tx_id: {:?} and block number: {:?}", + tx_id, + l1_batch_number + ); eth_sender_dal .insert_bogus_confirmed_eth_tx( l1_batch_number, @@ -104,20 +143,17 @@ impl MessageProcessor for VotableMessageProcessor { .await?; } } - // bootstrapping phase is already covered - FullInscriptionMessage::ProposeSequencer(_) - | FullInscriptionMessage::SystemBootstrapping(_) => { - // do nothing - } - // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor - FullInscriptionMessage::L1ToL2Message(_) - | FullInscriptionMessage::L1BatchDAReference(_) => { - // do nothing - } } - } else { - tracing::warn!("L1 batch number is not found for message: {:?}", msg); - continue; + // bootstrapping phase is already covered + FullInscriptionMessage::ProposeSequencer(_) + | FullInscriptionMessage::SystemBootstrapping(_) => { + // do nothing + } + // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor + FullInscriptionMessage::L1ToL2Message(_) + | FullInscriptionMessage::L1BatchDAReference(_) => { + // do nothing + } } } Ok(()) From 8f45234d3036e72b5d07ff14e64704d1c733b242 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Fri, 20 Dec 2024 10:22:19 +0100 Subject: [PATCH 057/212] fix: review fixes --- ...970ac92a60580e047d5a43b77e56ab5f3d2b4.json | 23 +++++++++++++++++++ ...d1a9f913563e6af55b0dd7293b30a7e210a61.json | 23 ------------------- ...6ffccdb4ea2a1495525fe76be9c1e77580c9.json} | 4 ++-- .../src/message_processors/votable.rs | 8 +++---- 4 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json delete mode 100644 core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json rename core/lib/dal/.sqlx/{query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json => query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json} (51%) diff --git a/core/lib/dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json b/core/lib/dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json new file mode 100644 index 000000000..7fff300d2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n is_finalized\n FROM\n via_votable_transactions\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_finalized", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4" +} diff --git a/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json b/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json deleted file mode 100644 index 17a3c47bf..000000000 --- a/core/lib/dal/.sqlx/query-d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT is_finalized\n FROM via_votable_transactions\n WHERE l1_batch_number = $1\n AND tx_id = $2\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "is_finalized", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Int8", - "Bytea" - ] - }, - "nullable": [ - false - ] - }, - "hash": "d34ee99dedb5ce422060dc48bffd1a9f913563e6af55b0dd7293b30a7e210a61" -} diff --git a/core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json b/core/lib/dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json similarity index 51% rename from core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json rename to core/lib/dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json index 2990d3d58..c1fda0d3d 100644 --- a/core/lib/dal/.sqlx/query-d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0.json +++ b/core/lib/dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT MAX(l1_batch_number) AS max_batch_number\n FROM via_votable_transactions\n ", + "query": "\n SELECT\n MAX(l1_batch_number) AS max_batch_number\n FROM\n via_votable_transactions\n ", "describe": { "columns": [ { @@ -16,5 +16,5 @@ null ] }, - "hash": "d9ffa820ff25f883c360d58edfb6ffdbc61d4d836abe2f0a08876836ec83c6f0" + "hash": "eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9" } diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 1a0153762..4b5b2f21f 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -49,10 +49,10 @@ impl MessageProcessor for VotableMessageProcessor { .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? .unwrap_or(0); - if l1_batch_number.0 <= last_inserted_block { + if l1_batch_number.0 != last_inserted_block + 1 { tracing::warn!( - "Skipping ProofDAReference message with l1_batch_number: {:?} because it is already processed", - l1_batch_number + "Skipping ProofDAReference message with l1_batch_number: {:?}. Last inserted block: {:?}", + l1_batch_number, last_inserted_block ); continue; } @@ -128,7 +128,7 @@ impl MessageProcessor for VotableMessageProcessor { { let mut eth_sender_dal = storage.eth_sender_dal(); - tracing::error!( + tracing::info!( "Finalizing transaction with tx_id: {:?} and block number: {:?}", tx_id, l1_batch_number From 1ff0215100b65060cc94db8f82cf98f720cc8c17 Mon Sep 17 00:00:00 2001 From: Miroslav Pavlovic Date: Fri, 20 Dec 2024 14:53:18 +0100 Subject: [PATCH 058/212] feat: add proof data handler layer --- core/bin/via_server/src/config.rs | 4 ++-- core/bin/via_server/src/node_builder.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/bin/via_server/src/config.rs b/core/bin/via_server/src/config.rs index 60a948842..8a567a1b9 100644 --- a/core/bin/via_server/src/config.rs +++ b/core/bin/via_server/src/config.rs @@ -7,7 +7,7 @@ use zksync_config::{ fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, BasicWitnessInputProducerConfig, FriProofCompressorConfig, FriProverConfig, - FriWitnessGeneratorConfig, ObservabilityConfig, PrometheusConfig, + FriWitnessGeneratorConfig, ObservabilityConfig, PrometheusConfig, ProofDataHandlerConfig, ProtectiveReadsWriterConfig, }, ApiConfig, DADispatcherConfig, DBConfig, ObjectStoreConfig, PostgresConfig, ViaBtcSenderConfig, @@ -60,7 +60,7 @@ pub(crate) fn load_env_config() -> anyhow::Result { fri_witness_vector_generator: None, fri_witness_generator_config: FriWitnessGeneratorConfig::from_env().ok(), prometheus_config: PrometheusConfig::from_env().ok(), - proof_data_handler_config: None, + proof_data_handler_config: ProofDataHandlerConfig::from_env().ok(), api_config: ApiConfig::from_env().ok(), db_config: DBConfig::from_env().ok(), eth_sender_config: None, diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 231016e0b..397e3064b 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -23,6 +23,7 @@ use zksync_node_framework::{ pools_layer::PoolsLayerBuilder, postgres_metrics::PostgresMetricsLayer, prometheus_exporter::PrometheusExporterLayer, + proof_data_handler::ProofDataHandlerLayer, query_eth_client::QueryEthClientLayer, sigint::SigintHandlerLayer, via_btc_sender::{ @@ -398,6 +399,14 @@ impl ViaNodeBuilder { Ok(self) } + fn add_proof_data_handler_layer(mut self) -> anyhow::Result { + self.node.add_layer(ProofDataHandlerLayer::new( + try_load_config!(self.configs.proof_data_handler_config), + self.genesis_config.l1_batch_commit_data_generator_mode, + )); + Ok(self) + } + /// Builds the node with the genesis initialization task only. pub fn only_genesis(mut self) -> anyhow::Result { self = self @@ -436,6 +445,7 @@ impl ViaNodeBuilder { .add_commitment_generator_layer()? .add_via_celestia_da_client_layer()? .add_da_dispatcher_layer()? + .add_proof_data_handler_layer()? .node .build()) } From f3525fb213a5859ca876c5ceb4e0c1b7053818f6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:30:55 +0100 Subject: [PATCH 059/212] feat: change the inscription_request_type to string --- core/lib/dal/src/btc_sender_dal.rs | 9 +++------ .../dal/src/models/storage_btc_inscription_request.rs | 2 +- core/lib/types/src/btc.rs | 1 - core/lib/types/src/btc_sender.rs | 4 +--- .../via_btc_sender/src/btc_inscription_aggregator.rs | 2 +- 5 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 core/lib/types/src/btc.rs diff --git a/core/lib/dal/src/btc_sender_dal.rs b/core/lib/dal/src/btc_sender_dal.rs index 9a37b387f..0c3ec63a8 100644 --- a/core/lib/dal/src/btc_sender_dal.rs +++ b/core/lib/dal/src/btc_sender_dal.rs @@ -1,10 +1,7 @@ use anyhow::Context; use bitcoin::hash_types::Txid; use zksync_db_connection::connection::Connection; -use zksync_types::{ - btc_inscription_operations::ViaBtcInscriptionRequestType, - btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}, -}; +use zksync_types::btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}; use crate::{ models::storage_btc_inscription_request::{ @@ -21,7 +18,7 @@ pub struct ViaBtcSenderDal<'a, 'c> { impl ViaBtcSenderDal<'_, '_> { pub async fn via_save_btc_inscriptions_request( &mut self, - inscription_request_type: ViaBtcInscriptionRequestType, + inscription_request_type: String, inscription_message: Vec, predicted_fee: u64, ) -> sqlx::Result { @@ -35,7 +32,7 @@ impl ViaBtcSenderDal<'_, '_> { RETURNING * "#, - inscription_request_type.to_string(), + inscription_request_type, inscription_message, predicted_fee as i64, ) diff --git a/core/lib/dal/src/models/storage_btc_inscription_request.rs b/core/lib/dal/src/models/storage_btc_inscription_request.rs index e083c9870..4aef6b110 100644 --- a/core/lib/dal/src/models/storage_btc_inscription_request.rs +++ b/core/lib/dal/src/models/storage_btc_inscription_request.rs @@ -37,7 +37,7 @@ impl From for ViaBtcInscriptionRequest { fn from(req: ViaStorageBtcInscriptionRequest) -> ViaBtcInscriptionRequest { ViaBtcInscriptionRequest { id: req.id, - request_type: ViaBtcInscriptionRequestType::from_str(&req.request_type).unwrap(), + request_type: req.request_type, inscription_message: req.inscription_message, confirmed_inscriptions_request_history_id: req .confirmed_inscriptions_request_history_id, diff --git a/core/lib/types/src/btc.rs b/core/lib/types/src/btc.rs deleted file mode 100644 index 0519ecba6..000000000 --- a/core/lib/types/src/btc.rs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/lib/types/src/btc_sender.rs b/core/lib/types/src/btc_sender.rs index 99b2ab0e2..6dbd4cfa7 100644 --- a/core/lib/types/src/btc_sender.rs +++ b/core/lib/types/src/btc_sender.rs @@ -1,12 +1,10 @@ use bitcoin::Txid; use chrono::NaiveDateTime; -use crate::btc_inscription_operations::ViaBtcInscriptionRequestType; - #[derive(Clone)] pub struct ViaBtcInscriptionRequest { pub id: i64, - pub request_type: ViaBtcInscriptionRequestType, + pub request_type: String, pub inscription_message: Option>, pub predicted_fee: Option, pub confirmed_inscriptions_request_history_id: Option, diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index 9c5ab99ec..081e3bbe1 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -104,7 +104,7 @@ impl ViaBtcInscriptionAggregator { let inscription_request = transaction .btc_sender_dal() .via_save_btc_inscriptions_request( - operation.get_inscription_request_type(), + operation.get_inscription_request_type().to_string(), InscriptionMessage::to_bytes(&inscription_message), prediction_fee.to_sat(), ) From d0af85640bc09f0c4fdd120fe27eb31b6de3872c Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:33:30 +0100 Subject: [PATCH 060/212] feat(dal): add dal helpers for votable transactions --- ...d8690e72af5ae37d0059be1fa43a432ec1375.json | 28 +++++++ ...8a4f575900be3a16a55297d521436dd27809b.json | 20 +++++ ...703fbb5f734284c380b316be30fd38aac8675.json | 16 ++++ .../20241209150000_create_via_votes.up.sql | 2 + core/lib/dal/src/via_votes_dal.rs | 78 +++++++++++++++++++ 5 files changed, 144 insertions(+) create mode 100644 core/lib/dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json create mode 100644 core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json create mode 100644 core/lib/dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json diff --git a/core/lib/dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json b/core/lib/dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json new file mode 100644 index 000000000..963590678 --- /dev/null +++ b/core/lib/dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_status,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n l1_batch_number = $1\n AND is_verified = TRUE\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_status", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375" +} diff --git a/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json b/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json new file mode 100644 index 000000000..222e9d57e --- /dev/null +++ b/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number\n FROM\n via_votable_transactions\n WHERE\n is_finalized = FALSE\n ORDER BY l1_batch_number ASC\n LIMIT 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b" +} diff --git a/core/lib/dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json b/core/lib/dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json new file mode 100644 index 000000000..1f2be9fbe --- /dev/null +++ b/core/lib/dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n is_verified = TRUE,\n l1_batch_status = $3,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675" +} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index d15858eed..2de67ad3d 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -2,6 +2,8 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( l1_batch_number BIGINT NOT NULL REFERENCES l1_batches (number) ON DELETE CASCADE, tx_id BYTEA, is_finalized BOOLEAN NOT NULL DEFAULT FALSE, + is_verified BOOLEAN NOT NULL DEFAULT FALSE, + l1_batch_status BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (l1_batch_number, tx_id) diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 18a346544..7493d7748 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -165,4 +165,82 @@ impl ViaVotesDal<'_, '_> { Ok(row.max_batch_number.map(|n| n as u32)) } + + pub async fn verify_votable_transaction( + &mut self, + l1_batch_number: u32, + tx_id: H256, + l1_batch_status: bool, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + is_verified = TRUE, + l1_batch_status = $3, + updated_at = NOW() + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + l1_batch_number as i64, + tx_id.as_bytes(), + l1_batch_status + ) + .instrument("verify_transaction") + .execute(self.storage) + .await?; + Ok(()) + } + + pub async fn get_first_not_finilized_block(&mut self) -> DalResult> { + let l1_block_number = sqlx::query_scalar!( + r#" + SELECT + l1_batch_number + FROM + via_votable_transactions + WHERE + is_finalized = FALSE + ORDER BY l1_batch_number ASC + LIMIT 1 + "#, + ) + .instrument("get_last_block_finilized") + .fetch_optional(self.storage) + .await?; + Ok(l1_block_number) + } + + pub async fn get_verifier_vote_status( + &mut self, + block_number: i64, + ) -> DalResult)>> { + let row = sqlx::query!( + r#" + SELECT + l1_batch_status, + tx_id + FROM + via_votable_transactions + WHERE + l1_batch_number = $1 + AND is_verified = TRUE + LIMIT + 1 + "#, + block_number + ) + .instrument("get_verifier_vote_status") + .fetch_optional(self.storage) + .await?; + + let result = row.map(|r| { + let l1_batch_status = r.l1_batch_status; + let tx_id = r.tx_id; + (l1_batch_status, tx_id) + }); + + Ok(result) + } } From 48611d6b5c9453ee218122336f9dfb71e17b9b3b Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:34:56 +0100 Subject: [PATCH 061/212] feat(dal): add verifier vote inscription table and queries --- ...8eef1a09c549c5c62c77b5527f771ae6370b0.json | 22 ++++++ ...a4a2263af9c4aa330638ffdc8c380aafa6d3a.json | 15 ++++ ...919_add_verifier_vote_inscription.down.sql | 1 + ...91919_add_verifier_vote_inscription.up.sql | 8 ++ core/lib/dal/src/lib.rs | 8 ++ core/lib/dal/src/via_verifier_blocks_dal.rs | 79 +++++++++++++++++++ core/lib/types/src/lib.rs | 1 + ...via_verifier_btc_inscription_operations.rs | 45 +++++++++++ 8 files changed, 179 insertions(+) create mode 100644 core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json create mode 100644 core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json create mode 100644 core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql create mode 100644 core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql create mode 100644 core/lib/dal/src/via_verifier_blocks_dal.rs create mode 100644 core/lib/types/src/via_verifier_btc_inscription_operations.rs diff --git a/core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json b/core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json new file mode 100644 index 000000000..d6681f247 --- /dev/null +++ b/core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT EXISTS(\n SELECT 1\n FROM via_l1_batch_vote_inscription_request\n WHERE l1_batch_number = $1\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0" +} diff --git a/core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json b/core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json new file mode 100644 index 000000000..f44a753ea --- /dev/null +++ b/core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_l1_batch_vote_inscription_request (l1_batch_number, vote_l1_batch_inscription_id, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ON CONFLICT DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a" +} diff --git a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql new file mode 100644 index 000000000..5361eff01 --- /dev/null +++ b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql @@ -0,0 +1 @@ +DROP TABLE via_l1_batch_vote_inscription_request; \ No newline at end of file diff --git a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql new file mode 100644 index 000000000..c53e8cce7 --- /dev/null +++ b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql @@ -0,0 +1,8 @@ +CREATE TABLE "via_l1_batch_vote_inscription_request" ( + "l1_batch_number" bigint UNIQUE NOT NULL, + "vote_l1_batch_inscription_id" bigint UNIQUE NOT NULL, + "created_at" timestamp NOT NULL DEFAULT 'now()', + "updated_at" timestamp NOT NULL +); + +ALTER TABLE "via_l1_batch_vote_inscription_request" ADD FOREIGN KEY ("vote_l1_batch_inscription_id") REFERENCES "via_btc_inscriptions_request" ("id"); diff --git a/core/lib/dal/src/lib.rs b/core/lib/dal/src/lib.rs index 7d914fa53..41c944ad5 100644 --- a/core/lib/dal/src/lib.rs +++ b/core/lib/dal/src/lib.rs @@ -5,6 +5,7 @@ use btc_sender_dal::ViaBtcSenderDal; pub use sqlx::{types::BigDecimal, Error as SqlxError}; +use via_verifier_blocks_dal::ViaVerifierBlocksDal; use zksync_db_connection::connection::DbMarker; pub use zksync_db_connection::{ connection::{Connection, IsolationLevel}, @@ -66,6 +67,7 @@ pub mod transactions_web3_dal; pub mod via_blocks_dal; pub mod via_data_availability_dal; pub mod via_transactions_dal; +pub mod via_verifier_blocks_dal; pub mod via_votes_dal; pub mod vm_runner_dal; @@ -105,6 +107,8 @@ where fn btc_sender_dal(&mut self) -> ViaBtcSenderDal<'_, 'a>; + fn via_verifier_block_dal(&mut self) -> ViaVerifierBlocksDal<'_, 'a>; + fn events_dal(&mut self) -> EventsDal<'_, 'a>; fn events_web3_dal(&mut self) -> EventsWeb3Dal<'_, 'a>; @@ -204,6 +208,10 @@ impl<'a> CoreDal<'a> for Connection<'a, Core> { ViaBtcSenderDal { storage: self } } + fn via_verifier_block_dal(&mut self) -> ViaVerifierBlocksDal<'_, 'a> { + ViaVerifierBlocksDal { storage: self } + } + fn events_dal(&mut self) -> EventsDal<'_, 'a> { EventsDal { storage: self } } diff --git a/core/lib/dal/src/via_verifier_blocks_dal.rs b/core/lib/dal/src/via_verifier_blocks_dal.rs new file mode 100644 index 000000000..b9dab3a55 --- /dev/null +++ b/core/lib/dal/src/via_verifier_blocks_dal.rs @@ -0,0 +1,79 @@ +use zksync_db_connection::{ + connection::Connection, + error::DalResult, + instrument::{InstrumentExt, Instrumented}, +}; +use zksync_types::{ + via_verifier_btc_inscription_operations::ViaVerifierBtcInscriptionRequestType, L1BatchNumber, +}; + +pub use crate::models::storage_block::{L1BatchMetadataError, L1BatchWithOptionalMetadata}; +use crate::Core; + +#[derive(Debug)] +pub struct ViaVerifierBlocksDal<'a, 'c> { + pub(crate) storage: &'a mut Connection<'c, Core>, +} + +impl ViaVerifierBlocksDal<'_, '_> { + pub async fn insert_vote_l1_batch_inscription_request_id( + &mut self, + batch_number: L1BatchNumber, + inscription_request_id: i64, + inscription_request: ViaVerifierBtcInscriptionRequestType, + ) -> DalResult<()> { + match inscription_request { + ViaVerifierBtcInscriptionRequestType::VoteOnchain => { + let instrumentation = Instrumented::new("set_inscription_request_tx_id#commit") + .with_arg("batch_number", &batch_number) + .with_arg("inscription_request_id", &inscription_request_id); + + let query = sqlx::query!( + r#" + INSERT INTO + via_l1_batch_vote_inscription_request (l1_batch_number, vote_l1_batch_inscription_id, created_at, updated_at) + VALUES + ($1, $2, NOW(), NOW()) + ON CONFLICT DO NOTHING + "#, + i64::from(batch_number.0), + inscription_request_id as i32, + ); + let result = instrumentation + .clone() + .with(query) + .execute(self.storage) + .await?; + + if result.rows_affected() == 0 { + let err = instrumentation.constraint_error(anyhow::anyhow!( + "Update commit_l1_batch_inscription_id that is is not null is not allowed" + )); + return Err(err); + } + Ok(()) + } + } + } + + pub async fn check_vote_l1_batch_inscription_request_if_exists( + &mut self, + batch_number: i64, + ) -> DalResult { + let exists = sqlx::query_scalar!( + r#" + SELECT EXISTS( + SELECT 1 + FROM via_l1_batch_vote_inscription_request + WHERE l1_batch_number = $1 + ) + "#, + batch_number + ) + .instrument("check_vote_l1_batch_inscription_request_id_exists") + .fetch_one(self.storage) + .await?; + + Ok(exists.unwrap_or(false)) + } +} diff --git a/core/lib/types/src/lib.rs b/core/lib/types/src/lib.rs index 0055adb10..4ca03aa0d 100644 --- a/core/lib/types/src/lib.rs +++ b/core/lib/types/src/lib.rs @@ -61,6 +61,7 @@ pub mod helpers; pub mod proto; pub mod transaction_request; pub mod utils; +pub mod via_verifier_btc_inscription_operations; /// Denotes the first byte of the special ZKsync's EIP-712-signed transaction. pub const EIP_712_TX_TYPE: u8 = 0x71; diff --git a/core/lib/types/src/via_verifier_btc_inscription_operations.rs b/core/lib/types/src/via_verifier_btc_inscription_operations.rs new file mode 100644 index 000000000..909a109d8 --- /dev/null +++ b/core/lib/types/src/via_verifier_btc_inscription_operations.rs @@ -0,0 +1,45 @@ +use std::{fmt, str::FromStr}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ViaVerifierBtcInscriptionRequestType { + VoteOnchain, +} + +impl ViaVerifierBtcInscriptionRequestType { + pub fn as_str(self) -> &'static str { + match self { + Self::VoteOnchain => "VoteOnchain", + } + } +} + +impl fmt::Display for ViaVerifierBtcInscriptionRequestType { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str(self.as_str()) + } +} + +impl From for ViaVerifierBtcInscriptionRequestType { + fn from(s: String) -> Self { + match s.as_str() { + "VoteOnchain" => ViaVerifierBtcInscriptionRequestType::VoteOnchain, + _ => panic!( + "Unexpected value for ViaVerifierBtcInscriptionRequestType: {}", + s + ), + } + } +} + +impl FromStr for ViaVerifierBtcInscriptionRequestType { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "VoteOnchain" => Ok(Self::VoteOnchain), + _ => Err( + "Incorrect aggregated action type; expected one of `VoteOnchain`, `CommitProofOnchain`", + ), + } + } +} From 84900e4683315a387e8fec5095d6b84a2765fd6b Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:40:34 +0100 Subject: [PATCH 062/212] feat(btc_sender): implement the vote inscription manager --- .../src/btc_vote_inscription.rs | 137 ++++++++++++++++++ core/node/via_btc_sender/src/lib.rs | 1 + 2 files changed, 138 insertions(+) create mode 100644 core/node/via_btc_sender/src/btc_vote_inscription.rs diff --git a/core/node/via_btc_sender/src/btc_vote_inscription.rs b/core/node/via_btc_sender/src/btc_vote_inscription.rs new file mode 100644 index 000000000..eccecb361 --- /dev/null +++ b/core/node/via_btc_sender/src/btc_vote_inscription.rs @@ -0,0 +1,137 @@ +use anyhow::Context; +use bitcoin::{hashes::Hash, Txid}; +use tokio::sync::watch; +use via_btc_client::{ + traits::Serializable, + types::{InscriptionMessage, ValidatorAttestationInput, Vote}, +}; +use zksync_config::ViaBtcSenderConfig; +use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; +use zksync_types::{ + via_verifier_btc_inscription_operations::ViaVerifierBtcInscriptionRequestType, L1BatchNumber, +}; + +pub struct ViaVoteInscription { + pool: ConnectionPool, + config: ViaBtcSenderConfig, +} + +impl ViaVoteInscription { + pub async fn new( + pool: ConnectionPool, + config: ViaBtcSenderConfig, + ) -> anyhow::Result { + Ok(Self { pool, config }) + } + + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut timer = tokio::time::interval(self.config.poll_interval()); + let pool = self.pool.clone(); + + while !*stop_receiver.borrow_and_update() { + tokio::select! { + _ = timer.tick() => { /* continue iterations */ } + _ = stop_receiver.changed() => break, + } + + let mut storage = pool + .connection_tagged("via_btc_inscription_creator") + .await?; + + match self.loop_iteration(&mut storage).await { + Ok(()) => { + tracing::info!("Verifier vote inscription task finished"); + } + Err(err) => { + tracing::error!("Failed to process Verifier btc_sender_inscription: {err}"); + } + } + } + + tracing::info!("Stop signal received, Verifier btc_sender_inscription is shutting down"); + Ok(()) + } + + pub async fn loop_iteration( + &mut self, + storage: &mut Connection<'_, Core>, + ) -> anyhow::Result<()> { + if let Some((l1_batch_number, vote, tx_id)) = self.get_voting_operation(storage).await? { + tracing::info!("New voting operation ready to be processed"); + let mut transaction = storage.start_transaction().await?; + let inscription_message = self.construct_voting_inscription_message(vote, tx_id)?; + + let inscription_request = transaction + .btc_sender_dal() + .via_save_btc_inscriptions_request( + ViaVerifierBtcInscriptionRequestType::VoteOnchain.to_string(), + InscriptionMessage::to_bytes(&inscription_message), + 0, + ) + .await + .context("Via save btc inscriptions request")?; + + transaction + .via_verifier_block_dal() + .insert_vote_l1_batch_inscription_request_id( + l1_batch_number, + inscription_request.id, + ViaVerifierBtcInscriptionRequestType::VoteOnchain, + ) + .await + .context("Via set inscription request id")?; + transaction.commit().await?; + } + Ok(()) + } + + pub async fn get_voting_operation( + &mut self, + storage: &mut Connection<'_, Core>, + ) -> anyhow::Result)>> { + if let Some(batch_number) = storage + .via_votes_dal() + .get_first_not_finilized_block() + .await? + { + // Check if already created a voting inscription + let exists = storage + .via_verifier_block_dal() + .check_vote_l1_batch_inscription_request_if_exists(batch_number) + .await?; + if exists { + return Ok(None); + } + + if let Some((vote, tx_id)) = storage + .via_votes_dal() + .get_verifier_vote_status(batch_number) + .await? + { + return Ok(Some(( + L1BatchNumber::from(batch_number as u32), + vote, + tx_id, + ))); + } + } + Ok(None) + } + + pub fn construct_voting_inscription_message( + &self, + vote: bool, + tx_id: Vec, + ) -> anyhow::Result { + let mut attestation = Vote::NotOk; + + if vote { + attestation = Vote::Ok; + } + let input = ValidatorAttestationInput { + reference_txid: Txid::from_slice(&tx_id)?, + attestation, + }; + return Ok(InscriptionMessage::ValidatorAttestation(input)); + } +} diff --git a/core/node/via_btc_sender/src/lib.rs b/core/node/via_btc_sender/src/lib.rs index 67fbb4ab6..34c3cef36 100644 --- a/core/node/via_btc_sender/src/lib.rs +++ b/core/node/via_btc_sender/src/lib.rs @@ -2,6 +2,7 @@ mod aggregated_operations; pub mod aggregator; pub mod btc_inscription_aggregator; pub mod btc_inscription_manager; +pub mod btc_vote_inscription; mod config; mod publish_criterion; #[cfg(test)] From 043cbdb0899c26ccc44d09abc4da0389b846e773 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:41:12 +0100 Subject: [PATCH 063/212] test(btc_sender): fix btc sender tests and add new vote inscripion tests --- .../src/tests/aggregator_test.rs | 5 +- .../tests/btc_inscription_aggregator_test.rs | 28 +- .../src/tests/btc_inscription_manager_test.rs | 45 ++- core/node/via_btc_sender/src/tests/mod.rs | 1 + core/node/via_btc_sender/src/tests/utils.rs | 48 ++- .../src/tests/vote_inscription_test.rs | 381 ++++++++++++++++++ 6 files changed, 487 insertions(+), 21 deletions(-) create mode 100644 core/node/via_btc_sender/src/tests/vote_inscription_test.rs diff --git a/core/node/via_btc_sender/src/tests/aggregator_test.rs b/core/node/via_btc_sender/src/tests/aggregator_test.rs index 96d53d98d..a0d713106 100644 --- a/core/node/via_btc_sender/src/tests/aggregator_test.rs +++ b/core/node/via_btc_sender/src/tests/aggregator_test.rs @@ -4,14 +4,15 @@ mod tests { use via_btc_client::{traits::Serializable, types::InscriptionMessage}; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, Core, CoreDal}; - use zksync_node_test_utils::{create_l1_batch, l1_batch_metadata_to_commitment_artifacts}; + use zksync_node_test_utils::l1_batch_metadata_to_commitment_artifacts; use zksync_types::{ btc_block::ViaBtcL1BlockDetails, btc_inscription_operations::ViaBtcInscriptionRequestType, ProtocolVersionId, }; use crate::tests::utils::{ - default_l1_batch_metadata, generate_random_bytes, get_btc_sender_config, ViaAggregatorTest, + create_l1_batch, default_l1_batch_metadata, generate_random_bytes, get_btc_sender_config, + ViaAggregatorTest, }; // Get the current operation (commitBatch or commitProof) to execute when there is no batches. Should return 'None' diff --git a/core/node/via_btc_sender/src/tests/btc_inscription_aggregator_test.rs b/core/node/via_btc_sender/src/tests/btc_inscription_aggregator_test.rs index bc70ce1b8..ab59d2533 100644 --- a/core/node/via_btc_sender/src/tests/btc_inscription_aggregator_test.rs +++ b/core/node/via_btc_sender/src/tests/btc_inscription_aggregator_test.rs @@ -2,19 +2,21 @@ mod tests { use std::str::FromStr; + use chrono::Utc; use tokio::{sync::watch, time}; use zksync_config::ViaBtcSenderConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, Core, CoreDal}; - use zksync_node_test_utils::{create_l1_batch, l1_batch_metadata_to_commitment_artifacts}; + use zksync_node_test_utils::l1_batch_metadata_to_commitment_artifacts; use zksync_types::{ block::L1BatchHeader, btc_inscription_operations::ViaBtcInscriptionRequestType, btc_sender::ViaBtcInscriptionRequest, ProtocolVersionId, H256, }; use crate::tests::utils::{ - default_l1_batch_metadata, get_btc_sender_config, get_inscription_aggregator_mock, - ViaAggregatorTest, + create_l1_batch, default_l1_batch_metadata, get_btc_sender_config, + get_inscription_aggregator_mock, ViaAggregatorTest, BOOTLOADER_CODE_HASH_TEST, + DEFAULT_AA_CODE_HASH_TEST, }; #[tokio::test] @@ -55,6 +57,19 @@ mod tests { l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), ) .await; + let sent_at = Utc::now().naive_utc(); + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_l1_batch_da(header.number, "blob_id", sent_at) + .await; + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_proof_da(header.number, "blob_id", sent_at) + .await; } // ----------------------------------------- EXECTION 1 ----------------------------------------- @@ -96,7 +111,7 @@ mod tests { assert_eq!(inscription_request_list.len(), 1); assert_eq!( inscription_request_list[0].request_type, - ViaBtcInscriptionRequestType::CommitProofOnchain + ViaBtcInscriptionRequestType::CommitProofOnchain.to_string() ); // We confirm that the proof inscription was processed. @@ -223,11 +238,10 @@ mod tests { } pub fn via_create_l1_batch(number: u32) -> L1BatchHeader { - let hex_str = "0000000000000000000000000000000000000000000000000000000000000000"; let mut header = create_l1_batch(number); header.base_system_contracts_hashes = BaseSystemContractsHashes { - bootloader: H256::from_str(hex_str).unwrap(), - default_aa: H256::from_str(hex_str).unwrap(), + bootloader: H256::from_str(BOOTLOADER_CODE_HASH_TEST).unwrap(), + default_aa: H256::from_str(DEFAULT_AA_CODE_HASH_TEST).unwrap(), }; header.protocol_version = Some(ProtocolVersionId::latest()); diff --git a/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs b/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs index 95ef5880b..1ef829a78 100644 --- a/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs +++ b/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs @@ -2,20 +2,22 @@ mod tests { use std::str::FromStr; + use chrono::Utc; use tokio::{sync::watch, time}; use via_btc_client::inscriber::test_utils::MockBitcoinOpsConfig; use zksync_config::ViaBtcSenderConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, Core, CoreDal}; - use zksync_node_test_utils::{create_l1_batch, l1_batch_metadata_to_commitment_artifacts}; + use zksync_node_test_utils::l1_batch_metadata_to_commitment_artifacts; use zksync_types::{ block::L1BatchHeader, btc_inscription_operations::ViaBtcInscriptionRequestType, ProtocolVersionId, H256, }; use crate::tests::utils::{ - default_l1_batch_metadata, get_btc_sender_config, get_inscription_aggregator_mock, - get_inscription_manager_mock, ViaAggregatorTest, + create_l1_batch, default_l1_batch_metadata, get_btc_sender_config, + get_inscription_aggregator_mock, get_inscription_manager_mock, ViaAggregatorTest, + BOOTLOADER_CODE_HASH_TEST, DEFAULT_AA_CODE_HASH_TEST, }; #[tokio::test] @@ -64,6 +66,20 @@ mod tests { l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), ) .await; + + let sent_at = Utc::now().naive_utc(); + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_l1_batch_da(header.number, "blob_id", sent_at) + .await; + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_proof_da(header.number, "blob_id", sent_at) + .await; } run_aggregator(pool.clone(), config.clone()).await; @@ -175,6 +191,20 @@ mod tests { l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), ) .await; + + let sent_at = Utc::now().naive_utc(); + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_l1_batch_da(header.number, "blob_id", sent_at) + .await; + + let _ = aggregator_test + .storage + .via_data_availability_dal() + .insert_proof_da(header.number, "blob_id", sent_at) + .await; } run_aggregator(pool.clone(), config.clone()).await; @@ -203,7 +233,7 @@ mod tests { .is_none()); assert_eq!( inflight_inscriptions[0].request_type, - ViaBtcInscriptionRequestType::CommitL1BatchOnchain + ViaBtcInscriptionRequestType::CommitL1BatchOnchain.to_string() ); // Start the manager @@ -246,7 +276,7 @@ mod tests { .is_none()); assert_eq!( inflight_inscriptions[0].request_type, - ViaBtcInscriptionRequestType::CommitProofOnchain + ViaBtcInscriptionRequestType::CommitProofOnchain.to_string() ); } @@ -314,11 +344,10 @@ mod tests { } pub fn via_create_l1_batch(number: u32) -> L1BatchHeader { - let hex_str = "0000000000000000000000000000000000000000000000000000000000000000"; let mut header = create_l1_batch(number); header.base_system_contracts_hashes = BaseSystemContractsHashes { - bootloader: H256::from_str(hex_str).unwrap(), - default_aa: H256::from_str(hex_str).unwrap(), + bootloader: H256::from_str(BOOTLOADER_CODE_HASH_TEST).unwrap(), + default_aa: H256::from_str(DEFAULT_AA_CODE_HASH_TEST).unwrap(), }; header.protocol_version = Some(ProtocolVersionId::latest()); diff --git a/core/node/via_btc_sender/src/tests/mod.rs b/core/node/via_btc_sender/src/tests/mod.rs index 786877161..471ef77a0 100644 --- a/core/node/via_btc_sender/src/tests/mod.rs +++ b/core/node/via_btc_sender/src/tests/mod.rs @@ -4,3 +4,4 @@ mod btc_inscription_manager_test; mod publish_criterion_test; #[cfg(test)] mod utils; +mod vote_inscription_test; diff --git a/core/node/via_btc_sender/src/tests/utils.rs b/core/node/via_btc_sender/src/tests/utils.rs index cd66a9920..bbf02b235 100644 --- a/core/node/via_btc_sender/src/tests/utils.rs +++ b/core/node/via_btc_sender/src/tests/utils.rs @@ -19,8 +19,9 @@ use zksync_types::{ btc_block::ViaBtcL1BlockDetails, btc_inscription_operations::ViaBtcInscriptionRequestType, commitment::{L1BatchCommitmentArtifacts, L1BatchMetaParameters, L1BatchMetadata}, + l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, - L1BatchNumber, ProtocolVersion, ProtocolVersionId, H256, + L1BatchNumber, ProtocolVersion, ProtocolVersionId, H160, H256, }; use crate::{ @@ -29,6 +30,11 @@ use crate::{ btc_inscription_manager::ViaBtcInscriptionManager, }; +pub const BOOTLOADER_CODE_HASH_TEST: &str = + "010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e"; +pub const DEFAULT_AA_CODE_HASH_TEST: &str = + "01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32"; + pub fn generate_random_bytes(length: usize) -> Vec { let mut bytes: Vec = vec![]; for _ in 0..length { @@ -38,6 +44,33 @@ pub fn generate_random_bytes(length: usize) -> Vec { bytes } +/// Creates an L1 batch header with the specified number and deterministic contents. +pub fn create_l1_batch(number: u32) -> L1BatchHeader { + let mut header = L1BatchHeader::new( + L1BatchNumber(number), + number.into(), + BaseSystemContractsHashes { + bootloader: H256::from_str(BOOTLOADER_CODE_HASH_TEST).unwrap(), + default_aa: H256::from_str(DEFAULT_AA_CODE_HASH_TEST).unwrap(), + }, + ProtocolVersionId::latest(), + ); + header.l1_tx_count = 3; + header.l2_tx_count = 5; + header.l2_to_l1_logs.push(UserL2ToL1Log(L2ToL1Log { + shard_id: 0, + is_service: false, + tx_number_in_block: 2, + sender: H160::random(), + key: H256::repeat_byte(3), + value: H256::zero(), + })); + header.l2_to_l1_messages.push(vec![22; 22]); + header.l2_to_l1_messages.push(vec![33; 33]); + + header +} + pub fn default_l1_batch_metadata() -> L1BatchMetadata { let hex_str = "0000000000000000000000000000000000000000000000000000000000000000"; L1BatchMetadata { @@ -49,8 +82,8 @@ pub fn default_l1_batch_metadata() -> L1BatchMetadata { l2_l1_merkle_root: H256::default(), block_meta_params: L1BatchMetaParameters { zkporter_is_available: false, - bootloader_code_hash: H256::from_str(hex_str).unwrap(), - default_aa_code_hash: H256::from_str(hex_str).unwrap(), + bootloader_code_hash: H256::from_str(BOOTLOADER_CODE_HASH_TEST).unwrap(), + default_aa_code_hash: H256::from_str(DEFAULT_AA_CODE_HASH_TEST).unwrap(), protocol_version: Some(ProtocolVersionId::latest()), }, aux_data_hash: H256::default(), @@ -239,7 +272,7 @@ impl ViaAggregatorTest { .storage .btc_sender_dal() .via_save_btc_inscriptions_request( - ViaBtcInscriptionRequestType::CommitL1BatchOnchain, + ViaBtcInscriptionRequestType::CommitL1BatchOnchain.to_string(), InscriptionMessage::to_bytes(&inscription_message), 0, ) @@ -271,6 +304,13 @@ impl ViaAggregatorTest { ) .await .unwrap(); + let sent_at = Utc::now().naive_utc(); + + let _ = self + .storage + .via_data_availability_dal() + .insert_proof_da(batch.number, "blob_id", sent_at) + .await; (inscription.id, inscription_request_history_id as i64) } diff --git a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs new file mode 100644 index 000000000..22319256c --- /dev/null +++ b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs @@ -0,0 +1,381 @@ +#[cfg(test)] +mod tests { + + use chrono::Utc; + use tokio::{sync::watch, time}; + use via_btc_client::{ + inscriber::test_utils::MockBitcoinOpsConfig, traits::Serializable, + types::InscriptionMessage, + }; + use zksync_config::ViaBtcSenderConfig; + use zksync_contracts::BaseSystemContractsHashes; + use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; + use zksync_node_test_utils::l1_batch_metadata_to_commitment_artifacts; + use zksync_types::{ + block::{L1BatchHeader, L1BatchTreeData}, + commitment::L1BatchCommitmentArtifacts, + protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, + L1BatchNumber, ProtocolVersionId, H256, + }; + + use crate::{ + btc_vote_inscription::ViaVoteInscription, + tests::utils::{ + create_l1_batch, default_l1_batch_metadata, generate_random_bytes, + get_btc_sender_config, get_inscription_manager_mock, + }, + }; + + pub struct ViaVoteInscriptionTest { + pub aggregator: ViaVoteInscription, + pub storage: Connection<'static, Core>, + } + + impl ViaVoteInscriptionTest { + pub async fn new( + protocol_version: ProtocolVersionId, + base_system_contracts_hashes: BaseSystemContractsHashes, + pool: ConnectionPool, + mut config: Option, + ) -> Self { + let mut storage = pool.connection().await.unwrap(); + + if config.is_none() { + config = Some(ViaBtcSenderConfig::for_tests()); + } + let aggregator = ViaVoteInscription::new(pool, config.unwrap()) + .await + .unwrap(); + + let timestamp = Utc::now().timestamp() as u64; + let protocol_version = zksync_types::ProtocolVersion { + l1_verifier_config: L1VerifierConfig { + recursion_scheduler_level_vk_hash: H256::random(), + }, + base_system_contracts_hashes, + timestamp, + tx: None, + version: ProtocolSemanticVersion { + minor: protocol_version, + patch: 0.into(), + }, + }; + + storage + .protocol_versions_dal() + .save_protocol_version_with_tx(&protocol_version) + .await + .unwrap(); + + Self { + aggregator, + storage, + } + } + + pub async fn insert_l1_batch( + &mut self, + header: L1BatchHeader, + l1_commitment_artifacts: L1BatchCommitmentArtifacts, + ) { + self.storage + .blocks_dal() + .insert_mock_l1_batch(&header) + .await + .unwrap(); + + self.storage + .blocks_dal() + .save_l1_batch_tree_data( + header.number, + &L1BatchTreeData { + hash: H256::random(), + rollup_last_leaf_index: 1, + }, + ) + .await + .unwrap(); + + self.storage + .blocks_dal() + .save_l1_batch_commitment_artifacts(header.number, &l1_commitment_artifacts) + .await + .unwrap(); + + let time = Utc::now().naive_utc(); + + self.storage + .via_data_availability_dal() + .insert_l1_batch_da(header.number, "blob_id", time) + .await + .expect("insert_l1_batch_da"); + + let random_slice: &[u8] = &generate_random_bytes(32); + + self.storage + .via_data_availability_dal() + .save_l1_batch_inclusion_data(header.number, random_slice) + .await + .expect("save_l1_batch_inclusion_data"); + } + } + + // Get the current operation (commitBatch or commitProof) to execute when there is no batches. Should return 'None' + #[tokio::test] + async fn test_get_next_ready_vote_operation() { + let pool = ConnectionPool::::test_pool().await; + let header = create_l1_batch(1); + let mut aggregator_test = ViaVoteInscriptionTest::new( + header.protocol_version.unwrap(), + header.base_system_contracts_hashes, + pool, + None, + ) + .await; + + aggregator_test + .insert_l1_batch( + header.clone(), + l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), + ) + .await; + + let tx_id = H256::random(); + let _ = aggregator_test + .storage + .via_votes_dal() + .insert_votable_transaction(1, tx_id) + .await; + + let op = aggregator_test + .aggregator + .get_voting_operation(&mut aggregator_test.storage) + .await + .unwrap(); + assert!(op.is_none()); + + let _ = aggregator_test + .storage + .via_votes_dal() + .verify_votable_transaction(1, tx_id, true) + .await; + + let op = aggregator_test + .aggregator + .get_voting_operation(&mut aggregator_test.storage) + .await + .unwrap(); + assert!(op.is_some()); + let (l1_block_number, vote, tx_id_vec) = op.unwrap(); + assert_eq!(l1_block_number, L1BatchNumber::from(1)); + assert_eq!(vote, true); + assert_eq!(H256::from_slice(&tx_id_vec), tx_id); + + let inscription = aggregator_test + .aggregator + .construct_voting_inscription_message(vote, tx_id_vec) + .unwrap(); + + aggregator_test + .aggregator + .loop_iteration(&mut aggregator_test.storage) + .await + .unwrap(); + + let inscriptions = aggregator_test + .storage + .btc_sender_dal() + .list_new_inscription_request(10) + .await + .unwrap(); + assert_eq!(inscriptions.len(), 1); + + assert_eq!( + InscriptionMessage::from_bytes( + inscriptions + .get(0) + .unwrap() + .inscription_message + .as_ref() + .unwrap() + ), + inscription + ); + } + + #[tokio::test] + async fn test_verifier_vote_inscription_manager() { + let pool = ConnectionPool::::test_pool().await; + let config = get_btc_sender_config(1, 1); + let mut mock_btc_ops_config = MockBitcoinOpsConfig::default(); + mock_btc_ops_config.set_block_height(1); + + let header = create_l1_batch(1); + let mut aggregator_test = ViaVoteInscriptionTest::new( + header.protocol_version.unwrap(), + header.base_system_contracts_hashes, + pool.clone(), + None, + ) + .await; + + aggregator_test + .insert_l1_batch( + header.clone(), + l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), + ) + .await; + let tx_id = H256::random(); + + let _ = aggregator_test + .storage + .via_votes_dal() + .insert_votable_transaction(1, tx_id) + .await; + + let _ = aggregator_test + .storage + .via_votes_dal() + .verify_votable_transaction(1, tx_id, true) + .await; + + run_aggregator(header, pool.clone()).await; + run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; + + let inflight_inscriptions_before = aggregator_test + .storage + .btc_sender_dal() + .get_inflight_inscriptions() + .await + .unwrap(); + + assert!(!inflight_inscriptions_before.is_empty()); + + let last_inscription_history_before = aggregator_test + .storage + .btc_sender_dal() + .get_last_inscription_request_history(inflight_inscriptions_before[0].id) + .await + .unwrap(); + + assert!(last_inscription_history_before.is_some()); + + // Simulate the transaction is stuck for 10 blocks + mock_btc_ops_config.set_block_height(10); + + // THis should create a new inscription_history + run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; + + let last_inscription_history_after = aggregator_test + .storage + .btc_sender_dal() + .get_last_inscription_request_history(inflight_inscriptions_before[0].id) + .await + .unwrap(); + + assert!(last_inscription_history_after.is_some()); + + assert_ne!( + last_inscription_history_after.unwrap().id, + last_inscription_history_before.unwrap().id + ); + + // Simulate the transaction was processed in next block + mock_btc_ops_config.set_block_height(11); + mock_btc_ops_config.set_tx_confirmation(true); + + run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; + + let inflight_inscriptions_after = aggregator_test + .storage + .btc_sender_dal() + .get_inflight_inscriptions() + .await + .unwrap(); + + assert!(inflight_inscriptions_after.is_empty()); + + let last_inscription_history_after = aggregator_test + .storage + .btc_sender_dal() + .get_last_inscription_request_history(inflight_inscriptions_before[0].id) + .await + .unwrap(); + + assert!(last_inscription_history_after + .unwrap() + .confirmed_at + .is_some()); + + // Run the manager to make sure there is no unexpected behavior + run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; + } + + async fn run_aggregator(header: L1BatchHeader, pool: ConnectionPool) { + { + // Create an async channel to break the while loop afer 3 seconds. + let (sender, receiver): (watch::Sender, watch::Receiver) = + watch::channel(false); + + let toggle_handler = tokio::spawn(async move { + let mut toggle = false; + + loop { + time::sleep(time::Duration::from_secs(3)).await; + toggle = !toggle; + if sender.send(toggle).is_err() { + break; + } + println!("Sent: {}", toggle); + } + }); + + let aggregator_test = ViaVoteInscriptionTest::new( + header.protocol_version.unwrap(), + header.base_system_contracts_hashes, + pool.clone(), + None, + ) + .await; + + aggregator_test.aggregator.run(receiver).await.unwrap(); + if let Err(e) = toggle_handler.await { + eprintln!("Toggle task failed: {:?}", e); + } + } + } + + async fn run_manager( + pool: ConnectionPool, + config: ViaBtcSenderConfig, + mock_btc_ops_config: MockBitcoinOpsConfig, + ) { + { + // Create an async channel to break the while loop afer 3 seconds. + let (sender, receiver): (watch::Sender, watch::Receiver) = + watch::channel(false); + + let toggle_handler = tokio::spawn(async move { + let mut toggle = false; + + loop { + time::sleep(time::Duration::from_secs(3)).await; + toggle = !toggle; + if sender.send(toggle).is_err() { + break; + } + println!("Sent: {}", toggle); + } + }); + + let inscription_manager_mock = + get_inscription_manager_mock(pool.clone(), config.clone(), mock_btc_ops_config) + .await; + + inscription_manager_mock.run(receiver).await.unwrap(); + if let Err(e) = toggle_handler.await { + eprintln!("Toggle task failed: {:?}", e); + } + } + } +} From 17de76d82b0bbb99842db764be6daad3089f5542 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:00:00 +0100 Subject: [PATCH 064/212] test(btc_sender): implement the vote inscription layer --- .../layers/via_btc_sender/mod.rs | 1 + .../layers/via_btc_sender/vote.rs | 69 +++++++++++++++++++ .../src/btc_vote_inscription.rs | 1 + 3 files changed, 71 insertions(+) create mode 100644 core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs diff --git a/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs b/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs index 6f0dc526e..c3bd700d1 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs @@ -1,2 +1,3 @@ pub mod aggregator; pub mod manager; +pub mod vote; diff --git a/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs new file mode 100644 index 000000000..fe75e8dc1 --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs @@ -0,0 +1,69 @@ +use via_btc_sender::btc_vote_inscription::ViaVoteInscription; +use zksync_config::ViaBtcSenderConfig; + +use crate::{ + implementations::resources::pools::{MasterPool, PoolResource}, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for btc_sender vote inscription +/// +/// Responsible for initialization and running of [`ViaVoteInscription`], that create `Vote` inscription requests +#[derive(Debug)] +pub struct ViaBtcVoteInscriptionLayer { + config: ViaBtcSenderConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + #[context(task)] + pub via_vote_inscription: ViaVoteInscription, +} + +impl ViaBtcVoteInscriptionLayer { + pub fn new(config: ViaBtcSenderConfig) -> Self { + Self { config } + } +} + +#[async_trait::async_trait] +impl WiringLayer for ViaBtcVoteInscriptionLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "via_btc_verifier_vote_inscription_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + // // Get resources. + let master_pool = input.master_pool.get().await.unwrap(); + + let via_vote_inscription = ViaVoteInscription::new(master_pool, self.config).await?; + + Ok(Output { + via_vote_inscription, + }) + } +} + +#[async_trait::async_trait] +impl Task for ViaVoteInscription { + fn id(&self) -> TaskId { + "via_vote_inscription".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/via_btc_sender/src/btc_vote_inscription.rs b/core/node/via_btc_sender/src/btc_vote_inscription.rs index eccecb361..c7531527c 100644 --- a/core/node/via_btc_sender/src/btc_vote_inscription.rs +++ b/core/node/via_btc_sender/src/btc_vote_inscription.rs @@ -11,6 +11,7 @@ use zksync_types::{ via_verifier_btc_inscription_operations::ViaVerifierBtcInscriptionRequestType, L1BatchNumber, }; +#[derive(Debug)] pub struct ViaVoteInscription { pool: ConnectionPool, config: ViaBtcSenderConfig, From aaf63824fa4c85c7cc42981843c2067edadd368a Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 09:53:54 +0330 Subject: [PATCH 065/212] add get_block_stats and get_fee_history to withdrawal builder mock --- .../via_btc_client/src/withdrawal_builder/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs index 9d5b34e59..dfba548e4 100644 --- a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs @@ -289,9 +289,9 @@ mod tests { use crate::types::BitcoinError; mock! { - BitcoinOps {} + BitcoinOpsService {} #[async_trait] - impl BitcoinOps for BitcoinOps { + impl BitcoinOps for BitcoinOpsService { async fn fetch_utxos(&self, _address: &Address) -> Result, BitcoinError> { // Mock implementation let txid = Txid::from_str( @@ -339,6 +339,14 @@ mod tests { async fn fetch_block_by_hash(&self, _hash: &bitcoin::BlockHash) -> Result { Ok(bitcoin::Block::default()) } + + async fn get_block_stats(&self, _height: u64) -> Result { + todo!() + } + + async fn get_fee_history(&self, _start: usize, _end: usize) -> Result, BitcoinError> { + Ok(vec![1]) + } } } @@ -350,7 +358,7 @@ mod tests { .require_network(network)?; // Create mock and set expectations - let mut mock_ops = MockBitcoinOps::new(); + let mut mock_ops = MockBitcoinOpsService::new(); mock_ops.expect_fetch_utxos().returning(|_| { let txid = Txid::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") From 7de32377f6e33cea93418f2eabe1849409f8a094 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 10:02:03 +0330 Subject: [PATCH 066/212] fix clippy warning in via_withdrawal_client --- core/lib/via_withdrawal_client/src/client.rs | 13 ++++++------- core/lib/via_withdrawal_client/src/pubdata.rs | 4 ++-- core/lib/via_withdrawal_client/src/types.rs | 1 + core/lib/via_withdrawal_client/src/withdraw.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/lib/via_withdrawal_client/src/client.rs b/core/lib/via_withdrawal_client/src/client.rs index bb7faf95c..18b78a58b 100644 --- a/core/lib/via_withdrawal_client/src/client.rs +++ b/core/lib/via_withdrawal_client/src/client.rs @@ -38,7 +38,7 @@ impl WithdrawalClient { fn l2_to_l1_messages_hashmap(pubdata: &Pubdata) -> HashMap> { let mut hashes: HashMap> = HashMap::new(); for message in &pubdata.l2_to_l1_messages { - let hash = H256::from(keccak256(&message)); + let hash = H256::from(keccak256(message)); hashes.insert(hash, message.clone()); } hashes @@ -48,7 +48,7 @@ impl WithdrawalClient { let mut withdrawals: Vec = Vec::new(); let l2_bridges_hash = H256::from(H160::from_str(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR).unwrap()); - let l2_to_l1_messages_hashmap = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); + let l2_to_l1_messages_hashmap = WithdrawalClient::l2_to_l1_messages_hashmap(pubdata); for log in pubdata.user_logs.clone() { // Ignore the logs if not from emitted from the L2 bridge contract if log.key != l2_bridges_hash { @@ -70,9 +70,8 @@ impl WithdrawalClient { for l2_bridge_log_metadata in l2_bridge_logs_metadata { let withdrawal_request = parse_l2_withdrawal_message(l2_bridge_log_metadata.message); - match withdrawal_request { - Ok(req) => withdrawal_requests.push(req), - Err(_) => (), + if let Ok(req) = withdrawal_request { + withdrawal_requests.push(req) } } withdrawal_requests @@ -95,7 +94,7 @@ mod tests { let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); - let hash = H256::from(pubdata.user_logs[0].value); + let hash = pubdata.user_logs[0].value; assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); } @@ -106,7 +105,7 @@ mod tests { let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); - let hash = H256::from(pubdata.user_logs[0].value); + let hash = pubdata.user_logs[0].value; assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); let l2_bridge_logs_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); diff --git a/core/lib/via_withdrawal_client/src/pubdata.rs b/core/lib/via_withdrawal_client/src/pubdata.rs index edca0e48e..d3f01ad75 100644 --- a/core/lib/via_withdrawal_client/src/pubdata.rs +++ b/core/lib/via_withdrawal_client/src/pubdata.rs @@ -66,6 +66,7 @@ impl Pubdata { } /// Helper function to read a specific number of bytes +#[allow(unused)] fn read_bytes(reader: &mut R, num_bytes: usize) -> anyhow::Result> { let mut buffer = vec![0u8; num_bytes]; reader.read_exact(&mut buffer)?; @@ -77,7 +78,6 @@ mod tests { use std::str::FromStr; use hex::encode; - use rand; use zksync_types::{web3::keccak256, Address, H256}; use super::*; @@ -165,7 +165,7 @@ mod tests { let pubdata = Pubdata { user_logs: user_logs.clone(), - l2_to_l1_messages: l2_to_l1_messages, + l2_to_l1_messages, }; let encoded_pubdata = pubdata.encode_pubdata(); diff --git a/core/lib/via_withdrawal_client/src/types.rs b/core/lib/via_withdrawal_client/src/types.rs index 514980156..44a8358c5 100644 --- a/core/lib/via_withdrawal_client/src/types.rs +++ b/core/lib/via_withdrawal_client/src/types.rs @@ -13,6 +13,7 @@ pub const WITHDRAW_FUNC_SIG: &str = "finalizeEthWithdrawal(uint256,uint256,uint1 pub const L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR: &str = "000000000000000000000000000000000000800a"; #[derive(Clone, Debug, Default)] +#[allow(unused)] pub struct L2BridgeLogMetadata { pub log: L1MessengerL2ToL1Log, pub message: Vec, diff --git a/core/lib/via_withdrawal_client/src/withdraw.rs b/core/lib/via_withdrawal_client/src/withdraw.rs index 420927ac0..7ff68b761 100644 --- a/core/lib/via_withdrawal_client/src/withdraw.rs +++ b/core/lib/via_withdrawal_client/src/withdraw.rs @@ -32,7 +32,7 @@ pub fn parse_l2_withdrawal_message(l2_to_l1_message: Vec) -> anyhow::Result< let amount_bytes = &l2_to_l1_message[address_size + 4..]; let amount = U256::from_big_endian(amount_bytes); - return Ok(WithdrawalRequest { address, amount }); + Ok(WithdrawalRequest { address, amount }) } /// Get the withdrawal function selector. @@ -52,7 +52,7 @@ mod tests { // Example transaction: https://etherscan.io/tx/0x70afe07734e9b0c2d8393ab2a51fda5ac2cfccc80a01cc4a5cf587eaea3c4610 let l2_to_l1_message = hex::decode("6c0960f96263317179383267617732687466643573736c706c70676d7a346b74663979336b37706163323232366b30776c6a6c6d7733617466773571776d346176340000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); let expected_receiver = BitcoinAddress::from_str( - &"bc1qy82gaw2htfd5sslplpgmz4ktf9y3k7pac2226k0wljlmw3atfw5qwm4av4", + "bc1qy82gaw2htfd5sslplpgmz4ktf9y3k7pac2226k0wljlmw3atfw5qwm4av4", ) .unwrap(); let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); @@ -66,7 +66,7 @@ mod tests { fn test_parse_l2_withdrawal_message_when_address_p2pkh() { let l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); let expected_receiver = - BitcoinAddress::from_str(&"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap(); + BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap(); let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); let res = parse_l2_withdrawal_message(l2_to_l1_message).unwrap(); From cd7967961bdcc769d6d9249c3e29d7d3341c5847 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 10:04:48 +0330 Subject: [PATCH 067/212] fix clippy warning in via_fee_model --- .../src/l1_gas_price/gas_adjuster/mod.rs | 3 +-- core/node/via_fee_model/src/lib.rs | 15 +++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs b/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs index cd51b8876..af9582c15 100644 --- a/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs +++ b/core/node/via_fee_model/src/l1_gas_price/gas_adjuster/mod.rs @@ -129,8 +129,7 @@ impl ViaGasAdjuster { } fn get_base_fee(&self) -> u64 { - let median = self.base_fee_statistics.median(); - median + self.base_fee_statistics.median() } fn get_priority_fee(&self) -> u64 { diff --git a/core/node/via_fee_model/src/lib.rs b/core/node/via_fee_model/src/lib.rs index 7b06e7917..b36744036 100644 --- a/core/node/via_fee_model/src/lib.rs +++ b/core/node/via_fee_model/src/lib.rs @@ -4,16 +4,11 @@ use anyhow::Context; use async_trait::async_trait; pub use l1_gas_price::gas_adjuster::ViaGasAdjuster; use zksync_dal::{ConnectionPool, Core, CoreDal}; -use zksync_node_fee_model::BaseTokenRatioProvider; pub use zksync_node_fee_model::BatchFeeModelInputProvider; -use zksync_types::{ - fee_model::{ - BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, - FeeParamsV2, PubdataIndependentBatchFeeModelInput, - }, - U256, +use zksync_types::fee_model::{ + BaseTokenConversionRatio, BatchFeeInput, FeeModelConfig, FeeModelConfigV2, FeeParams, + FeeParamsV2, PubdataIndependentBatchFeeModelInput, }; -use zksync_utils::ceil_div_u256; mod l1_gas_price; @@ -135,7 +130,7 @@ fn compute_batch_fee_model_input( let l1_pubdata_price = (l1_pubdata_price as f64 * l1_pubdata_price_scale_factor) as u64; // Todo: rename "batch_overhead_l1_gas" to "total_inscription_gas_vbyte" - let inscriptions_cost_satoshi = (config.batch_overhead_l1_gas * l1_gas_price) as u64; + let inscriptions_cost_satoshi = config.batch_overhead_l1_gas * l1_gas_price; // Scale the inscriptions_cost_satoshi to 18 decimals let gas_price_satoshi = inscriptions_cost_satoshi * 10_000_000_000 / config.max_gas_per_batch; // The "minimal_l2_gas_price" calculated from the operational cost to publish and verify block. @@ -143,7 +138,7 @@ fn compute_batch_fee_model_input( PubdataIndependentBatchFeeModelInput { l1_gas_price, - fair_l2_gas_price: fair_l2_gas_price, + fair_l2_gas_price, fair_pubdata_price: l1_pubdata_price, } } From 50825a7f0beaf8107ff9d1f955bc09c4efaef0ed Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 10:05:51 +0330 Subject: [PATCH 068/212] fix clippy warning in via_btc_watch --- core/node/via_btc_watch/src/message_processors/votable.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 4b5b2f21f..33f73ac59 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -34,13 +34,13 @@ impl MessageProcessor for VotableMessageProcessor { // Get the current timestamp let dt = Utc::now(); let naive_utc = dt.naive_utc(); - let offset = dt.offset().clone(); + let offset = *dt.offset(); let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); for msg in msgs { match msg { ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { let mut votes_dal = storage.via_votes_dal(); let last_inserted_block = votes_dal @@ -93,7 +93,7 @@ impl MessageProcessor for VotableMessageProcessor { } } ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { let mut votes_dal = storage.via_votes_dal(); let reference_txid = From 93b44f7ac050f2f782aa965136ffaf28e91119ed Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 10:06:30 +0330 Subject: [PATCH 069/212] fix clippy warning in via_btc_client --- core/lib/via_btc_client/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/via_btc_client/src/client/mod.rs b/core/lib/via_btc_client/src/client/mod.rs index 8ecacb82c..b6bc24e5f 100644 --- a/core/lib/via_btc_client/src/client/mod.rs +++ b/core/lib/via_btc_client/src/client/mod.rs @@ -1,4 +1,4 @@ -use std::{sync::Arc, u64}; +use std::sync::Arc; use async_trait::async_trait; use bitcoin::{Address, Block, BlockHash, Network, OutPoint, Transaction, TxOut, Txid}; From afc8570eb488f0015a47f1b9a2c312c30c6934f9 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 10:17:16 +0330 Subject: [PATCH 070/212] fix clippy warning in via related lib --- core/lib/dal/src/via_data_availability_dal.rs | 2 +- core/lib/dal/src/via_votes_dal.rs | 6 +++--- .../examples/zksync-era-verification-cli/contract.rs | 4 ++-- core/lib/via_verification/src/crypto.rs | 3 +++ core/lib/via_withdrawal_client/examples/withdraw.rs | 3 +-- core/lib/via_withdrawal_client/src/client.rs | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/lib/dal/src/via_data_availability_dal.rs b/core/lib/dal/src/via_data_availability_dal.rs index c88dba05b..f806981b1 100644 --- a/core/lib/dal/src/via_data_availability_dal.rs +++ b/core/lib/dal/src/via_data_availability_dal.rs @@ -476,7 +476,7 @@ impl ViaDataAvailabilityDal<'_, '_> { LIMIT 1 "#, - l1_batch_number.0 as i64 + i64::from(l1_batch_number.0) ) .instrument("get_da_blob") .fetch_optional(self.storage) diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 18a346544..e5f63ce50 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -23,7 +23,7 @@ impl ViaVotesDal<'_, '_> { ($1, $2) ON CONFLICT (l1_batch_number, tx_id) DO NOTHING "#, - l1_batch_number as i64, + i64::from(l1_batch_number), tx_id.as_bytes() ) .instrument("insert_votable_transaction") @@ -114,7 +114,7 @@ impl ViaVotesDal<'_, '_> { l1_batch_number = $1 AND tx_id = $2 "#, - l1_batch_number as i64, + i64::from(l1_batch_number), tx_id.as_bytes() ) .instrument("check_if_already_finalized") @@ -139,7 +139,7 @@ impl ViaVotesDal<'_, '_> { l1_batch_number = $1 AND tx_id = $2 "#, - l1_batch_number as i64, + i64::from(l1_batch_number), tx_id.as_bytes() ) .instrument("finalize_transaction_if_needed") diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs index a045e626b..c1af64e25 100644 --- a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs @@ -96,12 +96,12 @@ impl L1DataFetcher for ContractConfig { let (mut proof, block_number) = fetch_proof_from_l1( batch_number, - &self.provider.url().to_string(), + self.provider.url().as_ref(), protocol_version_id, ) .await?; let batch_l1_data = - fetch_l1_commit_data(batch_number, &self.provider.url().to_string()).await?; + fetch_l1_commit_data(batch_number, self.provider.url().as_ref()).await?; let inputs = generate_inputs(&batch_l1_data); proof.proof.inputs = inputs.clone(); diff --git a/core/lib/via_verification/src/crypto.rs b/core/lib/via_verification/src/crypto.rs index f1f7a2104..4211fecdd 100644 --- a/core/lib/via_verification/src/crypto.rs +++ b/core/lib/via_verification/src/crypto.rs @@ -224,9 +224,12 @@ pub fn deserialize_proof>(mut proof: Vec) -> Proof(point: &E::G1Affine, mut buffer: &mut Vec) -> anyhow::Result<()> { let (x, y) = point.as_xy(); + #[allow(clippy::needless_borrows_for_generic_args)] x.into_repr() .write_be(&mut buffer) .expect("Failed to write x coordinate"); + + #[allow(clippy::needless_borrows_for_generic_args)] y.into_repr() .write_be(&mut buffer) .expect("Failed to write y coordinate"); diff --git a/core/lib/via_withdrawal_client/examples/withdraw.rs b/core/lib/via_withdrawal_client/examples/withdraw.rs index 4971eceba..036f10b58 100644 --- a/core/lib/via_withdrawal_client/examples/withdraw.rs +++ b/core/lib/via_withdrawal_client/examples/withdraw.rs @@ -1,7 +1,6 @@ use std::{env, str::FromStr}; use anyhow::{Context, Result}; -use dotenv; use tracing::info; use via_da_clients::celestia::client::CelestiaClient; use via_withdrawal_client::client::WithdrawalClient; @@ -50,7 +49,7 @@ async fn main() -> Result<()> { let da_config = ViaCelestiaConfig { api_node_url: String::from(DEFAULT_CELESTIA), - auth_token: String::from(celestia_auth_token), + auth_token: celestia_auth_token, blob_size_limit: 1973786, }; diff --git a/core/lib/via_withdrawal_client/src/client.rs b/core/lib/via_withdrawal_client/src/client.rs index 18b78a58b..5d1e47fa1 100644 --- a/core/lib/via_withdrawal_client/src/client.rs +++ b/core/lib/via_withdrawal_client/src/client.rs @@ -83,7 +83,7 @@ mod tests { use std::str::FromStr; use bitcoin::Address; - use zksync_types::{H256, U256}; + use zksync_types::U256; use super::*; @@ -127,7 +127,7 @@ mod tests { let pubdata = Pubdata::decode_pubdata(encoded_pubdata).unwrap(); let hashes = WithdrawalClient::l2_to_l1_messages_hashmap(&pubdata); - let hash = H256::from(pubdata.user_logs[0].value); + let hash = pubdata.user_logs[0].value; assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); let l2_bridge_logs_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); From 900302068a40db0ed3c8b4d2ec4e5775507b86c9 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 11:03:10 +0330 Subject: [PATCH 071/212] seperate via_verifier directory --- Cargo.lock | 1319 ++--------------- Cargo.toml | 18 +- core/lib/via_musig2/Cargo.toml | 48 - via_verifier/CHANGELOG.md | 8 + .../bin/verifier_server}/Cargo.toml | 0 .../bin/verifier_server}/src/config.rs | 0 .../bin/verifier_server}/src/main.rs | 0 .../bin/verifier_server}/src/node_builder.rs | 0 via_verifier/lib/via_musig2/Cargo.toml | 11 + .../lib/via_musig2/examples/coordinator.rs | 0 .../examples/key_generation_setup.rs | 0 .../lib/via_musig2/examples/withdrawal.rs | 0 .../lib/via_musig2/src/lib.rs | 0 .../lib/via_verification/Cargo.toml | 0 .../abis/IVerifier.json | 0 .../abis/IZkSync.json | 0 .../zksync-era-verification-cli/contract.rs | 0 .../zksync-era-verification-cli/fetching.rs | 0 .../zksync-era-verification-cli/main.rs | 0 .../zksync-era-verification-cli/types.rs | 0 .../protocol_version/24/scheduler_key.json | 0 .../protocol_version/25/scheduler_key.json | 0 .../lib/via_verification/src/crypto.rs | 0 .../lib/via_verification/src/errors.rs | 0 .../via_verification/src/l1_data_fetcher.rs | 0 .../lib/via_verification/src/lib.rs | 0 .../lib/via_verification/src/proof.rs | 0 .../lib/via_verification/src/public_inputs.rs | 0 .../lib/via_verification/src/types.rs | 0 .../lib/via_verification/src/utils.rs | 0 .../lib/via_verification/src/verification.rs | 0 .../lib/via_withdrawal_client/Cargo.toml | 0 .../examples/withdraw.rs | 0 .../lib/via_withdrawal_client/src/client.rs | 0 .../lib/via_withdrawal_client/src/lib.rs | 0 .../lib/via_withdrawal_client/src/pubdata.rs | 0 .../lib/via_withdrawal_client/src/types.rs | 0 .../lib/via_withdrawal_client/src/withdraw.rs | 0 via_verifier/rust-toolchain | 1 + 39 files changed, 118 insertions(+), 1287 deletions(-) delete mode 100644 core/lib/via_musig2/Cargo.toml create mode 100644 via_verifier/CHANGELOG.md rename {core/bin/via_verifier => via_verifier/bin/verifier_server}/Cargo.toml (100%) rename {core/bin/via_verifier => via_verifier/bin/verifier_server}/src/config.rs (100%) rename {core/bin/via_verifier => via_verifier/bin/verifier_server}/src/main.rs (100%) rename {core/bin/via_verifier => via_verifier/bin/verifier_server}/src/node_builder.rs (100%) create mode 100644 via_verifier/lib/via_musig2/Cargo.toml rename {core => via_verifier}/lib/via_musig2/examples/coordinator.rs (100%) rename {core => via_verifier}/lib/via_musig2/examples/key_generation_setup.rs (100%) rename {core => via_verifier}/lib/via_musig2/examples/withdrawal.rs (100%) rename {core => via_verifier}/lib/via_musig2/src/lib.rs (100%) rename {core => via_verifier}/lib/via_verification/Cargo.toml (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/contract.rs (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/main.rs (100%) rename {core => via_verifier}/lib/via_verification/examples/zksync-era-verification-cli/types.rs (100%) rename {core => via_verifier}/lib/via_verification/keys/protocol_version/24/scheduler_key.json (100%) rename {core => via_verifier}/lib/via_verification/keys/protocol_version/25/scheduler_key.json (100%) rename {core => via_verifier}/lib/via_verification/src/crypto.rs (100%) rename {core => via_verifier}/lib/via_verification/src/errors.rs (100%) rename {core => via_verifier}/lib/via_verification/src/l1_data_fetcher.rs (100%) rename {core => via_verifier}/lib/via_verification/src/lib.rs (100%) rename {core => via_verifier}/lib/via_verification/src/proof.rs (100%) rename {core => via_verifier}/lib/via_verification/src/public_inputs.rs (100%) rename {core => via_verifier}/lib/via_verification/src/types.rs (100%) rename {core => via_verifier}/lib/via_verification/src/utils.rs (100%) rename {core => via_verifier}/lib/via_verification/src/verification.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/Cargo.toml (100%) rename {core => via_verifier}/lib/via_withdrawal_client/examples/withdraw.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/src/client.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/src/lib.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/src/pubdata.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/src/types.rs (100%) rename {core => via_verifier}/lib/via_withdrawal_client/src/withdraw.rs (100%) create mode 100644 via_verifier/rust-toolchain diff --git a/Cargo.lock b/Cargo.lock index 3de3538a6..eb33ce89e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addchain" version = "0.2.0" @@ -51,7 +41,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -423,17 +413,6 @@ dependencies = [ "syn 2.0.76", ] -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures 0.3.30", - "pharos", - "rustc_version 0.4.0", -] - [[package]] name = "atoi" version = "2.0.0" @@ -460,18 +439,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "auto_impl" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" -dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "auto_impl" version = "1.2.0" @@ -516,38 +483,6 @@ dependencies = [ "paste", ] -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "tokio", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.9" @@ -555,7 +490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "bytes", "futures-util", "http 1.1.0", @@ -582,23 +517,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.5" @@ -665,22 +583,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "base58check" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" -dependencies = [ - "base58", - "sha2 0.8.2", -] - [[package]] name = "base58ck" version = "0.1.0" @@ -691,12 +593,6 @@ dependencies = [ "bitcoin_hashes", ] -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.1" @@ -721,12 +617,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bech32" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" - [[package]] name = "bech32" version = "0.11.0" @@ -872,7 +762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6" dependencies = [ "base58ck", - "bech32 0.11.0", + "bech32", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -967,16 +857,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "bitvec" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" -dependencies = [ - "either", - "radium 0.3.0", -] - [[package]] name = "bitvec" version = "1.0.1" @@ -984,7 +864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", - "radium 0.7.0", + "radium", "tap", "wyz", ] @@ -997,7 +877,7 @@ checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ "crypto-mac", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug", ] [[package]] @@ -1062,26 +942,14 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding 0.1.5", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding 0.2.1", - "generic-array 0.14.7", + "block-padding", + "generic-array", ] [[package]] @@ -1090,16 +958,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -1237,12 +1096,6 @@ dependencies = [ "syn_derive", ] -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -1270,12 +1123,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytecheck" version = "0.6.12" @@ -1367,20 +1214,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "cargo_metadata" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.23", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cast" version = "0.3.0" @@ -1478,7 +1311,7 @@ version = "0.4.0" source = "git+https://github.com/eigerco/lumina.git#f11959550851afb8c2062b30e38cc87242467cdc" dependencies = [ "base64 0.22.1", - "bech32 0.11.0", + "bech32", "blockstore", "bytes", "celestia-proto", @@ -1622,19 +1455,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "circuit_definitions" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "circuit_encodings 0.150.16", - "crossbeam 0.8.4", - "derivative", - "seq-macro", - "serde", - "snark_wrapper", -] - [[package]] name = "circuit_encodings" version = "0.140.1" @@ -1683,17 +1503,6 @@ dependencies = [ "zkevm_circuits 0.150.4", ] -[[package]] -name = "circuit_encodings" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "derivative", - "serde", - "zk_evm 0.150.16", - "zkevm_circuits 0.150.16", -] - [[package]] name = "circuit_sequencer_api" version = "0.133.0" @@ -1867,63 +1676,6 @@ dependencies = [ "indexmap 1.9.3", ] -[[package]] -name = "coins-bip32" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" -dependencies = [ - "bincode", - "bs58 0.4.0", - "coins-core", - "digest 0.10.7", - "getrandom", - "hmac", - "k256 0.11.6", - "lazy_static", - "serde", - "sha2 0.10.8", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" -dependencies = [ - "bitvec 0.17.4", - "coins-bip32", - "getrandom", - "hex", - "hmac", - "pbkdf2", - "rand 0.8.5", - "sha2 0.10.8", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" -dependencies = [ - "base58check", - "base64 0.12.3", - "bech32 0.7.3", - "blake2 0.10.6", - "digest 0.10.7", - "generic-array 0.14.7", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2 0.10.8", - "sha3 0.10.8", - "thiserror", -] - [[package]] name = "colorchoice" version = "1.0.2" @@ -2240,7 +1992,7 @@ dependencies = [ "crossterm_winapi", "libc", "mio 0.8.11", - "parking_lot 0.12.3", + "parking_lot", "signal-hook", "signal-hook-mio", "winapi", @@ -2267,7 +2019,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "subtle", "zeroize", @@ -2279,7 +2031,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "subtle", "zeroize", @@ -2291,7 +2043,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "typenum", ] @@ -2302,7 +2054,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.7", + "generic-array", "subtle", ] @@ -2432,7 +2184,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -2446,7 +2198,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -2482,7 +2234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid 1.10.0", + "uuid", ] [[package]] @@ -2527,17 +2279,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.76", -] - [[package]] name = "derive_more" version = "1.0.0-beta.6" @@ -2565,22 +2306,13 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -2595,12 +2327,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "dotenvy" version = "0.15.7" @@ -2715,7 +2441,7 @@ dependencies = [ "der 0.6.1", "digest 0.10.7", "ff 0.12.1", - "generic-array 0.14.7", + "generic-array", "group 0.12.1", "pkcs8 0.9.0", "rand_core 0.6.4", @@ -2734,7 +2460,7 @@ dependencies = [ "crypto-bigint 0.5.5", "digest 0.10.7", "ff 0.13.0", - "generic-array 0.14.7", + "generic-array", "group 0.13.0", "pem-rfc7468", "pkcs8 0.10.2", @@ -2846,28 +2572,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest 0.10.7", - "hex", - "hmac", - "pbkdf2", - "rand 0.8.5", - "scrypt", - "serde", - "serde_json", - "sha2 0.10.8", - "sha3 0.10.8", - "thiserror", - "uuid 0.8.2", -] - [[package]] name = "ethabi" version = "18.0.0" @@ -2893,10 +2597,8 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", "fixed-hash", - "impl-codec", "impl-rlp", "impl-serde", - "scale-info", "tiny-keccak 2.0.2", ] @@ -2908,227 +2610,12 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ "ethbloom", "fixed-hash", - "impl-codec", "impl-rlp", "impl-serde", "primitive-types", - "scale-info", "uint", ] -[[package]] -name = "ethers" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f26f9d8d80da18ca72aca51804c65eb2153093af3bec74fd5ce32aa0c1f665" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", -] - -[[package]] -name = "ethers-addressbook" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4be54dd2260945d784e06ccdeb5ad573e8f1541838cee13a1ab885485eaa0b" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c3c3e119a89f0a9a1e539e7faecea815f74ddcf7c90d0b00d1f524db2fdc9c" -dependencies = [ - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "hex", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d4e5ad46aede34901f71afdb7bb555710ed9613d88d644245c657dc371aa228" -dependencies = [ - "Inflector", - "cfg-if 1.0.0", - "dunce", - "ethers-core", - "eyre", - "getrandom", - "hex", - "proc-macro2 1.0.86", - "quote 1.0.37", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 1.0.109", - "toml 0.5.11", - "url", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f192e8e4cf2b038318aae01e94e7644e0659a76219e94bcd3203df744341d61f" -dependencies = [ - "ethers-contract-abigen", - "ethers-core", - "hex", - "proc-macro2 1.0.86", - "quote 1.0.37", - "serde_json", - "syn 1.0.109", -] - -[[package]] -name = "ethers-core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" -dependencies = [ - "arrayvec 0.7.6", - "bytes", - "cargo_metadata 0.15.4", - "chrono", - "convert_case", - "elliptic-curve 0.12.3", - "ethabi", - "generic-array 0.14.7", - "hex", - "k256 0.11.6", - "once_cell", - "open-fastrlp", - "proc-macro2 1.0.86", - "rand 0.8.5", - "rlp", - "rlp-derive", - "serde", - "serde_json", - "strum 0.24.1", - "syn 1.0.109", - "thiserror", - "tiny-keccak 2.0.2", - "unicode-xid 0.2.5", -] - -[[package]] -name = "ethers-etherscan" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9713f525348e5dde025d09b0a4217429f8074e8ff22c886263cc191e87d8216" -dependencies = [ - "ethers-core", - "getrandom", - "reqwest 0.11.27", - "semver 1.0.23", - "serde", - "serde-aux", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e71df7391b0a9a51208ffb5c7f2d068900e99d6b3128d3a4849d138f194778b7" -dependencies = [ - "async-trait", - "auto_impl 0.5.0", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8" -dependencies = [ - "async-trait", - "auto_impl 1.2.0", - "base64 0.13.1", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "getrandom", - "hashers", - "hex", - "http 0.2.12", - "once_cell", - "parking_lot 0.11.2", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-timer", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f41ced186867f64773db2e55ffdd92959e094072a1d09a5e5e831d443204f98" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "elliptic-curve 0.12.3", - "eth-keystore", - "ethers-core", - "hex", - "rand 0.8.5", - "sha2 0.10.8", - "thiserror", -] - [[package]] name = "event-listener" version = "5.3.1" @@ -3147,14 +2634,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", - "once_cell", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + "once_cell", +] [[package]] name = "fastrand" @@ -3169,7 +2650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ "arrayvec 0.7.6", - "auto_impl 1.2.0", + "auto_impl", "bytes", ] @@ -3371,39 +2852,6 @@ dependencies = [ "tiny-keccak 1.5.0", ] -[[package]] -name = "franklin-crypto" -version = "0.30.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09876c8a2d5e706a8669f69d7db592ca9c48257cbfc4917fe32daf419a8ea78e" -dependencies = [ - "arr_macro", - "bit-vec", - "blake2 0.9.2", - "blake2-rfc_bellman_edition", - "blake2s_simd", - "boojum 0.30.9", - "byteorder", - "derivative", - "digest 0.9.0", - "hex", - "indexmap 1.9.3", - "itertools 0.10.5", - "lazy_static", - "num-bigint 0.4.6", - "num-derive 0.2.5", - "num-integer", - "num-traits", - "rand 0.4.6", - "serde", - "sha2 0.9.9", - "sha3 0.9.1", - "smallvec", - "splitmut", - "tiny-keccak 1.5.0", - "zksync_bellman", -] - [[package]] name = "fs_extra" version = "1.3.0" @@ -3479,7 +2927,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.3", + "parking_lot", ] [[package]] @@ -3488,16 +2936,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - [[package]] name = "futures-macro" version = "0.3.30" @@ -3528,7 +2966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", - "send_wrapper 0.4.0", + "send_wrapper", ] [[package]] @@ -3568,15 +3006,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -3631,7 +3060,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.1", + "opaque-debug", "polyval", ] @@ -3779,7 +3208,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.3", + "parking_lot", "quanta", "rand 0.8.5", "smallvec", @@ -3894,15 +3323,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - [[package]] name = "hashlink" version = "0.9.1" @@ -3921,12 +3341,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -4120,20 +3534,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.30", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.2" @@ -4145,10 +3545,10 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "log", - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tower-service", ] @@ -4343,7 +3743,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -4376,18 +3776,6 @@ dependencies = [ "similar", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -4528,13 +3916,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.23.2", "pin-project", - "rustls 0.23.12", + "rustls", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tokio-util", "tracing", "url", @@ -4551,13 +3939,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.24.3", "pin-project", - "rustls 0.23.12", + "rustls", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tokio-util", "tracing", "url", @@ -4579,7 +3967,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "jsonrpsee-types 0.23.2", - "parking_lot 0.12.3", + "parking_lot", "pin-project", "rand 0.8.5", "rustc-hash 1.1.0", @@ -4626,11 +4014,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls", "hyper-util", "jsonrpsee-core 0.23.2", "jsonrpsee-types 0.23.2", - "rustls 0.23.12", + "rustls", "rustls-platform-verifier", "serde", "serde_json", @@ -4651,11 +4039,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls", "hyper-util", "jsonrpsee-core 0.24.3", "jsonrpsee-types 0.24.3", - "rustls 0.23.12", + "rustls", "rustls-platform-verifier", "serde", "serde_json", @@ -4807,7 +4195,6 @@ dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", "sha2 0.10.8", - "sha3 0.10.8", ] [[package]] @@ -4893,7 +4280,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ - "bs58 0.5.1", + "bs58", "hkdf", "multihash", "quick-protobuf", @@ -5634,43 +5021,12 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec 0.7.6", - "auto_impl 1.2.0", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "openssl" version = "0.10.66" @@ -5877,7 +5233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.6", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", @@ -5902,17 +5258,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -5920,21 +5265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -5950,35 +5281,12 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac", - "password-hash", - "sha2 0.10.8", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -6065,16 +5373,6 @@ dependencies = [ "indexmap 2.6.0", ] -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures 0.3.30", - "rustc_version 0.4.0", -] - [[package]] name = "pin-project" version = "1.1.5" @@ -6179,7 +5477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug", "universal-hash", ] @@ -6191,7 +5489,7 @@ checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug", "universal-hash", ] @@ -6275,7 +5573,6 @@ dependencies = [ "impl-codec", "impl-rlp", "impl-serde", - "scale-info", "uint", ] @@ -6354,7 +5651,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot", "prometheus-client-derive-encode", ] @@ -6584,12 +5881,6 @@ dependencies = [ "proc-macro2 1.0.86", ] -[[package]] -name = "radium" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" - [[package]] name = "radium" version = "0.7.0" @@ -6710,15 +6001,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -6805,7 +6087,6 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -6815,7 +6096,6 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -6824,13 +6104,11 @@ dependencies = [ "system-configuration 0.5.1", "tokio", "tokio-native-tls", - "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.4", "winreg", ] @@ -6851,7 +6129,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -6906,31 +6184,7 @@ dependencies = [ "arrayvec 0.7.6", "blake2 0.10.6", "byteorder", - "franklin-crypto 0.1.0", - "num-bigint 0.3.3", - "num-integer", - "num-iter", - "num-traits", - "rand 0.4.6", - "serde", - "sha3 0.9.1", - "smallvec", -] - -[[package]] -name = "rescue_poseidon" -version = "0.30.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def7c91dcd919a62ca93bff4d67f710f8ae099e2639458fc5e3862f5812491a3" -dependencies = [ - "addchain", - "arrayvec 0.7.6", - "blake2 0.10.6", - "byteorder", - "derivative", - "franklin-crypto 0.30.9", - "lazy_static", - "log", + "franklin-crypto", "num-bigint 0.3.3", "num-integer", "num-iter", @@ -6939,7 +6193,6 @@ dependencies = [ "serde", "sha3 0.9.1", "smallvec", - "typemap_rev", ] [[package]] @@ -6978,22 +6231,13 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "rkyv" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ - "bitvec 1.0.1", + "bitvec", "bytecheck", "bytes", "hashbrown 0.12.3", @@ -7002,7 +6246,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid 1.10.0", + "uuid", ] [[package]] @@ -7026,17 +6270,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "rocksdb" version = "0.21.0" @@ -7174,18 +6407,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.12" @@ -7197,7 +6418,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki", "subtle", "zeroize", ] @@ -7251,13 +6472,13 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.12", + "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.102.7", + "rustls-webpki", "security-framework", "security-framework-sys", - "webpki-roots 0.26.3", + "webpki-roots", "winapi", ] @@ -7267,16 +6488,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.102.7" @@ -7301,15 +6512,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - [[package]] name = "same-file" version = "1.0.6" @@ -7319,66 +6521,20 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scale-info" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" -dependencies = [ - "cfg-if 1.0.0", - "derive_more 0.99.18", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" -dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.76", -] - [[package]] name = "schannel" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2", - "salsa20", - "sha2 0.10.8", +dependencies = [ + "windows-sys 0.52.0", ] [[package]] -name = "sct" -version = "0.7.1" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seahash" @@ -7394,7 +6550,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct 0.1.1", "der 0.6.1", - "generic-array 0.14.7", + "generic-array", "pkcs8 0.9.0", "subtle", "zeroize", @@ -7408,7 +6564,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", "der 0.7.9", - "generic-array 0.14.7", + "generic-array", "pkcs8 0.10.2", "subtle", "zeroize", @@ -7542,12 +6698,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "sentry" version = "0.31.8" @@ -7653,7 +6803,7 @@ dependencies = [ "thiserror", "time", "url", - "uuid 1.10.0", + "uuid", ] [[package]] @@ -7671,16 +6821,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-aux" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "serde-value" version = "0.7.0" @@ -7813,18 +6953,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha2" version = "0.9.9" @@ -7835,7 +6963,7 @@ dependencies = [ "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug", ] [[package]] @@ -7869,7 +6997,7 @@ dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", "keccak", - "opaque-debug 0.3.1", + "opaque-debug", ] [[package]] @@ -7998,7 +7126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" dependencies = [ "bytecount", - "cargo_metadata 0.14.2", + "cargo_metadata", "error-chain", "glob", "pulldown-cmark", @@ -8044,18 +7172,6 @@ dependencies = [ "zksync_vlog", ] -[[package]] -name = "snark_wrapper" -version = "0.30.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374c01372ffa80be5ae488fb54cf58ade53fd5279aa5a0340a44fc1da96d71a1" -dependencies = [ - "derivative", - "rand 0.4.6", - "rescue_poseidon 0.30.9", - "serde", -] - [[package]] name = "snow" version = "0.9.6" @@ -8260,7 +7376,7 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "generic-array 0.14.7", + "generic-array", "hex", "hkdf", "hmac", @@ -8416,35 +7532,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros 0.24.3", -] - [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.4", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.86", - "quote 1.0.37", - "rustversion", - "syn 1.0.109", + "strum_macros", ] [[package]] @@ -8837,7 +7931,7 @@ dependencies = [ "pin-project-lite", "thiserror", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", ] [[package]] @@ -8850,7 +7944,7 @@ dependencies = [ "bytes", "libc", "mio 1.0.2", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -8879,23 +7973,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls", "rustls-pki-types", "tokio", ] @@ -8926,15 +8010,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.8.19" @@ -8988,7 +8063,7 @@ checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" dependencies = [ "async-stream", "async-trait", - "axum 0.7.9", + "axum", "base64 0.22.1", "bytes", "h2 0.4.6", @@ -9108,16 +8183,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -9202,15 +8267,9 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml 0.8.19", + "toml", ] -[[package]] -name = "typemap_rev" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" - [[package]] name = "typenum" version = "1.17.0" @@ -9397,23 +8456,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - [[package]] name = "uuid" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "getrandom", "serde", ] @@ -9454,29 +8502,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "via-verification" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "circuit_definitions", - "clap 4.5.16", - "ethers", - "hex", - "once_cell", - "primitive-types", - "reqwest 0.12.7", - "serde", - "serde_json", - "sha3 0.10.8", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber", - "zksync_types", -] - [[package]] name = "via_btc_client" version = "0.1.0" @@ -9608,30 +8633,6 @@ dependencies = [ "zksync_utils", ] -[[package]] -name = "via_musig2" -version = "0.1.0" -dependencies = [ - "anyhow", - "axum 0.6.20", - "base64 0.21.7", - "bitcoin", - "bitcoincore-rpc", - "hex", - "hyper 0.14.30", - "musig2", - "rand 0.8.5", - "reqwest 0.12.7", - "secp256k1 0.30.0", - "serde", - "serde_json", - "tokio", - "tracing", - "tracing-subscriber", - "uuid 1.10.0", - "via_btc_client", -] - [[package]] name = "via_server" version = "0.1.0" @@ -9715,28 +8716,6 @@ dependencies = [ "zksync_vlog", ] -[[package]] -name = "via_withdrawal_client" -version = "0.1.0" -dependencies = [ - "anyhow", - "bitcoin", - "byteorder", - "dotenv", - "hex", - "rand 0.8.5", - "tokio", - "tracing", - "tracing-subscriber", - "via_da_clients", - "zksync_basic_types", - "zksync_config", - "zksync_da_client", - "zksync_dal", - "zksync_types", - "zksync_utils", -] - [[package]] name = "vise" version = "0.2.0" @@ -9921,21 +8900,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures 0.3.30", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.70" @@ -9956,12 +8920,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.3" @@ -10239,25 +9197,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures 0.3.30", - "js-sys", - "log", - "pharos", - "rustc_version 0.4.0", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wyz" version = "0.5.1" @@ -10395,20 +9334,6 @@ dependencies = [ "zk_evm_abstractions 0.150.4", ] -[[package]] -name = "zk_evm" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "anyhow", - "lazy_static", - "num", - "serde", - "serde_json", - "static_assertions", - "zk_evm_abstractions 0.150.16", -] - [[package]] name = "zk_evm_abstractions" version = "0.140.0" @@ -10448,18 +9373,6 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] -[[package]] -name = "zk_evm_abstractions" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "anyhow", - "num_enum 0.6.1", - "serde", - "static_assertions", - "zkevm_opcode_defs 0.150.16", -] - [[package]] name = "zkevm_circuits" version = "0.140.2" @@ -10524,25 +9437,6 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] -[[package]] -name = "zkevm_circuits" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "arrayvec 0.7.6", - "boojum 0.30.9", - "derivative", - "hex", - "itertools 0.10.5", - "rand 0.4.6", - "rand 0.8.5", - "seq-macro", - "serde", - "smallvec", - "zkevm_opcode_defs 0.150.16", - "zksync_cs_derive", -] - [[package]] name = "zkevm_opcode_defs" version = "0.131.0" @@ -10602,22 +9496,6 @@ dependencies = [ "sha3 0.10.8", ] -[[package]] -name = "zkevm_opcode_defs" -version = "0.150.16" -source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" -dependencies = [ - "bitflags 2.6.0", - "blake2 0.10.6", - "ethereum-types", - "k256 0.13.3", - "lazy_static", - "p256", - "serde", - "sha2 0.10.8", - "sha3 0.10.8", -] - [[package]] name = "zksync_base_token_adjuster" version = "0.1.0" @@ -10653,35 +9531,12 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum 0.26.3", + "strum", "thiserror", "tiny-keccak 2.0.2", "url", ] -[[package]] -name = "zksync_bellman" -version = "0.30.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fc1a740dfba0dd5e90a2689060910966c9c5ca837520428962ffe972223a61" -dependencies = [ - "arrayvec 0.7.6", - "bit-vec", - "blake2s_simd", - "byteorder", - "cfg-if 1.0.0", - "crossbeam 0.8.4", - "futures 0.3.30", - "hex", - "lazy_static", - "num_cpus", - "rand 0.4.6", - "serde", - "smallvec", - "tiny-keccak 1.5.0", - "zksync_pairing", -] - [[package]] name = "zksync_block_reverter" version = "0.1.0" @@ -10880,7 +9735,7 @@ dependencies = [ "thiserror", "tls-listener", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tracing", "vise", "zksync_concurrency", @@ -10977,7 +9832,7 @@ name = "zksync_contract_verification_server" version = "0.1.0" dependencies = [ "anyhow", - "axum 0.7.9", + "axum", "serde", "serde_json", "tokio", @@ -11140,7 +9995,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum 0.26.3", + "strum", "thiserror", "tokio", "tracing", @@ -11368,7 +10223,7 @@ name = "zksync_external_proof_integration_api" version = "0.1.0" dependencies = [ "anyhow", - "axum 0.7.9", + "axum", "bincode", "tokio", "tracing", @@ -11530,7 +10385,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum 0.7.9", + "axum", "futures 0.3.30", "itertools 0.10.5", "once_cell", @@ -11610,7 +10465,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum 0.7.9", + "axum", "chrono", "futures 0.3.30", "governor", @@ -11623,7 +10478,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "strum 0.26.3", + "strum", "test-casing", "thiserror", "thread_local", @@ -11948,7 +10803,7 @@ name = "zksync_proof_data_handler" version = "0.1.0" dependencies = [ "anyhow", - "axum 0.7.9", + "axum", "chrono", "hyper 1.4.1", "serde_json", @@ -12029,7 +10884,7 @@ name = "zksync_prover_dal" version = "0.1.0" dependencies = [ "sqlx", - "strum 0.26.3", + "strum", "zksync_basic_types", "zksync_db_connection", ] @@ -12044,7 +10899,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum 0.26.3", + "strum", "tokio", "zksync_multivm", "zksync_object_store", @@ -12156,11 +11011,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bac71750012656b207e8cdb67415823318909077d8c8e235111f0d2feeeeeda" dependencies = [ "ethereum-types", - "franklin-crypto 0.1.0", + "franklin-crypto", "handlebars", "hex", "paste", - "rescue_poseidon 0.4.1", + "rescue_poseidon", "serde", "serde_derive", "serde_json", @@ -12340,7 +11195,7 @@ dependencies = [ "bitcoin", "blake2 0.10.6", "chrono", - "derive_more 1.0.0-beta.6", + "derive_more", "hex", "itertools 0.10.5", "num", @@ -12351,7 +11206,7 @@ dependencies = [ "secp256k1 0.27.0", "serde", "serde_json", - "strum 0.26.3", + "strum", "thiserror", "tokio", "tracing", @@ -12487,7 +11342,7 @@ dependencies = [ "pin-project-lite", "rand 0.8.5", "rlp", - "rustls 0.23.12", + "rustls", "serde", "serde_json", "test-casing", diff --git a/Cargo.toml b/Cargo.toml index ee21f6f1a..c37ce9d6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,6 @@ members = [ # VIA Protocol Related Crates "core/lib/via_btc_client", "core/lib/via_da_clients", - "core/lib/via_verification", "core/node/via_btc_watch", "core/node/via_da_dispatcher", "core/bin/via_server", @@ -93,10 +92,12 @@ members = [ "core/node/via_fee_model", "core/node/via_state_keeper", "core/lib/via_da_clients", - "core/lib/via_musig2", - "core/lib/via_withdrawal_client", - "core/bin/via_verifier", + # VIA Verifier + "via_verifier/bin/verifier_server", + "via_verifier/lib/via_withdrawal_client", + "via_verifier/lib/via_verification", + "via_verifier/lib/via_musig2", ] resolver = "2" @@ -320,12 +321,15 @@ zksync_logs_bloom_backfill = { version = "0.1.0", path = "core/node/logs_bloom_b # VIA Protocol Related Components via_btc_client= { version = "0.1.0", path = "core/lib/via_btc_client" } -via_withdrawal_client = { version = "0.1.0", path = "core/lib/via_withdrawal_client" } via_da_clients = { version = "0.1.0", path = "core/lib/via_da_clients" } -via_validator_lib = { version = "0.1.0", path = "core/lib/via_validation" } via_btc_watch = { version = "0.1.0", path = "core/node/via_btc_watch" } via_da_dispatcher = { version = "0.1.0", path = "core/node/via_da_dispatcher" } via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } -via_musig2 = { version = "0.1.0", path = "core/lib/via_musig2" } + + +# VIA Verifier +via_withdrawal_client = { version = "0.1.0", path = "via_verifier/lib/via_withdrawal_client" } +via_verification = { version = "0.1.0", path = "via_verifier/lib/via_verification" } +via_musig2 = { version = "0.1.0", path = "via_verifier/lib/via_musig2" } diff --git a/core/lib/via_musig2/Cargo.toml b/core/lib/via_musig2/Cargo.toml deleted file mode 100644 index deed99b2d..000000000 --- a/core/lib/via_musig2/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "via_musig2" -description = "Via Network Musig2 Wrapper" -version.workspace = true -edition.workspace = true -authors = ["Via Network"] -homepage.workspace = true -repository.workspace = true -license.workspace = true -keywords.workspace = true -categories.workspace = true - -[dependencies] -rand.workspace = true -hex.workspace = true -via_btc_client.workspace = true -anyhow.workspace = true -tracing.workspace = true -tracing-subscriber.workspace = true -serde_json.workspace = true -serde.workspace = true -reqwest.workspace = true -bitcoincore-rpc = "0.19.0" -bitcoin = { version = "0.32.2", features = ["serde"] } -musig2 = "0.2.0" -secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} -tokio = { version = "1.0", features = ["full"] } -axum = "0.6" -uuid = { version = "1.3", features = ["v4"] } -hyper = { version = "0.14", features = ["full"] } -base64 = "0.21" - - - -[[example]] -name = "key_generation_setup" -path = "examples/key_generation_setup.rs" - - -[[example]] -name = "withdrawal" -path = "examples/withdrawal.rs" - - -[[example]] -name = "coordinator" -path = "examples/coordinator.rs" - diff --git a/via_verifier/CHANGELOG.md b/via_verifier/CHANGELOG.md new file mode 100644 index 000000000..e40c9125f --- /dev/null +++ b/via_verifier/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + + +## [x.x.x] Version + +### Features +### Bug Fixes + diff --git a/core/bin/via_verifier/Cargo.toml b/via_verifier/bin/verifier_server/Cargo.toml similarity index 100% rename from core/bin/via_verifier/Cargo.toml rename to via_verifier/bin/verifier_server/Cargo.toml diff --git a/core/bin/via_verifier/src/config.rs b/via_verifier/bin/verifier_server/src/config.rs similarity index 100% rename from core/bin/via_verifier/src/config.rs rename to via_verifier/bin/verifier_server/src/config.rs diff --git a/core/bin/via_verifier/src/main.rs b/via_verifier/bin/verifier_server/src/main.rs similarity index 100% rename from core/bin/via_verifier/src/main.rs rename to via_verifier/bin/verifier_server/src/main.rs diff --git a/core/bin/via_verifier/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs similarity index 100% rename from core/bin/via_verifier/src/node_builder.rs rename to via_verifier/bin/verifier_server/src/node_builder.rs diff --git a/via_verifier/lib/via_musig2/Cargo.toml b/via_verifier/lib/via_musig2/Cargo.toml new file mode 100644 index 000000000..f51834c08 --- /dev/null +++ b/via_verifier/lib/via_musig2/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "via_musig2" +version = "0.1.0" +edition = "2021" + +[dependencies] +musig2 = { git = "https://github.com/conduition/musig2" } +secp256k1-musig2 = { git = "https://github.com/conduition/secp256k1-musig2" } +rand = "0.8" + + diff --git a/core/lib/via_musig2/examples/coordinator.rs b/via_verifier/lib/via_musig2/examples/coordinator.rs similarity index 100% rename from core/lib/via_musig2/examples/coordinator.rs rename to via_verifier/lib/via_musig2/examples/coordinator.rs diff --git a/core/lib/via_musig2/examples/key_generation_setup.rs b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs similarity index 100% rename from core/lib/via_musig2/examples/key_generation_setup.rs rename to via_verifier/lib/via_musig2/examples/key_generation_setup.rs diff --git a/core/lib/via_musig2/examples/withdrawal.rs b/via_verifier/lib/via_musig2/examples/withdrawal.rs similarity index 100% rename from core/lib/via_musig2/examples/withdrawal.rs rename to via_verifier/lib/via_musig2/examples/withdrawal.rs diff --git a/core/lib/via_musig2/src/lib.rs b/via_verifier/lib/via_musig2/src/lib.rs similarity index 100% rename from core/lib/via_musig2/src/lib.rs rename to via_verifier/lib/via_musig2/src/lib.rs diff --git a/core/lib/via_verification/Cargo.toml b/via_verifier/lib/via_verification/Cargo.toml similarity index 100% rename from core/lib/via_verification/Cargo.toml rename to via_verifier/lib/via_verification/Cargo.toml diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/abis/IVerifier.json diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/abis/IZkSync.json diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/fetching.rs diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/main.rs b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/main.rs similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/main.rs rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/main.rs diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/types.rs b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/types.rs similarity index 100% rename from core/lib/via_verification/examples/zksync-era-verification-cli/types.rs rename to via_verifier/lib/via_verification/examples/zksync-era-verification-cli/types.rs diff --git a/core/lib/via_verification/keys/protocol_version/24/scheduler_key.json b/via_verifier/lib/via_verification/keys/protocol_version/24/scheduler_key.json similarity index 100% rename from core/lib/via_verification/keys/protocol_version/24/scheduler_key.json rename to via_verifier/lib/via_verification/keys/protocol_version/24/scheduler_key.json diff --git a/core/lib/via_verification/keys/protocol_version/25/scheduler_key.json b/via_verifier/lib/via_verification/keys/protocol_version/25/scheduler_key.json similarity index 100% rename from core/lib/via_verification/keys/protocol_version/25/scheduler_key.json rename to via_verifier/lib/via_verification/keys/protocol_version/25/scheduler_key.json diff --git a/core/lib/via_verification/src/crypto.rs b/via_verifier/lib/via_verification/src/crypto.rs similarity index 100% rename from core/lib/via_verification/src/crypto.rs rename to via_verifier/lib/via_verification/src/crypto.rs diff --git a/core/lib/via_verification/src/errors.rs b/via_verifier/lib/via_verification/src/errors.rs similarity index 100% rename from core/lib/via_verification/src/errors.rs rename to via_verifier/lib/via_verification/src/errors.rs diff --git a/core/lib/via_verification/src/l1_data_fetcher.rs b/via_verifier/lib/via_verification/src/l1_data_fetcher.rs similarity index 100% rename from core/lib/via_verification/src/l1_data_fetcher.rs rename to via_verifier/lib/via_verification/src/l1_data_fetcher.rs diff --git a/core/lib/via_verification/src/lib.rs b/via_verifier/lib/via_verification/src/lib.rs similarity index 100% rename from core/lib/via_verification/src/lib.rs rename to via_verifier/lib/via_verification/src/lib.rs diff --git a/core/lib/via_verification/src/proof.rs b/via_verifier/lib/via_verification/src/proof.rs similarity index 100% rename from core/lib/via_verification/src/proof.rs rename to via_verifier/lib/via_verification/src/proof.rs diff --git a/core/lib/via_verification/src/public_inputs.rs b/via_verifier/lib/via_verification/src/public_inputs.rs similarity index 100% rename from core/lib/via_verification/src/public_inputs.rs rename to via_verifier/lib/via_verification/src/public_inputs.rs diff --git a/core/lib/via_verification/src/types.rs b/via_verifier/lib/via_verification/src/types.rs similarity index 100% rename from core/lib/via_verification/src/types.rs rename to via_verifier/lib/via_verification/src/types.rs diff --git a/core/lib/via_verification/src/utils.rs b/via_verifier/lib/via_verification/src/utils.rs similarity index 100% rename from core/lib/via_verification/src/utils.rs rename to via_verifier/lib/via_verification/src/utils.rs diff --git a/core/lib/via_verification/src/verification.rs b/via_verifier/lib/via_verification/src/verification.rs similarity index 100% rename from core/lib/via_verification/src/verification.rs rename to via_verifier/lib/via_verification/src/verification.rs diff --git a/core/lib/via_withdrawal_client/Cargo.toml b/via_verifier/lib/via_withdrawal_client/Cargo.toml similarity index 100% rename from core/lib/via_withdrawal_client/Cargo.toml rename to via_verifier/lib/via_withdrawal_client/Cargo.toml diff --git a/core/lib/via_withdrawal_client/examples/withdraw.rs b/via_verifier/lib/via_withdrawal_client/examples/withdraw.rs similarity index 100% rename from core/lib/via_withdrawal_client/examples/withdraw.rs rename to via_verifier/lib/via_withdrawal_client/examples/withdraw.rs diff --git a/core/lib/via_withdrawal_client/src/client.rs b/via_verifier/lib/via_withdrawal_client/src/client.rs similarity index 100% rename from core/lib/via_withdrawal_client/src/client.rs rename to via_verifier/lib/via_withdrawal_client/src/client.rs diff --git a/core/lib/via_withdrawal_client/src/lib.rs b/via_verifier/lib/via_withdrawal_client/src/lib.rs similarity index 100% rename from core/lib/via_withdrawal_client/src/lib.rs rename to via_verifier/lib/via_withdrawal_client/src/lib.rs diff --git a/core/lib/via_withdrawal_client/src/pubdata.rs b/via_verifier/lib/via_withdrawal_client/src/pubdata.rs similarity index 100% rename from core/lib/via_withdrawal_client/src/pubdata.rs rename to via_verifier/lib/via_withdrawal_client/src/pubdata.rs diff --git a/core/lib/via_withdrawal_client/src/types.rs b/via_verifier/lib/via_withdrawal_client/src/types.rs similarity index 100% rename from core/lib/via_withdrawal_client/src/types.rs rename to via_verifier/lib/via_withdrawal_client/src/types.rs diff --git a/core/lib/via_withdrawal_client/src/withdraw.rs b/via_verifier/lib/via_withdrawal_client/src/withdraw.rs similarity index 100% rename from core/lib/via_withdrawal_client/src/withdraw.rs rename to via_verifier/lib/via_withdrawal_client/src/withdraw.rs diff --git a/via_verifier/rust-toolchain b/via_verifier/rust-toolchain new file mode 100644 index 000000000..03c040b91 --- /dev/null +++ b/via_verifier/rust-toolchain @@ -0,0 +1 @@ +nightly-2024-08-01 From 3193e315af83763ddcfed4270304d5c74e41ceab Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 11:11:14 +0330 Subject: [PATCH 072/212] fix via_musig2 cargo.toml --- Cargo.lock | 1311 ++++++++++++++++++++++-- via_verifier/lib/via_musig2/Cargo.toml | 46 +- 2 files changed, 1269 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb33ce89e..3de3538a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addchain" version = "0.2.0" @@ -41,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -413,6 +423,17 @@ dependencies = [ "syn 2.0.76", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures 0.3.30", + "pharos", + "rustc_version 0.4.0", +] + [[package]] name = "atoi" version = "2.0.0" @@ -439,6 +460,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -483,6 +516,38 @@ dependencies = [ "paste", ] +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "tokio", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + [[package]] name = "axum" version = "0.7.9" @@ -490,7 +555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.5", "bytes", "futures-util", "http 1.1.0", @@ -517,6 +582,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -583,6 +665,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58", + "sha2 0.8.2", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -593,6 +691,12 @@ dependencies = [ "bitcoin_hashes", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.1" @@ -617,6 +721,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + [[package]] name = "bech32" version = "0.11.0" @@ -762,7 +872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6" dependencies = [ "base58ck", - "bech32", + "bech32 0.11.0", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -857,6 +967,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + [[package]] name = "bitvec" version = "1.0.1" @@ -864,7 +984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", - "radium", + "radium 0.7.0", "tap", "wyz", ] @@ -877,7 +997,7 @@ checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ "crypto-mac", "digest 0.9.0", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -942,14 +1062,26 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", - "generic-array", + "block-padding 0.2.1", + "generic-array 0.14.7", ] [[package]] @@ -958,7 +1090,16 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -1096,6 +1237,12 @@ dependencies = [ "syn_derive", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + [[package]] name = "bs58" version = "0.5.1" @@ -1123,6 +1270,12 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "bytecheck" version = "0.6.12" @@ -1214,6 +1367,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.23", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cast" version = "0.3.0" @@ -1311,7 +1478,7 @@ version = "0.4.0" source = "git+https://github.com/eigerco/lumina.git#f11959550851afb8c2062b30e38cc87242467cdc" dependencies = [ "base64 0.22.1", - "bech32", + "bech32 0.11.0", "blockstore", "bytes", "celestia-proto", @@ -1455,6 +1622,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "circuit_definitions" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "circuit_encodings 0.150.16", + "crossbeam 0.8.4", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", +] + [[package]] name = "circuit_encodings" version = "0.140.1" @@ -1503,6 +1683,17 @@ dependencies = [ "zkevm_circuits 0.150.4", ] +[[package]] +name = "circuit_encodings" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "derivative", + "serde", + "zk_evm 0.150.16", + "zkevm_circuits 0.150.16", +] + [[package]] name = "circuit_sequencer_api" version = "0.133.0" @@ -1676,6 +1867,63 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "coins-bip32" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" +dependencies = [ + "bincode", + "bs58 0.4.0", + "coins-core", + "digest 0.10.7", + "getrandom", + "hmac", + "k256 0.11.6", + "lazy_static", + "serde", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32 0.7.3", + "blake2 0.10.6", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -1992,7 +2240,7 @@ dependencies = [ "crossterm_winapi", "libc", "mio 0.8.11", - "parking_lot", + "parking_lot 0.12.3", "signal-hook", "signal-hook-mio", "winapi", @@ -2019,7 +2267,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -2031,7 +2279,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -2043,7 +2291,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "typenum", ] @@ -2054,7 +2302,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array", + "generic-array 0.14.7", "subtle", ] @@ -2184,7 +2432,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2198,7 +2446,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2234,7 +2482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -2279,6 +2527,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.76", +] + [[package]] name = "derive_more" version = "1.0.0-beta.6" @@ -2306,13 +2565,22 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -2327,6 +2595,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dotenvy" version = "0.15.7" @@ -2441,7 +2715,7 @@ dependencies = [ "der 0.6.1", "digest 0.10.7", "ff 0.12.1", - "generic-array", + "generic-array 0.14.7", "group 0.12.1", "pkcs8 0.9.0", "rand_core 0.6.4", @@ -2460,7 +2734,7 @@ dependencies = [ "crypto-bigint 0.5.5", "digest 0.10.7", "ff 0.13.0", - "generic-array", + "generic-array 0.14.7", "group 0.13.0", "pem-rfc7468", "pkcs8 0.10.2", @@ -2572,6 +2846,28 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + [[package]] name = "ethabi" version = "18.0.0" @@ -2597,8 +2893,10 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", "fixed-hash", + "impl-codec", "impl-rlp", "impl-serde", + "scale-info", "tiny-keccak 2.0.2", ] @@ -2610,12 +2908,227 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ "ethbloom", "fixed-hash", + "impl-codec", "impl-rlp", "impl-serde", "primitive-types", + "scale-info", "uint", ] +[[package]] +name = "ethers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f26f9d8d80da18ca72aca51804c65eb2153093af3bec74fd5ce32aa0c1f665" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4be54dd2260945d784e06ccdeb5ad573e8f1541838cee13a1ab885485eaa0b" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c3c3e119a89f0a9a1e539e7faecea815f74ddcf7c90d0b00d1f524db2fdc9c" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4e5ad46aede34901f71afdb7bb555710ed9613d88d644245c657dc371aa228" +dependencies = [ + "Inflector", + "cfg-if 1.0.0", + "dunce", + "ethers-core", + "eyre", + "getrandom", + "hex", + "proc-macro2 1.0.86", + "quote 1.0.37", + "regex", + "reqwest 0.11.27", + "serde", + "serde_json", + "syn 1.0.109", + "toml 0.5.11", + "url", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f192e8e4cf2b038318aae01e94e7644e0659a76219e94bcd3203df744341d61f" +dependencies = [ + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2 1.0.86", + "quote 1.0.37", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "ethers-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" +dependencies = [ + "arrayvec 0.7.6", + "bytes", + "cargo_metadata 0.15.4", + "chrono", + "convert_case", + "elliptic-curve 0.12.3", + "ethabi", + "generic-array 0.14.7", + "hex", + "k256 0.11.6", + "once_cell", + "open-fastrlp", + "proc-macro2 1.0.86", + "rand 0.8.5", + "rlp", + "rlp-derive", + "serde", + "serde_json", + "strum 0.24.1", + "syn 1.0.109", + "thiserror", + "tiny-keccak 2.0.2", + "unicode-xid 0.2.5", +] + +[[package]] +name = "ethers-etherscan" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9713f525348e5dde025d09b0a4217429f8074e8ff22c886263cc191e87d8216" +dependencies = [ + "ethers-core", + "getrandom", + "reqwest 0.11.27", + "semver 1.0.23", + "serde", + "serde-aux", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71df7391b0a9a51208ffb5c7f2d068900e99d6b3128d3a4849d138f194778b7" +dependencies = [ + "async-trait", + "auto_impl 0.5.0", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8" +dependencies = [ + "async-trait", + "auto_impl 1.2.0", + "base64 0.13.1", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "getrandom", + "hashers", + "hex", + "http 0.2.12", + "once_cell", + "parking_lot 0.11.2", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f41ced186867f64773db2e55ffdd92959e094072a1d09a5e5e831d443204f98" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve 0.12.3", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + [[package]] name = "event-listener" version = "5.3.1" @@ -2637,6 +3150,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fastrand" version = "2.1.1" @@ -2650,7 +3169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ "arrayvec 0.7.6", - "auto_impl", + "auto_impl 1.2.0", "bytes", ] @@ -2852,6 +3371,39 @@ dependencies = [ "tiny-keccak 1.5.0", ] +[[package]] +name = "franklin-crypto" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09876c8a2d5e706a8669f69d7db592ca9c48257cbfc4917fe32daf419a8ea78e" +dependencies = [ + "arr_macro", + "bit-vec", + "blake2 0.9.2", + "blake2-rfc_bellman_edition", + "blake2s_simd", + "boojum 0.30.9", + "byteorder", + "derivative", + "digest 0.9.0", + "hex", + "indexmap 1.9.3", + "itertools 0.10.5", + "lazy_static", + "num-bigint 0.4.6", + "num-derive 0.2.5", + "num-integer", + "num-traits", + "rand 0.4.6", + "serde", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "splitmut", + "tiny-keccak 1.5.0", + "zksync_bellman", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -2927,7 +3479,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -2936,6 +3488,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -2966,7 +3528,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", - "send_wrapper", + "send_wrapper 0.4.0", ] [[package]] @@ -3006,6 +3568,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3060,7 +3631,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug", + "opaque-debug 0.3.1", "polyval", ] @@ -3208,7 +3779,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot", + "parking_lot 0.12.3", "quanta", "rand 0.8.5", "smallvec", @@ -3323,6 +3894,15 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "hashlink" version = "0.9.1" @@ -3341,6 +3921,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -3534,6 +4120,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.2" @@ -3545,10 +4145,10 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "log", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", ] @@ -3743,7 +4343,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -3776,6 +4376,18 @@ dependencies = [ "similar", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -3916,13 +4528,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.23.2", "pin-project", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -3939,13 +4551,13 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.24.3", "pin-project", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -3967,7 +4579,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "jsonrpsee-types 0.23.2", - "parking_lot", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "rustc-hash 1.1.0", @@ -4014,11 +4626,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core 0.23.2", "jsonrpsee-types 0.23.2", - "rustls", + "rustls 0.23.12", "rustls-platform-verifier", "serde", "serde_json", @@ -4039,11 +4651,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core 0.24.3", "jsonrpsee-types 0.24.3", - "rustls", + "rustls 0.23.12", "rustls-platform-verifier", "serde", "serde_json", @@ -4195,6 +4807,7 @@ dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", "sha2 0.10.8", + "sha3 0.10.8", ] [[package]] @@ -4280,7 +4893,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ - "bs58", + "bs58 0.5.1", "hkdf", "multihash", "quick-protobuf", @@ -5021,12 +5634,43 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.6", + "auto_impl 1.2.0", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "openssl" version = "0.10.66" @@ -5233,7 +5877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.6", - "bitvec", + "bitvec 1.0.1", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", @@ -5258,6 +5902,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -5265,7 +5920,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -5281,12 +5950,35 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2 0.10.8", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -5373,6 +6065,16 @@ dependencies = [ "indexmap 2.6.0", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures 0.3.30", + "rustc_version 0.4.0", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -5477,7 +6179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug", + "opaque-debug 0.3.1", "universal-hash", ] @@ -5489,7 +6191,7 @@ checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "opaque-debug", + "opaque-debug 0.3.1", "universal-hash", ] @@ -5573,6 +6275,7 @@ dependencies = [ "impl-codec", "impl-rlp", "impl-serde", + "scale-info", "uint", ] @@ -5651,7 +6354,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -5881,6 +6584,12 @@ dependencies = [ "proc-macro2 1.0.86", ] +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + [[package]] name = "radium" version = "0.7.0" @@ -6001,6 +6710,15 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -6087,6 +6805,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -6096,6 +6815,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -6104,11 +6824,13 @@ dependencies = [ "system-configuration 0.5.1", "tokio", "tokio-native-tls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.25.4", "winreg", ] @@ -6129,7 +6851,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -6184,7 +6906,31 @@ dependencies = [ "arrayvec 0.7.6", "blake2 0.10.6", "byteorder", - "franklin-crypto", + "franklin-crypto 0.1.0", + "num-bigint 0.3.3", + "num-integer", + "num-iter", + "num-traits", + "rand 0.4.6", + "serde", + "sha3 0.9.1", + "smallvec", +] + +[[package]] +name = "rescue_poseidon" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def7c91dcd919a62ca93bff4d67f710f8ae099e2639458fc5e3862f5812491a3" +dependencies = [ + "addchain", + "arrayvec 0.7.6", + "blake2 0.10.6", + "byteorder", + "derivative", + "franklin-crypto 0.30.9", + "lazy_static", + "log", "num-bigint 0.3.3", "num-integer", "num-iter", @@ -6193,6 +6939,7 @@ dependencies = [ "serde", "sha3 0.9.1", "smallvec", + "typemap_rev", ] [[package]] @@ -6231,13 +6978,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rkyv" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ - "bitvec", + "bitvec 1.0.1", "bytecheck", "bytes", "hashbrown 0.12.3", @@ -6246,7 +7002,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -6270,6 +7026,17 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -6407,6 +7174,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.12" @@ -6418,7 +7197,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.7", "subtle", "zeroize", ] @@ -6472,13 +7251,13 @@ dependencies = [ "jni", "log", "once_cell", - "rustls", + "rustls 0.23.12", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", + "rustls-webpki 0.102.7", "security-framework", "security-framework-sys", - "webpki-roots", + "webpki-roots 0.26.3", "winapi", ] @@ -6488,6 +7267,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.7" @@ -6512,6 +7301,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6521,6 +7319,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if 1.0.0", + "derive_more 0.99.18", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.76", +] + [[package]] name = "schannel" version = "0.1.23" @@ -6531,10 +7353,32 @@ dependencies = [ ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2 0.10.8", +] + +[[package]] +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] [[package]] name = "seahash" @@ -6550,7 +7394,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct 0.1.1", "der 0.6.1", - "generic-array", + "generic-array 0.14.7", "pkcs8 0.9.0", "subtle", "zeroize", @@ -6564,7 +7408,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", "der 0.7.9", - "generic-array", + "generic-array 0.14.7", "pkcs8 0.10.2", "subtle", "zeroize", @@ -6698,6 +7542,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "sentry" version = "0.31.8" @@ -6803,7 +7653,7 @@ dependencies = [ "thiserror", "time", "url", - "uuid", + "uuid 1.10.0", ] [[package]] @@ -6821,6 +7671,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-aux" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde-value" version = "0.7.0" @@ -6953,6 +7813,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + [[package]] name = "sha2" version = "0.9.9" @@ -6963,7 +7835,7 @@ dependencies = [ "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -6997,7 +7869,7 @@ dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", "keccak", - "opaque-debug", + "opaque-debug 0.3.1", ] [[package]] @@ -7126,7 +7998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" dependencies = [ "bytecount", - "cargo_metadata", + "cargo_metadata 0.14.2", "error-chain", "glob", "pulldown-cmark", @@ -7172,6 +8044,18 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "snark_wrapper" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374c01372ffa80be5ae488fb54cf58ade53fd5279aa5a0340a44fc1da96d71a1" +dependencies = [ + "derivative", + "rand 0.4.6", + "rescue_poseidon 0.30.9", + "serde", +] + [[package]] name = "snow" version = "0.9.6" @@ -7376,7 +8260,7 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "generic-array", + "generic-array 0.14.7", "hex", "hkdf", "hmac", @@ -7532,13 +8416,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "rustversion", + "syn 1.0.109", ] [[package]] @@ -7931,7 +8837,7 @@ dependencies = [ "pin-project-lite", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", ] [[package]] @@ -7944,7 +8850,7 @@ dependencies = [ "bytes", "libc", "mio 1.0.2", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -7973,13 +8879,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", ] @@ -8010,6 +8926,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -8063,7 +8988,7 @@ checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.7.9", "base64 0.22.1", "bytes", "h2 0.4.6", @@ -8183,6 +9108,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -8267,9 +9202,15 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", + "toml 0.8.19", ] +[[package]] +name = "typemap_rev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" + [[package]] name = "typenum" version = "1.17.0" @@ -8456,12 +9397,23 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "uuid" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ + "getrandom", "serde", ] @@ -8502,6 +9454,29 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "via-verification" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "circuit_definitions", + "clap 4.5.16", + "ethers", + "hex", + "once_cell", + "primitive-types", + "reqwest 0.12.7", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "zksync_types", +] + [[package]] name = "via_btc_client" version = "0.1.0" @@ -8633,6 +9608,30 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "via_musig2" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum 0.6.20", + "base64 0.21.7", + "bitcoin", + "bitcoincore-rpc", + "hex", + "hyper 0.14.30", + "musig2", + "rand 0.8.5", + "reqwest 0.12.7", + "secp256k1 0.30.0", + "serde", + "serde_json", + "tokio", + "tracing", + "tracing-subscriber", + "uuid 1.10.0", + "via_btc_client", +] + [[package]] name = "via_server" version = "0.1.0" @@ -8716,6 +9715,28 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "via_withdrawal_client" +version = "0.1.0" +dependencies = [ + "anyhow", + "bitcoin", + "byteorder", + "dotenv", + "hex", + "rand 0.8.5", + "tokio", + "tracing", + "tracing-subscriber", + "via_da_clients", + "zksync_basic_types", + "zksync_config", + "zksync_da_client", + "zksync_dal", + "zksync_types", + "zksync_utils", +] + [[package]] name = "vise" version = "0.2.0" @@ -8900,6 +9921,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures 0.3.30", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.70" @@ -8920,6 +9956,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.3" @@ -9197,6 +10239,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures 0.3.30", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -9334,6 +10395,20 @@ dependencies = [ "zk_evm_abstractions 0.150.4", ] +[[package]] +name = "zk_evm" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 0.150.16", +] + [[package]] name = "zk_evm_abstractions" version = "0.140.0" @@ -9373,6 +10448,18 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] +[[package]] +name = "zk_evm_abstractions" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "anyhow", + "num_enum 0.6.1", + "serde", + "static_assertions", + "zkevm_opcode_defs 0.150.16", +] + [[package]] name = "zkevm_circuits" version = "0.140.2" @@ -9437,6 +10524,25 @@ dependencies = [ "zkevm_opcode_defs 0.150.4", ] +[[package]] +name = "zkevm_circuits" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "arrayvec 0.7.6", + "boojum 0.30.9", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "smallvec", + "zkevm_opcode_defs 0.150.16", + "zksync_cs_derive", +] + [[package]] name = "zkevm_opcode_defs" version = "0.131.0" @@ -9496,6 +10602,22 @@ dependencies = [ "sha3 0.10.8", ] +[[package]] +name = "zkevm_opcode_defs" +version = "0.150.16" +source = "git+https://github.com/matter-labs/zksync-protocol.git?tag=v0.150.16#fb09cb3bd949af68572d98886905f55e9ae77eaf" +dependencies = [ + "bitflags 2.6.0", + "blake2 0.10.6", + "ethereum-types", + "k256 0.13.3", + "lazy_static", + "p256", + "serde", + "sha2 0.10.8", + "sha3 0.10.8", +] + [[package]] name = "zksync_base_token_adjuster" version = "0.1.0" @@ -9531,12 +10653,35 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", + "strum 0.26.3", "thiserror", "tiny-keccak 2.0.2", "url", ] +[[package]] +name = "zksync_bellman" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fc1a740dfba0dd5e90a2689060910966c9c5ca837520428962ffe972223a61" +dependencies = [ + "arrayvec 0.7.6", + "bit-vec", + "blake2s_simd", + "byteorder", + "cfg-if 1.0.0", + "crossbeam 0.8.4", + "futures 0.3.30", + "hex", + "lazy_static", + "num_cpus", + "rand 0.4.6", + "serde", + "smallvec", + "tiny-keccak 1.5.0", + "zksync_pairing", +] + [[package]] name = "zksync_block_reverter" version = "0.1.0" @@ -9735,7 +10880,7 @@ dependencies = [ "thiserror", "tls-listener", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tracing", "vise", "zksync_concurrency", @@ -9832,7 +10977,7 @@ name = "zksync_contract_verification_server" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "serde", "serde_json", "tokio", @@ -9995,7 +11140,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum", + "strum 0.26.3", "thiserror", "tokio", "tracing", @@ -10223,7 +11368,7 @@ name = "zksync_external_proof_integration_api" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "bincode", "tokio", "tracing", @@ -10385,7 +11530,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum", + "axum 0.7.9", "futures 0.3.30", "itertools 0.10.5", "once_cell", @@ -10465,7 +11610,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "axum", + "axum 0.7.9", "chrono", "futures 0.3.30", "governor", @@ -10478,7 +11623,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "strum", + "strum 0.26.3", "test-casing", "thiserror", "thread_local", @@ -10803,7 +11948,7 @@ name = "zksync_proof_data_handler" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.9", "chrono", "hyper 1.4.1", "serde_json", @@ -10884,7 +12029,7 @@ name = "zksync_prover_dal" version = "0.1.0" dependencies = [ "sqlx", - "strum", + "strum 0.26.3", "zksync_basic_types", "zksync_db_connection", ] @@ -10899,7 +12044,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", + "strum 0.26.3", "tokio", "zksync_multivm", "zksync_object_store", @@ -11011,11 +12156,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bac71750012656b207e8cdb67415823318909077d8c8e235111f0d2feeeeeda" dependencies = [ "ethereum-types", - "franklin-crypto", + "franklin-crypto 0.1.0", "handlebars", "hex", "paste", - "rescue_poseidon", + "rescue_poseidon 0.4.1", "serde", "serde_derive", "serde_json", @@ -11195,7 +12340,7 @@ dependencies = [ "bitcoin", "blake2 0.10.6", "chrono", - "derive_more", + "derive_more 1.0.0-beta.6", "hex", "itertools 0.10.5", "num", @@ -11206,7 +12351,7 @@ dependencies = [ "secp256k1 0.27.0", "serde", "serde_json", - "strum", + "strum 0.26.3", "thiserror", "tokio", "tracing", @@ -11342,7 +12487,7 @@ dependencies = [ "pin-project-lite", "rand 0.8.5", "rlp", - "rustls", + "rustls 0.23.12", "serde", "serde_json", "test-casing", diff --git a/via_verifier/lib/via_musig2/Cargo.toml b/via_verifier/lib/via_musig2/Cargo.toml index f51834c08..b40d36994 100644 --- a/via_verifier/lib/via_musig2/Cargo.toml +++ b/via_verifier/lib/via_musig2/Cargo.toml @@ -1,11 +1,47 @@ [package] name = "via_musig2" -version = "0.1.0" -edition = "2021" +description = "Via Network Musig2 Wrapper" +version.workspace = true +edition.workspace = true +authors = ["Via Network"] +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true [dependencies] -musig2 = { git = "https://github.com/conduition/musig2" } -secp256k1-musig2 = { git = "https://github.com/conduition/secp256k1-musig2" } -rand = "0.8" +rand.workspace = true +hex.workspace = true +via_btc_client.workspace = true +anyhow.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +serde_json.workspace = true +serde.workspace = true +reqwest.workspace = true +bitcoincore-rpc = "0.19.0" +bitcoin = { version = "0.32.2", features = ["serde"] } +musig2 = "0.2.0" +secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} +tokio = { version = "1.0", features = ["full"] } +axum = "0.6" +uuid = { version = "1.3", features = ["v4"] } +hyper = { version = "0.14", features = ["full"] } +base64 = "0.21" + +[[example]] +name = "key_generation_setup" +path = "examples/key_generation_setup.rs" + + +[[example]] +name = "withdrawal" +path = "examples/withdrawal.rs" + + +[[example]] +name = "coordinator" +path = "examples/coordinator.rs" From b6d69ccb104753a5e7bc5029f638c0bc753e3459 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 11:34:49 +0330 Subject: [PATCH 073/212] add via_verifier_dal --- Cargo.lock | 10 +++++++ Cargo.toml | 3 +++ via_verifier/lib/verifier_dal/Cargo.toml | 29 +++++++++++++++++++++ via_verifier/lib/verifier_dal/doc/Tables.md | 0 via_verifier/lib/verifier_dal/src/lib.rs | 29 +++++++++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 via_verifier/lib/verifier_dal/Cargo.toml create mode 100644 via_verifier/lib/verifier_dal/doc/Tables.md create mode 100644 via_verifier/lib/verifier_dal/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 3de3538a6..e46aa8205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9448,6 +9448,16 @@ dependencies = [ "zksync_types", ] +[[package]] +name = "verifier_dal" +version = "0.1.0" +dependencies = [ + "sqlx", + "strum 0.26.3", + "zksync_basic_types", + "zksync_db_connection", +] + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index c37ce9d6d..a2a5f47c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ members = [ "via_verifier/lib/via_withdrawal_client", "via_verifier/lib/via_verification", "via_verifier/lib/via_musig2", + "via_verifier/lib/verifier_dal", ] resolver = "2" @@ -333,3 +334,5 @@ via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } via_withdrawal_client = { version = "0.1.0", path = "via_verifier/lib/via_withdrawal_client" } via_verification = { version = "0.1.0", path = "via_verifier/lib/via_verification" } via_musig2 = { version = "0.1.0", path = "via_verifier/lib/via_musig2" } +via_verifier_dal = { version = "0.1.0", path = "via_verifier/lib/verifier_dal" } + diff --git a/via_verifier/lib/verifier_dal/Cargo.toml b/via_verifier/lib/verifier_dal/Cargo.toml new file mode 100644 index 000000000..cc1687613 --- /dev/null +++ b/via_verifier/lib/verifier_dal/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "verifier_dal" +description = "Via Verifier DAL" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +zksync_db_connection.workspace = true +zksync_basic_types.workspace = true + +strum = { workspace = true, features = ["derive"] } +sqlx = { workspace = true, features = [ + "runtime-tokio", + "tls-native-tls", + "macros", + "postgres", + "bigdecimal", + "rust_decimal", + "chrono", + "json", + "migrate", + "ipnetwork", +] } diff --git a/via_verifier/lib/verifier_dal/doc/Tables.md b/via_verifier/lib/verifier_dal/doc/Tables.md new file mode 100644 index 000000000..e69de29bb diff --git a/via_verifier/lib/verifier_dal/src/lib.rs b/via_verifier/lib/verifier_dal/src/lib.rs new file mode 100644 index 000000000..543eef537 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/lib.rs @@ -0,0 +1,29 @@ +use zksync_db_connection::connection::DbMarker; +pub use zksync_db_connection::{ + connection::Connection, + connection_pool::ConnectionPool, + utils::{duration_to_naive_time, pg_interval_from_duration}, +}; + +// This module is private and serves as a way to seal the trait. +mod private { + pub trait Sealed {} +} + +// Here we are making the trait sealed, because it should be public to function correctly, but we don't +// want to allow any other downstream implementations of this trait. +pub trait CoreDal<'a>: private::Sealed +where + Self: 'a, +{ +} + +#[derive(Clone, Debug)] +pub struct Core; + +// Implement the marker trait for the Core to be able to use it in Connection. +impl DbMarker for Core {} +// Implement the sealed trait for the struct itself. +impl private::Sealed for Connection<'_, Core> {} + +impl<'a> CoreDal<'a> for Connection<'a, Core> {} From dd7549aaa28cadf1d9d90c03cfc9da5d33b9e1f6 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 11:46:29 +0330 Subject: [PATCH 074/212] basic config for via_verifier_dal --- .prettierignore | 3 ++- Cargo.lock | 20 ++++++++++---------- infrastructure/zk/src/format_sql.ts | 2 +- via_verifier/lib/verifier_dal/Cargo.toml | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.prettierignore b/.prettierignore index d58a7f3e8..6e1731a85 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,7 +3,8 @@ bellman-cuda sdk/zksync-rs/CHANGELOG.md CHANGELOG.md core/lib/dal/.sqlx -prover/lib/dal/.sqlx +prover/lib/dal/. +verifier/lib/verifier_dal/.sqlx node_modules # Ignore contract submodules diff --git a/Cargo.lock b/Cargo.lock index e46aa8205..500eea9af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9448,16 +9448,6 @@ dependencies = [ "zksync_types", ] -[[package]] -name = "verifier_dal" -version = "0.1.0" -dependencies = [ - "sqlx", - "strum 0.26.3", - "zksync_basic_types", - "zksync_db_connection", -] - [[package]] name = "version_check" version = "0.9.5" @@ -9725,6 +9715,16 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "via_verifier_dal" +version = "0.1.0" +dependencies = [ + "sqlx", + "strum 0.26.3", + "zksync_basic_types", + "zksync_db_connection", +] + [[package]] name = "via_withdrawal_client" version = "0.1.0" diff --git a/infrastructure/zk/src/format_sql.ts b/infrastructure/zk/src/format_sql.ts index 09f655f54..ece4c7eb1 100644 --- a/infrastructure/zk/src/format_sql.ts +++ b/infrastructure/zk/src/format_sql.ts @@ -159,7 +159,7 @@ async function formatFile(filePath: string, check: boolean) { export async function formatSqlxQueries(check: boolean) { process.chdir(`${process.env.ZKSYNC_HOME}`); const { stdout: filesRaw } = await utils.exec( - 'find core/lib/dal -type f -name "*.rs" && find prover/crates/lib/prover_dal -type f -name "*.rs"' + 'find core/lib/dal -type f -name "*.rs" && find prover/crates/lib/prover_dal -type f -name "*.rs" && find verifier/lib/verifier_dal -type f -name "*.rs"' ); const files = filesRaw.trim().split('\n'); const formatResults = await Promise.all(files.map((file) => formatFile(file, check))); diff --git a/via_verifier/lib/verifier_dal/Cargo.toml b/via_verifier/lib/verifier_dal/Cargo.toml index cc1687613..882a58277 100644 --- a/via_verifier/lib/verifier_dal/Cargo.toml +++ b/via_verifier/lib/verifier_dal/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "verifier_dal" +name = "via_verifier_dal" description = "Via Verifier DAL" version.workspace = true edition.workspace = true From 68e5b730a95af1655f5c2fb2e1d2b0e9a5216cb4 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 22 Dec 2024 11:48:22 +0330 Subject: [PATCH 075/212] basic config for via_verifier_dal --- infrastructure/zk/src/format_sql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/zk/src/format_sql.ts b/infrastructure/zk/src/format_sql.ts index ece4c7eb1..fc12e8d9a 100644 --- a/infrastructure/zk/src/format_sql.ts +++ b/infrastructure/zk/src/format_sql.ts @@ -159,7 +159,7 @@ async function formatFile(filePath: string, check: boolean) { export async function formatSqlxQueries(check: boolean) { process.chdir(`${process.env.ZKSYNC_HOME}`); const { stdout: filesRaw } = await utils.exec( - 'find core/lib/dal -type f -name "*.rs" && find prover/crates/lib/prover_dal -type f -name "*.rs" && find verifier/lib/verifier_dal -type f -name "*.rs"' + 'find core/lib/dal -type f -name "*.rs" && find prover/crates/lib/prover_dal -type f -name "*.rs" && find via_verifier/lib/verifier_dal -type f -name "*.rs"' ); const files = filesRaw.trim().split('\n'); const formatResults = await Promise.all(files.map((file) => formatFile(file, check))); From bee245a908b10307399249436a2e7c37cd5abc71 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 22 Dec 2024 20:34:46 +0100 Subject: [PATCH 076/212] feat: btc_watcher for verifier --- Cargo.lock | 1 + core/bin/via_verifier/src/node_builder.rs | 17 ++- core/lib/config/src/configs/mod.rs | 2 +- core/lib/config/src/configs/via_btc_watch.rs | 2 +- core/lib/config/src/lib.rs | 2 +- .../20241209150000_create_via_votes.up.sql | 2 +- .../implementations/layers/via_btc_watch.rs | 1 + core/node/via_btc_watch/Cargo.toml | 1 + core/node/via_btc_watch/src/lib.rs | 30 +++-- .../src/message_processors/mod.rs | 14 +- .../src/message_processors/verifier.rs | 125 ++++++++++++++++++ .../src/message_processors/votable.rs | 16 +-- 12 files changed, 185 insertions(+), 28 deletions(-) create mode 100644 core/node/via_btc_watch/src/message_processors/verifier.rs diff --git a/Cargo.lock b/Cargo.lock index 3de3538a6..58d803372 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9543,6 +9543,7 @@ dependencies = [ "tracing", "via_btc_client", "vise", + "zksync_config", "zksync_dal", "zksync_shared_metrics", "zksync_types", diff --git a/core/bin/via_verifier/src/node_builder.rs b/core/bin/via_verifier/src/node_builder.rs index d35115cab..a8771fbd0 100644 --- a/core/bin/via_verifier/src/node_builder.rs +++ b/core/bin/via_verifier/src/node_builder.rs @@ -1,12 +1,12 @@ use anyhow::Context; use zksync_config::{ configs::{wallets::Wallets, Secrets}, - ContractsConfig, GenesisConfig, ViaGeneralConfig, + ActorRole, ContractsConfig, GenesisConfig, ViaGeneralConfig, }; use zksync_node_framework::{ implementations::layers::{ circuit_breaker_checker::CircuitBreakerCheckerLayer, healtcheck_server::HealthCheckLayer, - sigint::SigintHandlerLayer, + sigint::SigintHandlerLayer, via_btc_watch::BtcWatchLayer, }, service::{ZkStackService, ZkStackServiceBuilder}, }; @@ -71,11 +71,24 @@ impl ViaNodeBuilder { Ok(self) } + // VIA related layers + fn add_verifier_btc_watcher_layer(mut self) -> anyhow::Result { + let mut btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); + assert_eq!( + btc_watch_config.actor_role, + ActorRole::Verifier, + "Verifier role is expected" + ); + self.node.add_layer(BtcWatchLayer::new(btc_watch_config)); + Ok(self) + } + pub fn build(self) -> anyhow::Result { Ok(self .add_sigint_handler_layer()? .add_healthcheck_layer()? .add_circuit_breaker_checker_layer()? + .add_verifier_btc_watcher_layer()? .node .build()) } diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index f69b9392c..5bad710a2 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -29,7 +29,7 @@ pub use self::{ snapshots_creator::SnapshotsCreatorConfig, utils::PrometheusConfig, via_btc_sender::ViaBtcSenderConfig, - via_btc_watch::ViaBtcWatchConfig, + via_btc_watch::{ActorRole, ViaBtcWatchConfig}, via_celestia::ViaCelestiaConfig, via_general::ViaGeneralConfig, vm_runner::{BasicWitnessInputProducerConfig, ProtectiveReadsWriterConfig}, diff --git a/core/lib/config/src/configs/via_btc_watch.rs b/core/lib/config/src/configs/via_btc_watch.rs index 0113f3cef..1fc40b355 100644 --- a/core/lib/config/src/configs/via_btc_watch.rs +++ b/core/lib/config/src/configs/via_btc_watch.rs @@ -2,7 +2,7 @@ use std::time::Duration; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Copy)] pub enum ActorRole { Sequencer, Verifier, diff --git a/core/lib/config/src/lib.rs b/core/lib/config/src/lib.rs index 8964a722e..c05508aa5 100644 --- a/core/lib/config/src/lib.rs +++ b/core/lib/config/src/lib.rs @@ -1,7 +1,7 @@ #![allow(clippy::upper_case_acronyms, clippy::derive_partial_eq_without_eq)] pub use crate::configs::{ - ApiConfig, BaseTokenAdjusterConfig, ContractVerifierConfig, ContractsConfig, + ActorRole, ApiConfig, BaseTokenAdjusterConfig, ContractVerifierConfig, ContractsConfig, DADispatcherConfig, DBConfig, EthConfig, EthWatchConfig, ExternalProofIntegrationApiConfig, GasAdjusterConfig, GenesisConfig, ObjectStoreConfig, PostgresConfig, SnapshotsCreatorConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, ViaGeneralConfig, diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index 2de67ad3d..60a45a3d0 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -1,5 +1,5 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( - l1_batch_number BIGINT NOT NULL REFERENCES l1_batches (number) ON DELETE CASCADE, + l1_batch_number BIGINT UNIQUE NOT NULL, tx_id BYTEA, is_finalized BOOLEAN NOT NULL DEFAULT FALSE, is_verified BOOLEAN NOT NULL DEFAULT FALSE, diff --git a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs index 532fa6573..da141de3d 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs @@ -89,6 +89,7 @@ impl WiringLayer for BtcWatchLayer { main_pool, self.btc_watch_config.poll_interval(), btc_blocks_lag, + self.btc_watch_config.actor_role(), ) .await?; diff --git a/core/node/via_btc_watch/Cargo.toml b/core/node/via_btc_watch/Cargo.toml index 5b58de68f..72ebcf9ac 100644 --- a/core/node/via_btc_watch/Cargo.toml +++ b/core/node/via_btc_watch/Cargo.toml @@ -16,6 +16,7 @@ via_btc_client.workspace = true zksync_shared_metrics.workspace = true zksync_dal.workspace = true zksync_types.workspace = true +zksync_config.workspace = true tokio.workspace = true anyhow.workspace = true diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index b893f4fdc..dd7025025 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -11,6 +11,7 @@ use via_btc_client::{ indexer::BitcoinInscriptionIndexer, types::{BitcoinAddress, BitcoinTxid, NodeAuth}, }; +use zksync_config::ActorRole; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_types::PriorityOpId; @@ -20,7 +21,9 @@ use self::{ }, metrics::METRICS, }; -use crate::metrics::ErrorType; +use crate::{message_processors::VerifierMessageProcessor, metrics::ErrorType}; + +const DEFAULT_VOTING_THRESHOLD: f64 = 0.5; #[derive(Debug)] struct BtcWatchState { @@ -51,6 +54,7 @@ impl BtcWatch { pool: ConnectionPool, poll_interval: Duration, btc_blocks_lag: u32, + actor_role: &ActorRole, ) -> anyhow::Result { let indexer = BitcoinInscriptionIndexer::new(rpc_url, network, node_auth, bootstrap_txids).await?; @@ -59,13 +63,23 @@ impl BtcWatch { tracing::info!("initialized state: {state:?}"); drop(storage); - let message_processors: Vec> = vec![ - Box::new(L1ToL2MessageProcessor::new( - state.bridge_address.clone(), - state.next_expected_priority_id, - )), - Box::new(VotableMessageProcessor::new()), - ]; + // Only build message processors that match the actor role: + let message_processors: Vec> = match actor_role { + ActorRole::Verifier => { + vec![Box::new(VerifierMessageProcessor::new( + DEFAULT_VOTING_THRESHOLD, + ))] + } + _ => { + vec![ + Box::new(L1ToL2MessageProcessor::new( + state.bridge_address.clone(), + state.next_expected_priority_id, + )), + Box::new(VotableMessageProcessor::new(DEFAULT_VOTING_THRESHOLD)), + ] + } + }; let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); diff --git a/core/node/via_btc_watch/src/message_processors/mod.rs b/core/node/via_btc_watch/src/message_processors/mod.rs index af783ecfe..4088d3aed 100644 --- a/core/node/via_btc_watch/src/message_processors/mod.rs +++ b/core/node/via_btc_watch/src/message_processors/mod.rs @@ -1,9 +1,15 @@ pub(crate) use l1_to_l2::L1ToL2MessageProcessor; -use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; +pub(crate) use verifier::VerifierMessageProcessor; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinTxid, FullInscriptionMessage}, +}; pub(crate) use votable::VotableMessageProcessor; use zksync_dal::{Connection, Core}; +use zksync_types::H256; mod l1_to_l2; +mod verifier; mod votable; #[derive(Debug, thiserror::Error)] @@ -23,3 +29,9 @@ pub(super) trait MessageProcessor: 'static + std::fmt::Debug + Send + Sync { indexer: &mut BitcoinInscriptionIndexer, ) -> Result<(), MessageProcessorError>; } + +pub(crate) fn convert_txid_to_h256(txid: BitcoinTxid) -> H256 { + let mut tx_id_bytes = txid.as_raw_hash()[..].to_vec(); + tx_id_bytes.reverse(); + H256::from_slice(&tx_id_bytes) +} diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs new file mode 100644 index 000000000..9e1664de5 --- /dev/null +++ b/core/node/via_btc_watch/src/message_processors/verifier.rs @@ -0,0 +1,125 @@ +use sqlx::types::chrono::{DateTime, Utc}; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinTxid, FullInscriptionMessage}, +}; +use zksync_dal::{Connection, Core, CoreDal}; +use zksync_types::{aggregated_operations::AggregatedActionType, H256}; + +use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; + +#[derive(Debug)] +pub struct VerifierMessageProcessor { + threshold: f64, +} + +impl VerifierMessageProcessor { + pub fn new(threshold: f64) -> Self { + Self { threshold } + } +} + +#[async_trait::async_trait] +impl MessageProcessor for VerifierMessageProcessor { + async fn process_messages( + &mut self, + storage: &mut Connection<'_, Core>, + msgs: Vec, + indexer: &mut BitcoinInscriptionIndexer, + ) -> Result<(), MessageProcessorError> { + // Get the current timestamp + let dt = Utc::now(); + let naive_utc = dt.naive_utc(); + let offset = dt.offset().clone(); + let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); + + for msg in msgs { + match msg { + ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + let mut votes_dal = storage.via_votes_dal(); + + let last_inserted_block = votes_dal + .get_last_inserted_block() + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + .unwrap_or(0); + + if l1_batch_number.0 != last_inserted_block + 1 { + tracing::warn!( + "Skipping ProofDAReference message with l1_batch_number: {:?}. Last inserted block: {:?}", + l1_batch_number, last_inserted_block + ); + continue; + } + + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + + votes_dal + .insert_votable_transaction(l1_batch_number.0, tx_id) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + } else { + tracing::warn!( + "L1BatchNumber not found for ProofDAReference message : {:?}", + proof_msg + ); + } + } + ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + let mut votes_dal = storage.via_votes_dal(); + + let reference_txid = + convert_txid_to_h256(attestation_msg.input.reference_txid); + let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); + + // Vote = true if attestation_msg.input.attestation == Vote::Ok + let is_ok = matches!( + attestation_msg.input.attestation, + via_btc_client::types::Vote::Ok + ); + votes_dal + .insert_vote( + l1_batch_number.0, + reference_txid, + &attestation_msg.common.p2wpkh_address.to_string(), + is_ok, + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + // Check finalization + if votes_dal + .finalize_transaction_if_needed( + l1_batch_number.0, + reference_txid, + self.threshold, + indexer.get_number_of_verifiers(), + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + { + tracing::info!( + "Finalizing transaction with tx_id: {:?} and block number: {:?}", + tx_id, + l1_batch_number + ); + } + } + } + // bootstrapping phase is already covered + FullInscriptionMessage::ProposeSequencer(_) + | FullInscriptionMessage::SystemBootstrapping(_) => { + // do nothing + } + // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor + FullInscriptionMessage::L1ToL2Message(_) + | FullInscriptionMessage::L1BatchDAReference(_) => { + // do nothing + } + } + } + Ok(()) + } +} diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 4b5b2f21f..862ff5a93 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -6,9 +6,7 @@ use via_btc_client::{ use zksync_dal::{Connection, Core, CoreDal}; use zksync_types::{aggregated_operations::AggregatedActionType, H256}; -use super::{MessageProcessor, MessageProcessorError}; - -const DEFAULT_THRESHOLD: f64 = 0.5; +use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; #[derive(Debug)] pub struct VotableMessageProcessor { @@ -16,10 +14,8 @@ pub struct VotableMessageProcessor { } impl VotableMessageProcessor { - pub fn new() -> Self { - Self { - threshold: DEFAULT_THRESHOLD, - } + pub fn new(threshold: f64) -> Self { + Self { threshold } } } @@ -159,9 +155,3 @@ impl MessageProcessor for VotableMessageProcessor { Ok(()) } } - -fn convert_txid_to_h256(txid: BitcoinTxid) -> H256 { - let mut tx_id_bytes = txid.as_raw_hash()[..].to_vec(); - tx_id_bytes.reverse(); - H256::from_slice(&tx_id_bytes) -} From 49a302ff6bb5df7c5079db976b1e124d0ac99cf5 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 22 Dec 2024 21:44:47 +0100 Subject: [PATCH 077/212] fix: set the last bootloarder and aa hashes --- core/node/via_btc_sender/src/btc_inscription_aggregator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index 9c5ab99ec..69af67d05 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -128,13 +128,13 @@ impl ViaBtcInscriptionAggregator { // Todo: call indexer to fetch the data async fn get_bootloader_code_hash(&self) -> anyhow::Result { - let hex_str = "010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e"; + let hex_str = "010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491"; Ok(H256::from_str(hex_str).unwrap()) } // Todo: call indexer to fetch the data async fn get_aa_code_hash(&self) -> anyhow::Result { - let hex_str = "01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32"; + let hex_str = "01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f"; Ok(H256::from_str(hex_str).unwrap()) } From b7ed9456cc800c8f81717a74e007d3af2e28fade Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 23 Dec 2024 12:14:19 +0330 Subject: [PATCH 078/212] remove via_node_framework --- Cargo.lock | 4 ++++ Cargo.toml | 3 ++- via_verifier/node/verification_service/Cargo.toml | 11 +++++++++++ via_verifier/node/verification_service/src/lib.rs | 0 via_verifier/node/withdrawal_service/Cargo.toml | 11 +++++++++++ via_verifier/node/withdrawal_service/src/lib.rs | 1 + 6 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 via_verifier/node/verification_service/Cargo.toml create mode 100644 via_verifier/node/verification_service/src/lib.rs create mode 100644 via_verifier/node/withdrawal_service/Cargo.toml create mode 100644 via_verifier/node/withdrawal_service/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 500eea9af..c96aa48d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9747,6 +9747,10 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "via_withdrawal_service" +version = "0.1.0" + [[package]] name = "vise" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index a2a5f47c6..f69f80044 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,6 +99,7 @@ members = [ "via_verifier/lib/via_verification", "via_verifier/lib/via_musig2", "via_verifier/lib/verifier_dal", + "via_verifier/node/withdrawal_service", ] resolver = "2" @@ -335,4 +336,4 @@ via_withdrawal_client = { version = "0.1.0", path = "via_verifier/lib/via_withdr via_verification = { version = "0.1.0", path = "via_verifier/lib/via_verification" } via_musig2 = { version = "0.1.0", path = "via_verifier/lib/via_musig2" } via_verifier_dal = { version = "0.1.0", path = "via_verifier/lib/verifier_dal" } - +via_withdrawal_service = { version = "0.1.0", path = "via_verifier/node/withdrawal_service" } diff --git a/via_verifier/node/verification_service/Cargo.toml b/via_verifier/node/verification_service/Cargo.toml new file mode 100644 index 000000000..63cf7a09b --- /dev/null +++ b/via_verifier/node/verification_service/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "via_verification_service" +description = "Via Verification Service" +version.workspace = true +edition.workspace = true +authors = ["Via Network"] + + +[dependencies] + +[dev-dependencies] diff --git a/via_verifier/node/verification_service/src/lib.rs b/via_verifier/node/verification_service/src/lib.rs new file mode 100644 index 000000000..e69de29bb diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml new file mode 100644 index 000000000..08cf9c893 --- /dev/null +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "via_withdrawal_service" +description = "Via Withdrawal Service" +version.workspace = true +edition.workspace = true +authors = ["Via Network"] + + +[dependencies] + +[dev-dependencies] diff --git a/via_verifier/node/withdrawal_service/src/lib.rs b/via_verifier/node/withdrawal_service/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/lib.rs @@ -0,0 +1 @@ + From 54d918e54b7c263231f24c5cd7fa9cc0c511b93c Mon Sep 17 00:00:00 2001 From: Miroslav Pavlovic Date: Mon, 23 Dec 2024 15:51:28 +0100 Subject: [PATCH 079/212] fix: add house keeper layer --- core/bin/via_server/src/node_builder.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 397e3064b..59b0319d2 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -14,6 +14,7 @@ use zksync_node_framework::{ circuit_breaker_checker::CircuitBreakerCheckerLayer, commitment_generator::CommitmentGeneratorLayer, healtcheck_server::HealthCheckLayer, + house_keeper::HouseKeeperLayer, logs_bloom_backfill::LogsBloomBackfillLayer, metadata_calculator::MetadataCalculatorLayer, node_storage_init::{ @@ -368,6 +369,24 @@ impl ViaNodeBuilder { Ok(self) } + fn add_house_keeper_layer(mut self) -> anyhow::Result { + let house_keeper_config = try_load_config!(self.configs.house_keeper_config); + let fri_prover_config = try_load_config!(self.configs.prover_config); + let fri_witness_generator_config = try_load_config!(self.configs.witness_generator_config); + let fri_prover_group_config = try_load_config!(self.configs.prover_group_config); + let fri_proof_compressor_config = try_load_config!(self.configs.proof_compressor_config); + + self.node.add_layer(HouseKeeperLayer::new( + house_keeper_config, + fri_prover_config, + fri_witness_generator_config, + fri_prover_group_config, + fri_proof_compressor_config, + )); + + Ok(self) + } + fn add_commitment_generator_layer(mut self) -> anyhow::Result { self.node.add_layer(CommitmentGeneratorLayer::new( self.genesis_config.l1_batch_commit_data_generator_mode, @@ -446,6 +465,7 @@ impl ViaNodeBuilder { .add_via_celestia_da_client_layer()? .add_da_dispatcher_layer()? .add_proof_data_handler_layer()? + .add_house_keeper_layer()? .node .build()) } From cc894fba13fecd88622b738cf3a694574c1ee355 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sun, 22 Dec 2024 21:44:47 +0100 Subject: [PATCH 080/212] fix: set the last bootloarder and aa hashes --- core/node/via_btc_sender/src/btc_inscription_aggregator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index 081e3bbe1..8bd70d338 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -128,13 +128,13 @@ impl ViaBtcInscriptionAggregator { // Todo: call indexer to fetch the data async fn get_bootloader_code_hash(&self) -> anyhow::Result { - let hex_str = "010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e"; + let hex_str = "010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491"; Ok(H256::from_str(hex_str).unwrap()) } // Todo: call indexer to fetch the data async fn get_aa_code_hash(&self) -> anyhow::Result { - let hex_str = "01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32"; + let hex_str = "01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f"; Ok(H256::from_str(hex_str).unwrap()) } From 9248c8e54dcd5d732b91968f67afa64dfca01337 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 25 Dec 2024 01:06:55 +0100 Subject: [PATCH 081/212] feat: zk verifier layer --- Cargo.lock | 23 ++ Cargo.toml | 3 +- core/bin/via_server/src/node_builder.rs | 9 + core/bin/via_verifier/src/node_builder.rs | 1 + ...2589f611ef94174e6536811076cbc9d318fd3.json | 26 +++ ...762f56b1ea92dc3bdb03aef290a6457d6232b.json | 15 ++ .../20241209150000_create_via_votes.up.sql | 3 +- .../models/storage_btc_inscription_request.rs | 5 +- core/lib/dal/src/via_votes_dal.rs | 56 +++++ core/lib/via_btc_client/src/indexer/mod.rs | 11 +- core/lib/via_btc_client/src/lib.rs | 2 +- core/lib/via_btc_client/src/types.rs | 6 +- core/lib/via_btc_client/src/utils.rs | 8 + core/node/node_framework/Cargo.toml | 1 + .../src/implementations/layers/mod.rs | 2 + .../layers/via_zk_verification.rs | 96 ++++++++ .../src/message_processors/verifier.rs | 13 +- .../src/message_processors/votable.rs | 7 +- core/node/via_zk_verifier/Cargo.toml | 32 +++ core/node/via_zk_verifier/src/lib.rs | 212 ++++++++++++++++++ 20 files changed, 503 insertions(+), 28 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json create mode 100644 core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json create mode 100644 core/node/node_framework/src/implementations/layers/via_zk_verification.rs create mode 100644 core/node/via_zk_verifier/Cargo.toml create mode 100644 core/node/via_zk_verifier/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 58d803372..8719d02fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9738,6 +9738,28 @@ dependencies = [ "zksync_utils", ] +[[package]] +name = "via_zk_verifier" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "serde", + "sqlx", + "thiserror", + "tokio", + "tracing", + "via_btc_client", + "vise", + "zksync_config", + "zksync_da_client", + "zksync_dal", + "zksync_prover_interface", + "zksync_shared_metrics", + "zksync_types", +] + [[package]] name = "vise" version = "0.2.0" @@ -11758,6 +11780,7 @@ dependencies = [ "via_da_dispatcher", "via_fee_model", "via_state_keeper", + "via_zk_verifier", "zksync_base_token_adjuster", "zksync_block_reverter", "zksync_circuit_breaker", diff --git a/Cargo.toml b/Cargo.toml index ee21f6f1a..2f4545f92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,7 +96,7 @@ members = [ "core/lib/via_musig2", "core/lib/via_withdrawal_client", "core/bin/via_verifier", - + "core/node/via_zk_verifier", ] resolver = "2" @@ -329,3 +329,4 @@ via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } via_musig2 = { version = "0.1.0", path = "core/lib/via_musig2" } +via_zk_verifier = { version = "0.1.0", path = "core/node/via_zk_verifier" } diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 5cc6c10c0..06a5e137e 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -36,6 +36,7 @@ use zksync_node_framework::{ main_batch_executor::MainBatchExecutorLayer, mempool_io::MempoolIOLayer, output_handler::OutputHandlerLayer, RocksdbStorageOptions, StateKeeperLayer, }, + via_zk_verification::ViaBtcProofVerificationLayer, vm_runner::{ bwip::BasicWitnessInputProducerLayer, protective_reads::ProtectiveReadsWriterLayer, }, @@ -173,6 +174,13 @@ impl ViaNodeBuilder { self.node.add_layer(layer); Ok(self) } + // TODO: remove! + fn add_via_verification_test_layer(mut self) -> anyhow::Result { + let btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); + self.node + .add_layer(ViaBtcProofVerificationLayer::new(btc_watch_config)); + Ok(self) + } // VIA related layers fn add_btc_watcher_layer(mut self) -> anyhow::Result { @@ -448,6 +456,7 @@ impl ViaNodeBuilder { .add_commitment_generator_layer()? .add_via_celestia_da_client_layer()? .add_da_dispatcher_layer()? + .add_via_verification_test_layer()? .node .build()) } diff --git a/core/bin/via_verifier/src/node_builder.rs b/core/bin/via_verifier/src/node_builder.rs index a8771fbd0..5165aa163 100644 --- a/core/bin/via_verifier/src/node_builder.rs +++ b/core/bin/via_verifier/src/node_builder.rs @@ -74,6 +74,7 @@ impl ViaNodeBuilder { // VIA related layers fn add_verifier_btc_watcher_layer(mut self) -> anyhow::Result { let mut btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); + btc_watch_config.actor_role = ActorRole::Verifier; assert_eq!( btc_watch_config.actor_role, ActorRole::Verifier, diff --git a/core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json b/core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json new file mode 100644 index 000000000..cfdf7b0d7 --- /dev/null +++ b/core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_executed = FALSE\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false + ] + }, + "hash": "54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3" +} diff --git a/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json b/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json new file mode 100644 index 000000000..940c5ee19 --- /dev/null +++ b/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n is_executed = TRUE,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b" +} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index 60a45a3d0..56a647859 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -4,6 +4,7 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( is_finalized BOOLEAN NOT NULL DEFAULT FALSE, is_verified BOOLEAN NOT NULL DEFAULT FALSE, l1_batch_status BOOLEAN NOT NULL DEFAULT FALSE, + is_executed BOOLEAN NOT NULL DEFAULT FALSE, -- This flag is used to determine if the transaction has been executed by verifier created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (l1_batch_number, tx_id) @@ -17,5 +18,5 @@ CREATE TABLE IF NOT EXISTS via_votes ( created_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (l1_batch_number, tx_id, verifier_address), FOREIGN KEY (l1_batch_number, tx_id) REFERENCES via_votable_transactions (l1_batch_number, tx_id) ON DELETE CASCADE - ); +); diff --git a/core/lib/dal/src/models/storage_btc_inscription_request.rs b/core/lib/dal/src/models/storage_btc_inscription_request.rs index 4aef6b110..baf0d71f3 100644 --- a/core/lib/dal/src/models/storage_btc_inscription_request.rs +++ b/core/lib/dal/src/models/storage_btc_inscription_request.rs @@ -2,10 +2,7 @@ use std::str::FromStr; use bitcoin::Txid; use sqlx::types::chrono::NaiveDateTime; -use zksync_types::{ - btc_inscription_operations::ViaBtcInscriptionRequestType, - btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}, -}; +use zksync_types::btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}; #[derive(Debug, Clone)] pub struct ViaStorageBtcInscriptionRequest { diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 7493d7748..55483427c 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -243,4 +243,60 @@ impl ViaVotesDal<'_, '_> { Ok(result) } + + /// Marks a transaction as executed. + pub async fn mark_transaction_executed( + &mut self, + l1_batch_number: i64, + tx_id: H256, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + is_executed = TRUE, + updated_at = NOW() + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + l1_batch_number, + tx_id.as_bytes() + ) + .instrument("mark_transaction_executed") + .execute(self.storage) + .await?; + + Ok(()) + } + + /// Retrieve the first not executed block. (Similar to `get_first_not_finilized_block`, just with `is_executed = FALSE`). + pub async fn get_first_not_executed_block(&mut self) -> DalResult)>> { + let row = sqlx::query!( + r#" + SELECT + l1_batch_number, + tx_id + FROM + via_votable_transactions + WHERE + is_executed = FALSE + ORDER BY + l1_batch_number ASC + LIMIT + 1 + "#, + ) + .instrument("get_first_not_executed_block") + .fetch_optional(self.storage) + .await?; + + let result = row.map(|r| { + let l1_batch_number = r.l1_batch_number; + let tx_id = r.tx_id; + (l1_batch_number, tx_id) + }); + + Ok(result) + } } diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index c979048ba..7e8355f32 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -5,8 +5,7 @@ use bitcoincore_rpc::Auth; use tracing::{debug, error, info, instrument, warn}; mod parser; -pub use parser::get_eth_address; -use parser::MessageParser; +pub use parser::{get_eth_address, MessageParser}; use zksync_basic_types::L1BatchNumber; use zksync_types::H256; @@ -206,6 +205,14 @@ impl BitcoinInscriptionIndexer { pub fn get_number_of_verifiers(&self) -> usize { self.verifier_addresses.len() } + + pub async fn parse_transaction( + &mut self, + tx: &Txid, + ) -> BitcoinIndexerResult> { + let tx = self.client.get_transaction(&tx).await?; + Ok(self.parser.parse_transaction(&tx, 0)) + } } impl BitcoinInscriptionIndexer { diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index 02b64c37f..263cab453 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -7,5 +7,5 @@ pub mod inscriber; #[cfg(feature = "regtest")] pub mod regtest; pub(crate) mod signer; -pub(crate) mod utils; +pub mod utils; pub mod withdrawal_builder; diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index eb440f424..bdcc75c59 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -2,8 +2,8 @@ use std::collections::VecDeque; use bincode::{deserialize, serialize}; use bitcoin::{ - address::NetworkUnchecked, script::PushBytesBuf, taproot::Signature as TaprootSignature, - Amount, TxIn, TxOut, Txid, + address::NetworkUnchecked, hashes::FromSliceError, script::PushBytesBuf, + taproot::Signature as TaprootSignature, Amount, TxIn, TxOut, Txid, }; pub use bitcoin::{Address as BitcoinAddress, Network as BitcoinNetwork, Txid as BitcoinTxid}; pub use bitcoincore_rpc::Auth as NodeAuth; @@ -323,6 +323,8 @@ pub enum IndexerError { InvalidBlockHeight(u32), #[error("Bitcoin client error: {0}")] BitcoinClientError(#[from] BitcoinError), + #[error("Tx_id parsing error: {0}")] + TxIdParsingError(#[from] FromSliceError), } pub type BitcoinIndexerResult = std::result::Result; diff --git a/core/lib/via_btc_client/src/utils.rs b/core/lib/via_btc_client/src/utils.rs index 719f7bf98..33e6a1a06 100644 --- a/core/lib/via_btc_client/src/utils.rs +++ b/core/lib/via_btc_client/src/utils.rs @@ -1,5 +1,8 @@ +use bitcoin::{hashes::Hash, Txid}; use tokio::time::Duration; +use crate::types; + pub(crate) async fn with_retry( f: F, max_retries: u8, @@ -28,3 +31,8 @@ where } } } + +pub fn bytes_to_txid(bytes: &[u8]) -> Result { + let txid = Txid::from_slice(bytes).map_err(|e| types::IndexerError::TxIdParsingError(e))?; + Ok(txid) +} diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index be49135cf..9d7766fde 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -63,6 +63,7 @@ via_btc_sender.workspace = true via_fee_model.workspace = true via_da_dispatcher.workspace = true via_state_keeper.workspace = true +via_zk_verifier.workspace = true pin-project-lite.workspace = true tracing.workspace = true thiserror.workspace = true diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index cd8534b04..4198027de 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -41,5 +41,7 @@ pub mod via_da_dispatcher; pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; +// TODO: TMP in sequencer +pub mod via_zk_verification; pub mod vm_runner; pub mod web3_api; diff --git a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs new file mode 100644 index 000000000..278e1626f --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs @@ -0,0 +1,96 @@ +use async_trait::async_trait; +use via_btc_client::types::{BitcoinNetwork, NodeAuth}; +use via_zk_verifier::ViaVerifier; +use zksync_config::ViaBtcWatchConfig; + +use crate::{ + implementations::resources::{ + da_client::DAClientResource, + pools::{MasterPool, PoolResource}, + }, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +#[derive(Debug)] +pub struct ViaBtcProofVerificationLayer { + config: ViaBtcWatchConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct ProofVerificationInput { + pub master_pool: PoolResource, + pub da_client: DAClientResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct ProofVerificationOutput { + #[context(task)] + pub via_proof_verification: ViaVerifier, +} + +impl ViaBtcProofVerificationLayer { + pub fn new(config: ViaBtcWatchConfig) -> Self { + Self { config } + } +} + +#[async_trait] +impl WiringLayer for ViaBtcProofVerificationLayer { + type Input = ProofVerificationInput; + type Output = ProofVerificationOutput; + + fn layer_name(&self) -> &'static str { + "via_btc_proof_verification_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + let main_pool = input.master_pool.get().await?; + let network = BitcoinNetwork::from_core_arg(self.config.network()) + .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; + let node_auth = NodeAuth::UserPass( + self.config.rpc_user().to_string(), + self.config.rpc_password().to_string(), + ); + let bootstrap_txids = self + .config + .bootstrap_txids() + .iter() + .map(|txid| { + txid.parse() + .map_err(|_| WiringError::Configuration("Wrong txid in config".to_string())) + }) + .collect::, _>>()?; + + let via_proof_verification = ViaVerifier::new( + self.config.rpc_url(), + network, + node_auth, + bootstrap_txids, + main_pool, + input.da_client.0, + self.config.clone(), + ) + .await + .map_err(WiringError::internal)?; + + Ok(ProofVerificationOutput { + via_proof_verification, + }) + } +} + +#[async_trait::async_trait] +impl Task for ViaVerifier { + fn id(&self) -> TaskId { + "via_proof_verification".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs index 9e1664de5..e355aaf14 100644 --- a/core/node/via_btc_watch/src/message_processors/verifier.rs +++ b/core/node/via_btc_watch/src/message_processors/verifier.rs @@ -1,10 +1,5 @@ -use sqlx::types::chrono::{DateTime, Utc}; -use via_btc_client::{ - indexer::BitcoinInscriptionIndexer, - types::{BitcoinTxid, FullInscriptionMessage}, -}; +use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; use zksync_dal::{Connection, Core, CoreDal}; -use zksync_types::{aggregated_operations::AggregatedActionType, H256}; use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; @@ -27,12 +22,6 @@ impl MessageProcessor for VerifierMessageProcessor { msgs: Vec, indexer: &mut BitcoinInscriptionIndexer, ) -> Result<(), MessageProcessorError> { - // Get the current timestamp - let dt = Utc::now(); - let naive_utc = dt.naive_utc(); - let offset = dt.offset().clone(); - let dt = DateTime::::from_naive_utc_and_offset(naive_utc, offset); - for msg in msgs { match msg { ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 862ff5a93..4a0f4d4d8 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -1,10 +1,7 @@ use sqlx::types::chrono::{DateTime, Utc}; -use via_btc_client::{ - indexer::BitcoinInscriptionIndexer, - types::{BitcoinTxid, FullInscriptionMessage}, -}; +use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; use zksync_dal::{Connection, Core, CoreDal}; -use zksync_types::{aggregated_operations::AggregatedActionType, H256}; +use zksync_types::aggregated_operations::AggregatedActionType; use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; diff --git a/core/node/via_zk_verifier/Cargo.toml b/core/node/via_zk_verifier/Cargo.toml new file mode 100644 index 000000000..1b27e0b87 --- /dev/null +++ b/core/node/via_zk_verifier/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "via_zk_verifier" +description = "VIA zk verifier" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +vise.workspace = true +via_btc_client.workspace = true +zksync_shared_metrics.workspace = true +zksync_dal.workspace = true +zksync_types.workspace = true +zksync_config.workspace = true +zksync_da_client.workspace = true +zksync_prover_interface.workspace = true + +tokio.workspace = true +anyhow.workspace = true +bincode.workspace = true +thiserror.workspace = true +async-trait.workspace = true +tracing.workspace = true +sqlx.workspace = true +serde.workspace = true + +[dev-dependencies] diff --git a/core/node/via_zk_verifier/src/lib.rs b/core/node/via_zk_verifier/src/lib.rs new file mode 100644 index 000000000..6da15d099 --- /dev/null +++ b/core/node/via_zk_verifier/src/lib.rs @@ -0,0 +1,212 @@ +use anyhow::Context; +use tokio::sync::watch; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{ + BitcoinNetwork, BitcoinTxid, FullInscriptionMessage, L1BatchDAReference, NodeAuth, + ProofDAReference, + }, + utils::bytes_to_txid, +}; +use zksync_config::ViaBtcWatchConfig; +use zksync_da_client::{types::InclusionData, DataAvailabilityClient}; +use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; +use zksync_prover_interface::outputs::L1BatchProofForL1; +use zksync_types::{commitment::L1BatchWithMetadata, H256}; + +/// Copy of `zksync_l1_contract_interface::i_executor::methods::ProveBatches` +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ProveBatches { + pub prev_l1_batch: L1BatchWithMetadata, + pub l1_batches: Vec, + pub proofs: Vec, + pub should_verify: bool, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct L1BatchData { + pub pubdata: Vec, + pub l1_batch_number: u32, +} + +#[derive(Debug)] +pub struct ViaVerifier { + pool: ConnectionPool, + da_client: Box, + indexer: BitcoinInscriptionIndexer, + // TODO: Add config + config: ViaBtcWatchConfig, +} + +impl ViaVerifier { + pub async fn new( + rpc_url: &str, + network: BitcoinNetwork, + node_auth: NodeAuth, + bootstrap_txids: Vec, + pool: ConnectionPool, + client: Box, + config: ViaBtcWatchConfig, + ) -> anyhow::Result { + let indexer = + BitcoinInscriptionIndexer::new(rpc_url, network, node_auth, bootstrap_txids).await?; + Ok(Self { + pool, + da_client: client, + indexer, + config, + }) + } + + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut timer = tokio::time::interval(self.config.poll_interval()); + let pool = self.pool.clone(); + + while !*stop_receiver.borrow_and_update() { + tokio::select! { + _ = timer.tick() => { /* continue iterations */ } + _ = stop_receiver.changed() => break, + } + + let mut storage = pool.connection_tagged("via_zk_verifier").await?; + match self.loop_iteration(&mut storage).await { + Ok(()) => tracing::info!(""), + Err(err) => tracing::error!("Failed to process via_zk_verifier: {err}"), + } + } + + tracing::info!("Stop signal received, via_zk_verifier is shutting down"); + Ok(()) + } + + pub async fn loop_iteration( + &mut self, + storage: &mut Connection<'_, Core>, + ) -> anyhow::Result<()> { + if let Some((l1_batch_number, mut raw_tx_id)) = storage + .via_votes_dal() + .get_first_not_executed_block() + .await? + { + let db_raw_tx_id = H256::from_slice(&raw_tx_id); + tracing::info!("New non executed block ready to be processed"); + + raw_tx_id.reverse(); + let proof_txid = bytes_to_txid(&raw_tx_id).context("Failed to parse tx_id")?; + tracing::warn!("trying to get proof_txid: {}", proof_txid); + let proof_msgs = self.indexer.parse_transaction(&proof_txid).await?; + let proof_msg = self.expect_single_msg(&proof_msgs, "ProofDAReference")?; + + let proof_da = match proof_msg { + FullInscriptionMessage::ProofDAReference(ref a) => a, + _ => { + tracing::error!("Expected ProofDAReference, got something else"); + return Ok(()); + } + }; + + let (proof_blob, batch_tx_id) = self.process_proof_da_reference(proof_da).await?; + + let batch_msgs = self.indexer.parse_transaction(&batch_tx_id).await?; + let batch_msg = self.expect_single_msg(&batch_msgs, "L1BatchDAReference")?; + + let batch_da = match batch_msg { + FullInscriptionMessage::L1BatchDAReference(ref a) => a, + _ => { + tracing::error!("Expected L1BatchDAReference, got something else"); + return Ok(()); + } + }; + + let (batch_blob, batch_hash) = self.process_batch_da_reference(batch_da).await?; + + let is_verified = self + .verify_proof(batch_hash, proof_blob.data, batch_blob.data) + .await?; + + storage + .via_votes_dal() + .mark_transaction_executed(l1_batch_number, db_raw_tx_id) + .await?; + storage + .via_votes_dal() + .verify_votable_transaction(l1_batch_number as u32, db_raw_tx_id, is_verified) + .await?; + } + + Ok(()) + } + + /// Helper to ensure there's exactly one message in the array, or log an error. + fn expect_single_msg<'a>( + &self, + msgs: &'a [FullInscriptionMessage], + expected_type: &str, + ) -> anyhow::Result<&'a FullInscriptionMessage> { + match msgs.len() { + 1 => Ok(&msgs[0]), + n => { + tracing::error!("Expected 1 {expected_type} message, got {n}"); + Err(anyhow::anyhow!("Expected exactly 1 message, got {n}")) + } + } + } + + /// Processes a `ProofDAReference` message by retrieving the DA blob + async fn process_proof_da_reference( + &mut self, + proof_msg: &ProofDAReference, + ) -> anyhow::Result<(InclusionData, BitcoinTxid)> { + let blob = self + .da_client + .get_inclusion_data(&proof_msg.input.blob_id) + .await + .context("Failed to get blob")? + .ok_or_else(|| anyhow::anyhow!("Blob not found"))?; + let batch_tx_id = proof_msg.input.l1_batch_reveal_txid; + + Ok((blob, batch_tx_id)) + } + + /// Processes an `L1BatchDAReference` message by retrieving the DA blob + async fn process_batch_da_reference( + &mut self, + batch_msg: &L1BatchDAReference, + ) -> anyhow::Result<(InclusionData, H256)> { + let blob = self + .da_client + .get_inclusion_data(&batch_msg.input.blob_id) + .await + .context("Failed to get blob")? + .ok_or_else(|| anyhow::anyhow!("Blob not found"))?; + let hash = batch_msg.input.l1_batch_hash; + + Ok((blob, hash)) + } + + async fn verify_proof( + &self, + batch_hash: H256, + proof: Vec, + batch: Vec, + ) -> anyhow::Result { + tracing::info!( + ?batch_hash, + proof_len = proof.len(), + batch_len = batch.len(), + "Verifying proof" + ); + let proof: ProveBatches = bincode::deserialize(&proof)?; + + // TODO: fetch and verify pubdata + // let batch: L1BatchData = bincode::deserialize(&batch) + // .context("Failed to deserialize L1BatchWithMetadata")?; + + if !proof.should_verify { + Ok(true) + } else { + // TODO: Verify the proof + Ok(false) + } + } +} From 510eb3903f485538c44e114373ffd1d0a07642cc Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 26 Dec 2024 09:57:43 +0100 Subject: [PATCH 082/212] fix: code review - functtion name typo - optimize query - wrong error message --- ...a3cdd314652a88cd6009a9fca9358b6aa4e59.json | 20 +++++++++++++++++++ ...8a4f575900be3a16a55297d521436dd27809b.json | 20 ------------------- .../models/storage_btc_inscription_request.rs | 5 +---- core/lib/dal/src/via_verifier_blocks_dal.rs | 6 +++++- core/lib/dal/src/via_votes_dal.rs | 15 +++++++------- .../src/btc_vote_inscription.rs | 2 +- core/node/via_btc_sender/src/tests/utils.rs | 4 ++-- 7 files changed, 36 insertions(+), 36 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json delete mode 100644 core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json diff --git a/core/lib/dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json b/core/lib/dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json new file mode 100644 index 000000000..414285372 --- /dev/null +++ b/core/lib/dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(l1_batch_number) as \"l1_batch_number\"\n FROM via_votable_transactions\n WHERE\n is_finalized = FALSE \n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59" +} diff --git a/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json b/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json deleted file mode 100644 index 222e9d57e..000000000 --- a/core/lib/dal/.sqlx/query-cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n l1_batch_number\n FROM\n via_votable_transactions\n WHERE\n is_finalized = FALSE\n ORDER BY l1_batch_number ASC\n LIMIT 1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "l1_batch_number", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - false - ] - }, - "hash": "cc178cc45d4049d861e3ee0df418a4f575900be3a16a55297d521436dd27809b" -} diff --git a/core/lib/dal/src/models/storage_btc_inscription_request.rs b/core/lib/dal/src/models/storage_btc_inscription_request.rs index 4aef6b110..baf0d71f3 100644 --- a/core/lib/dal/src/models/storage_btc_inscription_request.rs +++ b/core/lib/dal/src/models/storage_btc_inscription_request.rs @@ -2,10 +2,7 @@ use std::str::FromStr; use bitcoin::Txid; use sqlx::types::chrono::NaiveDateTime; -use zksync_types::{ - btc_inscription_operations::ViaBtcInscriptionRequestType, - btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}, -}; +use zksync_types::btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}; #[derive(Debug, Clone)] pub struct ViaStorageBtcInscriptionRequest { diff --git a/core/lib/dal/src/via_verifier_blocks_dal.rs b/core/lib/dal/src/via_verifier_blocks_dal.rs index b9dab3a55..3c1206d73 100644 --- a/core/lib/dal/src/via_verifier_blocks_dal.rs +++ b/core/lib/dal/src/via_verifier_blocks_dal.rs @@ -47,7 +47,11 @@ impl ViaVerifierBlocksDal<'_, '_> { if result.rows_affected() == 0 { let err = instrumentation.constraint_error(anyhow::anyhow!( - "Update commit_l1_batch_inscription_id that is is not null is not allowed" + "Failed to insert into 'via_l1_batch_vote_inscription_request': \ + No rows were affected. This could be due to a conflict or invalid input values. \ + batch_number: {:?}, inscription_request_id: {:?}", + i64::from(batch_number.0), + inscription_request_id as i32 )); return Err(err); } diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index d1cd998bb..3014606b8 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -193,22 +193,21 @@ impl ViaVotesDal<'_, '_> { Ok(()) } - pub async fn get_first_not_finilized_block(&mut self) -> DalResult> { + pub async fn get_first_non_finalized_block(&mut self) -> DalResult> { let l1_block_number = sqlx::query_scalar!( r#" SELECT - l1_batch_number - FROM - via_votable_transactions + MIN(l1_batch_number) as "l1_batch_number" + FROM via_votable_transactions WHERE - is_finalized = FALSE - ORDER BY l1_batch_number ASC - LIMIT 1 + is_finalized = FALSE "#, ) .instrument("get_last_block_finilized") .fetch_optional(self.storage) - .await?; + .await? + .flatten(); + Ok(l1_block_number) } diff --git a/core/node/via_btc_sender/src/btc_vote_inscription.rs b/core/node/via_btc_sender/src/btc_vote_inscription.rs index c7531527c..92f2e754e 100644 --- a/core/node/via_btc_sender/src/btc_vote_inscription.rs +++ b/core/node/via_btc_sender/src/btc_vote_inscription.rs @@ -92,7 +92,7 @@ impl ViaVoteInscription { ) -> anyhow::Result)>> { if let Some(batch_number) = storage .via_votes_dal() - .get_first_not_finilized_block() + .get_first_non_finalized_block() .await? { // Check if already created a voting inscription diff --git a/core/node/via_btc_sender/src/tests/utils.rs b/core/node/via_btc_sender/src/tests/utils.rs index bbf02b235..558277606 100644 --- a/core/node/via_btc_sender/src/tests/utils.rs +++ b/core/node/via_btc_sender/src/tests/utils.rs @@ -31,9 +31,9 @@ use crate::{ }; pub const BOOTLOADER_CODE_HASH_TEST: &str = - "010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e"; + "010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491"; pub const DEFAULT_AA_CODE_HASH_TEST: &str = - "01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32"; + "01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f"; pub fn generate_random_bytes(length: usize) -> Vec { let mut bytes: Vec = vec![]; From 1bab89a3dcafe298aa248a7ab40adfa9d4fb9129 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Thu, 26 Dec 2024 18:55:02 +0100 Subject: [PATCH 083/212] feat: ViaVerifier layer --- Cargo.lock | 1 + Cargo.toml | 1 + core/bin/via_server/src/config.rs | 20 +- core/bin/via_server/src/main.rs | 1 + core/bin/via_server/src/node_builder.rs | 8 +- core/lib/config/src/configs/mod.rs | 2 + core/lib/config/src/configs/via_general.rs | 4 +- core/lib/config/src/configs/via_verifier.rs | 21 + core/lib/config/src/lib.rs | 2 +- core/lib/env_config/src/lib.rs | 2 + core/lib/env_config/src/via_verifier.rs | 9 + .../zksync-era-verification-cli/contract.rs | 5 +- .../protocol_version/26/scheduler_key.json | 399 ++++++++++++++++++ core/lib/via_verification/src/proof.rs | 15 +- .../lib/via_verification/src/public_inputs.rs | 11 +- core/lib/via_verification/src/utils.rs | 27 ++ .../layers/via_zk_verification.rs | 22 +- core/node/via_zk_verifier/Cargo.toml | 2 + core/node/via_zk_verifier/src/lib.rs | 102 +++-- etc/env/configs/via_base.toml | 4 + 20 files changed, 603 insertions(+), 55 deletions(-) create mode 100644 core/lib/config/src/configs/via_verifier.rs create mode 100644 core/lib/env_config/src/via_verifier.rs create mode 100644 core/lib/via_verification/keys/protocol_version/26/scheduler_key.json diff --git a/Cargo.lock b/Cargo.lock index 8719d02fd..94916b8b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9750,6 +9750,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "via-verification", "via_btc_client", "vise", "zksync_config", diff --git a/Cargo.toml b/Cargo.toml index 2f4545f92..94ea1c27b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -329,4 +329,5 @@ via_btc_sender = { version = "0.1.0", path = "core/node/via_btc_sender" } via_fee_model = { version = "0.1.0", path = "core/node/via_fee_model" } via_state_keeper = { version = "0.1.0", path = "core/node/via_state_keeper" } via_musig2 = { version = "0.1.0", path = "core/lib/via_musig2" } +via-verification = { version = "0.1.0", path = "core/lib/via_verification" } via_zk_verifier = { version = "0.1.0", path = "core/node/via_zk_verifier" } diff --git a/core/bin/via_server/src/config.rs b/core/bin/via_server/src/config.rs index 427373973..1251a909a 100644 --- a/core/bin/via_server/src/config.rs +++ b/core/bin/via_server/src/config.rs @@ -11,7 +11,7 @@ use zksync_config::{ ProtectiveReadsWriterConfig, }, ApiConfig, DADispatcherConfig, DBConfig, EthConfig, GasAdjusterConfig, ObjectStoreConfig, - PostgresConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, + PostgresConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, ViaVerifierConfig, }; use zksync_core_leftovers::temp_config_store::{decode_yaml_repr, TempConfigStore}; use zksync_env_config::FromEnv; @@ -84,14 +84,26 @@ pub(crate) fn load_env_config() -> anyhow::Result { } // TODO: temporary solution, should be removed after the config is refactored -pub(crate) fn via_load_env_config( -) -> anyhow::Result<(ViaBtcWatchConfig, ViaBtcSenderConfig, ViaCelestiaConfig)> { +pub(crate) fn via_load_env_config() -> anyhow::Result<( + ViaBtcWatchConfig, + ViaBtcSenderConfig, + ViaCelestiaConfig, + ViaVerifierConfig, +)> { let btc_watch_config = ViaBtcWatchConfig::from_env().context("Failed to load BTC watch config")?; let btc_sender_config = ViaBtcSenderConfig::from_env().context("Failed to load BTC sender config")?; let celestia_config = ViaCelestiaConfig::from_env().context("Failed to load celestia config")?; + // TODO: tmp + let verifier_config = + ViaVerifierConfig::from_env().context("Failed to load verifier config")?; - Ok((btc_watch_config, btc_sender_config, celestia_config)) + Ok(( + btc_watch_config, + btc_sender_config, + celestia_config, + verifier_config, + )) } diff --git a/core/bin/via_server/src/main.rs b/core/bin/via_server/src/main.rs index f2568296b..cadfbca0d 100644 --- a/core/bin/via_server/src/main.rs +++ b/core/bin/via_server/src/main.rs @@ -60,6 +60,7 @@ fn main() -> anyhow::Result<()> { via_general.via_btc_watch_config = Some(via_configs.0); via_general.via_btc_sender_config = Some(via_configs.1); via_general.via_celestia_config = Some(via_configs.2); + via_general.via_verifier_config = Some(via_configs.3); via_general } }; diff --git a/core/bin/via_server/src/node_builder.rs b/core/bin/via_server/src/node_builder.rs index 06a5e137e..9cdbcbcb5 100644 --- a/core/bin/via_server/src/node_builder.rs +++ b/core/bin/via_server/src/node_builder.rs @@ -177,8 +177,12 @@ impl ViaNodeBuilder { // TODO: remove! fn add_via_verification_test_layer(mut self) -> anyhow::Result { let btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); - self.node - .add_layer(ViaBtcProofVerificationLayer::new(btc_watch_config)); + let verifier_config = try_load_config!(self.configs.via_verifier_config); + + self.node.add_layer(ViaBtcProofVerificationLayer::new( + verifier_config, + btc_watch_config, + )); Ok(self) } diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index 5bad710a2..8834bc1bf 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -32,6 +32,7 @@ pub use self::{ via_btc_watch::{ActorRole, ViaBtcWatchConfig}, via_celestia::ViaCelestiaConfig, via_general::ViaGeneralConfig, + via_verifier::ViaVerifierConfig, vm_runner::{BasicWitnessInputProducerConfig, ProtectiveReadsWriterConfig}, }; @@ -72,6 +73,7 @@ pub mod via_btc_sender; pub mod via_btc_watch; pub mod via_celestia; pub mod via_general; +pub mod via_verifier; pub mod vm_runner; pub mod wallets; diff --git a/core/lib/config/src/configs/via_general.rs b/core/lib/config/src/configs/via_general.rs index 48680fad5..5b54d20eb 100644 --- a/core/lib/config/src/configs/via_general.rs +++ b/core/lib/config/src/configs/via_general.rs @@ -17,7 +17,7 @@ use crate::{ }, ApiConfig, ContractVerifierConfig, DBConfig, EthConfig, ExternalProofIntegrationApiConfig, ObjectStoreConfig, PostgresConfig, SnapshotsCreatorConfig, ViaBtcSenderConfig, - ViaBtcWatchConfig, ViaCelestiaConfig, + ViaBtcWatchConfig, ViaCelestiaConfig, ViaVerifierConfig, }; #[derive(Debug, Clone, PartialEq)] @@ -59,6 +59,7 @@ pub struct ViaGeneralConfig { pub via_btc_sender_config: Option, pub via_btc_watch_config: Option, pub via_celestia_config: Option, + pub via_verifier_config: Option, } impl From for ViaGeneralConfig { @@ -101,6 +102,7 @@ impl From for ViaGeneralConfig { via_btc_sender_config: None, via_btc_watch_config: None, via_celestia_config: None, + via_verifier_config: None, } } } diff --git a/core/lib/config/src/configs/via_verifier.rs b/core/lib/config/src/configs/via_verifier.rs new file mode 100644 index 000000000..34acbe4a3 --- /dev/null +++ b/core/lib/config/src/configs/via_verifier.rs @@ -0,0 +1,21 @@ +use std::time::Duration; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct ViaVerifierConfig { + /// How often the verifier should run its checks (milliseconds). + pub poll_interval: u64, +} + +impl ViaVerifierConfig { + pub fn poll_interval(&self) -> Duration { + Duration::from_millis(self.poll_interval) + } + + pub fn for_tests() -> Self { + Self { + poll_interval: 1000, + } + } +} diff --git a/core/lib/config/src/lib.rs b/core/lib/config/src/lib.rs index c05508aa5..6eed3401d 100644 --- a/core/lib/config/src/lib.rs +++ b/core/lib/config/src/lib.rs @@ -4,7 +4,7 @@ pub use crate::configs::{ ActorRole, ApiConfig, BaseTokenAdjusterConfig, ContractVerifierConfig, ContractsConfig, DADispatcherConfig, DBConfig, EthConfig, EthWatchConfig, ExternalProofIntegrationApiConfig, GasAdjusterConfig, GenesisConfig, ObjectStoreConfig, PostgresConfig, SnapshotsCreatorConfig, - ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, ViaGeneralConfig, + ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, ViaGeneralConfig, ViaVerifierConfig, }; pub mod configs; diff --git a/core/lib/env_config/src/lib.rs b/core/lib/env_config/src/lib.rs index 1402fbb30..d91b87d9d 100644 --- a/core/lib/env_config/src/lib.rs +++ b/core/lib/env_config/src/lib.rs @@ -23,6 +23,8 @@ mod utils; mod via_btc_sender; mod via_celestia; +mod via_verifier; + mod base_token_adjuster; mod da_dispatcher; mod external_price_api_client; diff --git a/core/lib/env_config/src/via_verifier.rs b/core/lib/env_config/src/via_verifier.rs new file mode 100644 index 000000000..6ecfd3e75 --- /dev/null +++ b/core/lib/env_config/src/via_verifier.rs @@ -0,0 +1,9 @@ +use zksync_config::ViaVerifierConfig; + +use crate::{envy_load, FromEnv}; + +impl FromEnv for ViaVerifierConfig { + fn from_env() -> anyhow::Result { + envy_load("via_verifier", "VIA_VERIFIER_") + } +} diff --git a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs index a045e626b..a28db09bc 100644 --- a/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs +++ b/core/lib/via_verification/examples/zksync-era-verification-cli/contract.rs @@ -102,7 +102,10 @@ impl L1DataFetcher for ContractConfig { .await?; let batch_l1_data = fetch_l1_commit_data(batch_number, &self.provider.url().to_string()).await?; - let inputs = generate_inputs(&batch_l1_data); + let inputs = generate_inputs( + &batch_l1_data.prev_batch_commitment, + &batch_l1_data.curr_batch_commitment, + ); proof.proof.inputs = inputs.clone(); Ok((proof, block_number)) diff --git a/core/lib/via_verification/keys/protocol_version/26/scheduler_key.json b/core/lib/via_verification/keys/protocol_version/26/scheduler_key.json new file mode 100644 index 000000000..2e02eafe6 --- /dev/null +++ b/core/lib/via_verification/keys/protocol_version/26/scheduler_key.json @@ -0,0 +1,399 @@ +{ + "n": 16777215, + "num_inputs": 1, + "state_width": 4, + "num_witness_polys": 0, + "gate_setup_commitments": [ + { + "x": [ + 14543631136906534221, + 11532161447842416044, + 11114175029926010938, + 1228896787564295039 + ], + "y": [ + 13293602262342424489, + 8897930584356943159, + 13256028170406220369, + 3214939367598363288 + ], + "infinity": false + }, + { + "x": [ + 11488992528554025682, + 12016824828223971094, + 11942004360057333370, + 316831626296641307 + ], + "y": [ + 304673622018339856, + 7139037552557818730, + 12475560967982555143, + 1055588351918295250 + ], + "infinity": false + }, + { + "x": [ + 2274984630539920017, + 5398167177582250136, + 16440396753384808945, + 1037682586893548769 + ], + "y": [ + 10168660308952593373, + 16526369642614237721, + 569062739734175056, + 155645558476901406 + ], + "infinity": false + }, + { + "x": [ + 14005362797509427677, + 2662603874351919260, + 14261489165672308143, + 1470528288349794782 + ], + "y": [ + 11144229651170108862, + 11439490264313454962, + 114993091474760680, + 1037267173208738614 + ], + "infinity": false + }, + { + "x": [ + 10726125240955612787, + 1916320162213728495, + 1058608086768277905, + 1651114031905829493 + ], + "y": [ + 13237242732587628574, + 4774776044666137690, + 14401013098807103799, + 2514139699916115771 + ], + "infinity": false + }, + { + "x": [ + 14434760601334248377, + 5316938318287831815, + 6221098547630910324, + 980422841280734466 + ], + "y": [ + 9201886393750447942, + 3840149540273146267, + 18179910191622136829, + 1563809864380914603 + ], + "infinity": false + }, + { + "x": [ + 9586697317366528906, + 2325800863365957883, + 1243781259615311278, + 3048012003267036960 + ], + "y": [ + 612821620743617231, + 1510385666449513894, + 9368337288452385056, + 2949736812933507034 + ], + "infinity": false + }, + { + "x": [ + 11830690209042008764, + 11761396005838073769, + 18271188400274886574, + 2896734446482773484 + ], + "y": [ + 1890606551566554401, + 10220931290312275762, + 3256711195869515344, + 2466626485328709457 + ], + "infinity": false + } + ], + "gate_selectors_commitments": [ + { + "x": [ + 10865727529243127085, + 4083978853392244827, + 14303622309482785753, + 2263042021033673595 + ], + "y": [ + 3019601017411802529, + 880444282195426618, + 9998743525359587628, + 2891421025832200233 + ], + "infinity": false + }, + { + "x": [ + 5208608554346323426, + 8575970970223832576, + 2966209169082345602, + 239576408267301488 + ], + "y": [ + 17715084817752316452, + 2726293100894160682, + 17920596859559317135, + 3485576345363305439 + ], + "infinity": false + } + ], + "permutation_commitments": [ + { + "x": [ + 14761045450946573029, + 17157644513453531531, + 2555518804134782053, + 1415819224310783987 + ], + "y": [ + 17265629196749977462, + 4128711855633066822, + 8435602817910411328, + 1408116296902303196 + ], + "infinity": false + }, + { + "x": [ + 3307267823832528482, + 2406249680085831639, + 9091964031261402109, + 2846274000290842933 + ], + "y": [ + 17374905554931807856, + 6690578002079222163, + 11809376320193686210, + 2676076649992974574 + ], + "infinity": false + }, + { + "x": [ + 3159118708748226574, + 5508845413629697013, + 13350869305506486049, + 689297560178790472 + ], + "y": [ + 15696011303896469684, + 12551611148155235140, + 14438660833518031207, + 425021756161657108 + ], + "infinity": false + }, + { + "x": [ + 18349397811516917436, + 4473982696343317918, + 13070312540813307819, + 2109468484629113245 + ], + "y": [ + 13254534552549721008, + 17388411854346636521, + 17875890960520499518, + 1062184221180884481 + ], + "infinity": false + } + ], + "total_lookup_entries_length": 1787472, + "lookup_selector_commitment": { + "x": [ + 9324906502432882695, + 14977861238256290580, + 12538013124354067293, + 3408438202312564138 + ], + "y": [ + 14942105932194201701, + 12210090881357612547, + 14774705021036784261, + 2531694948512337448 + ], + "infinity": false + }, + "lookup_tables_commitments": [ + { + "x": [ + 10873859091125335643, + 3906092213625635374, + 17046157606087980048, + 3193402705223440293 + ], + "y": [ + 10158946293873382504, + 2171386304067884865, + 6918663094168980658, + 350601565475975409 + ], + "infinity": false + }, + { + "x": [ + 12822112641313049260, + 3646552465186399021, + 10324071010773924047, + 2209084192380614662 + ], + "y": [ + 11045141628975531869, + 12589678537679955590, + 3065046617868727674, + 2099447669854151830 + ], + "infinity": false + }, + { + "x": [ + 11395032673621937545, + 3000063650268118516, + 7857619430005721792, + 805706808484810738 + ], + "y": [ + 6817063666434679427, + 1646386051225388537, + 4677946977082722827, + 1369650305976868514 + ], + "infinity": false + }, + { + "x": [ + 2885179371868476351, + 159944842081142878, + 6092294387055034894, + 213843603626505240 + ], + "y": [ + 11868113133779277990, + 8509646480531194854, + 14088068011597639414, + 707070630614027545 + ], + "infinity": false + } + ], + "lookup_table_type_commitment": { + "x": [ + 1732877442096985191, + 7537030715658833452, + 14073502080301311448, + 2178792007727681099 + ], + "y": [ + 8513095304113652904, + 6581396660744182779, + 13939755637576387431, + 2477157044961106453 + ], + "infinity": false + }, + "non_residues": [ + [ + 5, + 0, + 0, + 0 + ], + [ + 7, + 0, + 0, + 0 + ], + [ + 10, + 0, + 0, + 0 + ] + ], + "g2_elements": [ + { + "x": { + "c0": [ + 5106727233969649389, + 7440829307424791261, + 4785637993704342649, + 1729627375292849782 + ], + "c1": [ + 10945020018377822914, + 17413811393473931026, + 8241798111626485029, + 1841571559660931130 + ] + }, + "y": { + "c0": [ + 5541340697920699818, + 16416156555105522555, + 5380518976772849807, + 1353435754470862315 + ], + "c1": [ + 6173549831154472795, + 13567992399387660019, + 17050234209342075797, + 650358724130500725 + ] + }, + "infinity": false + }, + { + "x": { + "c0": [ + 9089143573911733168, + 11482283522806384523, + 13585589533905622862, + 79029415676722370 + ], + "c1": [ + 5692040832573735873, + 16884514497384809355, + 16717166481813659368, + 2742131088506155463 + ] + }, + "y": { + "c0": [ + 9604638503594647125, + 1289961608472612514, + 6217038149984805214, + 2521661352385209130 + ], + "c1": [ + 17168069778630926308, + 11309277837895768996, + 15154989611154567813, + 359271377050603491 + ] + }, + "infinity": false + } + ] + } \ No newline at end of file diff --git a/core/lib/via_verification/src/proof.rs b/core/lib/via_verification/src/proof.rs index bb2b38c96..8938deaef 100644 --- a/core/lib/via_verification/src/proof.rs +++ b/core/lib/via_verification/src/proof.rs @@ -1,13 +1,12 @@ -use circuit_definitions::{ +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::{ + better_better_cs::{setup::VerificationKey, verifier::verify}, + commitments::transcript::keccak_transcript::RollingKeccakTranscript, +}; +// Re-export the necessary types from the `circuit_definitions` crate. +pub use circuit_definitions::{ circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit, snark_wrapper::franklin_crypto::bellman::{ - bn256::Bn256, - plonk::{ - better_better_cs::{ - proof::Proof as ZkSyncProof, setup::VerificationKey, verifier::verify, - }, - commitments::transcript::keccak_transcript::RollingKeccakTranscript, - }, + bn256::Bn256, plonk::better_better_cs::proof::Proof as ZkSyncProof, }, }; diff --git a/core/lib/via_verification/src/public_inputs.rs b/core/lib/via_verification/src/public_inputs.rs index 14739e3d0..11ad541e3 100644 --- a/core/lib/via_verification/src/public_inputs.rs +++ b/core/lib/via_verification/src/public_inputs.rs @@ -2,17 +2,18 @@ use circuit_definitions::snark_wrapper::franklin_crypto::bellman::{ pairing::bn256::Fr, PrimeField, }; use ethers::types::U256; +use primitive_types::H256; use sha3::{Digest, Keccak256}; -use crate::{types::BatchL1Data, utils::to_fixed_bytes}; +use crate::utils::to_fixed_bytes; -/// Computes the public inputs for a given batch. +/// Computes the public inputs for a given batch commiements. /// Public inputs require us to fetch multiple data from L1 (like state hash etc). -pub fn generate_inputs(batch_l1_data: &BatchL1Data) -> Vec { +pub fn generate_inputs(prev_batch_commitment: &H256, curr_batch_commitment: &H256) -> Vec { // Prepare the input fields let input_fields = [ - batch_l1_data.prev_batch_commitment.to_fixed_bytes(), - batch_l1_data.curr_batch_commitment.to_fixed_bytes(), + prev_batch_commitment.to_fixed_bytes(), + curr_batch_commitment.to_fixed_bytes(), ]; let encoded_input_params = input_fields.into_iter().flatten().collect::>(); diff --git a/core/lib/via_verification/src/utils.rs b/core/lib/via_verification/src/utils.rs index 1dff7d48e..41808a299 100644 --- a/core/lib/via_verification/src/utils.rs +++ b/core/lib/via_verification/src/utils.rs @@ -64,6 +64,33 @@ pub async fn load_verification_key( .ok_or(VerificationError::VerificationKeyHashMismatch) } +/// Load the verification key for a given batch number. +pub async fn load_verification_key_without_l1_check( + protocol_version: String, +) -> Result, VerificationError> { + let file_path = format!( + "core/lib/via_verification/keys/protocol_version/{}/scheduler_key.json", + protocol_version + ); + let base_dir = env::var("VIA_HOME").map_err(|e| VerificationError::Other(e.to_string()))?; + let base_path = PathBuf::from(base_dir); + let file = base_path.join(&file_path); + + // Load the verification key from the specified file. + let verification_key_content = fs::read_to_string(file).map_err(|e| { + VerificationError::Other(format!( + "Failed to read verification key from {}: {}", + file_path, e + )) + })?; + let vk_inner: VerificationKey = + serde_json::from_str(&verification_key_content).map_err(|e| { + VerificationError::Other(format!("Failed to deserialize verification key: {}", e)) + })?; + + Ok(vk_inner) +} + pub(crate) fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { let mut result = [0u8; 32]; result.copy_from_slice(ins); diff --git a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs index 278e1626f..5f5012d3b 100644 --- a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs +++ b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use via_btc_client::types::{BitcoinNetwork, NodeAuth}; use via_zk_verifier::ViaVerifier; -use zksync_config::ViaBtcWatchConfig; +use zksync_config::{ViaBtcWatchConfig, ViaVerifierConfig}; use crate::{ implementations::resources::{ @@ -16,7 +16,8 @@ use crate::{ #[derive(Debug)] pub struct ViaBtcProofVerificationLayer { - config: ViaBtcWatchConfig, + config: ViaVerifierConfig, + btc_watcher_config: ViaBtcWatchConfig, } #[derive(Debug, FromContext)] @@ -34,8 +35,11 @@ pub struct ProofVerificationOutput { } impl ViaBtcProofVerificationLayer { - pub fn new(config: ViaBtcWatchConfig) -> Self { - Self { config } + pub fn new(config: ViaVerifierConfig, btc_watcher_config: ViaBtcWatchConfig) -> Self { + Self { + config, + btc_watcher_config, + } } } @@ -50,14 +54,14 @@ impl WiringLayer for ViaBtcProofVerificationLayer { async fn wire(self, input: Self::Input) -> Result { let main_pool = input.master_pool.get().await?; - let network = BitcoinNetwork::from_core_arg(self.config.network()) + let network = BitcoinNetwork::from_core_arg(self.btc_watcher_config.network()) .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; let node_auth = NodeAuth::UserPass( - self.config.rpc_user().to_string(), - self.config.rpc_password().to_string(), + self.btc_watcher_config.rpc_user().to_string(), + self.btc_watcher_config.rpc_password().to_string(), ); let bootstrap_txids = self - .config + .btc_watcher_config .bootstrap_txids() .iter() .map(|txid| { @@ -67,7 +71,7 @@ impl WiringLayer for ViaBtcProofVerificationLayer { .collect::, _>>()?; let via_proof_verification = ViaVerifier::new( - self.config.rpc_url(), + self.btc_watcher_config.rpc_url(), network, node_auth, bootstrap_txids, diff --git a/core/node/via_zk_verifier/Cargo.toml b/core/node/via_zk_verifier/Cargo.toml index 1b27e0b87..cd4736168 100644 --- a/core/node/via_zk_verifier/Cargo.toml +++ b/core/node/via_zk_verifier/Cargo.toml @@ -29,4 +29,6 @@ tracing.workspace = true sqlx.workspace = true serde.workspace = true +via-verification.workspace = true + [dev-dependencies] diff --git a/core/node/via_zk_verifier/src/lib.rs b/core/node/via_zk_verifier/src/lib.rs index 6da15d099..b5336fb80 100644 --- a/core/node/via_zk_verifier/src/lib.rs +++ b/core/node/via_zk_verifier/src/lib.rs @@ -1,4 +1,5 @@ use anyhow::Context; +use serde::{Deserialize, Serialize}; use tokio::sync::watch; use via_btc_client::{ indexer::BitcoinInscriptionIndexer, @@ -8,14 +9,18 @@ use via_btc_client::{ }, utils::bytes_to_txid, }; -use zksync_config::ViaBtcWatchConfig; +use via_verification::proof::{ + Bn256, ProofTrait, ViaZKProof, ZkSyncProof, ZkSyncSnarkWrapperCircuit, +}; +use zksync_config::ViaVerifierConfig; use zksync_da_client::{types::InclusionData, DataAvailabilityClient}; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; -use zksync_prover_interface::outputs::L1BatchProofForL1; -use zksync_types::{commitment::L1BatchWithMetadata, H256}; +use zksync_types::{ + commitment::L1BatchWithMetadata, protocol_version::ProtocolSemanticVersion, H256, +}; /// Copy of `zksync_l1_contract_interface::i_executor::methods::ProveBatches` -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProveBatches { pub prev_l1_batch: L1BatchWithMetadata, pub l1_batches: Vec, @@ -23,10 +28,11 @@ pub struct ProveBatches { pub should_verify: bool, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct L1BatchData { - pub pubdata: Vec, - pub l1_batch_number: u32, +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct L1BatchProofForL1 { + pub aggregation_result_coords: [[u8; 32]; 4], + pub scheduler_proof: ZkSyncProof, + pub protocol_version: ProtocolSemanticVersion, } #[derive(Debug)] @@ -34,8 +40,7 @@ pub struct ViaVerifier { pool: ConnectionPool, da_client: Box, indexer: BitcoinInscriptionIndexer, - // TODO: Add config - config: ViaBtcWatchConfig, + config: ViaVerifierConfig, } impl ViaVerifier { @@ -46,7 +51,7 @@ impl ViaVerifier { bootstrap_txids: Vec, pool: ConnectionPool, client: Box, - config: ViaBtcWatchConfig, + config: ViaVerifierConfig, ) -> anyhow::Result { let indexer = BitcoinInscriptionIndexer::new(rpc_url, network, node_auth, bootstrap_txids).await?; @@ -70,7 +75,7 @@ impl ViaVerifier { let mut storage = pool.connection_tagged("via_zk_verifier").await?; match self.loop_iteration(&mut storage).await { - Ok(()) => tracing::info!(""), + Ok(()) => {} Err(err) => tracing::error!("Failed to process via_zk_verifier: {err}"), } } @@ -93,7 +98,7 @@ impl ViaVerifier { raw_tx_id.reverse(); let proof_txid = bytes_to_txid(&raw_tx_id).context("Failed to parse tx_id")?; - tracing::warn!("trying to get proof_txid: {}", proof_txid); + tracing::info!("trying to get proof_txid: {}", proof_txid); let proof_msgs = self.indexer.parse_transaction(&proof_txid).await?; let proof_msg = self.expect_single_msg(&proof_msgs, "ProofDAReference")?; @@ -121,7 +126,7 @@ impl ViaVerifier { let (batch_blob, batch_hash) = self.process_batch_da_reference(batch_da).await?; let is_verified = self - .verify_proof(batch_hash, proof_blob.data, batch_blob.data) + .verify_proof(batch_hash, &proof_blob.data, &batch_blob.data) .await?; storage @@ -187,26 +192,75 @@ impl ViaVerifier { async fn verify_proof( &self, batch_hash: H256, - proof: Vec, - batch: Vec, + proof_bytes: &[u8], + batch_bytes: &[u8], ) -> anyhow::Result { tracing::info!( ?batch_hash, - proof_len = proof.len(), - batch_len = batch.len(), + proof_len = proof_bytes.len(), + batch_len = batch_bytes.len(), "Verifying proof" ); - let proof: ProveBatches = bincode::deserialize(&proof)?; + let proof_data: ProveBatches = bincode::deserialize(&proof_bytes)?; - // TODO: fetch and verify pubdata - // let batch: L1BatchData = bincode::deserialize(&batch) + if proof_data.l1_batches.len() != 1 { + tracing::error!( + "Expected exactly one L1Batch and one proof, got {} and {}", + proof_data.l1_batches.len(), + proof_data.proofs.len() + ); + return Ok(false); + } + + // TODO: decide if we need to verify the batch data (already have batch data from ProofDAReference inscription) + // let batch: PubData... = bincode::deserialize(&batch) // .context("Failed to deserialize L1BatchWithMetadata")?; - if !proof.should_verify { + let protocol_version = proof_data.l1_batches[0] + .header + .protocol_version + .unwrap() + .to_string(); + + if !proof_data.should_verify { + tracing::info!( + "Proof verification is disabled for proof with batch number : {:?}", + proof_data.l1_batches[0].header.number + ); + tracing::info!( + "Verifying proof with protocol version: {}", + protocol_version + ); + tracing::info!("Skipping verification"); Ok(true) } else { - // TODO: Verify the proof - Ok(false) + if proof_data.proofs.len() != 1 { + tracing::error!( + "Expected exactly one proof, got {}", + proof_data.proofs.len() + ); + return Ok(false); + } + + let (prev_commitment, curr_commitment) = ( + proof_data.prev_l1_batch.metadata.commitment, + proof_data.l1_batches[0].metadata.commitment, + ); + let mut proof = proof_data.proofs[0].scheduler_proof.clone(); + + // Put correct inputs + proof.inputs = via_verification::public_inputs::generate_inputs( + &prev_commitment, + &curr_commitment, + ); + + // Verify the proof + let via_proof = ViaZKProof { proof }; + let vk_inner = + via_verification::utils::load_verification_key_without_l1_check(protocol_version) + .await?; + + Ok(via_proof.verify(vk_inner)?) } } } diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml index 843dc00ad..c47ecaeec 100644 --- a/etc/env/configs/via_base.toml +++ b/etc/env/configs/via_base.toml @@ -32,6 +32,9 @@ api_node_url = "http://0.0.0.0:26658" auth_token = "" blob_size_limit = 1973786 +[via_verifier] +poll_interval = 1000 + [rust] log = """\ warn,\ @@ -68,4 +71,5 @@ via_state_keeper=debug,\ via_btc_sender=debug,\ via_da_dispatcher=debug,\ via_da_clients=debug,\ +via_zk_verifier=info,\ """ From 9119b31f79ea455025157d97c92a1249fe048a5c Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Fri, 27 Dec 2024 12:09:07 +0100 Subject: [PATCH 084/212] fix: voting table schema --- ...e1dcef9dd65f5751547525cc9b0839836da5.json} | 4 +-- ...762f56b1ea92dc3bdb03aef290a6457d6232b.json | 15 --------- .../20241209150000_create_via_votes.up.sql | 1 - core/lib/dal/src/via_votes_dal.rs | 32 ++----------------- core/node/via_zk_verifier/src/lib.rs | 6 +--- 5 files changed, 6 insertions(+), 52 deletions(-) rename core/lib/dal/.sqlx/{query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json => query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json} (72%) delete mode 100644 core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json diff --git a/core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json b/core/lib/dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json similarity index 72% rename from core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json rename to core/lib/dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json index cfdf7b0d7..6e898fb47 100644 --- a/core/lib/dal/.sqlx/query-54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3.json +++ b/core/lib/dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n l1_batch_number,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_executed = FALSE\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "query": "\n SELECT\n l1_batch_number,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_verified = FALSE\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -22,5 +22,5 @@ false ] }, - "hash": "54adc6a9cab00aab1c4e6ea43b62589f611ef94174e6536811076cbc9d318fd3" + "hash": "6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5" } diff --git a/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json b/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json deleted file mode 100644 index 940c5ee19..000000000 --- a/core/lib/dal/.sqlx/query-fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE via_votable_transactions\n SET\n is_executed = TRUE,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "fd4c396da4c102525f994a58325762f56b1ea92dc3bdb03aef290a6457d6232b" -} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index 56a647859..9f4784dce 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -4,7 +4,6 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( is_finalized BOOLEAN NOT NULL DEFAULT FALSE, is_verified BOOLEAN NOT NULL DEFAULT FALSE, l1_batch_status BOOLEAN NOT NULL DEFAULT FALSE, - is_executed BOOLEAN NOT NULL DEFAULT FALSE, -- This flag is used to determine if the transaction has been executed by verifier created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (l1_batch_number, tx_id) diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 37e745ad8..95e3cfd11 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -243,34 +243,8 @@ impl ViaVotesDal<'_, '_> { Ok(result) } - /// Marks a transaction as executed. - pub async fn mark_transaction_executed( - &mut self, - l1_batch_number: i64, - tx_id: H256, - ) -> DalResult<()> { - sqlx::query!( - r#" - UPDATE via_votable_transactions - SET - is_executed = TRUE, - updated_at = NOW() - WHERE - l1_batch_number = $1 - AND tx_id = $2 - "#, - l1_batch_number, - tx_id.as_bytes() - ) - .instrument("mark_transaction_executed") - .execute(self.storage) - .await?; - - Ok(()) - } - - /// Retrieve the first not executed block. (Similar to `get_first_not_finilized_block`, just with `is_executed = FALSE`). - pub async fn get_first_not_executed_block(&mut self) -> DalResult)>> { + /// Retrieve the first not executed block. (Similar to `get_first_not_finilized_block`, just with `is_verified = FALSE`). + pub async fn get_first_not_verified_block(&mut self) -> DalResult)>> { let row = sqlx::query!( r#" SELECT @@ -279,7 +253,7 @@ impl ViaVotesDal<'_, '_> { FROM via_votable_transactions WHERE - is_executed = FALSE + is_verified = FALSE ORDER BY l1_batch_number ASC LIMIT diff --git a/core/node/via_zk_verifier/src/lib.rs b/core/node/via_zk_verifier/src/lib.rs index b5336fb80..471b1d784 100644 --- a/core/node/via_zk_verifier/src/lib.rs +++ b/core/node/via_zk_verifier/src/lib.rs @@ -131,11 +131,7 @@ impl ViaVerifier { storage .via_votes_dal() - .mark_transaction_executed(l1_batch_number, db_raw_tx_id) - .await?; - storage - .via_votes_dal() - .verify_votable_transaction(l1_batch_number as u32, db_raw_tx_id, is_verified) + .get_first_not_verified_block(l1_batch_number as u32, db_raw_tx_id, is_verified) .await?; } From 06355e12be6976aefd5482763fa165515625eb58 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:22:19 +0100 Subject: [PATCH 085/212] feat(via_btc_watch): insert the blob_id, da_id and the proof_tx_id --- ...e70265a6fe24abd28e629dd2fa1f9c400c29d9.json | 18 ++++++++++++++++++ ...9d2e238e3263394702c9a4dafb1043aa3fb2c3.json | 15 --------------- .../20241209150000_create_via_votes.up.sql | 4 ++++ core/lib/dal/src/via_votes_dal.rs | 14 ++++++++++---- .../src/tests/vote_inscription_test.rs | 4 ++-- .../src/message_processors/votable.rs | 8 +++++++- 6 files changed, 41 insertions(+), 22 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json delete mode 100644 core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json diff --git a/core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json b/core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json new file mode 100644 index 000000000..472334232 --- /dev/null +++ b/core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Varchar", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9" +} diff --git a/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json b/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json deleted file mode 100644 index dc1fa1f4a..000000000 --- a/core/lib/dal/.sqlx/query-5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id)\n VALUES\n ($1, $2)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "5755f46b2e4e3e79793d8a7f429d2e238e3263394702c9a4dafb1043aa3fb2c3" -} diff --git a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql index 9f4784dce..1fdfa1484 100644 --- a/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql +++ b/core/lib/dal/migrations/20241209150000_create_via_votes.up.sql @@ -1,6 +1,10 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( l1_batch_number BIGINT UNIQUE NOT NULL, tx_id BYTEA, + da_identifier VARCHAR NOT NULL, + blob_id VARCHAR NOT NULL, + proof_tx_id VARCHAR NOT NULL, + withdrawal_tx_id BYTEA, is_finalized BOOLEAN NOT NULL DEFAULT FALSE, is_verified BOOLEAN NOT NULL DEFAULT FALSE, l1_batch_status BOOLEAN NOT NULL DEFAULT FALSE, diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 95e3cfd11..e8318b865 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -14,17 +14,23 @@ impl ViaVotesDal<'_, '_> { &mut self, l1_batch_number: u32, tx_id: H256, + da_identifier: String, + blob_id: String, + proof_tx_id: String, ) -> DalResult<()> { sqlx::query!( r#" INSERT INTO - via_votable_transactions (l1_batch_number, tx_id) + via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id) VALUES - ($1, $2) - ON CONFLICT (l1_batch_number, tx_id) DO NOTHING + ($1, $2, $3, $4, $5) + ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING "#, i64::from(l1_batch_number), - tx_id.as_bytes() + tx_id.as_bytes(), + da_identifier, + blob_id, + proof_tx_id ) .instrument("insert_votable_transaction") .fetch_optional(self.storage) diff --git a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs index 22319256c..93794f631 100644 --- a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs +++ b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs @@ -144,7 +144,7 @@ mod tests { let _ = aggregator_test .storage .via_votes_dal() - .insert_votable_transaction(1, tx_id) + .insert_votable_transaction(1, tx_id, "".to_string(), "".to_string(), "".to_string()) .await; let op = aggregator_test @@ -230,7 +230,7 @@ mod tests { let _ = aggregator_test .storage .via_votes_dal() - .insert_votable_transaction(1, tx_id) + .insert_votable_transaction(1, tx_id, "".to_string(), "".to_string(), "".to_string()) .await; let _ = aggregator_test diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 07b7a648b..5164de85f 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -55,7 +55,13 @@ impl MessageProcessor for VotableMessageProcessor { convert_txid_to_h256(proof_msg.input.l1_batch_reveal_txid); votes_dal - .insert_votable_transaction(l1_batch_number.0, tx_id) + .insert_votable_transaction( + l1_batch_number.0, + tx_id, + proof_msg.input.da_identifier.clone(), + proof_msg.input.blob_id.clone(), + proof_msg.input.l1_batch_reveal_txid.to_string(), + ) .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; From 6d32d5bc982212951f169ac187cb8aa19c7fb9e1 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:24:18 +0100 Subject: [PATCH 086/212] feat(config): add via verifier config --- core/lib/config/src/configs/via_verifier.rs | 41 +++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/core/lib/config/src/configs/via_verifier.rs b/core/lib/config/src/configs/via_verifier.rs index 34acbe4a3..609f0a3d3 100644 --- a/core/lib/config/src/configs/via_verifier.rs +++ b/core/lib/config/src/configs/via_verifier.rs @@ -1,21 +1,56 @@ -use std::time::Duration; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + time::Duration, +}; use serde::{Deserialize, Serialize}; +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub enum VerifierRole { + VERIFIER = 0, + COORDINATOR = 1, +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct ViaVerifierConfig { - /// How often the verifier should run its checks (milliseconds). + /// Interval between polling db for verification requests (in ms). pub poll_interval: u64, + /// Coordinator server port. + pub port: u16, + /// Coordinator server url. + pub url: String, + /// The signer private key. + pub private_key: String, + /// The verifiers public keys. + pub verifiers_pub_keys_str: Vec, + /// The bridge address. + pub bridge_address_str: String, + /// The minimum required signers. + pub required_signers: usize, + /// The role. + pub role: VerifierRole, } impl ViaVerifierConfig { - pub fn poll_interval(&self) -> Duration { + pub fn polling_interval(&self) -> Duration { Duration::from_millis(self.poll_interval) } + pub fn bind_addr(&self) -> SocketAddr { + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), self.port) + } +} +impl ViaVerifierConfig { pub fn for_tests() -> Self { Self { + private_key: "private".to_string(), poll_interval: 1000, + port: 0, + url: "".to_string(), + verifiers_pub_keys_str: Vec::new(), + bridge_address_str: "".to_string(), + required_signers: 2, + role: VerifierRole::VERIFIER, } } } From 099aedf9ced0f323e92fac42f810e76ba0579317 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:25:36 +0100 Subject: [PATCH 087/212] feat(dal): add verifier dal queries --- ...7b9c39534c83e3738db90e7111345df0281a2.json | 22 ++++++ ...dec6e1783a3763df3a30d0babe4c0feded254.json | 15 ++++ ...22ac740322906842a49122ea8d535296f296e.json | 32 ++++++++ core/lib/dal/src/via_votes_dal.rs | 79 +++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 core/lib/dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json create mode 100644 core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json create mode 100644 core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json diff --git a/core/lib/dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json b/core/lib/dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json new file mode 100644 index 000000000..4ed034e04 --- /dev/null +++ b/core/lib/dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n withdrawal_tx_id\n FROM via_votable_transactions\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "withdrawal_tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2" +} diff --git a/core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json b/core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json new file mode 100644 index 000000000..784f40dc6 --- /dev/null +++ b/core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n withdrawal_tx_id = $1\n WHERE\n is_finalized = TRUE AND\n is_verified = TRUE AND\n withdrawal_tx_id IS NULL AND\n l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254" +} diff --git a/core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json b/core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json new file mode 100644 index 000000000..1ad66057d --- /dev/null +++ b/core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n blob_id,\n proof_tx_id\n FROM via_votable_transactions\n WHERE\n is_finalized = TRUE AND\n is_verified = TRUE AND\n withdrawal_tx_id IS NULL\n ORDER BY l1_batch_number ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "blob_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "proof_tx_id", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e" +} diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index e8318b865..f2c57a4db 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -278,4 +278,83 @@ impl ViaVotesDal<'_, '_> { Ok(result) } + pub async fn get_finalized_blocks_and_non_processed_withdrawals( + &mut self, + ) -> DalResult> { + let rows = sqlx::query!( + r#" + SELECT + l1_batch_number, + blob_id, + proof_tx_id + FROM + via_votable_transactions + WHERE + is_finalized = TRUE + AND is_verified = TRUE + AND withdrawal_tx_id IS NULL + ORDER BY + l1_batch_number ASC + "#, + ) + .instrument("get_finalized_blocks_and_non_processed_withdrawals") + .fetch_all(self.storage) + .await?; + + // Map the rows into a Vec<(l1_batch_number, blob_id, proof_tx_id)> + let result: Vec<(i64, String, String)> = rows + .into_iter() + .map(|r| (r.l1_batch_number, r.blob_id, r.proof_tx_id)) + .collect(); + + Ok(result) + } + + pub async fn mark_vote_transaction_as_processed_withdrawals( + &mut self, + tx_id: H256, + l1_batch_number: i64, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + withdrawal_tx_id = $1 + WHERE + is_finalized = TRUE + AND is_verified = TRUE + AND withdrawal_tx_id IS NULL + AND l1_batch_number = $2 + "#, + tx_id.as_bytes(), + l1_batch_number + ) + .instrument("mark_vote_transaction_as_processed_withdrawals") + .execute(self.storage) + .await?; + + Ok(()) + } + + pub async fn get_vote_transaction_withdrawal_tx( + &mut self, + l1_batch_number: i64, + ) -> DalResult>> { + let withdrawal_tx_id = sqlx::query_scalar!( + r#" + SELECT + withdrawal_tx_id + FROM via_votable_transactions + WHERE + l1_batch_number = $1 + "#, + l1_batch_number + ) + .instrument("get_vote_transaction_withdrawal_tx") + .fetch_optional(self.storage) + .await? + .flatten(); + + Ok(withdrawal_tx_id) + } } From 5e6550232f658caf0944caae6bc29cf10862fccf Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:26:21 +0100 Subject: [PATCH 088/212] feat: impl serializable to the usigned withdrawal tx --- .../src/withdrawal_builder/mod.rs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs index dfba548e4..8f96a1125 100644 --- a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs @@ -3,17 +3,22 @@ // and then it will use client to get available utxo, and then perform utxo selection based on the total amount of the withdrawal // and now we know the number of input and output we can estimate the fee and perform final utxo selection // create a unsigned transaction and return it to the caller - use std::{collections::HashMap, sync::Arc}; use anyhow::Result; +use bincode::{deserialize, serialize}; use bitcoin::{ absolute, hashes::Hash, script::PushBytesBuf, transaction, Address, Amount, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, }; +use serde::{Deserialize, Serialize}; use tracing::{debug, info, instrument}; -use crate::{client::BitcoinClient, traits::BitcoinOps, types::BitcoinNetwork}; +use crate::{ + client::BitcoinClient, + traits::{BitcoinOps, Serializable}, + types::BitcoinNetwork, +}; #[derive(Debug)] pub struct WithdrawalBuilder { @@ -27,7 +32,7 @@ pub struct WithdrawalRequest { pub amount: Amount, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct UnsignedWithdrawalTx { pub tx: Transaction, pub txid: Txid, @@ -35,6 +40,19 @@ pub struct UnsignedWithdrawalTx { pub change_amount: Amount, } +impl Serializable for UnsignedWithdrawalTx { + fn to_bytes(&self) -> Vec { + serialize(self).expect("error serialize the UnsignedWithdrawalTx") + } + + fn from_bytes(bytes: &[u8]) -> Self + where + Self: Sized, + { + deserialize(bytes).expect("error deserialize the UnsignedWithdrawalTx") + } +} + const OP_RETURN_PREFIX: &[u8] = b"VIA_PROTOCOL:WITHDRAWAL:"; impl WithdrawalBuilder { From 2821c9fdf7cae4196b9df8d941f03b29f288b0f2 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:27:53 +0100 Subject: [PATCH 089/212] feat(via_withdrawal_client): add network check to to validate the addresses --- .../lib/via_withdrawal_client/Cargo.toml | 3 +- .../examples/withdraw.rs | 2 +- .../lib/via_withdrawal_client/src/client.rs | 32 +++++++++++-------- .../lib/via_withdrawal_client/src/withdraw.rs | 32 ++++++++++++------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/via_verifier/lib/via_withdrawal_client/Cargo.toml b/via_verifier/lib/via_withdrawal_client/Cargo.toml index d76034a99..63c0d161e 100644 --- a/via_verifier/lib/via_withdrawal_client/Cargo.toml +++ b/via_verifier/lib/via_withdrawal_client/Cargo.toml @@ -19,8 +19,8 @@ zksync_types.workspace = true zksync_utils.workspace = true tokio.workspace = true tracing.workspace = true -via_da_clients.workspace = true tracing-subscriber.workspace = true +via_btc_client.workspace = true bitcoin = { version = "0.32.2", features = ["serde"] } byteorder = "1.4" @@ -29,6 +29,7 @@ byteorder = "1.4" rand = "0.8" zksync_dal.workspace = true dotenv = "0.15" +via_da_clients.workspace = true [[example]] name = "withdraw" diff --git a/via_verifier/lib/via_withdrawal_client/examples/withdraw.rs b/via_verifier/lib/via_withdrawal_client/examples/withdraw.rs index 036f10b58..40bf79c90 100644 --- a/via_verifier/lib/via_withdrawal_client/examples/withdraw.rs +++ b/via_verifier/lib/via_withdrawal_client/examples/withdraw.rs @@ -56,7 +56,7 @@ async fn main() -> Result<()> { // Connect to withdrawl client let client = CelestiaClient::new(da_config).await?; let da_client: Box = Box::new(client); - let withdrawal_client = WithdrawalClient::new(da_client); + let withdrawal_client = WithdrawalClient::new(da_client, bitcoin::Network::Regtest); let withdrawals = withdrawal_client .get_withdrawals(header.blob_id.as_str()) diff --git a/via_verifier/lib/via_withdrawal_client/src/client.rs b/via_verifier/lib/via_withdrawal_client/src/client.rs index 5d1e47fa1..56b8915da 100644 --- a/via_verifier/lib/via_withdrawal_client/src/client.rs +++ b/via_verifier/lib/via_withdrawal_client/src/client.rs @@ -1,29 +1,32 @@ use std::{collections::HashMap, str::FromStr}; +use bitcoin::Network; +use via_btc_client::withdrawal_builder::WithdrawalRequest; use zksync_da_client::DataAvailabilityClient; use zksync_types::{web3::keccak256, H160, H256}; use crate::{ pubdata::Pubdata, - types::{L2BridgeLogMetadata, WithdrawalRequest, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR}, + types::{L2BridgeLogMetadata, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR}, withdraw::parse_l2_withdrawal_message, }; #[derive(Debug)] pub struct WithdrawalClient { + network: Network, client: Box, } impl WithdrawalClient { - pub fn new(client: Box) -> Self { - Self { client } + pub fn new(client: Box, network: Network) -> Self { + Self { client, network } } pub async fn get_withdrawals(&self, blob_id: &str) -> anyhow::Result> { let pubdata_bytes = self.fetch_pubdata(blob_id).await?; let pubdata = Pubdata::decode_pubdata(pubdata_bytes)?; let l2_bridge_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); - let withdrawals = WithdrawalClient::get_valid_withdrawals(l2_bridge_metadata); + let withdrawals = WithdrawalClient::get_valid_withdrawals(self.network, l2_bridge_metadata); Ok(withdrawals) } @@ -64,11 +67,13 @@ impl WithdrawalClient { } fn get_valid_withdrawals( + network: Network, l2_bridge_logs_metadata: Vec, ) -> Vec { let mut withdrawal_requests: Vec = Vec::new(); for l2_bridge_log_metadata in l2_bridge_logs_metadata { - let withdrawal_request = parse_l2_withdrawal_message(l2_bridge_log_metadata.message); + let withdrawal_request = + parse_l2_withdrawal_message(l2_bridge_log_metadata.message, network); if let Ok(req) = withdrawal_request { withdrawal_requests.push(req) @@ -82,7 +87,7 @@ impl WithdrawalClient { mod tests { use std::str::FromStr; - use bitcoin::Address; + use bitcoin::{Address, Amount}; use zksync_types::U256; use super::*; @@ -131,14 +136,15 @@ mod tests { assert_eq!(hashes[&hash], pubdata.l2_to_l1_messages[0]); let l2_bridge_logs_metadata = WithdrawalClient::list_l2_bridge_metadata(&pubdata); - let withdrawals = WithdrawalClient::get_valid_withdrawals(l2_bridge_logs_metadata); + let withdrawals = + WithdrawalClient::get_valid_withdrawals(Network::Regtest, l2_bridge_logs_metadata); let expected_user_address = - Address::from_str("bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56").unwrap(); + Address::from_str("bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56") + .unwrap() + .assume_checked(); assert_eq!(withdrawals.len(), 1); - assert_eq!(withdrawals[0].clone().address, expected_user_address); - assert_eq!( - withdrawals[0].clone().amount, - U256::from_dec_str("100000000").unwrap() - ); + assert_eq!(&withdrawals[0].address, &expected_user_address); + let expected_amount = Amount::from_sat(100000000); + assert_eq!(&withdrawals[0].amount, &expected_amount); } } diff --git a/via_verifier/lib/via_withdrawal_client/src/withdraw.rs b/via_verifier/lib/via_withdrawal_client/src/withdraw.rs index 7ff68b761..1a1efc876 100644 --- a/via_verifier/lib/via_withdrawal_client/src/withdraw.rs +++ b/via_verifier/lib/via_withdrawal_client/src/withdraw.rs @@ -1,12 +1,16 @@ use std::str::FromStr; use anyhow::Context; -use bitcoin::Address as BitcoinAddress; +use bitcoin::{Address as BitcoinAddress, Amount, Network}; +use via_btc_client::withdrawal_builder::WithdrawalRequest; use zksync_basic_types::{web3::keccak256, U256}; -use crate::types::{WithdrawalRequest, WITHDRAW_FUNC_SIG}; +use crate::types::WITHDRAW_FUNC_SIG; -pub fn parse_l2_withdrawal_message(l2_to_l1_message: Vec) -> anyhow::Result { +pub fn parse_l2_withdrawal_message( + l2_to_l1_message: Vec, + network: Network, +) -> anyhow::Result { // We check that the message is long enough to read the data. // Please note that there are two versions of the message: // The message that is sent by `withdraw(address _l1Receiver)` @@ -26,11 +30,13 @@ pub fn parse_l2_withdrawal_message(l2_to_l1_message: Vec) -> anyhow::Result< let address_bytes = &l2_to_l1_message[4..4 + address_size]; let address_str = String::from_utf8(address_bytes.to_vec()).context("Parse address to string")?; - let address = BitcoinAddress::from_str(&address_str).context("parse bitcoin address")?; + let address = BitcoinAddress::from_str(&address_str) + .context("parse bitcoin address")? + .require_network(network)?; // The last 32 bytes represent the amount (uint256) let amount_bytes = &l2_to_l1_message[address_size + 4..]; - let amount = U256::from_big_endian(amount_bytes); + let amount = Amount::from_sat(U256::from_big_endian(amount_bytes).as_u64()); Ok(WithdrawalRequest { address, amount }) } @@ -54,9 +60,10 @@ mod tests { let expected_receiver = BitcoinAddress::from_str( "bc1qy82gaw2htfd5sslplpgmz4ktf9y3k7pac2226k0wljlmw3atfw5qwm4av4", ) - .unwrap(); - let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); - let res = parse_l2_withdrawal_message(l2_to_l1_message).unwrap(); + .unwrap() + .assume_checked(); + let expected_amount = Amount::from_sat(1000000000000000000); + let res = parse_l2_withdrawal_message(l2_to_l1_message, Network::Bitcoin).unwrap(); assert_eq!(res.address, expected_receiver); assert_eq!(res.amount, expected_amount); @@ -65,10 +72,11 @@ mod tests { #[test] fn test_parse_l2_withdrawal_message_when_address_p2pkh() { let l2_to_l1_message = hex::decode("6c0960f93141317a5031655035514765666932444d505466544c35534c6d7637446976664e610000000000000000000000000000000000000000000000000de0b6b3a7640000").unwrap(); - let expected_receiver = - BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap(); - let expected_amount = U256::from_dec_str("1000000000000000000").unwrap(); - let res = parse_l2_withdrawal_message(l2_to_l1_message).unwrap(); + let expected_receiver = BitcoinAddress::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") + .unwrap() + .assume_checked(); + let expected_amount = Amount::from_sat(1000000000000000000); + let res = parse_l2_withdrawal_message(l2_to_l1_message, Network::Bitcoin).unwrap(); assert_eq!(res.address, expected_receiver); assert_eq!(res.amount, expected_amount); From 161e8eb5a7cded8daef99226c62554bcd71806e1 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:29:56 +0100 Subject: [PATCH 090/212] feat(coordinator): implement the coordinator rest api --- Cargo.lock | 24 ++ .../node/withdrawal_service/Cargo.toml | 24 ++ .../withdrawal_service/src/coordinator/api.rs | 40 +++ .../src/coordinator/api_decl.rs | 59 +++++ .../src/coordinator/api_impl.rs | 241 ++++++++++++++++++ .../withdrawal_service/src/coordinator/mod.rs | 3 + .../node/withdrawal_service/src/lib.rs | 3 + .../node/withdrawal_service/src/types.rs | 48 ++++ .../node/withdrawal_service/src/utils.rs | 65 +++++ 9 files changed, 507 insertions(+) create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/api.rs create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/mod.rs create mode 100644 via_verifier/node/withdrawal_service/src/types.rs create mode 100644 via_verifier/node/withdrawal_service/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index b409e6ae4..d282510a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9739,6 +9739,7 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", + "via_btc_client", "via_da_clients", "zksync_basic_types", "zksync_config", @@ -9751,6 +9752,29 @@ dependencies = [ [[package]] name = "via_withdrawal_service" version = "0.1.0" +dependencies = [ + "anyhow", + "axum 0.7.9", + "base64 0.21.7", + "bitcoin", + "hex", + "musig2", + "reqwest 0.12.7", + "secp256k1 0.30.0", + "serde", + "serde_json", + "tokio", + "tower-http", + "tracing", + "uuid 1.10.0", + "via_btc_client", + "via_musig2", + "via_withdrawal_client", + "vise", + "zksync_config", + "zksync_dal", + "zksync_types", +] [[package]] name = "vise" diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index 08cf9c893..7a5a0d9c5 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -7,5 +7,29 @@ authors = ["Via Network"] [dependencies] +hex.workspace = true +uuid = { version = "1.3", features = ["v4"] } +zksync_config.workspace = true +zksync_dal.workspace = true +zksync_types.workspace = true +vise.workspace = true +via_btc_client.workspace = true +via_musig2.workspace = true +reqwest.workspace = true +via_withdrawal_client.workspace = true + +anyhow.workspace = true +axum.workspace = true +tokio = { workspace = true, features = ["time"] } +tower-http = { workspace = true, features = ["cors"] } +tracing.workspace = true +serde.workspace = true +serde_json.workspace = true +bitcoin = { version = "0.32.2", features = ["serde"] } +secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = [ + "rand", +] } +musig2 = "0.2.0" +base64 = "0.21" [dev-dependencies] diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api.rs b/via_verifier/node/withdrawal_service/src/coordinator/api.rs new file mode 100644 index 000000000..e67c6615e --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/api.rs @@ -0,0 +1,40 @@ +use anyhow::Context as _; +use tokio::sync::watch; +use via_btc_client::withdrawal_builder::WithdrawalBuilder; +use via_withdrawal_client::client::WithdrawalClient; +use zksync_config::configs::via_verifier::ViaVerifierConfig; +use zksync_dal::{ConnectionPool, Core}; + +use crate::coordinator::api_decl::RestApi; + +pub async fn start_coordinator_server( + config: ViaVerifierConfig, + master_connection_pool: ConnectionPool, + withdrawal_builder: WithdrawalBuilder, + withdrawal_client: WithdrawalClient, + mut stop_receiver: watch::Receiver, +) -> anyhow::Result<()> { + let bind_address = config.bind_addr(); + let api = RestApi::new( + config, + master_connection_pool, + withdrawal_builder, + withdrawal_client, + )? + .into_router(); + + let listener = tokio::net::TcpListener::bind(bind_address) + .await + .context("Cannot bind to the specified address")?; + axum::serve(listener, api) + .with_graceful_shutdown(async move { + if stop_receiver.changed().await.is_err() { + tracing::warn!("Stop signal sender for coordinator server was dropped without sending a signal"); + } + tracing::info!("Stop signal received, coordinator server is shutting down"); + }) + .await + .context("coordinator handler server failed")?; + tracing::info!("coordinator handler server shut down"); + Ok(()) +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs new file mode 100644 index 000000000..9d4ae9d82 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -0,0 +1,59 @@ +use std::{str::FromStr, sync::Arc}; + +use bitcoin::{Address, Network}; +use tokio::sync::RwLock; +use tower_http::cors::CorsLayer; +use via_btc_client::withdrawal_builder::WithdrawalBuilder; +use via_withdrawal_client::client::WithdrawalClient; +use zksync_config::configs::via_verifier::ViaVerifierConfig; +use zksync_dal::{ConnectionPool, Core}; + +use crate::types::{SigningSession, ViaWithdrawalState}; + +pub struct RestApi { + pub master_connection_pool: ConnectionPool, + pub state: ViaWithdrawalState, + pub withdrawal_builder: WithdrawalBuilder, + pub withdrawal_client: WithdrawalClient, +} + +impl RestApi { + pub fn new( + config: ViaVerifierConfig, + master_connection_pool: ConnectionPool, + withdrawal_builder: WithdrawalBuilder, + withdrawal_client: WithdrawalClient, + ) -> anyhow::Result { + let state = ViaWithdrawalState { + signing_session: Arc::new(RwLock::new(SigningSession::default())), + required_signers: config.required_signers, + }; + Ok(Self { + master_connection_pool, + state, + withdrawal_builder, + withdrawal_client, + }) + } + + pub fn into_router(self) -> axum::Router<()> { + let router = axum::Router::new() + .route("/new", axum::routing::post(Self::new_session)) + .route("/", axum::routing::get(Self::get_session)) + .route( + "/signature", + axum::routing::post(Self::submit_partial_signature), + ) + .route( + "/signature", + axum::routing::get(Self::get_submitted_signatures), + ) + .route("/nonce", axum::routing::post(Self::submit_nonce)) + .route("/nonce", axum::routing::get(Self::get_nonces)) + .layer(CorsLayer::permissive()); + + axum::Router::new() + .nest("/session", router) + .with_state(Arc::new(self)) + } +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs new file mode 100644 index 000000000..c688507a9 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -0,0 +1,241 @@ +use std::{collections::HashMap, sync::Arc}; + +use anyhow::Context; +use axum::{extract::State, response::Response, Json}; +use base64::Engine; +use bitcoin::{hashes::Hash, Txid}; +use musig2::{BinaryEncoding, PubNonce}; +use serde::Serialize; +use tracing::instrument; +use via_btc_client::{traits::Serializable, withdrawal_builder::WithdrawalRequest}; +use zksync_dal::CoreDal; +use zksync_types::H256; + +use super::api_decl::RestApi; +use crate::{ + types::{NoncePair, PartialSignaturePair, SigningSession, SigningSessionResponse}, + utils::{decode_signature, encode_signature}, +}; + +fn ok_json(data: T) -> Response { + Response::builder() + .status(axum::http::StatusCode::OK) + .body(serde_json::to_string(&data).expect("Failed to serialize")) + .unwrap() +} + +fn bad_request(message: &str) -> Response { + Response::builder() + .status(axum::http::StatusCode::BAD_REQUEST) + .body(message.to_string()) + .unwrap() +} + +fn not_found(message: &str) -> Response { + Response::builder() + .status(axum::http::StatusCode::NOT_FOUND) + .body(message.to_string()) + .unwrap() +} + +impl RestApi { + #[instrument(skip(self_))] + pub async fn new_session(State(self_): State>) -> Response { + let mut l1_block_number: i64; + + { + let signing_session = self_.state.signing_session.read().await; + l1_block_number = signing_session.l1_block_number; + } + + if l1_block_number != 0 { + let withdrawal_tx = self_ + .master_connection_pool + .connection_tagged("coordinator") + .await + .unwrap() + .via_votes_dal() + .get_vote_transaction_withdrawal_tx(l1_block_number) + .await + .unwrap(); + + if withdrawal_tx.is_none() { + // The withdrawal process is in progress + return ok_json(l1_block_number); + } + } + + // Get the l1 batches finilized but withdrawals not yet processed + let blocks = self_ + .master_connection_pool + .connection_tagged("coordinator") + .await + .unwrap() + .via_votes_dal() + .get_finalized_blocks_and_non_processed_withdrawals() + .await + .unwrap(); + + if blocks.len() == 0 { + return not_found("No block ready to process withdrawals found"); + } + + let mut withdrawals_to_process: Vec = Vec::new(); + let mut proof_txid = Txid::all_zeros(); + + for i in 0..blocks.len() { + let (block_number, blob_id, proof_tx) = &blocks[i]; + let withdrawals = self_ + .withdrawal_client + .get_withdrawals(&blob_id) + .await + .unwrap(); + + if withdrawals.len() > 0 { + proof_txid = Txid::from_slice(proof_tx.as_bytes()) + .context("Invalid proof id") + .unwrap(); + l1_block_number = block_number.clone(); + withdrawals_to_process = withdrawals; + break; + } else { + // If there is no withdrawals to process in a batch, update the status and mark it as processed + _ = self_ + .master_connection_pool + .connection_tagged("coordinator") + .await + .unwrap() + .via_votes_dal() + .mark_vote_transaction_as_processed_withdrawals( + H256::zero(), + l1_block_number.clone(), + ) + } + } + + if withdrawals_to_process.is_empty() { + { + let mut session = self_.state.signing_session.write().await; + *session = SigningSession::default(); + } + return bad_request("There are no withdrawals to process in this block"); + } + + let unsigned_tx = self_ + .withdrawal_builder + .create_unsigned_withdrawal_tx(withdrawals_to_process, proof_txid) + .await + .unwrap(); + + let message = unsigned_tx + .tx + .compute_txid() + .as_raw_hash() + .as_byte_array() + .to_vec(); + + let new_sesssion = SigningSession { + l1_block_number, + received_nonces: HashMap::new(), + received_sigs: HashMap::new(), + message: message.clone(), + unsigned_tx: Some(unsigned_tx), + }; + + { + let mut session = self_.state.signing_session.write().await; + *session = new_sesssion; + } + + return ok_json(l1_block_number); + } + + #[instrument(skip(self_))] + pub async fn get_session(State(self_): State>) -> Response { + let session = self_.state.signing_session.read().await; + + let mut unsigned_tx_bytes = Vec::new(); + if let Some(unsigned_tx) = self_.state.signing_session.read().await.unsigned_tx.clone() { + unsigned_tx_bytes = unsigned_tx.to_bytes(); + }; + + return ok_json(SigningSessionResponse { + l1_block_number: session.l1_block_number, + message_to_sign: hex::encode(&session.message), + required_signers: self_.state.required_signers, + received_nonces: session.received_nonces.len(), + received_partial_signatures: session.received_sigs.len(), + unsigned_tx: unsigned_tx_bytes, + }); + } + + #[instrument(skip(self_))] + pub async fn submit_nonce( + State(self_): State>, + Json(nonce_pair): Json, + ) -> Response { + let decoded_nonce = + match base64::engine::general_purpose::STANDARD.decode(&nonce_pair.nonce) { + Ok(nonce) => nonce, + Err(_) => return bad_request("Invalid nonce pair"), + }; + + let pub_nonce = match PubNonce::from_bytes(&decoded_nonce) { + Ok(nonce) => nonce, + Err(_) => return bad_request("Invalid pub nonce"), + }; + + let mut session = self_.state.signing_session.write().await; + + session + .received_nonces + .insert(nonce_pair.signer_index, pub_nonce); + + ok_json("Success") + } + + #[instrument(skip(self_))] + pub async fn submit_partial_signature( + State(self_): State>, + Json(sig_pair): Json, + ) -> Response { + let partial_sig = match decode_signature(sig_pair.signature) { + Ok(sig) => sig, + Err(_) => return bad_request("Invalid signature"), + }; + + { + let mut session = self_.state.signing_session.write().await; + + session + .received_sigs + .insert(sig_pair.signer_index, partial_sig); + } + ok_json("Success") + } + + #[instrument(skip(self_))] + pub async fn get_nonces(State(self_): State>) -> Response { + let session = self_.state.signing_session.read().await; + + let mut nonces = HashMap::new(); + for (&idx, nonce) in &session.received_nonces { + nonces.insert( + idx, + base64::engine::general_purpose::STANDARD.encode(nonce.to_bytes()), + ); + } + ok_json(nonces) + } + + #[instrument(skip(self_))] + pub async fn get_submitted_signatures(State(self_): State>) -> Response { + let session = self_.state.signing_session.read().await; + let mut signatures = HashMap::new(); + for (&signer_index, signature) in &session.received_sigs { + let sig = encode_signature(signer_index, signature.clone()).unwrap(); + signatures.insert(signer_index, sig); + } + ok_json(signatures) + } +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/mod.rs b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs new file mode 100644 index 000000000..63c0a9149 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs @@ -0,0 +1,3 @@ +pub mod api; +mod api_decl; +mod api_impl; diff --git a/via_verifier/node/withdrawal_service/src/lib.rs b/via_verifier/node/withdrawal_service/src/lib.rs index 8b1378917..d66baff02 100644 --- a/via_verifier/node/withdrawal_service/src/lib.rs +++ b/via_verifier/node/withdrawal_service/src/lib.rs @@ -1 +1,4 @@ +pub mod coordinator; +mod types; +mod utils; diff --git a/via_verifier/node/withdrawal_service/src/types.rs b/via_verifier/node/withdrawal_service/src/types.rs new file mode 100644 index 000000000..bfe8ab5c2 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/types.rs @@ -0,0 +1,48 @@ +use std::{clone::Clone, collections::HashMap, sync::Arc}; + +use musig2::{PartialSignature, PubNonce}; +use serde::{Deserialize, Serialize}; +use tokio::sync::RwLock; +use via_btc_client::withdrawal_builder::UnsignedWithdrawalTx; + +#[derive(Clone)] +pub struct ViaWithdrawalState { + pub signing_session: Arc>, + pub required_signers: usize, +} + +#[derive(Default, Debug, Clone)] +pub struct SigningSession { + pub l1_block_number: i64, + pub unsigned_tx: Option, + pub received_nonces: HashMap, + pub received_sigs: HashMap, + pub message: Vec, +} + +/// Data posted by other signers to submit their nonce +#[derive(Serialize, Deserialize, Debug)] +pub struct NoncePair { + pub signer_index: usize, + /// Base64 encoded signer nonce + pub nonce: String, +} + +/// Data posted by other signers to submit their partial signature +#[derive(Serialize, Deserialize, Debug)] +pub struct PartialSignaturePair { + pub signer_index: usize, + /// Base64 encoded signature + pub signature: String, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct SigningSessionResponse { + pub l1_block_number: i64, + /// hex-encoded message (txid) + pub message_to_sign: String, + pub required_signers: usize, + pub unsigned_tx: Vec, + pub received_nonces: usize, + pub received_partial_signatures: usize, +} diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs new file mode 100644 index 000000000..dff463957 --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -0,0 +1,65 @@ +use std::{clone::Clone, str::FromStr}; + +use anyhow::Context; +use base64::Engine; +use musig2::{BinaryEncoding, PartialSignature, PubNonce}; +use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; +use via_musig2::Signer; + +use crate::types::{NoncePair, PartialSignaturePair}; + +pub fn get_signer( + private_key: &str, + verifiers_pub_keys_str: Vec, +) -> anyhow::Result { + let secret_key = + SecretKey::from_str(private_key).context("Error to compute the coordinator sk")?; + let secp = Secp256k1::new(); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + + let mut all_pubkeys = Vec::new(); + all_pubkeys.push(public_key); + + let mut signer_index = 0; + for i in 0..verifiers_pub_keys_str.len() { + let pk = PublicKey::from_slice(verifiers_pub_keys_str[i].as_bytes())?; + all_pubkeys.push(pk); + if pk == public_key { + signer_index = i; + } + } + + let signer = Signer::new(secret_key, signer_index, all_pubkeys.clone())?; + Ok(signer) +} + +pub fn decode_signature(signature: String) -> anyhow::Result { + let decoded_sig = base64::engine::general_purpose::STANDARD.decode(&signature)?; + Ok(PartialSignature::from_slice(&decoded_sig)?) +} + +pub fn encode_signature( + signer_index: usize, + partial_sig: PartialSignature, +) -> anyhow::Result { + let sig_b64 = base64::engine::general_purpose::STANDARD.encode(partial_sig.serialize()); + let sig_pair = PartialSignaturePair { + signer_index, + signature: sig_b64, + }; + Ok(sig_pair) +} + +pub fn encode_nonce(signer_index: usize, nonce: PubNonce) -> anyhow::Result { + let nonce = base64::engine::general_purpose::STANDARD.encode(nonce.to_bytes()); + Ok(NoncePair { + signer_index, + nonce, + }) +} + +pub fn decode_nonce(nonce_pair: NoncePair) -> anyhow::Result { + let decoded_nonce = base64::engine::general_purpose::STANDARD.decode(&nonce_pair.nonce)?; + let pub_nonce = PubNonce::from_bytes(&decoded_nonce)?; + Ok(pub_nonce) +} From 1a27a34ab5681b4f4cebf1089015891933e9e232 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 09:30:32 +0100 Subject: [PATCH 091/212] feat(coordinator): implement the verifier task --- .../node/withdrawal_service/src/lib.rs | 2 +- .../withdrawal_service/src/verifier/mod.rs | 285 ++++++++++++++++++ 2 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 via_verifier/node/withdrawal_service/src/verifier/mod.rs diff --git a/via_verifier/node/withdrawal_service/src/lib.rs b/via_verifier/node/withdrawal_service/src/lib.rs index d66baff02..101e452e7 100644 --- a/via_verifier/node/withdrawal_service/src/lib.rs +++ b/via_verifier/node/withdrawal_service/src/lib.rs @@ -1,4 +1,4 @@ pub mod coordinator; mod types; mod utils; - +pub mod verifier; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs new file mode 100644 index 000000000..7282f3ffd --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -0,0 +1,285 @@ +use std::{collections::HashMap, sync::Arc}; + +use anyhow::Result; +use bitcoin::hashes::Hash; +use musig2::{CompactSignature, PartialSignature}; +use reqwest::{Client, StatusCode}; +use tokio::sync::watch; +use via_btc_client::{ + traits::{BitcoinOps, Serializable}, + withdrawal_builder::UnsignedWithdrawalTx, +}; +use via_musig2::{verify_signature, Signer}; +use zksync_config::configs::via_verifier::{VerifierRole, ViaVerifierConfig}; +use zksync_dal::{ConnectionPool, Core, CoreDal}; +use zksync_types::H256; + +use crate::{ + types::{NoncePair, SigningSessionResponse}, + utils::{decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer}, +}; + +pub struct ViaWithdrawalVerifier { + master_connection_pool: ConnectionPool, + btc_client: Arc, + config: ViaVerifierConfig, + client: Client, + signer: Signer, +} + +impl ViaWithdrawalVerifier { + pub async fn new( + master_connection_pool: ConnectionPool, + btc_client: Arc, + config: ViaVerifierConfig, + ) -> anyhow::Result { + let signer = get_signer( + &config.private_key.clone(), + config.verifiers_pub_keys_str.clone(), + )?; + + Ok(Self { + master_connection_pool, + btc_client, + signer, + client: Client::new(), + config, + }) + } + + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut timer = tokio::time::interval(self.config.polling_interval()); + + while !*stop_receiver.borrow_and_update() { + tokio::select! { + _ = timer.tick() => { /* continue iterations */ } + _ = stop_receiver.changed() => break, + } + + match self.loop_iteration().await { + Ok(()) => { + tracing::info!("Verifier withdrawal task finished"); + } + Err(err) => { + tracing::error!("Failed to process verifier withdrawal task: {err}"); + } + } + } + + tracing::info!("Stop signal received, verifier withdrawal is shutting down"); + Ok(()) + } + + async fn loop_iteration(&mut self) -> Result<(), anyhow::Error> { + if self.config.role == VerifierRole::COORDINATOR { + self.create_new_session().await?; + self.build_and_broadcast_final_transaction().await?; + } + + let session_info = self.get_session().await?; + + let session_signature = self.get_session_signatures().await?; + let session_nonces = self.get_session_nonces().await?; + let verifier_index = self.signer.signer_index(); + + if session_signature.get(&verifier_index).is_some() + && session_nonces.get(&verifier_index).is_some() + { + // The verifier already sent his nonce and partial signature + return Ok(()); + } + + // Reinit the signer incase the coordinator lost his in memory data + if session_signature.get(&verifier_index).is_none() + && session_nonces.get(&verifier_index).is_none() + && (self.signer.has_created_partial_sig() || self.signer.has_submitted_nonce()) + { + _ = self.reinit_signer(); + } + + if session_info.received_nonces < session_info.required_signers { + let message = hex::decode(&session_info.message_to_sign)?; + + if self.signer.has_not_started() { + self.signer.start_signing_session(message)?; + } + + if session_nonces.get(&verifier_index).is_none() { + self.submit_nonce().await?; + } + } else if session_info.received_nonces >= session_info.required_signers { + if self.signer.has_created_partial_sig() { + return Ok(()); + } + self.submit_partial_signature(session_nonces).await?; + } + + Ok(()) + } + + async fn get_session(&self) -> anyhow::Result { + let url = format!("{}/session/", self.config.url); + let resp = self.client.get(&url).send().await?; + if resp.status().as_u16() != StatusCode::OK.as_u16() { + anyhow::bail!("Error to fetch the session"); + } + let session_info: SigningSessionResponse = resp.json().await?; + Ok(session_info) + } + + async fn get_session_nonces(&self) -> anyhow::Result> { + // We need to fetch all nonces from the coordinator + let nonces_url = format!("{}/session/nonce/", self.config.url); + let resp = self.client.get(&nonces_url).send().await?; + let nonces: HashMap = resp.json().await?; + Ok(nonces) + } + + async fn submit_nonce(&mut self) -> anyhow::Result<()> { + let nonce = self + .signer + .our_nonce() + .ok_or_else(|| anyhow::anyhow!("No nonce available"))?; + + let nonce_pair = encode_nonce(self.signer.signer_index(), nonce).unwrap(); + let url = format!("{}/session/nonce/", self.config.url); + let res = self.client.post(&url).json(&nonce_pair).send().await?; + + if res.status().is_success() { + self.signer.mark_nonce_submitted(); + return Ok(()); + } + Ok(()) + } + + async fn get_session_signatures(&self) -> anyhow::Result> { + let url = format!("{}/session/signature/", self.config.url); + let resp = self.client.get(&url).send().await?; + let signatures: HashMap = resp.json().await?; + let mut partial_sigs: HashMap = HashMap::new(); + for (idx, sig) in signatures { + partial_sigs.insert(idx, decode_signature(sig).unwrap()); + } + Ok(partial_sigs) + } + + async fn submit_partial_signature( + &mut self, + session_nonces: HashMap, + ) -> anyhow::Result<()> { + // Process each nonce + for (idx, nonce_b64) in session_nonces { + if idx != self.signer.signer_index() { + let nonce = decode_nonce(NoncePair { + signer_index: idx, + nonce: nonce_b64, + })?; + self.signer + .receive_nonce(idx, nonce.clone()) + .map_err(|e| anyhow::anyhow!("Failed to receive nonce: {}", e))?; + } + } + + let partial_sig = self.signer.create_partial_signature()?; + let sig_pair = encode_signature(self.signer.signer_index(), partial_sig)?; + + let url = format!("{}/session/signature/", self.config.url,); + let resp = self.client.post(&url).json(&sig_pair).send().await?; + if resp.status().is_success() { + self.signer.mark_partial_sig_submitted(); + } + Ok(()) + } + + fn reinit_signer(&mut self) -> anyhow::Result<()> { + let signer = get_signer( + &self.config.private_key.clone(), + self.config.verifiers_pub_keys_str.clone(), + )?; + self.signer = signer; + Ok(()) + } + + async fn create_new_session(&mut self) -> anyhow::Result<()> { + let session_info = self.get_session().await?; + if session_info.l1_block_number == 0 { + let url = format!("{}/session/new/", self.config.url,); + let resp = self.client.post(&url).send().await?; + if !resp.status().is_success() {} + } + Ok(()) + } + + async fn create_final_signature(&mut self) -> anyhow::Result> { + let session_info = self.get_session().await?; + + if session_info.received_partial_signatures >= session_info.required_signers { + let signatures = self.get_session_signatures().await?; + if session_info.received_partial_signatures >= session_info.required_signers { + for (&i, sig) in &signatures { + if self.signer.signer_index() != i { + self.signer.receive_partial_signature(i, *sig)?; + } + } + } + + let final_sig = self.signer.create_final_signature()?; + let agg_pub = self.signer.aggregated_pubkey(); + verify_signature( + agg_pub, + final_sig, + &hex::decode(&session_info.message_to_sign)?, + )?; + return Ok(Some(final_sig)); + } + Ok(None) + } + + fn sign_transaction( + &self, + unsigned_tx: UnsignedWithdrawalTx, + musig2_signature: CompactSignature, + ) -> String { + // Todo: sign the transaction + "".to_string() + } + + async fn build_and_broadcast_final_transaction(&mut self) -> anyhow::Result<()> { + let session_info = self.get_session().await?; + + if let Some(musig2_signature) = self.create_final_signature().await? { + let withdrawal_txid = self + .master_connection_pool + .connection_tagged("coordinator task") + .await + .unwrap() + .via_votes_dal() + .get_vote_transaction_withdrawal_tx(session_info.l1_block_number) + .await?; + + if withdrawal_txid.is_some() { + return Ok(()); + } + let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session_info.unsigned_tx); + let signed_tx = self.sign_transaction(unsigned_tx, musig2_signature); + + let txid = self + .btc_client + .broadcast_signed_transaction(&signed_tx) + .await?; + + _ = self + .master_connection_pool + .connection_tagged("coordinator task") + .await + .unwrap() + .via_votes_dal() + .mark_vote_transaction_as_processed_withdrawals( + H256::from_slice(&txid.as_raw_hash().to_byte_array()), + session_info.l1_block_number, + ) + .await?; + } + Ok(()) + } +} From 7973f31076ce7aef1d899968535e21add14a7587 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:25:16 +0100 Subject: [PATCH 092/212] chore: update the sqlx queries --- ...bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json} | 4 ++-- ...a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename core/lib/dal/.sqlx/{query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json => query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json} (53%) rename core/lib/dal/.sqlx/{query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json => query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json} (63%) diff --git a/core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json b/core/lib/dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json similarity index 53% rename from core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json rename to core/lib/dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json index 784f40dc6..1a6e3e10c 100644 --- a/core/lib/dal/.sqlx/query-c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254.json +++ b/core/lib/dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE via_votable_transactions\n SET\n withdrawal_tx_id = $1\n WHERE\n is_finalized = TRUE AND\n is_verified = TRUE AND\n withdrawal_tx_id IS NULL AND\n l1_batch_number = $2\n ", + "query": "\n UPDATE via_votable_transactions\n SET\n withdrawal_tx_id = $1\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n AND l1_batch_number = $2\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "c7ae45d794daf0a26f0980bb969dec6e1783a3763df3a30d0babe4c0feded254" + "hash": "32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4" } diff --git a/core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json b/core/lib/dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json similarity index 63% rename from core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json rename to core/lib/dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json index 1ad66057d..3e41688ab 100644 --- a/core/lib/dal/.sqlx/query-ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e.json +++ b/core/lib/dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n l1_batch_number,\n blob_id,\n proof_tx_id\n FROM via_votable_transactions\n WHERE\n is_finalized = TRUE AND\n is_verified = TRUE AND\n withdrawal_tx_id IS NULL\n ORDER BY l1_batch_number ASC\n ", + "query": "\n SELECT\n l1_batch_number,\n blob_id,\n proof_tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n ORDER BY\n l1_batch_number ASC\n ", "describe": { "columns": [ { @@ -28,5 +28,5 @@ false ] }, - "hash": "ec22470c7ffd548a8646a7b5dac22ac740322906842a49122ea8d535296f296e" + "hash": "ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba" } From 307a895d41e66433074c4e3829496ff4d0ee2216 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:25:52 +0100 Subject: [PATCH 093/212] feat: add sign signature logic --- .../withdrawal_service/src/coordinator/api_decl.rs | 3 +-- .../node/withdrawal_service/src/verifier/mod.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs index 9d4ae9d82..9cafa3b84 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -1,6 +1,5 @@ -use std::{str::FromStr, sync::Arc}; +use std::sync::Arc; -use bitcoin::{Address, Network}; use tokio::sync::RwLock; use tower_http::cors::CorsLayer; use via_btc_client::withdrawal_builder::WithdrawalBuilder; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 7282f3ffd..4ab34726a 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::Result; -use bitcoin::hashes::Hash; +use bitcoin::{hashes::Hash, TapSighashType, Witness}; use musig2::{CompactSignature, PartialSignature}; use reqwest::{Client, StatusCode}; use tokio::sync::watch; @@ -240,8 +240,14 @@ impl ViaWithdrawalVerifier { unsigned_tx: UnsignedWithdrawalTx, musig2_signature: CompactSignature, ) -> String { - // Todo: sign the transaction - "".to_string() + let mut unsigned_tx = unsigned_tx; + let mut final_sig_with_hashtype = musig2_signature.serialize().to_vec(); + let sighash_type = TapSighashType::All; + final_sig_with_hashtype.push(sighash_type as u8); + for tx in &mut unsigned_tx.tx.input { + tx.witness = Witness::from(vec![final_sig_with_hashtype.clone()]); + } + bitcoin::consensus::encode::serialize_hex(&unsigned_tx.tx) } async fn build_and_broadcast_final_transaction(&mut self) -> anyhow::Result<()> { @@ -261,7 +267,7 @@ impl ViaWithdrawalVerifier { return Ok(()); } let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session_info.unsigned_tx); - let signed_tx = self.sign_transaction(unsigned_tx, musig2_signature); + let signed_tx = self.sign_transaction(unsigned_tx.clone(), musig2_signature); let txid = self .btc_client From 20bb59d49b4b1e0568441ddf66180892797ee423 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 27 Dec 2024 18:26:19 +0100 Subject: [PATCH 094/212] feat: add coordinator api and verifier task layers --- Cargo.lock | 2 + core/node/node_framework/Cargo.toml | 2 + .../src/implementations/layers/mod.rs | 1 + .../layers/via_verifier/coordinator_api.rs | 110 ++++++++++++++++++ .../layers/via_verifier/mod.rs | 2 + .../layers/via_verifier/verifier.rs | 79 +++++++++++++ .../src/message_processors/verifier.rs | 10 +- 7 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs create mode 100644 core/node/node_framework/src/implementations/layers/via_verifier/mod.rs create mode 100644 core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs diff --git a/Cargo.lock b/Cargo.lock index d282510a0..9aa4cf7a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11796,6 +11796,8 @@ dependencies = [ "via_da_dispatcher", "via_fee_model", "via_state_keeper", + "via_withdrawal_client", + "via_withdrawal_service", "zksync_base_token_adjuster", "zksync_block_reverter", "zksync_circuit_breaker", diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index be49135cf..efecbf779 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -63,6 +63,8 @@ via_btc_sender.workspace = true via_fee_model.workspace = true via_da_dispatcher.workspace = true via_state_keeper.workspace = true +via_withdrawal_service.workspace = true +via_withdrawal_client.workspace = true pin-project-lite.workspace = true tracing.workspace = true thiserror.workspace = true diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index 4198027de..a94aab2f5 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -42,6 +42,7 @@ pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; // TODO: TMP in sequencer +pub mod via_verifier; pub mod via_zk_verification; pub mod vm_runner; pub mod web3_api; diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs b/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs new file mode 100644 index 000000000..ce73bedcc --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs @@ -0,0 +1,110 @@ +use std::str::FromStr; + +use anyhow::Context; +use via_btc_client::{ + types::{BitcoinAddress, NodeAuth}, + withdrawal_builder::WithdrawalBuilder, +}; +use via_btc_watch::BitcoinNetwork; +use via_withdrawal_client::client::WithdrawalClient; +use zksync_config::{ViaBtcSenderConfig, ViaVerifierConfig}; +use zksync_dal::{ConnectionPool, Core}; + +use crate::{ + implementations::resources::{ + da_client::DAClientResource, + pools::{MasterPool, PoolResource}, + }, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for coordinator api +#[derive(Debug)] +pub struct ViaCoordinatorApiLayer { + pub config: ViaVerifierConfig, + pub btc_sender_config: ViaBtcSenderConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, + pub client: DAClientResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + #[context(task)] + pub via_coordinator_api_task: ViaCoordinatorApiTask, +} + +#[async_trait::async_trait] +impl WiringLayer for ViaCoordinatorApiLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "via_coordinator_api_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + let master_pool = input.master_pool.get().await?; + let auth = NodeAuth::UserPass( + self.btc_sender_config.rpc_user().to_string(), + self.btc_sender_config.rpc_password().to_string(), + ); + let network = BitcoinNetwork::from_str(self.btc_sender_config.network()).unwrap(); + let bridge_address = BitcoinAddress::from_str(self.config.bridge_address_str.as_str()) + .context("Error parse bridge address")? + .assume_checked(); + + let withdrawal_builder = WithdrawalBuilder::new( + self.btc_sender_config.rpc_url(), + network, + auth, + bridge_address, + ) + .await?; + + let withdrawal_client = WithdrawalClient::new(input.client.0, network); + let via_coordinator_api_task = ViaCoordinatorApiTask { + master_pool, + config: self.config, + withdrawal_builder, + withdrawal_client, + }; + Ok(Output { + via_coordinator_api_task, + }) + } +} + +#[derive(Debug)] +pub struct ViaCoordinatorApiTask { + master_pool: ConnectionPool, + config: ViaVerifierConfig, + withdrawal_builder: WithdrawalBuilder, + withdrawal_client: WithdrawalClient, +} + +#[async_trait::async_trait] +impl Task for ViaCoordinatorApiTask { + fn id(&self) -> TaskId { + "via_coordinator_api".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + via_withdrawal_service::coordinator::api::start_coordinator_server( + self.config, + self.master_pool, + self.withdrawal_builder, + self.withdrawal_client, + stop_receiver.0, + ) + .await + } +} diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/mod.rs b/core/node/node_framework/src/implementations/layers/via_verifier/mod.rs new file mode 100644 index 000000000..18a507a8f --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_verifier/mod.rs @@ -0,0 +1,2 @@ +pub mod coordinator_api; +pub mod verifier; diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs new file mode 100644 index 000000000..eea53cbd9 --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs @@ -0,0 +1,79 @@ +use std::{str::FromStr, sync::Arc}; + +use anyhow::Context; +use via_btc_client::{client::BitcoinClient, types::NodeAuth}; +use via_btc_watch::BitcoinNetwork; +use via_withdrawal_service::verifier::ViaWithdrawalVerifier; +use zksync_config::{ViaBtcSenderConfig, ViaVerifierConfig}; + +use crate::{ + implementations::resources::pools::{MasterPool, PoolResource}, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for verifier task +#[derive(Debug)] +pub struct ViaWithdrawalVerifierLayer { + pub config: ViaVerifierConfig, + pub btc_sender_config: ViaBtcSenderConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + #[context(task)] + pub via_withdrawal_verifier_task: ViaWithdrawalVerifier, +} + +#[async_trait::async_trait] +impl WiringLayer for ViaWithdrawalVerifierLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "via_withdrawal_verifier_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + let master_pool = input.master_pool.get().await?; + let auth = NodeAuth::UserPass( + self.btc_sender_config.rpc_user().to_string(), + self.btc_sender_config.rpc_password().to_string(), + ); + let network = BitcoinNetwork::from_str(self.btc_sender_config.network()).unwrap(); + + let btc_client = Arc::new( + BitcoinClient::new(self.btc_sender_config.rpc_url(), network, auth) + .context("Error to init the btc client for verifier task")?, + ); + + let via_withdrawal_verifier_task = + ViaWithdrawalVerifier::new(master_pool, btc_client, self.config) + .await + .context("Error to init the via withdrawal verifier")?; + + Ok(Output { + via_withdrawal_verifier_task, + }) + } +} + +#[async_trait::async_trait] +impl Task for ViaWithdrawalVerifier { + fn id(&self) -> TaskId { + "via_withdrawal_verifier".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs index e355aaf14..a5be3e365 100644 --- a/core/node/via_btc_watch/src/message_processors/verifier.rs +++ b/core/node/via_btc_watch/src/message_processors/verifier.rs @@ -42,10 +42,16 @@ impl MessageProcessor for VerifierMessageProcessor { continue; } - let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id.clone()); votes_dal - .insert_votable_transaction(l1_batch_number.0, tx_id) + .insert_votable_transaction( + l1_batch_number.0, + tx_id, + proof_msg.input.da_identifier.clone(), + proof_msg.input.blob_id.clone(), + proof_msg.input.l1_batch_reveal_txid.to_string(), + ) .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; } else { From f82434d53d8bd0711c1eae1857b3e4956934eeb2 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 7 Jan 2025 06:14:34 +0330 Subject: [PATCH 095/212] chore(via): fix clippy warning in whole devnet-2, resolve verifier example issue --- core/lib/dal/src/via_votes_dal.rs | 2 +- core/lib/via_btc_client/src/indexer/mod.rs | 2 +- core/lib/via_btc_client/src/utils.rs | 2 +- core/node/via_btc_sender/src/btc_vote_inscription.rs | 2 +- core/node/via_btc_sender/src/tests/utils.rs | 1 - core/node/via_btc_sender/src/tests/vote_inscription_test.rs | 4 ++-- core/node/via_btc_watch/src/message_processors/verifier.rs | 4 ++-- .../examples/zksync-era-verification-cli/contract.rs | 4 +--- 8 files changed, 9 insertions(+), 12 deletions(-) diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index 95e3cfd11..43e50eba2 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -183,7 +183,7 @@ impl ViaVotesDal<'_, '_> { l1_batch_number = $1 AND tx_id = $2 "#, - l1_batch_number as i64, + i64::from(l1_batch_number), tx_id.as_bytes(), l1_batch_status ) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 7e8355f32..4f6ad7044 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -210,7 +210,7 @@ impl BitcoinInscriptionIndexer { &mut self, tx: &Txid, ) -> BitcoinIndexerResult> { - let tx = self.client.get_transaction(&tx).await?; + let tx = self.client.get_transaction(tx).await?; Ok(self.parser.parse_transaction(&tx, 0)) } } diff --git a/core/lib/via_btc_client/src/utils.rs b/core/lib/via_btc_client/src/utils.rs index 33e6a1a06..31f76fe6c 100644 --- a/core/lib/via_btc_client/src/utils.rs +++ b/core/lib/via_btc_client/src/utils.rs @@ -33,6 +33,6 @@ where } pub fn bytes_to_txid(bytes: &[u8]) -> Result { - let txid = Txid::from_slice(bytes).map_err(|e| types::IndexerError::TxIdParsingError(e))?; + let txid = Txid::from_slice(bytes).map_err(types::IndexerError::TxIdParsingError)?; Ok(txid) } diff --git a/core/node/via_btc_sender/src/btc_vote_inscription.rs b/core/node/via_btc_sender/src/btc_vote_inscription.rs index 92f2e754e..cff564dba 100644 --- a/core/node/via_btc_sender/src/btc_vote_inscription.rs +++ b/core/node/via_btc_sender/src/btc_vote_inscription.rs @@ -133,6 +133,6 @@ impl ViaVoteInscription { reference_txid: Txid::from_slice(&tx_id)?, attestation, }; - return Ok(InscriptionMessage::ValidatorAttestation(input)); + Ok(InscriptionMessage::ValidatorAttestation(input)) } } diff --git a/core/node/via_btc_sender/src/tests/utils.rs b/core/node/via_btc_sender/src/tests/utils.rs index 558277606..32eeaf281 100644 --- a/core/node/via_btc_sender/src/tests/utils.rs +++ b/core/node/via_btc_sender/src/tests/utils.rs @@ -72,7 +72,6 @@ pub fn create_l1_batch(number: u32) -> L1BatchHeader { } pub fn default_l1_batch_metadata() -> L1BatchMetadata { - let hex_str = "0000000000000000000000000000000000000000000000000000000000000000"; L1BatchMetadata { root_hash: H256::default(), rollup_last_leaf_index: 0, diff --git a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs index 22319256c..b0fcc1384 100644 --- a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs +++ b/core/node/via_btc_sender/src/tests/vote_inscription_test.rs @@ -168,7 +168,7 @@ mod tests { assert!(op.is_some()); let (l1_block_number, vote, tx_id_vec) = op.unwrap(); assert_eq!(l1_block_number, L1BatchNumber::from(1)); - assert_eq!(vote, true); + assert!(vote); assert_eq!(H256::from_slice(&tx_id_vec), tx_id); let inscription = aggregator_test @@ -193,7 +193,7 @@ mod tests { assert_eq!( InscriptionMessage::from_bytes( inscriptions - .get(0) + .first() .unwrap() .inscription_message .as_ref() diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs index e355aaf14..f3b0ca934 100644 --- a/core/node/via_btc_watch/src/message_processors/verifier.rs +++ b/core/node/via_btc_watch/src/message_processors/verifier.rs @@ -25,7 +25,7 @@ impl MessageProcessor for VerifierMessageProcessor { for msg in msgs { match msg { ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { let mut votes_dal = storage.via_votes_dal(); let last_inserted_block = votes_dal @@ -56,7 +56,7 @@ impl MessageProcessor for VerifierMessageProcessor { } } ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(&f).await { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { let mut votes_dal = storage.via_votes_dal(); let reference_txid = diff --git a/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs index 626318a39..58ac144b0 100644 --- a/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs +++ b/via_verifier/lib/via_verification/examples/zksync-era-verification-cli/contract.rs @@ -101,13 +101,11 @@ impl L1DataFetcher for ContractConfig { ) .await?; let batch_l1_data = - fetch_l1_commit_data(batch_number, &self.provider.url().to_string()).await?; + fetch_l1_commit_data(batch_number, self.provider.url().as_ref()).await?; let inputs = generate_inputs( &batch_l1_data.prev_batch_commitment, &batch_l1_data.curr_batch_commitment, ); - fetch_l1_commit_data(batch_number, self.provider.url().as_ref()).await?; - let inputs = generate_inputs(&batch_l1_data); proof.proof.inputs = inputs.clone(); Ok((proof, block_number)) From 7f636b8416e867e29789a7e214772c4ce440b386 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 8 Jan 2025 10:07:56 +0330 Subject: [PATCH 096/212] chore(via): fix clippy warning and errors in feat/via-verifier-withdrawal --- .../layers/via_verifier/verifier.rs | 2 +- .../src/message_processors/verifier.rs | 2 +- .../lib/via_withdrawal_client/src/client.rs | 1 - .../lib/via_withdrawal_client/src/types.rs | 1 + .../src/coordinator/api_impl.rs | 15 +++++++-------- via_verifier/node/withdrawal_service/src/utils.rs | 4 ++-- .../node/withdrawal_service/src/verifier/mod.rs | 12 ++++++------ 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs index eea53cbd9..743f3fc53 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs @@ -27,7 +27,7 @@ pub struct Input { pub master_pool: PoolResource, } -#[derive(Debug, IntoContext)] +#[derive(IntoContext)] #[context(crate = crate)] pub struct Output { #[context(task)] diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs index 23501021f..5007e505a 100644 --- a/core/node/via_btc_watch/src/message_processors/verifier.rs +++ b/core/node/via_btc_watch/src/message_processors/verifier.rs @@ -42,7 +42,7 @@ impl MessageProcessor for VerifierMessageProcessor { continue; } - let tx_id = convert_txid_to_h256(proof_msg.common.tx_id.clone()); + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); votes_dal .insert_votable_transaction( diff --git a/via_verifier/lib/via_withdrawal_client/src/client.rs b/via_verifier/lib/via_withdrawal_client/src/client.rs index 56b8915da..cdb8bc465 100644 --- a/via_verifier/lib/via_withdrawal_client/src/client.rs +++ b/via_verifier/lib/via_withdrawal_client/src/client.rs @@ -88,7 +88,6 @@ mod tests { use std::str::FromStr; use bitcoin::{Address, Amount}; - use zksync_types::U256; use super::*; diff --git a/via_verifier/lib/via_withdrawal_client/src/types.rs b/via_verifier/lib/via_withdrawal_client/src/types.rs index 44a8358c5..22bdcd3be 100644 --- a/via_verifier/lib/via_withdrawal_client/src/types.rs +++ b/via_verifier/lib/via_withdrawal_client/src/types.rs @@ -20,6 +20,7 @@ pub struct L2BridgeLogMetadata { } #[derive(Clone, Debug)] +#[allow(unused)] pub struct WithdrawalRequest { /// The receiver l1 address. pub address: BitcoinAddress, diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index c688507a9..7d1fafe69 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -76,26 +76,25 @@ impl RestApi { .await .unwrap(); - if blocks.len() == 0 { + if blocks.is_empty() { return not_found("No block ready to process withdrawals found"); } let mut withdrawals_to_process: Vec = Vec::new(); let mut proof_txid = Txid::all_zeros(); - for i in 0..blocks.len() { - let (block_number, blob_id, proof_tx) = &blocks[i]; + for (block_number, blob_id, proof_tx) in blocks.iter() { let withdrawals = self_ .withdrawal_client - .get_withdrawals(&blob_id) + .get_withdrawals(blob_id) .await .unwrap(); - if withdrawals.len() > 0 { + if !withdrawals.is_empty() { proof_txid = Txid::from_slice(proof_tx.as_bytes()) .context("Invalid proof id") .unwrap(); - l1_block_number = block_number.clone(); + l1_block_number = *block_number; withdrawals_to_process = withdrawals; break; } else { @@ -108,7 +107,7 @@ impl RestApi { .via_votes_dal() .mark_vote_transaction_as_processed_withdrawals( H256::zero(), - l1_block_number.clone(), + l1_block_number, ) } } @@ -233,7 +232,7 @@ impl RestApi { let session = self_.state.signing_session.read().await; let mut signatures = HashMap::new(); for (&signer_index, signature) in &session.received_sigs { - let sig = encode_signature(signer_index, signature.clone()).unwrap(); + let sig = encode_signature(signer_index, *signature).unwrap(); signatures.insert(signer_index, sig); } ok_json(signatures) diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index dff463957..4ed7bac1c 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -21,8 +21,8 @@ pub fn get_signer( all_pubkeys.push(public_key); let mut signer_index = 0; - for i in 0..verifiers_pub_keys_str.len() { - let pk = PublicKey::from_slice(verifiers_pub_keys_str[i].as_bytes())?; + for (i, key) in verifiers_pub_keys_str.iter().enumerate() { + let pk = PublicKey::from_slice(key.as_bytes())?; all_pubkeys.push(pk); if pk == public_key { signer_index = i; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 4ab34726a..4f6fa942d 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -82,16 +82,16 @@ impl ViaWithdrawalVerifier { let session_nonces = self.get_session_nonces().await?; let verifier_index = self.signer.signer_index(); - if session_signature.get(&verifier_index).is_some() - && session_nonces.get(&verifier_index).is_some() + if session_signature.contains_key(&verifier_index) + && session_nonces.contains_key(&verifier_index) { // The verifier already sent his nonce and partial signature return Ok(()); } // Reinit the signer incase the coordinator lost his in memory data - if session_signature.get(&verifier_index).is_none() - && session_nonces.get(&verifier_index).is_none() + if !session_signature.contains_key(&verifier_index) + && !session_nonces.contains_key(&verifier_index) && (self.signer.has_created_partial_sig() || self.signer.has_submitted_nonce()) { _ = self.reinit_signer(); @@ -104,7 +104,7 @@ impl ViaWithdrawalVerifier { self.signer.start_signing_session(message)?; } - if session_nonces.get(&verifier_index).is_none() { + if !session_nonces.contains_key(&verifier_index) { self.submit_nonce().await?; } } else if session_info.received_nonces >= session_info.required_signers { @@ -274,7 +274,7 @@ impl ViaWithdrawalVerifier { .broadcast_signed_transaction(&signed_tx) .await?; - _ = self + self .master_connection_pool .connection_tagged("coordinator task") .await From 63c9ac7596b39ac581272d07b72afe73be7311de Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 8 Jan 2025 10:08:19 +0330 Subject: [PATCH 097/212] chore(via): fix clippy warning and errors in feat/via-verifier-withdrawal --- .../node/withdrawal_service/src/coordinator/api_impl.rs | 5 +---- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 7d1fafe69..6adc96062 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -105,10 +105,7 @@ impl RestApi { .await .unwrap() .via_votes_dal() - .mark_vote_transaction_as_processed_withdrawals( - H256::zero(), - l1_block_number, - ) + .mark_vote_transaction_as_processed_withdrawals(H256::zero(), l1_block_number) } } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 4f6fa942d..bc95d05de 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -274,8 +274,7 @@ impl ViaWithdrawalVerifier { .broadcast_signed_transaction(&signed_tx) .await?; - self - .master_connection_pool + self.master_connection_pool .connection_tagged("coordinator task") .await .unwrap() From 4b79fa00427a87b4c2385f98a74e2ae81b5cd0ad Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Wed, 8 Jan 2025 11:18:53 +0330 Subject: [PATCH 098/212] chore(via): switch from arabica to mocha --- docker-compose-via.yml | 6 ++-- infrastructure/via/src/celestia.ts | 56 ++++++++++++++++-------------- infrastructure/via/src/config.ts | 2 +- infrastructure/via/src/verifier.ts | 2 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 977e5d751..b671d1e30 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -108,18 +108,18 @@ services: - POSTGRES_PASSWORD=notsecurepassword celestia-node: - image: "ghcr.io/celestiaorg/celestia-node:v0.20.2-arabica" + image: "ghcr.io/celestiaorg/celestia-node:v0.20.4-mocha" container_name: celestia-node volumes: - type: bind source: ./volumes/celestia target: /home/celestia - command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip validator-2.celestia-arabica-11.com --p2p.network arabica + command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip full.consensus.mocha-4.celestia-mocha.com --p2p.network mocha ports: - '26658:26658' environment: - NODE_TYPE=light - - P2P_NETWORK=arabica + - P2P_NETWORK=mocha volumes: bitcoin_data: diff --git a/infrastructure/via/src/celestia.ts b/infrastructure/via/src/celestia.ts index af15166a8..af21f896c 100644 --- a/infrastructure/via/src/celestia.ts +++ b/infrastructure/via/src/celestia.ts @@ -24,7 +24,7 @@ function runCommand(command: string): Promise { const get_node_address_command = "docker exec $(docker ps -q -f name=celestia-node) celestia state account-address | jq -r '.result'"; const get_auth_node_command = - 'docker exec $(docker ps -q -f name=celestia-node) celestia light auth admin --p2p.network arabica'; + 'docker exec $(docker ps -q -f name=celestia-node) celestia light auth admin --p2p.network mocha'; const restart_celestia_container_command = 'docker restart celestia-node'; async function updateEnvironment(auth_token: string) { @@ -36,31 +36,33 @@ async function updateEnvironment(auth_token: string) { } async function get_celestia_faucet_token(node_address: string) { - const response = await fetch('https://faucet.celestia-arabica-11.com/api/v1/faucet/give_me', { - headers: { - accept: '*/*', - 'accept-language': 'en-US,en;q=0.9', - 'content-type': 'application/json', - priority: 'u=1, i', - 'sec-ch-ua': '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"', - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': '"macOS"', - 'sec-fetch-dest': 'empty', - 'sec-fetch-mode': 'cors', - 'sec-fetch-site': 'same-origin', - Referer: 'https://faucet.celestia-arabica-11.com/', - 'Referrer-Policy': 'strict-origin-when-cross-origin' - }, - body: JSON.stringify({ - address: node_address, - chainId: 'arabica-11' - }), - method: 'POST' - }); - - const data = await response.json(); - console.log('Faucet Response:', data); - return data.token; + // const response = await fetch('https://faucet.celestia-arabica-11.com/api/v1/faucet/give_me', { + // headers: { + // accept: '*/*', + // 'accept-language': 'en-US,en;q=0.9', + // 'content-type': 'application/json', + // priority: 'u=1, i', + // 'sec-ch-ua': '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"', + // 'sec-ch-ua-mobile': '?0', + // 'sec-ch-ua-platform': '"macOS"', + // 'sec-fetch-dest': 'empty', + // 'sec-fetch-mode': 'cors', + // 'sec-fetch-site': 'same-origin', + // Referer: 'https://faucet.celestia-arabica-11.com/', + // 'Referrer-Policy': 'strict-origin-when-cross-origin' + // }, + // body: JSON.stringify({ + // address: node_address, + // chainId: 'arabica-11' + // }), + // method: 'POST' + // }); + + // const data = await response.json(); + // console.log('Faucet Response:', data); + // return data.token; + + console.log('For Mocha faucet,you should send the request in celestia discord channel'); } async function fix_celestia_config() { @@ -151,7 +153,7 @@ export async function via_celestia() { console.log('Request Sent to Faucet'); await get_celestia_faucet_token(node_address); await get_celestia_faucet_token(node_address); - console.log(`Check your balance at https://arabica.celenium.io/address/${node_address}?tab=transactions`); + console.log(`Check your balance at https://mocha.celenium.io/address/${node_address}?tab=transactions`); } catch (error) { console.error('Error getting faucet token:', error); } diff --git a/infrastructure/via/src/config.ts b/infrastructure/via/src/config.ts index 2364ea389..f0288f396 100644 --- a/infrastructure/via/src/config.ts +++ b/infrastructure/via/src/config.ts @@ -188,7 +188,7 @@ const fetchCelestiaTrustedHash = async () => { let environment = process.env.VIA_ENV!; const l2InitFile = `etc/env/l2-inits/${environment}.init.env`; - const response = await (await fetch('https://rpc.celestia-arabica-11.com/header')).json(); + const response = await (await fetch('http://public-celestia-mocha4-consensus.numia.xyz:26657/header')).json(); const { last_block_id, height } = response.result.header; const envFilePath1 = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index 3aad834dd..c394397f3 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -4,7 +4,7 @@ import * as env from './env'; export async function verifier(isCoordinator: boolean) { let options = ''; - console.log(isCoordinator); + console.log('Is Verifier Coordinator Instance', isCoordinator); if (isCoordinator) { options += '--coordinator'; } From e929e56d51a6f2123baf74ef839e35fcc8da7a8a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:55:43 +0100 Subject: [PATCH 099/212] fix: rename verifier config role --- core/lib/config/src/configs/via_verifier.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/lib/config/src/configs/via_verifier.rs b/core/lib/config/src/configs/via_verifier.rs index 609f0a3d3..636729aa7 100644 --- a/core/lib/config/src/configs/via_verifier.rs +++ b/core/lib/config/src/configs/via_verifier.rs @@ -6,7 +6,7 @@ use std::{ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub enum VerifierRole { +pub enum VerifierMode { VERIFIER = 0, COORDINATOR = 1, } @@ -28,7 +28,7 @@ pub struct ViaVerifierConfig { /// The minimum required signers. pub required_signers: usize, /// The role. - pub role: VerifierRole, + pub verifier_mode: VerifierMode, } impl ViaVerifierConfig { @@ -50,7 +50,7 @@ impl ViaVerifierConfig { verifiers_pub_keys_str: Vec::new(), bridge_address_str: "".to_string(), required_signers: 2, - role: VerifierRole::VERIFIER, + verifier_mode: VerifierMode::VERIFIER, } } } From 6b71917b28a16ffaf41ebaf1b154c975fc1205d0 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:02:46 +0100 Subject: [PATCH 100/212] fix: withdrawal service task and api --- .../src/coordinator/api_impl.rs | 45 ++++++++---- .../node/withdrawal_service/src/types.rs | 4 +- .../node/withdrawal_service/src/utils.rs | 19 +++-- .../withdrawal_service/src/verifier/mod.rs | 70 +++++++++++++------ 4 files changed, 91 insertions(+), 47 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index c688507a9..1b37845d2 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -3,7 +3,11 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::Context; use axum::{extract::State, response::Response, Json}; use base64::Engine; -use bitcoin::{hashes::Hash, Txid}; +use bitcoin::{ + hashes::Hash, + sighash::{Prevouts, SighashCache}, + TapSighashType, Txid, +}; use musig2::{BinaryEncoding, PubNonce}; use serde::Serialize; use tracing::instrument; @@ -51,7 +55,7 @@ impl RestApi { if l1_block_number != 0 { let withdrawal_tx = self_ .master_connection_pool - .connection_tagged("coordinator") + .connection_tagged("coordinator api") .await .unwrap() .via_votes_dal() @@ -77,7 +81,10 @@ impl RestApi { .unwrap(); if blocks.len() == 0 { - return not_found("No block ready to process withdrawals found"); + if l1_block_number != 0 { + self_.reset_session().await; + } + return not_found("No block found for processing withdrawals"); } let mut withdrawals_to_process: Vec = Vec::new(); @@ -89,6 +96,7 @@ impl RestApi { .withdrawal_client .get_withdrawals(&blob_id) .await + .context("Error to get withdrawals") .unwrap(); if withdrawals.len() > 0 { @@ -114,31 +122,33 @@ impl RestApi { } if withdrawals_to_process.is_empty() { - { - let mut session = self_.state.signing_session.write().await; - *session = SigningSession::default(); - } - return bad_request("There are no withdrawals to process in this block"); + self_.reset_session().await; + return not_found("There are no withdrawals to process"); } let unsigned_tx = self_ .withdrawal_builder .create_unsigned_withdrawal_tx(withdrawals_to_process, proof_txid) .await + .context("Error to create a unsigned withdrawal transaction") .unwrap(); - let message = unsigned_tx - .tx - .compute_txid() - .as_raw_hash() - .as_byte_array() - .to_vec(); + let mut sighash_cache = SighashCache::new(&unsigned_tx.tx); + let sighash_type = TapSighashType::All; + let mut txout_list = Vec::with_capacity(unsigned_tx.utxos.len()); + + for (_, txout) in unsigned_tx.utxos.clone() { + txout_list.push(txout); + } + let sighash = sighash_cache + .taproot_key_spend_signature_hash(0, &Prevouts::All(&txout_list), sighash_type) + .unwrap(); let new_sesssion = SigningSession { l1_block_number, received_nonces: HashMap::new(), received_sigs: HashMap::new(), - message: message.clone(), + message: sighash.to_byte_array().to_vec(), unsigned_tx: Some(unsigned_tx), }; @@ -238,4 +248,9 @@ impl RestApi { } ok_json(signatures) } + + pub async fn reset_session(&self) { + let mut session = self.state.signing_session.write().await; + *session = SigningSession::default(); + } } diff --git a/via_verifier/node/withdrawal_service/src/types.rs b/via_verifier/node/withdrawal_service/src/types.rs index bfe8ab5c2..e2f6703f8 100644 --- a/via_verifier/node/withdrawal_service/src/types.rs +++ b/via_verifier/node/withdrawal_service/src/types.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use via_btc_client::withdrawal_builder::UnsignedWithdrawalTx; -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct ViaWithdrawalState { pub signing_session: Arc>, pub required_signers: usize, @@ -36,7 +36,7 @@ pub struct PartialSignaturePair { pub signature: String, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct SigningSessionResponse { pub l1_block_number: i64, /// hex-encoded message (txid) diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index dff463957..92da0edbf 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -2,6 +2,7 @@ use std::{clone::Clone, str::FromStr}; use anyhow::Context; use base64::Engine; +use bitcoin::PrivateKey; use musig2::{BinaryEncoding, PartialSignature, PubNonce}; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; use via_musig2::Signer; @@ -9,20 +10,20 @@ use via_musig2::Signer; use crate::types::{NoncePair, PartialSignaturePair}; pub fn get_signer( - private_key: &str, + private_key_wif: &str, verifiers_pub_keys_str: Vec, ) -> anyhow::Result { - let secret_key = - SecretKey::from_str(private_key).context("Error to compute the coordinator sk")?; + let private_key = PrivateKey::from_wif(private_key_wif)?; + let secret_key = SecretKey::from_byte_array(&private_key.inner.secret_bytes()) + .context("Error to compute the coordinator sk")?; let secp = Secp256k1::new(); let public_key = PublicKey::from_secret_key(&secp, &secret_key); let mut all_pubkeys = Vec::new(); - all_pubkeys.push(public_key); let mut signer_index = 0; for i in 0..verifiers_pub_keys_str.len() { - let pk = PublicKey::from_slice(verifiers_pub_keys_str[i].as_bytes())?; + let pk = PublicKey::from_str(&verifiers_pub_keys_str[i])?; all_pubkeys.push(pk); if pk == public_key { signer_index = i; @@ -34,7 +35,9 @@ pub fn get_signer( } pub fn decode_signature(signature: String) -> anyhow::Result { - let decoded_sig = base64::engine::general_purpose::STANDARD.decode(&signature)?; + let decoded_sig = base64::engine::general_purpose::STANDARD + .decode(&signature) + .context("error to decode signature")?; Ok(PartialSignature::from_slice(&decoded_sig)?) } @@ -59,7 +62,9 @@ pub fn encode_nonce(signer_index: usize, nonce: PubNonce) -> anyhow::Result anyhow::Result { - let decoded_nonce = base64::engine::general_purpose::STANDARD.decode(&nonce_pair.nonce)?; + let decoded_nonce = base64::engine::general_purpose::STANDARD + .decode(&nonce_pair.nonce) + .context("error to encode nonde")?; let pub_nonce = PubNonce::from_bytes(&decoded_nonce)?; Ok(pub_nonce) } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 4ab34726a..49f5871d2 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,30 +1,32 @@ use std::{collections::HashMap, sync::Arc}; -use anyhow::Result; +use anyhow::{Context, Result}; use bitcoin::{hashes::Hash, TapSighashType, Witness}; use musig2::{CompactSignature, PartialSignature}; -use reqwest::{Client, StatusCode}; +use reqwest::{header, Client, StatusCode}; use tokio::sync::watch; use via_btc_client::{ traits::{BitcoinOps, Serializable}, withdrawal_builder::UnsignedWithdrawalTx, }; use via_musig2::{verify_signature, Signer}; -use zksync_config::configs::via_verifier::{VerifierRole, ViaVerifierConfig}; +use zksync_config::configs::via_verifier::{VerifierMode, ViaVerifierConfig}; use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_types::H256; use crate::{ - types::{NoncePair, SigningSessionResponse}, + types::{NoncePair, PartialSignaturePair, SigningSessionResponse}, utils::{decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer}, }; +#[derive(Debug)] pub struct ViaWithdrawalVerifier { master_connection_pool: ConnectionPool, btc_client: Arc, config: ViaVerifierConfig, client: Client, signer: Signer, + final_sig: Option, } impl ViaWithdrawalVerifier { @@ -44,6 +46,7 @@ impl ViaWithdrawalVerifier { signer, client: Client::new(), config, + final_sig: None, }) } @@ -71,12 +74,18 @@ impl ViaWithdrawalVerifier { } async fn loop_iteration(&mut self) -> Result<(), anyhow::Error> { - if self.config.role == VerifierRole::COORDINATOR { + if self.config.verifier_mode == VerifierMode::COORDINATOR { self.create_new_session().await?; + + tracing::info!("create a new session"); self.build_and_broadcast_final_transaction().await?; } let session_info = self.get_session().await?; + if session_info.l1_block_number == 0 { + tracing::info!("Empty session, nothing to process"); + return Ok(()); + } let session_signature = self.get_session_signatures().await?; let session_nonces = self.get_session_nonces().await?; @@ -118,7 +127,7 @@ impl ViaWithdrawalVerifier { } async fn get_session(&self) -> anyhow::Result { - let url = format!("{}/session/", self.config.url); + let url = format!("{}/session", self.config.url); let resp = self.client.get(&url).send().await?; if resp.status().as_u16() != StatusCode::OK.as_u16() { anyhow::bail!("Error to fetch the session"); @@ -129,7 +138,7 @@ impl ViaWithdrawalVerifier { async fn get_session_nonces(&self) -> anyhow::Result> { // We need to fetch all nonces from the coordinator - let nonces_url = format!("{}/session/nonce/", self.config.url); + let nonces_url = format!("{}/session/nonce", self.config.url); let resp = self.client.get(&nonces_url).send().await?; let nonces: HashMap = resp.json().await?; Ok(nonces) @@ -142,7 +151,7 @@ impl ViaWithdrawalVerifier { .ok_or_else(|| anyhow::anyhow!("No nonce available"))?; let nonce_pair = encode_nonce(self.signer.signer_index(), nonce).unwrap(); - let url = format!("{}/session/nonce/", self.config.url); + let url = format!("{}/session/nonce", self.config.url); let res = self.client.post(&url).json(&nonce_pair).send().await?; if res.status().is_success() { @@ -153,12 +162,12 @@ impl ViaWithdrawalVerifier { } async fn get_session_signatures(&self) -> anyhow::Result> { - let url = format!("{}/session/signature/", self.config.url); + let url = format!("{}/session/signature", self.config.url); let resp = self.client.get(&url).send().await?; - let signatures: HashMap = resp.json().await?; + let signatures: HashMap = resp.json().await?; let mut partial_sigs: HashMap = HashMap::new(); for (idx, sig) in signatures { - partial_sigs.insert(idx, decode_signature(sig).unwrap()); + partial_sigs.insert(idx, decode_signature(sig.signature).unwrap()); } Ok(partial_sigs) } @@ -183,7 +192,7 @@ impl ViaWithdrawalVerifier { let partial_sig = self.signer.create_partial_signature()?; let sig_pair = encode_signature(self.signer.signer_index(), partial_sig)?; - let url = format!("{}/session/signature/", self.config.url,); + let url = format!("{}/session/signature", self.config.url,); let resp = self.client.post(&url).json(&sig_pair).send().await?; if resp.status().is_success() { self.signer.mark_partial_sig_submitted(); @@ -197,29 +206,39 @@ impl ViaWithdrawalVerifier { self.config.verifiers_pub_keys_str.clone(), )?; self.signer = signer; + self.final_sig = None; Ok(()) } async fn create_new_session(&mut self) -> anyhow::Result<()> { let session_info = self.get_session().await?; if session_info.l1_block_number == 0 { - let url = format!("{}/session/new/", self.config.url,); - let resp = self.client.post(&url).send().await?; + let url = format!("{}/session/new", self.config.url,); + let resp = self + .client + .post(&url) + .header(header::CONTENT_TYPE, "application/json") + .send() + .await?; + + println!("{:?}", resp); if !resp.status().is_success() {} } Ok(()) } - async fn create_final_signature(&mut self) -> anyhow::Result> { + async fn create_final_signature(&mut self) -> anyhow::Result<()> { + if self.final_sig.is_some() { + return Ok(()); + } let session_info = self.get_session().await?; if session_info.received_partial_signatures >= session_info.required_signers { let signatures = self.get_session_signatures().await?; - if session_info.received_partial_signatures >= session_info.required_signers { - for (&i, sig) in &signatures { - if self.signer.signer_index() != i { - self.signer.receive_partial_signature(i, *sig)?; - } + for (&i, sig) in &signatures { + println!("1"); + if self.signer.signer_index() != i { + self.signer.receive_partial_signature(i, *sig)?; } } @@ -230,9 +249,11 @@ impl ViaWithdrawalVerifier { final_sig, &hex::decode(&session_info.message_to_sign)?, )?; - return Ok(Some(final_sig)); + self.final_sig = Some(final_sig); + + return Ok(()); } - Ok(None) + Ok(()) } fn sign_transaction( @@ -252,8 +273,11 @@ impl ViaWithdrawalVerifier { async fn build_and_broadcast_final_transaction(&mut self) -> anyhow::Result<()> { let session_info = self.get_session().await?; + self.create_final_signature() + .await + .context("Error create final signature")?; - if let Some(musig2_signature) = self.create_final_signature().await? { + if let Some(musig2_signature) = self.final_sig { let withdrawal_txid = self .master_connection_pool .connection_tagged("coordinator task") From 0a0537ebeff558f8f12cc5a195e200884ce54e13 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:04:15 +0100 Subject: [PATCH 101/212] clean: remove unused imports --- via_verifier/lib/via_withdrawal_client/src/client.rs | 1 - via_verifier/lib/via_withdrawal_client/src/types.rs | 9 --------- 2 files changed, 10 deletions(-) diff --git a/via_verifier/lib/via_withdrawal_client/src/client.rs b/via_verifier/lib/via_withdrawal_client/src/client.rs index 56b8915da..cdb8bc465 100644 --- a/via_verifier/lib/via_withdrawal_client/src/client.rs +++ b/via_verifier/lib/via_withdrawal_client/src/client.rs @@ -88,7 +88,6 @@ mod tests { use std::str::FromStr; use bitcoin::{Address, Amount}; - use zksync_types::U256; use super::*; diff --git a/via_verifier/lib/via_withdrawal_client/src/types.rs b/via_verifier/lib/via_withdrawal_client/src/types.rs index 44a8358c5..056572d2b 100644 --- a/via_verifier/lib/via_withdrawal_client/src/types.rs +++ b/via_verifier/lib/via_withdrawal_client/src/types.rs @@ -1,7 +1,6 @@ use std::io::Read; use anyhow::Context; -use bitcoin::{address::NetworkUnchecked, Address as BitcoinAddress}; use byteorder::{BigEndian, ReadBytesExt}; use zksync_types::{Address, H160, H256, U256}; use zksync_utils::{u256_to_bytes_be, u256_to_h256}; @@ -19,14 +18,6 @@ pub struct L2BridgeLogMetadata { pub message: Vec, } -#[derive(Clone, Debug)] -pub struct WithdrawalRequest { - /// The receiver l1 address. - pub address: BitcoinAddress, - /// The amount user will receive. - pub amount: U256, -} - /// Corresponds to the following solidity event: /// ```solidity /// struct L2ToL1Log { From ba7c5c42e0609bbf353045e39946655d12a0db9a Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 08:16:05 +0330 Subject: [PATCH 102/212] chore(via): switch from core dal to verifer dal in withdrawal service --- Cargo.lock | 2 +- .../20241209150000_create_via_votes.down.sql | 2 ++ .../20241209150000_create_via_votes.up.sql | 24 +++++++++++++++++++ .../lib/verifier_dal/src/migrations.rs | 16 +++++++++++++ .../node/withdrawal_service/Cargo.toml | 2 +- .../withdrawal_service/src/coordinator/api.rs | 2 +- .../src/coordinator/api_decl.rs | 2 +- .../src/coordinator/api_impl.rs | 2 +- .../withdrawal_service/src/verifier/mod.rs | 2 +- 9 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql create mode 100644 via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql create mode 100644 via_verifier/lib/verifier_dal/src/migrations.rs diff --git a/Cargo.lock b/Cargo.lock index 9aa4cf7a0..d465a9d36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9769,10 +9769,10 @@ dependencies = [ "uuid 1.10.0", "via_btc_client", "via_musig2", + "via_verifier_dal", "via_withdrawal_client", "vise", "zksync_config", - "zksync_dal", "zksync_types", ] diff --git a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql b/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql new file mode 100644 index 000000000..5c0924943 --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS via_votes; +DROP TABLE IF EXISTS via_votable_transactions; \ No newline at end of file diff --git a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql b/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql new file mode 100644 index 000000000..c51a373cd --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql @@ -0,0 +1,24 @@ +CREATE TABLE IF NOT EXISTS via_votable_transactions ( + l1_batch_number BIGINT UNIQUE NOT NULL, + tx_id BYTEA, + da_identifier VARCHAR NOT NULL, + blob_id VARCHAR NOT NULL, + proof_tx_id VARCHAR NOT NULL, + withdrawal_tx_id BYTEA, + is_finalized BOOLEAN NOT NULL DEFAULT FALSE, + is_verified BOOLEAN NOT NULL DEFAULT FALSE, + l1_batch_status BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (l1_batch_number, tx_id) +); + +CREATE TABLE IF NOT EXISTS via_votes ( + l1_batch_number BIGINT NOT NULL, + tx_id BYTEA NOT NULL, + verifier_address TEXT NOT NULL, + vote BOOLEAN NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (l1_batch_number, tx_id, verifier_address), + FOREIGN KEY (l1_batch_number, tx_id) REFERENCES via_votable_transactions (l1_batch_number, tx_id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/via_verifier/lib/verifier_dal/src/migrations.rs b/via_verifier/lib/verifier_dal/src/migrations.rs new file mode 100644 index 000000000..67eb15e38 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/migrations.rs @@ -0,0 +1,16 @@ +use anyhow::Context; +use sqlx::{migrate::Migrator, PgPool}; +use std::path::Path; + +/// Runs migrations for the verifier database. +pub async fn migrate(pool: &PgPool) -> anyhow::Result<()> { + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("migrations"); + let migrator = Migrator::new(path) + .await + .context("Failed to create migrator")?; + migrator + .run(pool) + .await + .context("Failed to run migrations")?; + Ok(()) +} \ No newline at end of file diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index 7a5a0d9c5..d6e8b492d 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Via Network"] hex.workspace = true uuid = { version = "1.3", features = ["v4"] } zksync_config.workspace = true -zksync_dal.workspace = true +via_verifier_dal.workspace=true zksync_types.workspace = true vise.workspace = true via_btc_client.workspace = true diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api.rs b/via_verifier/node/withdrawal_service/src/coordinator/api.rs index e67c6615e..503d4aaf1 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api.rs @@ -1,9 +1,9 @@ use anyhow::Context as _; use tokio::sync::watch; use via_btc_client::withdrawal_builder::WithdrawalBuilder; +use via_verifier_dal::{ConnectionPool, Core}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::ViaVerifierConfig; -use zksync_dal::{ConnectionPool, Core}; use crate::coordinator::api_decl::RestApi; diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs index 9cafa3b84..004f20e8f 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use tokio::sync::RwLock; use tower_http::cors::CorsLayer; use via_btc_client::withdrawal_builder::WithdrawalBuilder; +use via_verifier_dal::{ConnectionPool, Core}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::ViaVerifierConfig; -use zksync_dal::{ConnectionPool, Core}; use crate::types::{SigningSession, ViaWithdrawalState}; diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 6adc96062..ca41139ca 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -8,7 +8,7 @@ use musig2::{BinaryEncoding, PubNonce}; use serde::Serialize; use tracing::instrument; use via_btc_client::{traits::Serializable, withdrawal_builder::WithdrawalRequest}; -use zksync_dal::CoreDal; +use via_verifier_dal::CoreDal; use zksync_types::H256; use super::api_decl::RestApi; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index bc95d05de..a2ce06504 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -10,8 +10,8 @@ use via_btc_client::{ withdrawal_builder::UnsignedWithdrawalTx, }; use via_musig2::{verify_signature, Signer}; +use via_verifier_dal::{ConnectionPool, Core, CoreDal}; use zksync_config::configs::via_verifier::{VerifierRole, ViaVerifierConfig}; -use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_types::H256; use crate::{ From c00873afb934d1c18622572d328065f5ab4d9a00 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 08:26:14 +0330 Subject: [PATCH 103/212] chore(via): add verifier pools layer --- .../src/implementations/layers/mod.rs | 1 + .../layers/verifier_pools_layer.rs | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index a94aab2f5..01bfa4082 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -42,6 +42,7 @@ pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; // TODO: TMP in sequencer +pub mod verifier_pools_layer; pub mod via_verifier; pub mod via_zk_verification; pub mod vm_runner; diff --git a/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs b/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs new file mode 100644 index 000000000..c426d1cbb --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs @@ -0,0 +1,33 @@ +use std::sync::Arc; + +use sqlx::PgPool; +use verifier_dal::Connection; + +use crate::implementations::layers::Layer; + +pub struct VerifierPoolsLayer { + pub pool: Arc, +} + +impl VerifierPoolsLayer { + pub fn new(pool: PgPool) -> Self { + Self { + pool: Arc::new(pool), + } + } + + pub async fn access_storage<'a, F, Ret>(&self, callback: F) -> Ret + where + F: FnOnce(&mut Connection<'_>) -> Ret, + { + let mut conn = self.pool.acquire().await.unwrap(); + let mut storage = Connection::new(&mut conn); + callback(&mut storage) + } +} + +impl Layer for VerifierPoolsLayer { + fn layer_name(&self) -> &'static str { + "verifier_pools" + } +} From de9ddff634549cb81ea90ce328bb852db35293ce Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 08:27:06 +0330 Subject: [PATCH 104/212] chore(via): add verifier pools layer --- core/node/node_framework/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index efecbf779..e3ffc187a 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -65,6 +65,7 @@ via_da_dispatcher.workspace = true via_state_keeper.workspace = true via_withdrawal_service.workspace = true via_withdrawal_client.workspace = true +via_verifier_dal.workspace = true pin-project-lite.workspace = true tracing.workspace = true thiserror.workspace = true From 64bd7cc33df6830a3a00a27ee761f07aeb47d618 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 09:28:31 +0330 Subject: [PATCH 105/212] feat(via): add migrations, via vote dal and fix error in node_framework for verfier dal --- ...93c3a0a389b0c96da70be09697d71874f49f4.json | 15 + ...70265a6fe24abd28e629dd2fa1f9c400c29d9.json | 18 + ...0073159cb97bf34ebf2740e3f40b863515cce.json | 29 ++ ...6e1dcef9dd65f5751547525cc9b0839836da5.json | 26 ++ ...a3cdd314652a88cd6009a9fca9358b6aa4e59.json | 20 + ...7b9c39534c83e3738db90e7111345df0281a2.json | 22 ++ ...d8690e72af5ae37d0059be1fa43a432ec1375.json | 28 ++ ...f6d91830eac4268a83112781a6d9c521c5be9.json | 15 + ...970ac92a60580e047d5a43b77e56ab5f3d2b4.json | 23 ++ ...510b32864e18832c7f6d4bd54c14783f54cca.json | 17 + ...a074871ce49f2c81be801c233032ec1d046ba.json | 32 ++ ...86ffccdb4ea2a1495525fe76be9c1e77580c9.json | 20 + ...703fbb5f734284c380b316be30fd38aac8675.json | 16 + via_verifier/lib/verifier_dal/Cargo.toml | 2 + .../20241209150000_create_via_votes.down.sql | 2 - ...0250112053854_create_via_votes.up.down.sql | 2 + ...20250112053854_create_via_votes.up.up.sql} | 3 +- via_verifier/lib/verifier_dal/src/lib.rs | 34 +- .../lib/verifier_dal/src/tests/mod.rs | 20 + .../lib/verifier_dal/src/via_votes_dal.rs | 360 ++++++++++++++++++ 20 files changed, 693 insertions(+), 11 deletions(-) create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json delete mode 100644 via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql create mode 100644 via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.down.sql rename via_verifier/lib/verifier_dal/migrations/{20241209150000_create_via_votes.up.sql => 20250112053854_create_via_votes.up.up.sql} (99%) create mode 100644 via_verifier/lib/verifier_dal/src/tests/mod.rs create mode 100644 via_verifier/lib/verifier_dal/src/via_votes_dal.rs diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json b/via_verifier/lib/verifier_dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json new file mode 100644 index 000000000..1a6e3e10c --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n withdrawal_tx_id = $1\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n AND l1_batch_number = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "32a1a262d383bab472b28dedbde93c3a0a389b0c96da70be09697d71874f49f4" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json b/via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json new file mode 100644 index 000000000..472334232 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Varchar", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json b/via_verifier/lib/verifier_dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json new file mode 100644 index 000000000..2dedade5f --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(*) FILTER (\n WHERE\n vote = TRUE\n ) AS ok_votes,\n COUNT(*) AS total_votes\n FROM\n via_votes\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "ok_votes", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "total_votes", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "42d4dac4050c296b9f1804dcf6b0073159cb97bf34ebf2740e3f40b863515cce" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json b/via_verifier/lib/verifier_dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json new file mode 100644 index 000000000..6e898fb47 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_verified = FALSE\n ORDER BY\n l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false + ] + }, + "hash": "6851a0c44cca95d6f0f21dddc056e1dcef9dd65f5751547525cc9b0839836da5" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json b/via_verifier/lib/verifier_dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json new file mode 100644 index 000000000..414285372 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(l1_batch_number) as \"l1_batch_number\"\n FROM via_votable_transactions\n WHERE\n is_finalized = FALSE \n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "81fbd3f476db005b3260f6600aea3cdd314652a88cd6009a9fca9358b6aa4e59" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json b/via_verifier/lib/verifier_dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json new file mode 100644 index 000000000..4ed034e04 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n withdrawal_tx_id\n FROM via_votable_transactions\n WHERE\n l1_batch_number = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "withdrawal_tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + true + ] + }, + "hash": "8958c9555cb62efc73eccc2215d7b9c39534c83e3738db90e7111345df0281a2" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json b/via_verifier/lib/verifier_dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json new file mode 100644 index 000000000..963590678 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_status,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n l1_batch_number = $1\n AND is_verified = TRUE\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_status", + "type_info": "Bool" + }, + { + "ordinal": 1, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "9c5faf8349565e8eedb040d4a72d8690e72af5ae37d0059be1fa43a432ec1375" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json b/via_verifier/lib/verifier_dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json new file mode 100644 index 000000000..5a7d4a2de --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n is_finalized = TRUE,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "ad6d50d69c52bacd18be392d583f6d91830eac4268a83112781a6d9c521c5be9" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json b/via_verifier/lib/verifier_dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json new file mode 100644 index 000000000..7fff300d2 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n is_finalized\n FROM\n via_votable_transactions\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_finalized", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int8", + "Bytea" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c00edea696d125effe23b50c656970ac92a60580e047d5a43b77e56ab5f3d2b4" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json b/via_verifier/lib/verifier_dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json new file mode 100644 index 000000000..9133c893a --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votes (l1_batch_number, tx_id, verifier_address, vote)\n VALUES\n ($1, $2, $3, $4)\n ON CONFLICT (l1_batch_number, tx_id, verifier_address) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "d574f696c92de6af8a597071dad510b32864e18832c7f6d4bd54c14783f54cca" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json b/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json new file mode 100644 index 000000000..3e41688ab --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n blob_id,\n proof_tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n ORDER BY\n l1_batch_number ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "blob_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "proof_tx_id", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json b/via_verifier/lib/verifier_dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json new file mode 100644 index 000000000..c1fda0d3d --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MAX(l1_batch_number) AS max_batch_number\n FROM\n via_votable_transactions\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "eb4413d3d75a4a014f741d6f23486ffccdb4ea2a1495525fe76be9c1e77580c9" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json b/via_verifier/lib/verifier_dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json new file mode 100644 index 000000000..1f2be9fbe --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_votable_transactions\n SET\n is_verified = TRUE,\n l1_batch_status = $3,\n updated_at = NOW()\n WHERE\n l1_batch_number = $1\n AND tx_id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "f9bb84f6a995fd6590f96491066703fbb5f734284c380b316be30fd38aac8675" +} diff --git a/via_verifier/lib/verifier_dal/Cargo.toml b/via_verifier/lib/verifier_dal/Cargo.toml index 882a58277..9df6f97fe 100644 --- a/via_verifier/lib/verifier_dal/Cargo.toml +++ b/via_verifier/lib/verifier_dal/Cargo.toml @@ -13,6 +13,8 @@ categories.workspace = true [dependencies] zksync_db_connection.workspace = true zksync_basic_types.workspace = true +zksync_types.workspace = true +thiserror.workspace = true strum = { workspace = true, features = ["derive"] } sqlx = { workspace = true, features = [ diff --git a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql b/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql deleted file mode 100644 index 5c0924943..000000000 --- a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS via_votes; -DROP TABLE IF EXISTS via_votable_transactions; \ No newline at end of file diff --git a/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.down.sql b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.down.sql new file mode 100644 index 000000000..9bce83ce9 --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS via_votes; +DROP TABLE IF EXISTS via_votable_transactions; diff --git a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql similarity index 99% rename from via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql rename to via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql index c51a373cd..1fdfa1484 100644 --- a/via_verifier/lib/verifier_dal/migrations/20241209150000_create_via_votes.up.sql +++ b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql @@ -21,4 +21,5 @@ CREATE TABLE IF NOT EXISTS via_votes ( created_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (l1_batch_number, tx_id, verifier_address), FOREIGN KEY (l1_batch_number, tx_id) REFERENCES via_votable_transactions (l1_batch_number, tx_id) ON DELETE CASCADE -); \ No newline at end of file +); + diff --git a/via_verifier/lib/verifier_dal/src/lib.rs b/via_verifier/lib/verifier_dal/src/lib.rs index 543eef537..39af27f50 100644 --- a/via_verifier/lib/verifier_dal/src/lib.rs +++ b/via_verifier/lib/verifier_dal/src/lib.rs @@ -1,10 +1,23 @@ +//! Data access layer (DAL) for ZKsync Era. + +// Linter settings. +#![warn(clippy::cast_lossless)] + +pub use sqlx::{types::BigDecimal, Error as SqlxError}; use zksync_db_connection::connection::DbMarker; pub use zksync_db_connection::{ - connection::Connection, - connection_pool::ConnectionPool, - utils::{duration_to_naive_time, pg_interval_from_duration}, + connection::{Connection, IsolationLevel}, + connection_pool::{ConnectionPool, ConnectionPoolBuilder}, + error::{DalError, DalResult}, }; +use crate::via_votes_dal::ViaVotesDal; + +pub mod via_votes_dal; + +#[cfg(test)] +mod tests; + // This module is private and serves as a way to seal the trait. mod private { pub trait Sealed {} @@ -12,18 +25,23 @@ mod private { // Here we are making the trait sealed, because it should be public to function correctly, but we don't // want to allow any other downstream implementations of this trait. -pub trait CoreDal<'a>: private::Sealed +pub trait VerifierDal<'a>: private::Sealed where Self: 'a, { + fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a>; } #[derive(Clone, Debug)] -pub struct Core; +pub struct Verifier; // Implement the marker trait for the Core to be able to use it in Connection. -impl DbMarker for Core {} +impl DbMarker for Verifier {} // Implement the sealed trait for the struct itself. -impl private::Sealed for Connection<'_, Core> {} +impl private::Sealed for Connection<'_, Verifier> {} -impl<'a> CoreDal<'a> for Connection<'a, Core> {} +impl<'a> VerifierDal<'a> for Connection<'a, Verifier> { + fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a> { + ViaVotesDal { storage: self } + } +} diff --git a/via_verifier/lib/verifier_dal/src/tests/mod.rs b/via_verifier/lib/verifier_dal/src/tests/mod.rs new file mode 100644 index 000000000..b9fbb6599 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/tests/mod.rs @@ -0,0 +1,20 @@ +use std::time::Duration; + +use zksync_db_connection::connection_pool::ConnectionPool; +use zksync_types::{ + block::{L1BatchHeader, L2BlockHasher, L2BlockHeader}, + fee::Fee, + fee_model::BatchFeeInput, + helpers::unix_timestamp_ms, + l1::{L1Tx, OpProcessingType, PriorityQueueType}, + l2::L2Tx, + l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, + protocol_upgrade::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, + snapshots::SnapshotRecoveryStatus, + Address, Execute, K256PrivateKey, L1BatchNumber, L1BlockNumber, L1TxCommonData, L2BlockNumber, + L2ChainId, PriorityOpId, ProtocolVersion, ProtocolVersionId, H160, H256, U256, +}; + +use crate::Verifier; + +// TODO: Add tests here diff --git a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs new file mode 100644 index 000000000..251c31a03 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs @@ -0,0 +1,360 @@ +use zksync_db_connection::{connection::Connection, error::DalResult, instrument::InstrumentExt}; +use zksync_types::H256; + +use crate::Verifier; + +pub struct ViaVotesDal<'c, 'a> { + pub(crate) storage: &'c mut Connection<'a, Verifier>, +} + +impl ViaVotesDal<'_, '_> { + /// Inserts a new row in `via_votable_transactions`. + /// Notice we haven’t changed this since the PK is still (l1_batch_number, tx_id). + pub async fn insert_votable_transaction( + &mut self, + l1_batch_number: u32, + tx_id: H256, + da_identifier: String, + blob_id: String, + proof_tx_id: String, + ) -> DalResult<()> { + sqlx::query!( + r#" + INSERT INTO + via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id) + VALUES + ($1, $2, $3, $4, $5) + ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING + "#, + i64::from(l1_batch_number), + tx_id.as_bytes(), + da_identifier, + blob_id, + proof_tx_id + ) + .instrument("insert_votable_transaction") + .fetch_optional(self.storage) + .await?; + + Ok(()) + } + + /// Inserts a new vote row in `via_votes`. + /// Now requires `l1_batch_number` as part of the primary key / FK. + pub async fn insert_vote( + &mut self, + l1_batch_number: u32, + tx_id: H256, + verifier_address: &str, + vote: bool, + ) -> DalResult<()> { + sqlx::query!( + r#" + INSERT INTO + via_votes (l1_batch_number, tx_id, verifier_address, vote) + VALUES + ($1, $2, $3, $4) + ON CONFLICT (l1_batch_number, tx_id, verifier_address) DO NOTHING + "#, + l1_batch_number as i32, + tx_id.as_bytes(), + verifier_address, + vote + ) + .instrument("insert_vote") + .fetch_optional(self.storage) + .await?; + + Ok(()) + } + + /// Returns (ok_votes, total_votes) for the given `(l1_batch_number, tx_id)`. + /// Must also filter on `l1_batch_number`. + pub async fn get_vote_count( + &mut self, + l1_batch_number: u32, + tx_id: H256, + ) -> DalResult<(i64, i64)> { + let row = sqlx::query!( + r#" + SELECT + COUNT(*) FILTER ( + WHERE + vote = TRUE + ) AS ok_votes, + COUNT(*) AS total_votes + FROM + via_votes + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + l1_batch_number as i32, + tx_id.as_bytes() + ) + .instrument("get_vote_count") + .fetch_one(self.storage) + .await?; + + let ok_votes = row.ok_votes.unwrap_or(0); + let total_votes = row.total_votes.unwrap_or(0); + Ok((ok_votes, total_votes)) + } + + /// Marks the transaction as finalized if #ok_votes / #total_votes >= threshold. + /// Must use `(l1_batch_number, tx_id)` in both vote counting and the UPDATE statement. + pub async fn finalize_transaction_if_needed( + &mut self, + l1_batch_number: u32, + tx_id: H256, + threshold: f64, + number_of_verifiers: usize, + ) -> DalResult { + let row = sqlx::query!( + r#" + SELECT + is_finalized + FROM + via_votable_transactions + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + i64::from(l1_batch_number), + tx_id.as_bytes() + ) + .instrument("check_if_already_finalized") + .fetch_one(self.storage) + .await?; + + if row.is_finalized { + return Ok(false); + } + + let (ok_votes, _total_votes) = self.get_vote_count(l1_batch_number, tx_id).await?; + let is_threshold_reached = (ok_votes as f64) / (number_of_verifiers as f64) >= threshold; + + if is_threshold_reached { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + is_finalized = TRUE, + updated_at = NOW() + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + i64::from(l1_batch_number), + tx_id.as_bytes() + ) + .instrument("finalize_transaction_if_needed") + .execute(self.storage) + .await?; + } + + Ok(is_threshold_reached) + } + + pub async fn get_last_inserted_block(&mut self) -> DalResult> { + let row = sqlx::query!( + r#" + SELECT + MAX(l1_batch_number) AS max_batch_number + FROM + via_votable_transactions + "# + ) + .instrument("get_last_inserted_block") + .fetch_one(self.storage) + .await?; + + Ok(row.max_batch_number.map(|n| n as u32)) + } + + pub async fn verify_votable_transaction( + &mut self, + l1_batch_number: u32, + tx_id: H256, + l1_batch_status: bool, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + is_verified = TRUE, + l1_batch_status = $3, + updated_at = NOW() + WHERE + l1_batch_number = $1 + AND tx_id = $2 + "#, + i64::from(l1_batch_number), + tx_id.as_bytes(), + l1_batch_status + ) + .instrument("verify_transaction") + .execute(self.storage) + .await?; + Ok(()) + } + + pub async fn get_first_non_finalized_block(&mut self) -> DalResult> { + let l1_block_number = sqlx::query_scalar!( + r#" + SELECT + MIN(l1_batch_number) as "l1_batch_number" + FROM via_votable_transactions + WHERE + is_finalized = FALSE + "#, + ) + .instrument("get_last_block_finilized") + .fetch_optional(self.storage) + .await? + .flatten(); + + Ok(l1_block_number) + } + + pub async fn get_verifier_vote_status( + &mut self, + block_number: i64, + ) -> DalResult)>> { + let row = sqlx::query!( + r#" + SELECT + l1_batch_status, + tx_id + FROM + via_votable_transactions + WHERE + l1_batch_number = $1 + AND is_verified = TRUE + LIMIT + 1 + "#, + block_number + ) + .instrument("get_verifier_vote_status") + .fetch_optional(self.storage) + .await?; + + let result = row.map(|r| { + let l1_batch_status = r.l1_batch_status; + let tx_id = r.tx_id; + (l1_batch_status, tx_id) + }); + + Ok(result) + } + + /// Retrieve the first not executed block. (Similar to `get_first_not_finilized_block`, just with `is_verified = FALSE`). + pub async fn get_first_not_verified_block(&mut self) -> DalResult)>> { + let row = sqlx::query!( + r#" + SELECT + l1_batch_number, + tx_id + FROM + via_votable_transactions + WHERE + is_verified = FALSE + ORDER BY + l1_batch_number ASC + LIMIT + 1 + "#, + ) + .instrument("get_first_not_executed_block") + .fetch_optional(self.storage) + .await?; + + let result = row.map(|r| { + let l1_batch_number = r.l1_batch_number; + let tx_id = r.tx_id; + (l1_batch_number, tx_id) + }); + + Ok(result) + } + pub async fn get_finalized_blocks_and_non_processed_withdrawals( + &mut self, + ) -> DalResult> { + let rows = sqlx::query!( + r#" + SELECT + l1_batch_number, + blob_id, + proof_tx_id + FROM + via_votable_transactions + WHERE + is_finalized = TRUE + AND is_verified = TRUE + AND withdrawal_tx_id IS NULL + ORDER BY + l1_batch_number ASC + "#, + ) + .instrument("get_finalized_blocks_and_non_processed_withdrawals") + .fetch_all(self.storage) + .await?; + + // Map the rows into a Vec<(l1_batch_number, blob_id, proof_tx_id)> + let result: Vec<(i64, String, String)> = rows + .into_iter() + .map(|r| (r.l1_batch_number, r.blob_id, r.proof_tx_id)) + .collect(); + + Ok(result) + } + + pub async fn mark_vote_transaction_as_processed_withdrawals( + &mut self, + tx_id: H256, + l1_batch_number: i64, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_votable_transactions + SET + withdrawal_tx_id = $1 + WHERE + is_finalized = TRUE + AND is_verified = TRUE + AND withdrawal_tx_id IS NULL + AND l1_batch_number = $2 + "#, + tx_id.as_bytes(), + l1_batch_number + ) + .instrument("mark_vote_transaction_as_processed_withdrawals") + .execute(self.storage) + .await?; + + Ok(()) + } + + pub async fn get_vote_transaction_withdrawal_tx( + &mut self, + l1_batch_number: i64, + ) -> DalResult>> { + let withdrawal_tx_id = sqlx::query_scalar!( + r#" + SELECT + withdrawal_tx_id + FROM via_votable_transactions + WHERE + l1_batch_number = $1 + "#, + l1_batch_number + ) + .instrument("get_vote_transaction_withdrawal_tx") + .fetch_optional(self.storage) + .await? + .flatten(); + + Ok(withdrawal_tx_id) + } +} From 529ac291d341647269ee46631b9bfb2a5269d4d2 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 09:28:51 +0330 Subject: [PATCH 106/212] feat(via): add migrations, via vote dal and fix error in node_framework for verfier dal --- Cargo.lock | 3 + .../layers/verifier_pools_layer.rs | 162 ++++++++++++++++-- .../layers/via_verifier/coordinator_api.rs | 8 +- .../layers/via_verifier/verifier.rs | 4 +- .../src/implementations/resources/pools.rs | 13 ++ .../withdrawal_service/src/coordinator/api.rs | 4 +- .../src/coordinator/api_decl.rs | 6 +- .../src/coordinator/api_impl.rs | 2 +- .../withdrawal_service/src/verifier/mod.rs | 12 +- 9 files changed, 176 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d465a9d36..5dd9916f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9722,8 +9722,10 @@ version = "0.1.0" dependencies = [ "sqlx", "strum 0.26.3", + "thiserror", "zksync_basic_types", "zksync_db_connection", + "zksync_types", ] [[package]] @@ -11796,6 +11798,7 @@ dependencies = [ "via_da_dispatcher", "via_fee_model", "via_state_keeper", + "via_verifier_dal", "via_withdrawal_client", "via_withdrawal_service", "zksync_base_token_adjuster", diff --git a/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs b/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs index c426d1cbb..734f6f0cc 100644 --- a/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs +++ b/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs @@ -1,33 +1,157 @@ -use std::sync::Arc; +use zksync_config::configs::{DatabaseSecrets, PostgresConfig}; +use zksync_dal::{ConnectionPool, Core}; -use sqlx::PgPool; -use verifier_dal::Connection; +use crate::{ + implementations::resources::pools::{MasterPool, PoolResource, ProverPool, ReplicaPool}, + wiring_layer::{WiringError, WiringLayer}, + IntoContext, +}; -use crate::implementations::layers::Layer; - -pub struct VerifierPoolsLayer { - pub pool: Arc, +/// Builder for the [`PoolsLayer`]. +#[derive(Debug)] +pub struct PoolsLayerBuilder { + config: PostgresConfig, + with_master: bool, + with_replica: bool, + with_prover: bool, + secrets: DatabaseSecrets, } -impl VerifierPoolsLayer { - pub fn new(pool: PgPool) -> Self { +impl PoolsLayerBuilder { + /// Creates a new builder with the provided configuration and secrets. + /// By default, no pulls are enabled. + pub fn empty(config: PostgresConfig, database_secrets: DatabaseSecrets) -> Self { Self { - pool: Arc::new(pool), + config, + with_master: false, + with_replica: false, + with_prover: false, + secrets: database_secrets, } } - pub async fn access_storage<'a, F, Ret>(&self, callback: F) -> Ret - where - F: FnOnce(&mut Connection<'_>) -> Ret, - { - let mut conn = self.pool.acquire().await.unwrap(); - let mut storage = Connection::new(&mut conn); - callback(&mut storage) + /// Allows to enable the master pool. + pub fn with_master(mut self, with_master: bool) -> Self { + self.with_master = with_master; + self + } + + /// Allows to enable the replica pool. + pub fn with_replica(mut self, with_replica: bool) -> Self { + self.with_replica = with_replica; + self + } + + /// Allows to enable the prover pool. + pub fn with_prover(mut self, with_prover: bool) -> Self { + self.with_prover = with_prover; + self + } + + /// Builds the [`PoolsLayer`] with the provided configuration. + pub fn build(self) -> PoolsLayer { + PoolsLayer { + config: self.config, + secrets: self.secrets, + with_master: self.with_master, + with_replica: self.with_replica, + with_prover: self.with_prover, + } } } -impl Layer for VerifierPoolsLayer { +/// Wiring layer for connection pools. +/// During wiring, also prepares the global configuration for the connection pools. +/// +/// ## Adds resources +/// +/// - `PoolResource::` (if master pool is enabled) +/// - `PoolResource::` (if replica pool is enabled) +/// - `PoolResource::` (if prover pool is enabled) +#[derive(Debug)] +pub struct PoolsLayer { + config: PostgresConfig, + secrets: DatabaseSecrets, + with_master: bool, + with_replica: bool, + with_prover: bool, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + pub master_pool: Option>, + pub replica_pool: Option>, + pub prover_pool: Option>, +} + +#[async_trait::async_trait] +impl WiringLayer for PoolsLayer { + type Input = (); + type Output = Output; + fn layer_name(&self) -> &'static str { - "verifier_pools" + "pools_layer" + } + + async fn wire(self, _input: Self::Input) -> Result { + if !self.with_master && !self.with_replica && !self.with_prover { + return Err(WiringError::Configuration( + "At least one pool should be enabled".to_string(), + )); + } + + if self.with_master || self.with_replica { + if let Some(threshold) = self.config.slow_query_threshold() { + ConnectionPool::::global_config().set_slow_query_threshold(threshold)?; + } + if let Some(threshold) = self.config.long_connection_threshold() { + ConnectionPool::::global_config().set_long_connection_threshold(threshold)?; + } + } + + let master_pool = if self.with_master { + let pool_size = self.config.max_connections()?; + let pool_size_master = self.config.max_connections_master().unwrap_or(pool_size); + + Some(PoolResource::::new( + self.secrets.master_url()?, + pool_size_master, + None, + None, + )) + } else { + None + }; + + let replica_pool = if self.with_replica { + // We're most interested in setting acquire / statement timeouts for the API server, which puts the most load + // on Postgres. + Some(PoolResource::::new( + self.secrets.replica_url()?, + self.config.max_connections()?, + self.config.statement_timeout(), + self.config.acquire_timeout(), + )) + } else { + None + }; + + let prover_pool = if self.with_prover { + Some(PoolResource::::new( + self.secrets.prover_url()?, + self.config.max_connections()?, + None, + None, + )) + } else { + None + }; + + Ok(Output { + master_pool, + replica_pool, + prover_pool, + }) } } diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs b/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs index ce73bedcc..0044b6700 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier/coordinator_api.rs @@ -6,14 +6,14 @@ use via_btc_client::{ withdrawal_builder::WithdrawalBuilder, }; use via_btc_watch::BitcoinNetwork; +use via_verifier_dal::{ConnectionPool, Verifier}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::{ViaBtcSenderConfig, ViaVerifierConfig}; -use zksync_dal::{ConnectionPool, Core}; use crate::{ implementations::resources::{ da_client::DAClientResource, - pools::{MasterPool, PoolResource}, + pools::{PoolResource, VerifierPool}, }, service::StopReceiver, task::{Task, TaskId}, @@ -31,7 +31,7 @@ pub struct ViaCoordinatorApiLayer { #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { - pub master_pool: PoolResource, + pub master_pool: PoolResource, pub client: DAClientResource, } @@ -85,7 +85,7 @@ impl WiringLayer for ViaCoordinatorApiLayer { #[derive(Debug)] pub struct ViaCoordinatorApiTask { - master_pool: ConnectionPool, + master_pool: ConnectionPool, config: ViaVerifierConfig, withdrawal_builder: WithdrawalBuilder, withdrawal_client: WithdrawalClient, diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs index 743f3fc53..111cecbff 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs @@ -7,7 +7,7 @@ use via_withdrawal_service::verifier::ViaWithdrawalVerifier; use zksync_config::{ViaBtcSenderConfig, ViaVerifierConfig}; use crate::{ - implementations::resources::pools::{MasterPool, PoolResource}, + implementations::resources::pools::{PoolResource, VerifierPool}, service::StopReceiver, task::{Task, TaskId}, wiring_layer::{WiringError, WiringLayer}, @@ -24,7 +24,7 @@ pub struct ViaWithdrawalVerifierLayer { #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { - pub master_pool: PoolResource, + pub master_pool: PoolResource, } #[derive(IntoContext)] diff --git a/core/node/node_framework/src/implementations/resources/pools.rs b/core/node/node_framework/src/implementations/resources/pools.rs index 8355bb1bd..0e6176f68 100644 --- a/core/node/node_framework/src/implementations/resources/pools.rs +++ b/core/node/node_framework/src/implementations/resources/pools.rs @@ -7,6 +7,7 @@ use std::{ }; use tokio::sync::Mutex; +use via_verifier_dal::Verifier; use zksync_dal::{ConnectionPool, Core}; use zksync_db_connection::connection_pool::ConnectionPoolBuilder; use zksync_prover_dal::Prover; @@ -113,6 +114,10 @@ pub struct ReplicaPool {} #[non_exhaustive] pub struct ProverPool {} +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct VerifierPool {} + pub trait PoolKind: Clone + Sync + Send + 'static { type DbMarker: zksync_db_connection::connection::DbMarker; @@ -142,3 +147,11 @@ impl PoolKind for ProverPool { "prover" } } + +impl PoolKind for VerifierPool { + type DbMarker = Verifier; + + fn kind_str() -> &'static str { + "verifier" + } +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api.rs b/via_verifier/node/withdrawal_service/src/coordinator/api.rs index 503d4aaf1..9eaec8b7f 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api.rs @@ -1,7 +1,7 @@ use anyhow::Context as _; use tokio::sync::watch; use via_btc_client::withdrawal_builder::WithdrawalBuilder; -use via_verifier_dal::{ConnectionPool, Core}; +use via_verifier_dal::{ConnectionPool, Verifier}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::ViaVerifierConfig; @@ -9,7 +9,7 @@ use crate::coordinator::api_decl::RestApi; pub async fn start_coordinator_server( config: ViaVerifierConfig, - master_connection_pool: ConnectionPool, + master_connection_pool: ConnectionPool, withdrawal_builder: WithdrawalBuilder, withdrawal_client: WithdrawalClient, mut stop_receiver: watch::Receiver, diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs index 004f20e8f..f84aa8296 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -3,14 +3,14 @@ use std::sync::Arc; use tokio::sync::RwLock; use tower_http::cors::CorsLayer; use via_btc_client::withdrawal_builder::WithdrawalBuilder; -use via_verifier_dal::{ConnectionPool, Core}; +use via_verifier_dal::{ConnectionPool, Verifier}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::ViaVerifierConfig; use crate::types::{SigningSession, ViaWithdrawalState}; pub struct RestApi { - pub master_connection_pool: ConnectionPool, + pub master_connection_pool: ConnectionPool, pub state: ViaWithdrawalState, pub withdrawal_builder: WithdrawalBuilder, pub withdrawal_client: WithdrawalClient, @@ -19,7 +19,7 @@ pub struct RestApi { impl RestApi { pub fn new( config: ViaVerifierConfig, - master_connection_pool: ConnectionPool, + master_connection_pool: ConnectionPool, withdrawal_builder: WithdrawalBuilder, withdrawal_client: WithdrawalClient, ) -> anyhow::Result { diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index ca41139ca..69e8f97a4 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -8,7 +8,7 @@ use musig2::{BinaryEncoding, PubNonce}; use serde::Serialize; use tracing::instrument; use via_btc_client::{traits::Serializable, withdrawal_builder::WithdrawalRequest}; -use via_verifier_dal::CoreDal; +use via_verifier_dal::VerifierDal; use zksync_types::H256; use super::api_decl::RestApi; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index a2ce06504..f35d4430b 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -10,7 +10,7 @@ use via_btc_client::{ withdrawal_builder::UnsignedWithdrawalTx, }; use via_musig2::{verify_signature, Signer}; -use via_verifier_dal::{ConnectionPool, Core, CoreDal}; +use via_verifier_dal::{ConnectionPool, Verifier, VerifierDal}; use zksync_config::configs::via_verifier::{VerifierRole, ViaVerifierConfig}; use zksync_types::H256; @@ -20,7 +20,7 @@ use crate::{ }; pub struct ViaWithdrawalVerifier { - master_connection_pool: ConnectionPool, + master_connection_pool: ConnectionPool, btc_client: Arc, config: ViaVerifierConfig, client: Client, @@ -29,7 +29,7 @@ pub struct ViaWithdrawalVerifier { impl ViaWithdrawalVerifier { pub async fn new( - master_connection_pool: ConnectionPool, + master_connection_pool: ConnectionPool, btc_client: Arc, config: ViaVerifierConfig, ) -> anyhow::Result { @@ -257,8 +257,7 @@ impl ViaWithdrawalVerifier { let withdrawal_txid = self .master_connection_pool .connection_tagged("coordinator task") - .await - .unwrap() + .await? .via_votes_dal() .get_vote_transaction_withdrawal_tx(session_info.l1_block_number) .await?; @@ -276,8 +275,7 @@ impl ViaWithdrawalVerifier { self.master_connection_pool .connection_tagged("coordinator task") - .await - .unwrap() + .await? .via_votes_dal() .mark_vote_transaction_as_processed_withdrawals( H256::from_slice(&txid.as_raw_hash().to_byte_array()), From 42574380b4fb4f281586657b3f54fc117cf3034e Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 09:56:50 +0330 Subject: [PATCH 107/212] feat(via): add tests for via_vote_dal --- Cargo.lock | 2 + ...f7f7dc59a40e03457c442d14fa5c4d37182b.json} | 4 +- via_verifier/lib/verifier_dal/Cargo.toml | 4 + .../lib/verifier_dal/src/tests/mod.rs | 87 ++++++++++++++----- .../lib/verifier_dal/src/via_votes_dal.rs | 2 +- 5 files changed, 76 insertions(+), 23 deletions(-) rename via_verifier/lib/verifier_dal/.sqlx/{query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json => query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json} (71%) diff --git a/Cargo.lock b/Cargo.lock index 5dd9916f7..bff61f30b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9720,9 +9720,11 @@ dependencies = [ name = "via_verifier_dal" version = "0.1.0" dependencies = [ + "rand 0.8.5", "sqlx", "strum 0.26.3", "thiserror", + "tokio", "zksync_basic_types", "zksync_db_connection", "zksync_types", diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json b/via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json similarity index 71% rename from via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json rename to via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json index 472334232..3f4dc4c6e 100644 --- a/via_verifier/lib/verifier_dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json +++ b/via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING\n ", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", "describe": { "columns": [], "parameters": { @@ -14,5 +14,5 @@ }, "nullable": [] }, - "hash": "39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9" + "hash": "aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b" } diff --git a/via_verifier/lib/verifier_dal/Cargo.toml b/via_verifier/lib/verifier_dal/Cargo.toml index 9df6f97fe..35c0406fe 100644 --- a/via_verifier/lib/verifier_dal/Cargo.toml +++ b/via_verifier/lib/verifier_dal/Cargo.toml @@ -29,3 +29,7 @@ sqlx = { workspace = true, features = [ "migrate", "ipnetwork", ] } + +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } +rand = { workspace = true } diff --git a/via_verifier/lib/verifier_dal/src/tests/mod.rs b/via_verifier/lib/verifier_dal/src/tests/mod.rs index b9fbb6599..0d868c8ac 100644 --- a/via_verifier/lib/verifier_dal/src/tests/mod.rs +++ b/via_verifier/lib/verifier_dal/src/tests/mod.rs @@ -1,20 +1,67 @@ -use std::time::Duration; - -use zksync_db_connection::connection_pool::ConnectionPool; -use zksync_types::{ - block::{L1BatchHeader, L2BlockHasher, L2BlockHeader}, - fee::Fee, - fee_model::BatchFeeInput, - helpers::unix_timestamp_ms, - l1::{L1Tx, OpProcessingType, PriorityQueueType}, - l2::L2Tx, - l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, - protocol_upgrade::{ProtocolUpgradeTx, ProtocolUpgradeTxCommonData}, - snapshots::SnapshotRecoveryStatus, - Address, Execute, K256PrivateKey, L1BatchNumber, L1BlockNumber, L1TxCommonData, L2BlockNumber, - L2ChainId, PriorityOpId, ProtocolVersion, ProtocolVersionId, H160, H256, U256, -}; - -use crate::Verifier; - -// TODO: Add tests here +use rand::random; +use zksync_db_connection::{connection::Connection, connection_pool::ConnectionPool}; +use zksync_types::H256; + +use crate::{Verifier, VerifierDal}; + +// Helper functions for testing +async fn create_test_connection() -> Connection<'static, Verifier> { + let connection_pool = ConnectionPool::::test_pool().await; + connection_pool.connection().await.unwrap() +} + +fn mock_via_vote() -> (u32, H256, String, bool) { + ( + 1, // l1_batch_number + H256::random(), + "0x1234567890123456789012345678901234567890".to_string(), // verifier_address + random::(), + ) +} + +#[tokio::test] +async fn test_via_vote_workflow() { + let mut storage = create_test_connection().await; + + // Create test data + let (l1_batch_number, tx_id, verifier_address, vote) = mock_via_vote(); + + // First insert a votable transaction + storage + .via_votes_dal() + .insert_votable_transaction( + l1_batch_number, + tx_id, + "test_da_id".to_string(), + "test_blob_id".to_string(), + "test_proof_tx_id".to_string(), + ) + .await + .unwrap(); + + // Test inserting a vote + storage + .via_votes_dal() + .insert_vote(l1_batch_number, tx_id, &verifier_address, vote) + .await + .unwrap(); + + // Test getting vote count + let (ok_votes, total_votes) = storage + .via_votes_dal() + .get_vote_count(l1_batch_number, tx_id) + .await + .unwrap(); + + assert_eq!(total_votes, 1); + assert_eq!(ok_votes, if vote { 1 } else { 0 }); + + // Test finalizing transaction + let is_finalized = storage + .via_votes_dal() + .finalize_transaction_if_needed(l1_batch_number, tx_id, 0.5, 1) + .await + .unwrap(); + + assert_eq!(is_finalized, vote); // Should be finalized if the vote was true +} diff --git a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs index 251c31a03..fde6f6c90 100644 --- a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs @@ -24,7 +24,7 @@ impl ViaVotesDal<'_, '_> { via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id) VALUES ($1, $2, $3, $4, $5) - ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING + ON CONFLICT (l1_batch_number, tx_id) DO NOTHING "#, i64::from(l1_batch_number), tx_id.as_bytes(), From 9ab1ea485bcf0bdc89333bea6d28cbf15d0ea16c Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 15:16:04 +0330 Subject: [PATCH 108/212] feat(via): add verifier db env --- core/bin/external_node/src/node_builder.rs | 1 + core/lib/config/src/configs/secrets.rs | 8 + core/lib/config/src/testonly.rs | 1 + core/lib/env_config/src/database.rs | 13 ++ .../src/proto/config/secrets.proto | 1 + core/lib/protobuf_config/src/secrets.rs | 11 ++ .../src/implementations/layers/mod.rs | 1 - .../src/implementations/layers/pools_layer.rs | 29 +++- .../layers/verifier_pools_layer.rs | 157 ------------------ 9 files changed, 62 insertions(+), 160 deletions(-) delete mode 100644 core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs diff --git a/core/bin/external_node/src/node_builder.rs b/core/bin/external_node/src/node_builder.rs index c30cc1a43..5ec8446da 100644 --- a/core/bin/external_node/src/node_builder.rs +++ b/core/bin/external_node/src/node_builder.rs @@ -117,6 +117,7 @@ impl ExternalNodeBuilder { server_url: Some(self.config.postgres.database_url()), server_replica_url: Some(self.config.postgres.database_url()), prover_url: None, + verifier_url: None, }; let pools_layer = PoolsLayerBuilder::empty(config, secrets) .with_master(true) diff --git a/core/lib/config/src/configs/secrets.rs b/core/lib/config/src/configs/secrets.rs index 71197f5d9..1cbdb0d86 100644 --- a/core/lib/config/src/configs/secrets.rs +++ b/core/lib/config/src/configs/secrets.rs @@ -8,6 +8,7 @@ pub struct DatabaseSecrets { pub server_url: Option, pub prover_url: Option, pub server_replica_url: Option, + pub verifier_url: Option, } #[derive(Debug, Clone, PartialEq)] @@ -41,4 +42,11 @@ impl DatabaseSecrets { pub fn prover_url(&self) -> anyhow::Result { self.prover_url.clone().context("Prover DB URL is absent") } + + /// Returns a copy of the verifier database URL as a `Result` to simplify error propagation. + pub fn verifier_url(&self) -> anyhow::Result { + self.verifier_url + .clone() + .context("Verifier DB URL is absent") + } } diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 2ec91f5be..5a33c4a74 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -854,6 +854,7 @@ impl Distribution for EncodeDist { server_url: Some(format!("localhost:{}", rng.gen::()).parse().unwrap()), server_replica_url: Some(format!("localhost:{}", rng.gen::()).parse().unwrap()), prover_url: Some(format!("localhost:{}", rng.gen::()).parse().unwrap()), + verifier_url: Some(format!("localhost:{}", rng.gen::()).parse().unwrap()), } } } diff --git a/core/lib/env_config/src/database.rs b/core/lib/env_config/src/database.rs index c067c96de..aa0d1f325 100644 --- a/core/lib/env_config/src/database.rs +++ b/core/lib/env_config/src/database.rs @@ -45,11 +45,17 @@ impl FromEnv for DatabaseSecrets { .map(|s| s.parse()) .transpose()? .or_else(|| server_url.clone()); + let verifier_url = env::var("DATABASE_VERIFIER_URL") + .ok() + .map(|s| s.parse()) + .transpose()? + .or_else(|| server_url.clone()); Ok(Self { server_url, prover_url, server_replica_url, + verifier_url, }) } } @@ -217,6 +223,7 @@ mod tests { DATABASE_URL=postgres://postgres:notsecurepassword@localhost/zksync_local DATABASE_REPLICA_URL=postgres://postgres:notsecurepassword@localhost/zksync_replica_local DATABASE_PROVER_URL=postgres://postgres:notsecurepassword@localhost/zksync_prover_local + DATABASE_VERIFIER_URL=postgres://postgres:notsecurepassword@localhost/via_verifier_local "#; lock.set_env(config); @@ -239,5 +246,11 @@ mod tests { .parse() .unwrap() ); + assert_eq!( + postgres_config.verifier_url().unwrap(), + "postgres://postgres:notsecurepassword@localhost/via_verifier_local" + .parse() + .unwrap() + ); } } diff --git a/core/lib/protobuf_config/src/proto/config/secrets.proto b/core/lib/protobuf_config/src/proto/config/secrets.proto index b711d81d5..704afbe19 100644 --- a/core/lib/protobuf_config/src/proto/config/secrets.proto +++ b/core/lib/protobuf_config/src/proto/config/secrets.proto @@ -7,6 +7,7 @@ message DatabaseSecrets { optional string server_url = 1; // optional optional string server_replica_url = 2; // optional optional string prover_url = 3; // optional + optional string verifier_url = 4; // optional } message L1Secrets { diff --git a/core/lib/protobuf_config/src/secrets.rs b/core/lib/protobuf_config/src/secrets.rs index 7d10bef88..a6add9632 100644 --- a/core/lib/protobuf_config/src/secrets.rs +++ b/core/lib/protobuf_config/src/secrets.rs @@ -53,10 +53,17 @@ impl ProtoRepr for proto::DatabaseSecrets { .map(str::parse::) .transpose() .context("prover_url")?; + let verifier_url = self + .verifier_url + .as_deref() + .map(str::parse::) + .transpose() + .context("verifier_url")?; Ok(Self::Type { server_url, prover_url, server_replica_url, + verifier_url, }) } @@ -68,6 +75,10 @@ impl ProtoRepr for proto::DatabaseSecrets { .as_ref() .map(|a| a.expose_str().to_string()), prover_url: this.prover_url.as_ref().map(|a| a.expose_str().to_string()), + verifier_url: this + .verifier_url + .as_ref() + .map(|a| a.expose_str().to_string()), } } } diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index 01bfa4082..a94aab2f5 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -42,7 +42,6 @@ pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; // TODO: TMP in sequencer -pub mod verifier_pools_layer; pub mod via_verifier; pub mod via_zk_verification; pub mod vm_runner; diff --git a/core/node/node_framework/src/implementations/layers/pools_layer.rs b/core/node/node_framework/src/implementations/layers/pools_layer.rs index 734f6f0cc..7ed306965 100644 --- a/core/node/node_framework/src/implementations/layers/pools_layer.rs +++ b/core/node/node_framework/src/implementations/layers/pools_layer.rs @@ -2,7 +2,9 @@ use zksync_config::configs::{DatabaseSecrets, PostgresConfig}; use zksync_dal::{ConnectionPool, Core}; use crate::{ - implementations::resources::pools::{MasterPool, PoolResource, ProverPool, ReplicaPool}, + implementations::resources::pools::{ + MasterPool, PoolResource, ProverPool, ReplicaPool, VerifierPool, + }, wiring_layer::{WiringError, WiringLayer}, IntoContext, }; @@ -14,6 +16,7 @@ pub struct PoolsLayerBuilder { with_master: bool, with_replica: bool, with_prover: bool, + with_verifier: bool, secrets: DatabaseSecrets, } @@ -26,6 +29,7 @@ impl PoolsLayerBuilder { with_master: false, with_replica: false, with_prover: false, + with_verifier: false, secrets: database_secrets, } } @@ -48,6 +52,12 @@ impl PoolsLayerBuilder { self } + /// Allows to enable the verifier pool. + pub fn with_verifier(mut self, with_verifier: bool) -> Self { + self.with_verifier = with_verifier; + self + } + /// Builds the [`PoolsLayer`] with the provided configuration. pub fn build(self) -> PoolsLayer { PoolsLayer { @@ -56,6 +66,7 @@ impl PoolsLayerBuilder { with_master: self.with_master, with_replica: self.with_replica, with_prover: self.with_prover, + with_verifier: self.with_verifier, } } } @@ -75,6 +86,7 @@ pub struct PoolsLayer { with_master: bool, with_replica: bool, with_prover: bool, + with_verifier: bool, } #[derive(Debug, IntoContext)] @@ -83,6 +95,7 @@ pub struct Output { pub master_pool: Option>, pub replica_pool: Option>, pub prover_pool: Option>, + pub verifier_pool: Option>, } #[async_trait::async_trait] @@ -95,7 +108,7 @@ impl WiringLayer for PoolsLayer { } async fn wire(self, _input: Self::Input) -> Result { - if !self.with_master && !self.with_replica && !self.with_prover { + if !self.with_master && !self.with_replica && !self.with_prover && !self.with_verifier { return Err(WiringError::Configuration( "At least one pool should be enabled".to_string(), )); @@ -148,10 +161,22 @@ impl WiringLayer for PoolsLayer { None }; + let verifier_pool = if self.with_verifier { + Some(PoolResource::::new( + self.secrets.verifier_url()?, + self.config.max_connections()?, + None, + None, + )) + } else { + None + }; + Ok(Output { master_pool, replica_pool, prover_pool, + verifier_pool, }) } } diff --git a/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs b/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs deleted file mode 100644 index 734f6f0cc..000000000 --- a/core/node/node_framework/src/implementations/layers/verifier_pools_layer.rs +++ /dev/null @@ -1,157 +0,0 @@ -use zksync_config::configs::{DatabaseSecrets, PostgresConfig}; -use zksync_dal::{ConnectionPool, Core}; - -use crate::{ - implementations::resources::pools::{MasterPool, PoolResource, ProverPool, ReplicaPool}, - wiring_layer::{WiringError, WiringLayer}, - IntoContext, -}; - -/// Builder for the [`PoolsLayer`]. -#[derive(Debug)] -pub struct PoolsLayerBuilder { - config: PostgresConfig, - with_master: bool, - with_replica: bool, - with_prover: bool, - secrets: DatabaseSecrets, -} - -impl PoolsLayerBuilder { - /// Creates a new builder with the provided configuration and secrets. - /// By default, no pulls are enabled. - pub fn empty(config: PostgresConfig, database_secrets: DatabaseSecrets) -> Self { - Self { - config, - with_master: false, - with_replica: false, - with_prover: false, - secrets: database_secrets, - } - } - - /// Allows to enable the master pool. - pub fn with_master(mut self, with_master: bool) -> Self { - self.with_master = with_master; - self - } - - /// Allows to enable the replica pool. - pub fn with_replica(mut self, with_replica: bool) -> Self { - self.with_replica = with_replica; - self - } - - /// Allows to enable the prover pool. - pub fn with_prover(mut self, with_prover: bool) -> Self { - self.with_prover = with_prover; - self - } - - /// Builds the [`PoolsLayer`] with the provided configuration. - pub fn build(self) -> PoolsLayer { - PoolsLayer { - config: self.config, - secrets: self.secrets, - with_master: self.with_master, - with_replica: self.with_replica, - with_prover: self.with_prover, - } - } -} - -/// Wiring layer for connection pools. -/// During wiring, also prepares the global configuration for the connection pools. -/// -/// ## Adds resources -/// -/// - `PoolResource::` (if master pool is enabled) -/// - `PoolResource::` (if replica pool is enabled) -/// - `PoolResource::` (if prover pool is enabled) -#[derive(Debug)] -pub struct PoolsLayer { - config: PostgresConfig, - secrets: DatabaseSecrets, - with_master: bool, - with_replica: bool, - with_prover: bool, -} - -#[derive(Debug, IntoContext)] -#[context(crate = crate)] -pub struct Output { - pub master_pool: Option>, - pub replica_pool: Option>, - pub prover_pool: Option>, -} - -#[async_trait::async_trait] -impl WiringLayer for PoolsLayer { - type Input = (); - type Output = Output; - - fn layer_name(&self) -> &'static str { - "pools_layer" - } - - async fn wire(self, _input: Self::Input) -> Result { - if !self.with_master && !self.with_replica && !self.with_prover { - return Err(WiringError::Configuration( - "At least one pool should be enabled".to_string(), - )); - } - - if self.with_master || self.with_replica { - if let Some(threshold) = self.config.slow_query_threshold() { - ConnectionPool::::global_config().set_slow_query_threshold(threshold)?; - } - if let Some(threshold) = self.config.long_connection_threshold() { - ConnectionPool::::global_config().set_long_connection_threshold(threshold)?; - } - } - - let master_pool = if self.with_master { - let pool_size = self.config.max_connections()?; - let pool_size_master = self.config.max_connections_master().unwrap_or(pool_size); - - Some(PoolResource::::new( - self.secrets.master_url()?, - pool_size_master, - None, - None, - )) - } else { - None - }; - - let replica_pool = if self.with_replica { - // We're most interested in setting acquire / statement timeouts for the API server, which puts the most load - // on Postgres. - Some(PoolResource::::new( - self.secrets.replica_url()?, - self.config.max_connections()?, - self.config.statement_timeout(), - self.config.acquire_timeout(), - )) - } else { - None - }; - - let prover_pool = if self.with_prover { - Some(PoolResource::::new( - self.secrets.prover_url()?, - self.config.max_connections()?, - None, - None, - )) - } else { - None - }; - - Ok(Output { - master_pool, - replica_pool, - prover_pool, - }) - } -} From adadb1d96fb6ed4fbb03e8f075f2f9c694935001 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sun, 12 Jan 2025 16:10:15 +0330 Subject: [PATCH 109/212] feat(via): add verifier dal to via command --- .../src/implementations/layers/via_btc_watch.rs | 1 + infrastructure/via/src/config.ts | 13 +++++++++++++ infrastructure/via/src/database.ts | 11 ++++++++++- infrastructure/via/src/init.ts | 4 ++-- .../bin/verifier_server/src/node_builder.rs | 13 ++++++++++++- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs index da141de3d..6fd69ed2c 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs @@ -22,6 +22,7 @@ pub struct BtcWatchLayer { btc_watch_config: ViaBtcWatchConfig, } +// TODO: add verifier pool and make btc_watch verifier compatible #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { diff --git a/infrastructure/via/src/config.ts b/infrastructure/via/src/config.ts index f0288f396..b23aa3a66 100644 --- a/infrastructure/via/src/config.ts +++ b/infrastructure/via/src/config.ts @@ -174,6 +174,19 @@ export async function pushConfig(environment?: string, diff?: string) { l2InitFile, false ); + + env.modify( + `DATABASE_VERIFIER_URL`, + `postgres://postgres:notsecurepassword@localhost/verifier_${environment}`, + l2InitFile, + false + ); + env.modify( + `TEST_DATABASE_VERIFIER_URL`, + `postgres://postgres:notsecurepassword@localhost/verifier_${environment}_test`, + l2InitFile, + false + ); } env.modify('DATABASE_STATE_KEEPER_DB_PATH', `./db/${environment}/state_keeper`, l2InitFile, false); diff --git a/infrastructure/via/src/database.ts b/infrastructure/via/src/database.ts index a56d20392..a57b20341 100644 --- a/infrastructure/via/src/database.ts +++ b/infrastructure/via/src/database.ts @@ -10,12 +10,14 @@ export async function reset(opts: DbOpts) { export enum DalPath { CoreDal = 'core/lib/dal', - ProverDal = 'prover/crates/lib/prover_dal' + ProverDal = 'prover/crates/lib/prover_dal', + ViaVerifierDal = 'via_verifier/lib/verifier_dal' } export interface DbOpts { core: boolean; prover: boolean; + verifier: boolean; } function getDals(opts: DbOpts): Map { @@ -32,6 +34,9 @@ function getDals(opts: DbOpts): Map { if (opts.core) { dals.set(DalPath.CoreDal, process.env.DATABASE_URL!); } + if (opts.verifier) { + dals.set(DalPath.ViaVerifierDal, process.env.DATABASE_VERIFIER_URL!); + } return dals; } @@ -40,6 +45,7 @@ function getTestDals(opts: DbOpts): Map { if (!opts.prover && !opts.core) { dals.set(DalPath.CoreDal, process.env.TEST_DATABASE_URL!); dals.set(DalPath.ProverDal, process.env.TEST_DATABASE_PROVER_URL!); + dals.set(DalPath.ViaVerifierDal, process.env.TEST_DATABASE_VERIFIER_URL!); } if (opts.prover) { dals.set(DalPath.ProverDal, process.env.TEST_DATABASE_PROVER_URL!); @@ -47,6 +53,9 @@ function getTestDals(opts: DbOpts): Map { if (opts.core) { dals.set(DalPath.CoreDal, process.env.TEST_DATABASE_URL!); } + if (opts.verifier) { + dals.set(DalPath.ViaVerifierDal, process.env.TEST_DATABASE_VERIFIER_URL!); + } return dals; } diff --git a/infrastructure/via/src/init.ts b/infrastructure/via/src/init.ts index f64df3b1f..2bc7e480c 100644 --- a/infrastructure/via/src/init.ts +++ b/infrastructure/via/src/init.ts @@ -71,8 +71,8 @@ const initSetup = async ({ }; const initDatabase = async (shouldCheck: boolean = true): Promise => { - await announced('Drop postgres db', db.drop({ core: true, prover: true })); - await announced('Setup postgres db', db.setup({ core: true, prover: true }, shouldCheck)); + await announced('Drop postgres db', db.drop({ core: true, prover: true, verifier: true })); + await announced('Setup postgres db', db.setup({ core: true, prover: true, verifier: true }, shouldCheck)); await announced('Clean rocksdb', clean(`db/${process.env.VIA_ENV!}`)); await announced('Clean backups', clean(`backups/${process.env.VIA_ENV!}`)); }; diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 5165aa163..0d9fadfcd 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -6,7 +6,7 @@ use zksync_config::{ use zksync_node_framework::{ implementations::layers::{ circuit_breaker_checker::CircuitBreakerCheckerLayer, healtcheck_server::HealthCheckLayer, - sigint::SigintHandlerLayer, via_btc_watch::BtcWatchLayer, + pools_layer::PoolsLayerBuilder, sigint::SigintHandlerLayer, via_btc_watch::BtcWatchLayer, }, service::{ZkStackService, ZkStackServiceBuilder}, }; @@ -84,8 +84,19 @@ impl ViaNodeBuilder { Ok(self) } + fn add_pools_layer(mut self) -> anyhow::Result { + let config = try_load_config!(self.configs.postgres_config); + let secrets = try_load_config!(self.secrets.database); + let pools_layer = PoolsLayerBuilder::empty(config, secrets) + .with_verifier(true) + .build(); + self.node.add_layer(pools_layer); + Ok(self) + } + pub fn build(self) -> anyhow::Result { Ok(self + .add_pools_layer()? .add_sigint_handler_layer()? .add_healthcheck_layer()? .add_circuit_breaker_checker_layer()? From 91f9b7c4c2e4409263a7da963b8c2d7e90d8a8cd Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 12 Jan 2025 22:30:09 +0100 Subject: [PATCH 110/212] chore: new btc_watch for verifier, verifier related crates moved --- Cargo.lock | 90 ++++++-- Cargo.toml | 4 + core/node/node_framework/Cargo.toml | 2 + .../src/implementations/layers/mod.rs | 1 + .../implementations/layers/via_btc_watch.rs | 1 - .../layers/via_verifier_btc_watch.rs | 113 ++++++++++ .../layers/via_zk_verification.rs | 200 +++++++++--------- core/node/via_btc_watch/src/lib.rs | 2 + .../bin/verifier_server/src/node_builder.rs | 6 +- via_verifier/lib/via_verification/Cargo.toml | 2 +- .../protocol_version/26/scheduler_key.json | 0 via_verifier/node/via_btc_watch/Cargo.toml | 30 +++ via_verifier/node/via_btc_watch/src/lib.rs | 174 +++++++++++++++ .../src/message_processors/mod.rs | 33 +++ .../src/message_processors/verifier.rs | 120 +++++++++++ .../node/via_btc_watch/src/metrics.rs | 20 ++ .../node/via_zk_verifier/Cargo.toml | 3 +- .../node/via_zk_verifier/src/lib.rs | 14 +- 18 files changed, 680 insertions(+), 135 deletions(-) create mode 100644 core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs rename {core => via_verifier}/lib/via_verification/keys/protocol_version/26/scheduler_key.json (100%) create mode 100644 via_verifier/node/via_btc_watch/Cargo.toml create mode 100644 via_verifier/node/via_btc_watch/src/lib.rs create mode 100644 via_verifier/node/via_btc_watch/src/message_processors/mod.rs create mode 100644 via_verifier/node/via_btc_watch/src/message_processors/verifier.rs create mode 100644 via_verifier/node/via_btc_watch/src/metrics.rs rename {core => via_verifier}/node/via_zk_verifier/Cargo.toml (91%) rename {core => via_verifier}/node/via_zk_verifier/src/lib.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index bff61f30b..41ea6672f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9454,29 +9454,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "via-verification" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "circuit_definitions", - "clap 4.5.16", - "ethers", - "hex", - "once_cell", - "primitive-types", - "reqwest 0.12.7", - "serde", - "serde_json", - "sha3 0.10.8", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber", - "zksync_types", -] - [[package]] name = "via_btc_client" version = "0.1.0" @@ -9693,6 +9670,29 @@ dependencies = [ "zksync_vm_utils", ] +[[package]] +name = "via_verification" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "circuit_definitions", + "clap 4.5.16", + "ethers", + "hex", + "once_cell", + "primitive-types", + "reqwest 0.12.7", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "zksync_types", +] + [[package]] name = "via_verifier" version = "0.1.0" @@ -9716,6 +9716,24 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "via_verifier_btc_watch" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "sqlx", + "thiserror", + "tokio", + "tracing", + "via_btc_client", + "via_verifier_dal", + "vise", + "zksync_config", + "zksync_shared_metrics", + "zksync_types", +] + [[package]] name = "via_verifier_dal" version = "0.1.0" @@ -9780,6 +9798,30 @@ dependencies = [ "zksync_types", ] +[[package]] +name = "via_zk_verifier" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "serde", + "sqlx", + "thiserror", + "tokio", + "tracing", + "via_btc_client", + "via_verification", + "via_verifier_dal", + "vise", + "zksync_config", + "zksync_da_client", + "zksync_dal", + "zksync_prover_interface", + "zksync_shared_metrics", + "zksync_types", +] + [[package]] name = "vise" version = "0.2.0" @@ -11800,9 +11842,11 @@ dependencies = [ "via_da_dispatcher", "via_fee_model", "via_state_keeper", + "via_verifier_btc_watch", "via_verifier_dal", "via_withdrawal_client", "via_withdrawal_service", + "via_zk_verifier", "zksync_base_token_adjuster", "zksync_block_reverter", "zksync_circuit_breaker", diff --git a/Cargo.toml b/Cargo.toml index f69f80044..31f84410e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,8 @@ members = [ "via_verifier/lib/via_musig2", "via_verifier/lib/verifier_dal", "via_verifier/node/withdrawal_service", + "via_verifier/node/via_zk_verifier", + "via_verifier/node/via_btc_watch", ] resolver = "2" @@ -337,3 +339,5 @@ via_verification = { version = "0.1.0", path = "via_verifier/lib/via_verificatio via_musig2 = { version = "0.1.0", path = "via_verifier/lib/via_musig2" } via_verifier_dal = { version = "0.1.0", path = "via_verifier/lib/verifier_dal" } via_withdrawal_service = { version = "0.1.0", path = "via_verifier/node/withdrawal_service" } +via_zk_verifier = { version = "0.1.0", path = "via_verifier/node/via_zk_verifier" } +via_verifier_btc_watch = { version = "0.1.0", path = "via_verifier/node/via_btc_watch" } diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index e3ffc187a..d6ab18b38 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -66,6 +66,8 @@ via_state_keeper.workspace = true via_withdrawal_service.workspace = true via_withdrawal_client.workspace = true via_verifier_dal.workspace = true +via_zk_verifier.workspace = true +via_verifier_btc_watch.workspace = true pin-project-lite.workspace = true tracing.workspace = true thiserror.workspace = true diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index a94aab2f5..9c2116ab9 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -41,6 +41,7 @@ pub mod via_da_dispatcher; pub mod via_gas_adjuster; pub mod via_l1_gas; pub mod via_state_keeper; +pub mod via_verifier_btc_watch; // TODO: TMP in sequencer pub mod via_verifier; pub mod via_zk_verification; diff --git a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs index 6fd69ed2c..da141de3d 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_watch.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_watch.rs @@ -22,7 +22,6 @@ pub struct BtcWatchLayer { btc_watch_config: ViaBtcWatchConfig, } -// TODO: add verifier pool and make btc_watch verifier compatible #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { diff --git a/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs new file mode 100644 index 000000000..6f4a50462 --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs @@ -0,0 +1,113 @@ +use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::NodeAuth}; +use via_btc_watch::BitcoinNetwork; +use via_verifier_btc_watch::VerifierBtcWatch; +use zksync_config::ViaBtcWatchConfig; + +use crate::{ + implementations::resources::{ + pools::{PoolResource, VerifierPool}, + via_btc_indexer::BtcIndexerResource, + }, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for bitcoin watcher +/// +/// Responsible for initializing and running of [`VerifierBtcWatch`] component, that polls the Bitcoin node for the relevant events. +#[derive(Debug)] +pub struct VerifierBtcWatchLayer { + // TODO: divide into multiple configs + btc_watch_config: ViaBtcWatchConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + pub btc_indexer_resource: BtcIndexerResource, + #[context(task)] + pub btc_watch: VerifierBtcWatch, +} + +impl VerifierBtcWatchLayer { + pub fn new(btc_watch_config: ViaBtcWatchConfig) -> Self { + Self { btc_watch_config } + } +} + +#[async_trait::async_trait] +impl WiringLayer for VerifierBtcWatchLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "verifier_btc_watch_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + let main_pool = input.master_pool.get().await?; + let network = BitcoinNetwork::from_core_arg(self.btc_watch_config.network()) + .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; + let node_auth = NodeAuth::UserPass( + self.btc_watch_config.rpc_user().to_string(), + self.btc_watch_config.rpc_password().to_string(), + ); + let bootstrap_txids = self + .btc_watch_config + .bootstrap_txids() + .iter() + .map(|txid| { + txid.parse() + .map_err(|_| WiringError::Configuration("Wrong txid in config".to_string())) + }) + .collect::, _>>()?; + let btc_blocks_lag = self.btc_watch_config.btc_blocks_lag(); + + let indexer = BtcIndexerResource::from( + BitcoinInscriptionIndexer::new( + self.btc_watch_config.rpc_url(), + network, + node_auth.clone(), + bootstrap_txids.clone(), + ) + .await + .map_err(|e| WiringError::Internal(e.into()))?, + ); + let btc_watch = VerifierBtcWatch::new( + self.btc_watch_config.rpc_url(), + network, + node_auth, + self.btc_watch_config.confirmations_for_btc_msg, + bootstrap_txids, + main_pool, + self.btc_watch_config.poll_interval(), + btc_blocks_lag, + self.btc_watch_config.actor_role(), + ) + .await?; + + Ok(Output { + btc_indexer_resource: indexer, + btc_watch, + }) + } +} + +#[async_trait::async_trait] +impl Task for VerifierBtcWatch { + fn id(&self) -> TaskId { + "verifier_btc_watch".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs index e343412d9..e48b38923 100644 --- a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs +++ b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs @@ -1,100 +1,100 @@ -// use async_trait::async_trait; -// use via_btc_client::types::{BitcoinNetwork, NodeAuth}; -// // use via_zk_verifier::ViaVerifier; -// use zksync_config::{ViaBtcWatchConfig, ViaVerifierConfig}; -// -// use crate::{ -// implementations::resources::{ -// da_client::DAClientResource, -// pools::{MasterPool, PoolResource}, -// }, -// service::StopReceiver, -// task::{Task, TaskId}, -// wiring_layer::{WiringError, WiringLayer}, -// FromContext, IntoContext, -// }; -// -// #[derive(Debug)] -// pub struct ViaBtcProofVerificationLayer { -// config: ViaVerifierConfig, -// btc_watcher_config: ViaBtcWatchConfig, -// } -// -// #[derive(Debug, FromContext)] -// #[context(crate = crate)] -// pub struct ProofVerificationInput { -// pub master_pool: PoolResource, -// pub da_client: DAClientResource, -// } -// -// #[derive(Debug, IntoContext)] -// #[context(crate = crate)] -// pub struct ProofVerificationOutput { -// #[context(task)] -// pub via_proof_verification: ViaVerifier, -// } -// -// impl ViaBtcProofVerificationLayer { -// pub fn new(config: ViaVerifierConfig, btc_watcher_config: ViaBtcWatchConfig) -> Self { -// Self { -// config, -// btc_watcher_config, -// } -// } -// } -// -// #[async_trait] -// impl WiringLayer for ViaBtcProofVerificationLayer { -// type Input = ProofVerificationInput; -// type Output = ProofVerificationOutput; -// -// fn layer_name(&self) -> &'static str { -// "via_btc_proof_verification_layer" -// } -// -// async fn wire(self, input: Self::Input) -> Result { -// let main_pool = input.master_pool.get().await?; -// let network = BitcoinNetwork::from_core_arg(self.btc_watcher_config.network()) -// .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; -// let node_auth = NodeAuth::UserPass( -// self.btc_watcher_config.rpc_user().to_string(), -// self.btc_watcher_config.rpc_password().to_string(), -// ); -// let bootstrap_txids = self -// .btc_watcher_config -// .bootstrap_txids() -// .iter() -// .map(|txid| { -// txid.parse() -// .map_err(|_| WiringError::Configuration("Wrong txid in config".to_string())) -// }) -// .collect::, _>>()?; -// -// let via_proof_verification = ViaVerifier::new( -// self.btc_watcher_config.rpc_url(), -// network, -// node_auth, -// bootstrap_txids, -// main_pool, -// input.da_client.0, -// self.config.clone(), -// ) -// .await -// .map_err(WiringError::internal)?; -// -// Ok(ProofVerificationOutput { -// via_proof_verification, -// }) -// } -// } -// -// #[async_trait::async_trait] -// impl Task for ViaVerifier { -// fn id(&self) -> TaskId { -// "via_proof_verification".into() -// } -// -// async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { -// (*self).run(stop_receiver.0).await -// } -// } +use async_trait::async_trait; +use via_btc_client::types::{BitcoinNetwork, NodeAuth}; +use via_zk_verifier::ViaVerifier; +use zksync_config::{ViaBtcWatchConfig, ViaVerifierConfig}; + +use crate::{ + implementations::resources::{ + da_client::DAClientResource, + pools::{PoolResource, VerifierPool}, + }, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +#[derive(Debug)] +pub struct ViaBtcProofVerificationLayer { + config: ViaVerifierConfig, + btc_watcher_config: ViaBtcWatchConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct ProofVerificationInput { + pub master_pool: PoolResource, + pub da_client: DAClientResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct ProofVerificationOutput { + #[context(task)] + pub via_proof_verification: ViaVerifier, +} + +impl ViaBtcProofVerificationLayer { + pub fn new(config: ViaVerifierConfig, btc_watcher_config: ViaBtcWatchConfig) -> Self { + Self { + config, + btc_watcher_config, + } + } +} + +#[async_trait] +impl WiringLayer for ViaBtcProofVerificationLayer { + type Input = ProofVerificationInput; + type Output = ProofVerificationOutput; + + fn layer_name(&self) -> &'static str { + "via_btc_proof_verification_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + let main_pool = input.master_pool.get().await?; + let network = BitcoinNetwork::from_core_arg(self.btc_watcher_config.network()) + .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; + let node_auth = NodeAuth::UserPass( + self.btc_watcher_config.rpc_user().to_string(), + self.btc_watcher_config.rpc_password().to_string(), + ); + let bootstrap_txids = self + .btc_watcher_config + .bootstrap_txids() + .iter() + .map(|txid| { + txid.parse() + .map_err(|_| WiringError::Configuration("Wrong txid in config".to_string())) + }) + .collect::, _>>()?; + + let via_proof_verification = ViaVerifier::new( + self.btc_watcher_config.rpc_url(), + network, + node_auth, + bootstrap_txids, + main_pool, + input.da_client.0, + self.config.clone(), + ) + .await + .map_err(WiringError::internal)?; + + Ok(ProofVerificationOutput { + via_proof_verification, + }) + } +} + +#[async_trait::async_trait] +impl Task for ViaVerifier { + fn id(&self) -> TaskId { + "via_proof_verification".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index dd7025025..129501e71 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -63,6 +63,8 @@ impl BtcWatch { tracing::info!("initialized state: {state:?}"); drop(storage); + assert_eq!(actor_role, &ActorRole::Sequencer); + // Only build message processors that match the actor role: let message_processors: Vec> = match actor_role { ActorRole::Verifier => { diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 0d9fadfcd..6b393f4e4 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -6,7 +6,8 @@ use zksync_config::{ use zksync_node_framework::{ implementations::layers::{ circuit_breaker_checker::CircuitBreakerCheckerLayer, healtcheck_server::HealthCheckLayer, - pools_layer::PoolsLayerBuilder, sigint::SigintHandlerLayer, via_btc_watch::BtcWatchLayer, + pools_layer::PoolsLayerBuilder, sigint::SigintHandlerLayer, + via_verifier_btc_watch::VerifierBtcWatchLayer, }, service::{ZkStackService, ZkStackServiceBuilder}, }; @@ -80,7 +81,8 @@ impl ViaNodeBuilder { ActorRole::Verifier, "Verifier role is expected" ); - self.node.add_layer(BtcWatchLayer::new(btc_watch_config)); + self.node + .add_layer(VerifierBtcWatchLayer::new(btc_watch_config)); Ok(self) } diff --git a/via_verifier/lib/via_verification/Cargo.toml b/via_verifier/lib/via_verification/Cargo.toml index 98c4fe804..71d8c22bd 100644 --- a/via_verifier/lib/via_verification/Cargo.toml +++ b/via_verifier/lib/via_verification/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "via-verification" +name = "via_verification" version = "0.1.0" edition = "2021" diff --git a/core/lib/via_verification/keys/protocol_version/26/scheduler_key.json b/via_verifier/lib/via_verification/keys/protocol_version/26/scheduler_key.json similarity index 100% rename from core/lib/via_verification/keys/protocol_version/26/scheduler_key.json rename to via_verifier/lib/via_verification/keys/protocol_version/26/scheduler_key.json diff --git a/via_verifier/node/via_btc_watch/Cargo.toml b/via_verifier/node/via_btc_watch/Cargo.toml new file mode 100644 index 000000000..45489839c --- /dev/null +++ b/via_verifier/node/via_btc_watch/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "via_verifier_btc_watch" +description = "VIA Bitcoin watcher for verifier" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +vise.workspace = true +via_btc_client.workspace = true +zksync_shared_metrics.workspace = true +zksync_types.workspace = true +zksync_config.workspace = true + +tokio.workspace = true +anyhow.workspace = true +thiserror.workspace = true +async-trait.workspace = true +tracing.workspace = true +sqlx.workspace = true + +via_verifier_dal.workspace = true + + +[dev-dependencies] diff --git a/via_verifier/node/via_btc_watch/src/lib.rs b/via_verifier/node/via_btc_watch/src/lib.rs new file mode 100644 index 000000000..42f05a838 --- /dev/null +++ b/via_verifier/node/via_btc_watch/src/lib.rs @@ -0,0 +1,174 @@ +mod message_processors; +mod metrics; + +use std::time::Duration; + +use anyhow::Context as _; +use tokio::sync::watch; +// re-export via_btc_client types +pub use via_btc_client::types::BitcoinNetwork; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinTxid, NodeAuth}, +}; +use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; +use zksync_config::ActorRole; + +use self::{ + message_processors::{MessageProcessor, MessageProcessorError}, + metrics::METRICS, +}; +use crate::{message_processors::VerifierMessageProcessor, metrics::ErrorType}; + +const DEFAULT_VOTING_THRESHOLD: f64 = 0.5; + +#[derive(Debug)] +struct BtcWatchState { + last_processed_bitcoin_block: u32, +} + +#[derive(Debug)] +pub struct VerifierBtcWatch { + indexer: BitcoinInscriptionIndexer, + poll_interval: Duration, + confirmations_for_btc_msg: u64, + last_processed_bitcoin_block: u32, + pool: ConnectionPool, + message_processors: Vec>, + btc_blocks_lag: u32, +} + +impl VerifierBtcWatch { + #[allow(clippy::too_many_arguments)] + pub async fn new( + rpc_url: &str, + network: BitcoinNetwork, + node_auth: NodeAuth, + confirmations_for_btc_msg: Option, + bootstrap_txids: Vec, + pool: ConnectionPool, + poll_interval: Duration, + btc_blocks_lag: u32, + actor_role: &ActorRole, + ) -> anyhow::Result { + let indexer = + BitcoinInscriptionIndexer::new(rpc_url, network, node_auth, bootstrap_txids).await?; + let mut storage = pool.connection_tagged("via_btc_watch").await?; + let state = Self::initialize_state(&indexer, &mut storage, btc_blocks_lag).await?; + tracing::info!("initialized state: {state:?}"); + drop(storage); + + assert_eq!(actor_role, &ActorRole::Verifier); + + let message_processors: Vec> = vec![Box::new( + VerifierMessageProcessor::new(DEFAULT_VOTING_THRESHOLD), + )]; + + let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); + + // We should not set confirmations_for_btc_msg to 0 for mainnet, + // because we need to wait for some confirmations to be sure that the transaction is included in a block. + if network == BitcoinNetwork::Bitcoin && confirmations_for_btc_msg == 0 { + return Err(anyhow::anyhow!( + "confirmations_for_btc_msg cannot be 0 for mainnet" + )); + } + + Ok(Self { + indexer, + poll_interval, + confirmations_for_btc_msg, + last_processed_bitcoin_block: state.last_processed_bitcoin_block, + pool, + message_processors, + btc_blocks_lag, + }) + } + + async fn initialize_state( + indexer: &BitcoinInscriptionIndexer, + storage: &mut Connection<'_, Verifier>, + btc_blocks_lag: u32, + ) -> anyhow::Result { + let last_processed_bitcoin_block = + match storage.via_votes_dal().get_last_inserted_block().await? { + Some(block) => block.saturating_sub(1), + None => indexer + .fetch_block_height() + .await + .context("cannot get current Bitcoin block")? + .saturating_sub(btc_blocks_lag as u128) as u32, // TODO: remove cast + }; + + // TODO: get the bridge address from the database? + let (_bridge_address, ..) = indexer.get_state(); + + Ok(BtcWatchState { + last_processed_bitcoin_block, + }) + } + + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut timer = tokio::time::interval(self.poll_interval); + let pool = self.pool.clone(); + + while !*stop_receiver.borrow_and_update() { + tokio::select! { + _ = timer.tick() => { /* continue iterations */ } + _ = stop_receiver.changed() => break, + } + METRICS.btc_poll.inc(); + + let mut storage = pool.connection_tagged("via_btc_watch").await?; + match self.loop_iteration(&mut storage).await { + Ok(()) => { /* everything went fine */ } + Err(MessageProcessorError::Internal(err)) => { + METRICS.errors[&ErrorType::InternalError].inc(); + tracing::error!("Internal error processing new blocks: {err:?}"); + return Err(err); + } + Err(err) => { + tracing::error!("Failed to process new blocks: {err}"); + self.last_processed_bitcoin_block = + Self::initialize_state(&self.indexer, &mut storage, self.btc_blocks_lag) + .await? + .last_processed_bitcoin_block; + } + } + } + + tracing::info!("Stop signal received, via_btc_watch is shutting down"); + Ok(()) + } + + async fn loop_iteration( + &mut self, + storage: &mut Connection<'_, Verifier>, + ) -> Result<(), MessageProcessorError> { + let to_block = self + .indexer + .fetch_block_height() + .await + .map_err(|e| MessageProcessorError::Internal(anyhow::anyhow!(e.to_string())))? + .saturating_sub(self.confirmations_for_btc_msg as u128) as u32; + if to_block <= self.last_processed_bitcoin_block { + return Ok(()); + } + + let messages = self + .indexer + .process_blocks(self.last_processed_bitcoin_block + 1, to_block) + .await + .map_err(|e| MessageProcessorError::Internal(e.into()))?; + + for processor in self.message_processors.iter_mut() { + processor + .process_messages(storage, messages.clone(), &mut self.indexer) + .await + .map_err(|e| MessageProcessorError::Internal(e.into()))?; + } + + self.last_processed_bitcoin_block = to_block; + Ok(()) + } +} diff --git a/via_verifier/node/via_btc_watch/src/message_processors/mod.rs b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs new file mode 100644 index 000000000..0c84c751b --- /dev/null +++ b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs @@ -0,0 +1,33 @@ +pub(crate) use verifier::VerifierMessageProcessor; +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinTxid, FullInscriptionMessage}, +}; +use via_verifier_dal::{Connection, Verifier}; +use zksync_types::H256; + +mod verifier; + +#[derive(Debug, thiserror::Error)] +pub(super) enum MessageProcessorError { + #[error("internal processing error: {0:?}")] + Internal(#[from] anyhow::Error), + #[error("database error: {0}")] + DatabaseError(String), +} + +#[async_trait::async_trait] +pub(super) trait MessageProcessor: 'static + std::fmt::Debug + Send + Sync { + async fn process_messages( + &mut self, + storage: &mut Connection<'_, Verifier>, + msgs: Vec, + indexer: &mut BitcoinInscriptionIndexer, + ) -> Result<(), MessageProcessorError>; +} + +pub(crate) fn convert_txid_to_h256(txid: BitcoinTxid) -> H256 { + let mut tx_id_bytes = txid.as_raw_hash()[..].to_vec(); + tx_id_bytes.reverse(); + H256::from_slice(&tx_id_bytes) +} diff --git a/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs new file mode 100644 index 000000000..1156476f4 --- /dev/null +++ b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs @@ -0,0 +1,120 @@ +use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; +use via_verifier_dal::{Connection, Verifier, VerifierDal}; + +use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; + +#[derive(Debug)] +pub struct VerifierMessageProcessor { + threshold: f64, +} + +impl VerifierMessageProcessor { + pub fn new(threshold: f64) -> Self { + Self { threshold } + } +} + +#[async_trait::async_trait] +impl MessageProcessor for VerifierMessageProcessor { + async fn process_messages( + &mut self, + storage: &mut Connection<'_, Verifier>, + msgs: Vec, + indexer: &mut BitcoinInscriptionIndexer, + ) -> Result<(), MessageProcessorError> { + for msg in msgs { + match msg { + ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { + let mut votes_dal = storage.via_votes_dal(); + + let last_inserted_block = votes_dal + .get_last_inserted_block() + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + .unwrap_or(0); + + if l1_batch_number.0 != last_inserted_block + 1 { + tracing::warn!( + "Skipping ProofDAReference message with l1_batch_number: {:?}. Last inserted block: {:?}", + l1_batch_number, last_inserted_block + ); + continue; + } + + let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + + votes_dal + .insert_votable_transaction( + l1_batch_number.0, + tx_id, + proof_msg.input.da_identifier.clone(), + proof_msg.input.blob_id.clone(), + proof_msg.input.l1_batch_reveal_txid.to_string(), + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + } else { + tracing::warn!( + "L1BatchNumber not found for ProofDAReference message : {:?}", + proof_msg + ); + } + } + ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { + if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { + let mut votes_dal = storage.via_votes_dal(); + + let reference_txid = + convert_txid_to_h256(attestation_msg.input.reference_txid); + let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); + + // Vote = true if attestation_msg.input.attestation == Vote::Ok + let is_ok = matches!( + attestation_msg.input.attestation, + via_btc_client::types::Vote::Ok + ); + votes_dal + .insert_vote( + l1_batch_number.0, + reference_txid, + &attestation_msg.common.p2wpkh_address.to_string(), + is_ok, + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + + // Check finalization + if votes_dal + .finalize_transaction_if_needed( + l1_batch_number.0, + reference_txid, + self.threshold, + indexer.get_number_of_verifiers(), + ) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + { + tracing::info!( + "Finalizing transaction with tx_id: {:?} and block number: {:?}", + tx_id, + l1_batch_number + ); + } + } + } + // bootstrapping phase is already covered + FullInscriptionMessage::ProposeSequencer(_) + | FullInscriptionMessage::SystemBootstrapping(_) => { + // do nothing + } + // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor + FullInscriptionMessage::L1ToL2Message(_) + | FullInscriptionMessage::L1BatchDAReference(_) => { + // do nothing + } + } + } + Ok(()) + } +} diff --git a/via_verifier/node/via_btc_watch/src/metrics.rs b/via_verifier/node/via_btc_watch/src/metrics.rs new file mode 100644 index 000000000..1d37c8e82 --- /dev/null +++ b/via_verifier/node/via_btc_watch/src/metrics.rs @@ -0,0 +1,20 @@ +use vise::{Counter, EncodeLabelSet, EncodeLabelValue, Family, Metrics}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "error_type", rename_all = "snake_case")] +pub enum ErrorType { + InternalError, +} + +#[derive(Debug, Metrics)] +#[metrics(prefix = "via_verifier_btc_watch")] +pub struct ViaVerifierBtcWatcherMetrics { + /// Number of times Bitcoin was polled. + pub btc_poll: Counter, + + /// Number of errors encountered, labeled by error type. + pub errors: Family, +} + +#[vise::register] +pub static METRICS: vise::Global = vise::Global::new(); diff --git a/core/node/via_zk_verifier/Cargo.toml b/via_verifier/node/via_zk_verifier/Cargo.toml similarity index 91% rename from core/node/via_zk_verifier/Cargo.toml rename to via_verifier/node/via_zk_verifier/Cargo.toml index cd4736168..9a9e8ba44 100644 --- a/core/node/via_zk_verifier/Cargo.toml +++ b/via_verifier/node/via_zk_verifier/Cargo.toml @@ -29,6 +29,7 @@ tracing.workspace = true sqlx.workspace = true serde.workspace = true -via-verification.workspace = true +via_verification.workspace = true +via_verifier_dal.workspace = true [dev-dependencies] diff --git a/core/node/via_zk_verifier/src/lib.rs b/via_verifier/node/via_zk_verifier/src/lib.rs similarity index 95% rename from core/node/via_zk_verifier/src/lib.rs rename to via_verifier/node/via_zk_verifier/src/lib.rs index 471b1d784..81ed13b48 100644 --- a/core/node/via_zk_verifier/src/lib.rs +++ b/via_verifier/node/via_zk_verifier/src/lib.rs @@ -12,9 +12,9 @@ use via_btc_client::{ use via_verification::proof::{ Bn256, ProofTrait, ViaZKProof, ZkSyncProof, ZkSyncSnarkWrapperCircuit, }; +use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; use zksync_config::ViaVerifierConfig; use zksync_da_client::{types::InclusionData, DataAvailabilityClient}; -use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_types::{ commitment::L1BatchWithMetadata, protocol_version::ProtocolSemanticVersion, H256, }; @@ -37,7 +37,7 @@ pub struct L1BatchProofForL1 { #[derive(Debug)] pub struct ViaVerifier { - pool: ConnectionPool, + pool: ConnectionPool, da_client: Box, indexer: BitcoinInscriptionIndexer, config: ViaVerifierConfig, @@ -49,7 +49,7 @@ impl ViaVerifier { network: BitcoinNetwork, node_auth: NodeAuth, bootstrap_txids: Vec, - pool: ConnectionPool, + pool: ConnectionPool, client: Box, config: ViaVerifierConfig, ) -> anyhow::Result { @@ -64,7 +64,7 @@ impl ViaVerifier { } pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { - let mut timer = tokio::time::interval(self.config.poll_interval()); + let mut timer = tokio::time::interval(self.config.polling_interval()); let pool = self.pool.clone(); while !*stop_receiver.borrow_and_update() { @@ -86,11 +86,11 @@ impl ViaVerifier { pub async fn loop_iteration( &mut self, - storage: &mut Connection<'_, Core>, + storage: &mut Connection<'_, Verifier>, ) -> anyhow::Result<()> { if let Some((l1_batch_number, mut raw_tx_id)) = storage .via_votes_dal() - .get_first_not_executed_block() + .get_first_not_verified_block() .await? { let db_raw_tx_id = H256::from_slice(&raw_tx_id); @@ -131,7 +131,7 @@ impl ViaVerifier { storage .via_votes_dal() - .get_first_not_verified_block(l1_batch_number as u32, db_raw_tx_id, is_verified) + .verify_votable_transaction(l1_batch_number as u32, db_raw_tx_id, is_verified) .await?; } From ba4fa6db22601714eb8300275f8066ffadcbae97 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 12 Jan 2025 22:40:30 +0100 Subject: [PATCH 111/212] chore: delete rest of the verifier part from main btc_watcher --- core/node/via_btc_watch/src/lib.rs | 26 ++-- .../src/message_processors/mod.rs | 2 - .../src/message_processors/verifier.rs | 120 ------------------ 3 files changed, 8 insertions(+), 140 deletions(-) delete mode 100644 core/node/via_btc_watch/src/message_processors/verifier.rs diff --git a/core/node/via_btc_watch/src/lib.rs b/core/node/via_btc_watch/src/lib.rs index 129501e71..0bc7ac266 100644 --- a/core/node/via_btc_watch/src/lib.rs +++ b/core/node/via_btc_watch/src/lib.rs @@ -19,9 +19,8 @@ use self::{ message_processors::{ L1ToL2MessageProcessor, MessageProcessor, MessageProcessorError, VotableMessageProcessor, }, - metrics::METRICS, + metrics::{ErrorType, METRICS}, }; -use crate::{message_processors::VerifierMessageProcessor, metrics::ErrorType}; const DEFAULT_VOTING_THRESHOLD: f64 = 0.5; @@ -66,22 +65,13 @@ impl BtcWatch { assert_eq!(actor_role, &ActorRole::Sequencer); // Only build message processors that match the actor role: - let message_processors: Vec> = match actor_role { - ActorRole::Verifier => { - vec![Box::new(VerifierMessageProcessor::new( - DEFAULT_VOTING_THRESHOLD, - ))] - } - _ => { - vec![ - Box::new(L1ToL2MessageProcessor::new( - state.bridge_address.clone(), - state.next_expected_priority_id, - )), - Box::new(VotableMessageProcessor::new(DEFAULT_VOTING_THRESHOLD)), - ] - } - }; + let message_processors: Vec> = vec![ + Box::new(L1ToL2MessageProcessor::new( + state.bridge_address.clone(), + state.next_expected_priority_id, + )), + Box::new(VotableMessageProcessor::new(DEFAULT_VOTING_THRESHOLD)), + ]; let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); diff --git a/core/node/via_btc_watch/src/message_processors/mod.rs b/core/node/via_btc_watch/src/message_processors/mod.rs index 4088d3aed..a8ad2979e 100644 --- a/core/node/via_btc_watch/src/message_processors/mod.rs +++ b/core/node/via_btc_watch/src/message_processors/mod.rs @@ -1,5 +1,4 @@ pub(crate) use l1_to_l2::L1ToL2MessageProcessor; -pub(crate) use verifier::VerifierMessageProcessor; use via_btc_client::{ indexer::BitcoinInscriptionIndexer, types::{BitcoinTxid, FullInscriptionMessage}, @@ -9,7 +8,6 @@ use zksync_dal::{Connection, Core}; use zksync_types::H256; mod l1_to_l2; -mod verifier; mod votable; #[derive(Debug, thiserror::Error)] diff --git a/core/node/via_btc_watch/src/message_processors/verifier.rs b/core/node/via_btc_watch/src/message_processors/verifier.rs deleted file mode 100644 index 5007e505a..000000000 --- a/core/node/via_btc_watch/src/message_processors/verifier.rs +++ /dev/null @@ -1,120 +0,0 @@ -use via_btc_client::{indexer::BitcoinInscriptionIndexer, types::FullInscriptionMessage}; -use zksync_dal::{Connection, Core, CoreDal}; - -use super::{convert_txid_to_h256, MessageProcessor, MessageProcessorError}; - -#[derive(Debug)] -pub struct VerifierMessageProcessor { - threshold: f64, -} - -impl VerifierMessageProcessor { - pub fn new(threshold: f64) -> Self { - Self { threshold } - } -} - -#[async_trait::async_trait] -impl MessageProcessor for VerifierMessageProcessor { - async fn process_messages( - &mut self, - storage: &mut Connection<'_, Core>, - msgs: Vec, - indexer: &mut BitcoinInscriptionIndexer, - ) -> Result<(), MessageProcessorError> { - for msg in msgs { - match msg { - ref f @ FullInscriptionMessage::ProofDAReference(ref proof_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { - let mut votes_dal = storage.via_votes_dal(); - - let last_inserted_block = votes_dal - .get_last_inserted_block() - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? - .unwrap_or(0); - - if l1_batch_number.0 != last_inserted_block + 1 { - tracing::warn!( - "Skipping ProofDAReference message with l1_batch_number: {:?}. Last inserted block: {:?}", - l1_batch_number, last_inserted_block - ); - continue; - } - - let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); - - votes_dal - .insert_votable_transaction( - l1_batch_number.0, - tx_id, - proof_msg.input.da_identifier.clone(), - proof_msg.input.blob_id.clone(), - proof_msg.input.l1_batch_reveal_txid.to_string(), - ) - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; - } else { - tracing::warn!( - "L1BatchNumber not found for ProofDAReference message : {:?}", - proof_msg - ); - } - } - ref f @ FullInscriptionMessage::ValidatorAttestation(ref attestation_msg) => { - if let Some(l1_batch_number) = indexer.get_l1_batch_number(f).await { - let mut votes_dal = storage.via_votes_dal(); - - let reference_txid = - convert_txid_to_h256(attestation_msg.input.reference_txid); - let tx_id = convert_txid_to_h256(attestation_msg.common.tx_id); - - // Vote = true if attestation_msg.input.attestation == Vote::Ok - let is_ok = matches!( - attestation_msg.input.attestation, - via_btc_client::types::Vote::Ok - ); - votes_dal - .insert_vote( - l1_batch_number.0, - reference_txid, - &attestation_msg.common.p2wpkh_address.to_string(), - is_ok, - ) - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; - - // Check finalization - if votes_dal - .finalize_transaction_if_needed( - l1_batch_number.0, - reference_txid, - self.threshold, - indexer.get_number_of_verifiers(), - ) - .await - .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? - { - tracing::info!( - "Finalizing transaction with tx_id: {:?} and block number: {:?}", - tx_id, - l1_batch_number - ); - } - } - } - // bootstrapping phase is already covered - FullInscriptionMessage::ProposeSequencer(_) - | FullInscriptionMessage::SystemBootstrapping(_) => { - // do nothing - } - // Non-votable messages like L1BatchDAReference or L1ToL2Message are ignored by this processor - FullInscriptionMessage::L1ToL2Message(_) - | FullInscriptionMessage::L1BatchDAReference(_) => { - // do nothing - } - } - } - Ok(()) - } -} From 2ebdc0e8aea206e9ebc4719e0ffcc2deea811976 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 13 Jan 2025 13:46:33 +0330 Subject: [PATCH 112/212] feat(via): add volume for celestia key --- docker-compose-via.yml | 3 +++ infrastructure/via/src/up.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index b671d1e30..9fe2321dd 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -114,6 +114,9 @@ services: - type: bind source: ./volumes/celestia target: /home/celestia + - type: bind + source: ./volumes/celestia-keys + target: /root/.celestia-light-mocha-4/keys command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip full.consensus.mocha-4.celestia-mocha.com --p2p.network mocha ports: - '26658:26658' diff --git a/infrastructure/via/src/up.ts b/infrastructure/via/src/up.ts index 0c1835767..69f9a50aa 100644 --- a/infrastructure/via/src/up.ts +++ b/infrastructure/via/src/up.ts @@ -21,6 +21,9 @@ export function createVolumes() { fs.mkdirSync(`${process.env.VIA_HOME}/volumes/btc-explorer/mysql`, { recursive: true }); + fs.mkdirSync(`${process.env.VIA_HOME}/volumes/celestia-keys`, { + recursive: true + }); } export async function up(composeFile?: string, envFilePath?: string) { From 8ee9188dc700c403925f99c7379a432ec16d7a47 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:55:43 +0100 Subject: [PATCH 113/212] fix: rename verifier config role --- core/lib/config/src/configs/via_verifier.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/lib/config/src/configs/via_verifier.rs b/core/lib/config/src/configs/via_verifier.rs index 609f0a3d3..636729aa7 100644 --- a/core/lib/config/src/configs/via_verifier.rs +++ b/core/lib/config/src/configs/via_verifier.rs @@ -6,7 +6,7 @@ use std::{ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub enum VerifierRole { +pub enum VerifierMode { VERIFIER = 0, COORDINATOR = 1, } @@ -28,7 +28,7 @@ pub struct ViaVerifierConfig { /// The minimum required signers. pub required_signers: usize, /// The role. - pub role: VerifierRole, + pub verifier_mode: VerifierMode, } impl ViaVerifierConfig { @@ -50,7 +50,7 @@ impl ViaVerifierConfig { verifiers_pub_keys_str: Vec::new(), bridge_address_str: "".to_string(), required_signers: 2, - role: VerifierRole::VERIFIER, + verifier_mode: VerifierMode::VERIFIER, } } } From 2ded87430b081c01ffc10b0ec0b416002c99b279 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:02:46 +0100 Subject: [PATCH 114/212] fix: withdrawal service task and api --- .../src/coordinator/api_impl.rs | 45 ++++++++---- .../node/withdrawal_service/src/types.rs | 4 +- .../node/withdrawal_service/src/utils.rs | 18 +++-- .../withdrawal_service/src/verifier/mod.rs | 70 +++++++++++++------ 4 files changed, 91 insertions(+), 46 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 69e8f97a4..1f38b93ac 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -3,7 +3,11 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::Context; use axum::{extract::State, response::Response, Json}; use base64::Engine; -use bitcoin::{hashes::Hash, Txid}; +use bitcoin::{ + hashes::Hash, + sighash::{Prevouts, SighashCache}, + TapSighashType, Txid, +}; use musig2::{BinaryEncoding, PubNonce}; use serde::Serialize; use tracing::instrument; @@ -51,7 +55,7 @@ impl RestApi { if l1_block_number != 0 { let withdrawal_tx = self_ .master_connection_pool - .connection_tagged("coordinator") + .connection_tagged("coordinator api") .await .unwrap() .via_votes_dal() @@ -77,7 +81,10 @@ impl RestApi { .unwrap(); if blocks.is_empty() { - return not_found("No block ready to process withdrawals found"); + if l1_block_number != 0 { + self_.reset_session().await; + } + return not_found("No block found for processing withdrawals"); } let mut withdrawals_to_process: Vec = Vec::new(); @@ -88,6 +95,7 @@ impl RestApi { .withdrawal_client .get_withdrawals(blob_id) .await + .context("Error to get withdrawals") .unwrap(); if !withdrawals.is_empty() { @@ -110,31 +118,33 @@ impl RestApi { } if withdrawals_to_process.is_empty() { - { - let mut session = self_.state.signing_session.write().await; - *session = SigningSession::default(); - } - return bad_request("There are no withdrawals to process in this block"); + self_.reset_session().await; + return not_found("There are no withdrawals to process"); } let unsigned_tx = self_ .withdrawal_builder .create_unsigned_withdrawal_tx(withdrawals_to_process, proof_txid) .await + .context("Error to create a unsigned withdrawal transaction") .unwrap(); - let message = unsigned_tx - .tx - .compute_txid() - .as_raw_hash() - .as_byte_array() - .to_vec(); + let mut sighash_cache = SighashCache::new(&unsigned_tx.tx); + let sighash_type = TapSighashType::All; + let mut txout_list = Vec::with_capacity(unsigned_tx.utxos.len()); + + for (_, txout) in unsigned_tx.utxos.clone() { + txout_list.push(txout); + } + let sighash = sighash_cache + .taproot_key_spend_signature_hash(0, &Prevouts::All(&txout_list), sighash_type) + .unwrap(); let new_sesssion = SigningSession { l1_block_number, received_nonces: HashMap::new(), received_sigs: HashMap::new(), - message: message.clone(), + message: sighash.to_byte_array().to_vec(), unsigned_tx: Some(unsigned_tx), }; @@ -234,4 +244,9 @@ impl RestApi { } ok_json(signatures) } + + pub async fn reset_session(&self) { + let mut session = self.state.signing_session.write().await; + *session = SigningSession::default(); + } } diff --git a/via_verifier/node/withdrawal_service/src/types.rs b/via_verifier/node/withdrawal_service/src/types.rs index bfe8ab5c2..e2f6703f8 100644 --- a/via_verifier/node/withdrawal_service/src/types.rs +++ b/via_verifier/node/withdrawal_service/src/types.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use via_btc_client::withdrawal_builder::UnsignedWithdrawalTx; -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct ViaWithdrawalState { pub signing_session: Arc>, pub required_signers: usize, @@ -36,7 +36,7 @@ pub struct PartialSignaturePair { pub signature: String, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct SigningSessionResponse { pub l1_block_number: i64, /// hex-encoded message (txid) diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index 4ed7bac1c..75297a194 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -2,6 +2,7 @@ use std::{clone::Clone, str::FromStr}; use anyhow::Context; use base64::Engine; +use bitcoin::PrivateKey; use musig2::{BinaryEncoding, PartialSignature, PubNonce}; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; use via_musig2::Signer; @@ -9,18 +10,19 @@ use via_musig2::Signer; use crate::types::{NoncePair, PartialSignaturePair}; pub fn get_signer( - private_key: &str, + private_key_wif: &str, verifiers_pub_keys_str: Vec, ) -> anyhow::Result { - let secret_key = - SecretKey::from_str(private_key).context("Error to compute the coordinator sk")?; + let private_key = PrivateKey::from_wif(private_key_wif)?; + let secret_key = SecretKey::from_byte_array(&private_key.inner.secret_bytes()) + .context("Error to compute the coordinator sk")?; let secp = Secp256k1::new(); let public_key = PublicKey::from_secret_key(&secp, &secret_key); let mut all_pubkeys = Vec::new(); - all_pubkeys.push(public_key); let mut signer_index = 0; + for (i, key) in verifiers_pub_keys_str.iter().enumerate() { let pk = PublicKey::from_slice(key.as_bytes())?; all_pubkeys.push(pk); @@ -34,7 +36,9 @@ pub fn get_signer( } pub fn decode_signature(signature: String) -> anyhow::Result { - let decoded_sig = base64::engine::general_purpose::STANDARD.decode(&signature)?; + let decoded_sig = base64::engine::general_purpose::STANDARD + .decode(&signature) + .context("error to decode signature")?; Ok(PartialSignature::from_slice(&decoded_sig)?) } @@ -59,7 +63,9 @@ pub fn encode_nonce(signer_index: usize, nonce: PubNonce) -> anyhow::Result anyhow::Result { - let decoded_nonce = base64::engine::general_purpose::STANDARD.decode(&nonce_pair.nonce)?; + let decoded_nonce = base64::engine::general_purpose::STANDARD + .decode(&nonce_pair.nonce) + .context("error to encode nonde")?; let pub_nonce = PubNonce::from_bytes(&decoded_nonce)?; Ok(pub_nonce) } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index f35d4430b..3f3183290 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,9 +1,9 @@ use std::{collections::HashMap, sync::Arc}; -use anyhow::Result; +use anyhow::{Context, Result}; use bitcoin::{hashes::Hash, TapSighashType, Witness}; use musig2::{CompactSignature, PartialSignature}; -use reqwest::{Client, StatusCode}; +use reqwest::{header, Client, StatusCode}; use tokio::sync::watch; use via_btc_client::{ traits::{BitcoinOps, Serializable}, @@ -11,20 +11,22 @@ use via_btc_client::{ }; use via_musig2::{verify_signature, Signer}; use via_verifier_dal::{ConnectionPool, Verifier, VerifierDal}; -use zksync_config::configs::via_verifier::{VerifierRole, ViaVerifierConfig}; +use zksync_config::configs::via_verifier::{VerifierMode, ViaVerifierConfig}; use zksync_types::H256; use crate::{ - types::{NoncePair, SigningSessionResponse}, + types::{NoncePair, PartialSignaturePair, SigningSessionResponse}, utils::{decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer}, }; +#[derive(Debug)] pub struct ViaWithdrawalVerifier { master_connection_pool: ConnectionPool, btc_client: Arc, config: ViaVerifierConfig, client: Client, signer: Signer, + final_sig: Option, } impl ViaWithdrawalVerifier { @@ -44,6 +46,7 @@ impl ViaWithdrawalVerifier { signer, client: Client::new(), config, + final_sig: None, }) } @@ -71,12 +74,18 @@ impl ViaWithdrawalVerifier { } async fn loop_iteration(&mut self) -> Result<(), anyhow::Error> { - if self.config.role == VerifierRole::COORDINATOR { + if self.config.verifier_mode == VerifierMode::COORDINATOR { self.create_new_session().await?; + + tracing::info!("create a new session"); self.build_and_broadcast_final_transaction().await?; } let session_info = self.get_session().await?; + if session_info.l1_block_number == 0 { + tracing::info!("Empty session, nothing to process"); + return Ok(()); + } let session_signature = self.get_session_signatures().await?; let session_nonces = self.get_session_nonces().await?; @@ -118,7 +127,7 @@ impl ViaWithdrawalVerifier { } async fn get_session(&self) -> anyhow::Result { - let url = format!("{}/session/", self.config.url); + let url = format!("{}/session", self.config.url); let resp = self.client.get(&url).send().await?; if resp.status().as_u16() != StatusCode::OK.as_u16() { anyhow::bail!("Error to fetch the session"); @@ -129,7 +138,7 @@ impl ViaWithdrawalVerifier { async fn get_session_nonces(&self) -> anyhow::Result> { // We need to fetch all nonces from the coordinator - let nonces_url = format!("{}/session/nonce/", self.config.url); + let nonces_url = format!("{}/session/nonce", self.config.url); let resp = self.client.get(&nonces_url).send().await?; let nonces: HashMap = resp.json().await?; Ok(nonces) @@ -142,7 +151,7 @@ impl ViaWithdrawalVerifier { .ok_or_else(|| anyhow::anyhow!("No nonce available"))?; let nonce_pair = encode_nonce(self.signer.signer_index(), nonce).unwrap(); - let url = format!("{}/session/nonce/", self.config.url); + let url = format!("{}/session/nonce", self.config.url); let res = self.client.post(&url).json(&nonce_pair).send().await?; if res.status().is_success() { @@ -153,12 +162,12 @@ impl ViaWithdrawalVerifier { } async fn get_session_signatures(&self) -> anyhow::Result> { - let url = format!("{}/session/signature/", self.config.url); + let url = format!("{}/session/signature", self.config.url); let resp = self.client.get(&url).send().await?; - let signatures: HashMap = resp.json().await?; + let signatures: HashMap = resp.json().await?; let mut partial_sigs: HashMap = HashMap::new(); for (idx, sig) in signatures { - partial_sigs.insert(idx, decode_signature(sig).unwrap()); + partial_sigs.insert(idx, decode_signature(sig.signature).unwrap()); } Ok(partial_sigs) } @@ -183,7 +192,7 @@ impl ViaWithdrawalVerifier { let partial_sig = self.signer.create_partial_signature()?; let sig_pair = encode_signature(self.signer.signer_index(), partial_sig)?; - let url = format!("{}/session/signature/", self.config.url,); + let url = format!("{}/session/signature", self.config.url,); let resp = self.client.post(&url).json(&sig_pair).send().await?; if resp.status().is_success() { self.signer.mark_partial_sig_submitted(); @@ -197,29 +206,39 @@ impl ViaWithdrawalVerifier { self.config.verifiers_pub_keys_str.clone(), )?; self.signer = signer; + self.final_sig = None; Ok(()) } async fn create_new_session(&mut self) -> anyhow::Result<()> { let session_info = self.get_session().await?; if session_info.l1_block_number == 0 { - let url = format!("{}/session/new/", self.config.url,); - let resp = self.client.post(&url).send().await?; + let url = format!("{}/session/new", self.config.url,); + let resp = self + .client + .post(&url) + .header(header::CONTENT_TYPE, "application/json") + .send() + .await?; + + println!("{:?}", resp); if !resp.status().is_success() {} } Ok(()) } - async fn create_final_signature(&mut self) -> anyhow::Result> { + async fn create_final_signature(&mut self) -> anyhow::Result<()> { + if self.final_sig.is_some() { + return Ok(()); + } let session_info = self.get_session().await?; if session_info.received_partial_signatures >= session_info.required_signers { let signatures = self.get_session_signatures().await?; - if session_info.received_partial_signatures >= session_info.required_signers { - for (&i, sig) in &signatures { - if self.signer.signer_index() != i { - self.signer.receive_partial_signature(i, *sig)?; - } + for (&i, sig) in &signatures { + println!("1"); + if self.signer.signer_index() != i { + self.signer.receive_partial_signature(i, *sig)?; } } @@ -230,9 +249,11 @@ impl ViaWithdrawalVerifier { final_sig, &hex::decode(&session_info.message_to_sign)?, )?; - return Ok(Some(final_sig)); + self.final_sig = Some(final_sig); + + return Ok(()); } - Ok(None) + Ok(()) } fn sign_transaction( @@ -252,8 +273,11 @@ impl ViaWithdrawalVerifier { async fn build_and_broadcast_final_transaction(&mut self) -> anyhow::Result<()> { let session_info = self.get_session().await?; + self.create_final_signature() + .await + .context("Error create final signature")?; - if let Some(musig2_signature) = self.create_final_signature().await? { + if let Some(musig2_signature) = self.final_sig { let withdrawal_txid = self .master_connection_pool .connection_tagged("coordinator task") From 7eff82a489e5ec615299c98bfe0de41a56e99318 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:04:15 +0100 Subject: [PATCH 115/212] clean: remove unused imports --- via_verifier/lib/via_withdrawal_client/src/types.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/via_verifier/lib/via_withdrawal_client/src/types.rs b/via_verifier/lib/via_withdrawal_client/src/types.rs index 22bdcd3be..056572d2b 100644 --- a/via_verifier/lib/via_withdrawal_client/src/types.rs +++ b/via_verifier/lib/via_withdrawal_client/src/types.rs @@ -1,7 +1,6 @@ use std::io::Read; use anyhow::Context; -use bitcoin::{address::NetworkUnchecked, Address as BitcoinAddress}; use byteorder::{BigEndian, ReadBytesExt}; use zksync_types::{Address, H160, H256, U256}; use zksync_utils::{u256_to_bytes_be, u256_to_h256}; @@ -19,15 +18,6 @@ pub struct L2BridgeLogMetadata { pub message: Vec, } -#[derive(Clone, Debug)] -#[allow(unused)] -pub struct WithdrawalRequest { - /// The receiver l1 address. - pub address: BitcoinAddress, - /// The amount user will receive. - pub amount: U256, -} - /// Corresponds to the following solidity event: /// ```solidity /// struct L2ToL1Log { From e7d8189f75db26d8aee7dd96ec735ec5a9519e29 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 13 Jan 2025 14:06:39 +0330 Subject: [PATCH 116/212] feat(via): fix clippy warning --- via_verifier/node/via_zk_verifier/src/lib.rs | 2 +- via_verifier/node/withdrawal_service/src/utils.rs | 2 -- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/via_verifier/node/via_zk_verifier/src/lib.rs b/via_verifier/node/via_zk_verifier/src/lib.rs index 81ed13b48..d1411851b 100644 --- a/via_verifier/node/via_zk_verifier/src/lib.rs +++ b/via_verifier/node/via_zk_verifier/src/lib.rs @@ -197,7 +197,7 @@ impl ViaVerifier { batch_len = batch_bytes.len(), "Verifying proof" ); - let proof_data: ProveBatches = bincode::deserialize(&proof_bytes)?; + let proof_data: ProveBatches = bincode::deserialize(proof_bytes)?; if proof_data.l1_batches.len() != 1 { tracing::error!( diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index 75297a194..795617aed 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -1,5 +1,3 @@ -use std::{clone::Clone, str::FromStr}; - use anyhow::Context; use base64::Engine; use bitcoin::PrivateKey; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index cecfe6e74..f966c8e61 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -20,7 +20,6 @@ use crate::{ utils::{decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer}, }; -#[derive(Debug)] pub struct ViaWithdrawalVerifier { master_connection_pool: ConnectionPool, btc_client: Arc, From 1a24f3fd1724888bd14e17defb7944d95b287ec6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:59:29 +0100 Subject: [PATCH 117/212] fix: parse public key --- via_verifier/node/withdrawal_service/src/utils.rs | 4 +++- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index 795617aed..dc8b906ec 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use anyhow::Context; use base64::Engine; use bitcoin::PrivateKey; @@ -22,7 +24,7 @@ pub fn get_signer( let mut signer_index = 0; for (i, key) in verifiers_pub_keys_str.iter().enumerate() { - let pk = PublicKey::from_slice(key.as_bytes())?; + let pk = PublicKey::from_str(key)?; all_pubkeys.push(pk); if pk == public_key { signer_index = i; diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index f966c8e61..1826ff36a 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -12,7 +12,6 @@ use via_btc_client::{ use via_musig2::{verify_signature, Signer}; use via_verifier_dal::{ConnectionPool, Verifier, VerifierDal}; use zksync_config::configs::via_verifier::{VerifierMode, ViaVerifierConfig}; - use zksync_types::H256; use crate::{ From 1fd7370490311861f1dc80e3759e21e19307b9a1 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:11:01 +0100 Subject: [PATCH 118/212] feat: add debug and update package --- via_verifier/lib/via_musig2/Cargo.toml | 5 ++++- via_verifier/lib/via_musig2/src/lib.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/via_verifier/lib/via_musig2/Cargo.toml b/via_verifier/lib/via_musig2/Cargo.toml index b40d36994..130780d80 100644 --- a/via_verifier/lib/via_musig2/Cargo.toml +++ b/via_verifier/lib/via_musig2/Cargo.toml @@ -23,7 +23,10 @@ reqwest.workspace = true bitcoincore-rpc = "0.19.0" bitcoin = { version = "0.32.2", features = ["serde"] } musig2 = "0.2.0" -secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = ["rand"]} +secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = [ + "rand", + "hashes", +] } tokio = { version = "1.0", features = ["full"] } axum = "0.6" uuid = { version = "1.3", features = ["v4"] } diff --git a/via_verifier/lib/via_musig2/src/lib.rs b/via_verifier/lib/via_musig2/src/lib.rs index ddb316d92..841261ab0 100644 --- a/via_verifier/lib/via_musig2/src/lib.rs +++ b/via_verifier/lib/via_musig2/src/lib.rs @@ -44,6 +44,19 @@ pub struct Signer { partial_sig_submitted: bool, } +impl fmt::Debug for Signer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Signer") + .field("_public_key", &self._public_key) + .field("signer_index", &self.signer_index) + .field("key_agg_ctx", &self.key_agg_ctx) + .field("message", &self.message) + .field("nonce_submitted", &self.nonce_submitted) + .field("partial_sig_submitted", &self.partial_sig_submitted) + .finish() + } +} + impl Signer { /// Create a new signer with the given secret key and index pub fn new( From 1f5696f314d0f6b30bba3d1f0a07976f461ddf60 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:07:38 +0100 Subject: [PATCH 119/212] clean: remove println --- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 1826ff36a..40e7a2375 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -220,7 +220,6 @@ impl ViaWithdrawalVerifier { .send() .await?; - println!("{:?}", resp); if !resp.status().is_success() {} } Ok(()) From 6eb65a59e329fb17cae3de9101992d78c05fdbc5 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:10:46 +0100 Subject: [PATCH 120/212] feat: refactor via config and add verifier and coordinator configs --- etc/env/configs/via_base.toml | 3 --- etc/env/configs/via_coordinator.toml | 27 ++++++++++++++++++++++++++- etc/env/configs/via_verifier.toml | 27 ++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml index c47ecaeec..57dea7ef2 100644 --- a/etc/env/configs/via_base.toml +++ b/etc/env/configs/via_base.toml @@ -32,9 +32,6 @@ api_node_url = "http://0.0.0.0:26658" auth_token = "" blob_size_limit = 1973786 -[via_verifier] -poll_interval = 1000 - [rust] log = """\ warn,\ diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index 16ed64eb1..573cdc698 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -1 +1,26 @@ -__imports__ = [ "base", "l2-inits/via_coordinator.init.env", "configs/via_base.toml" ] +__imports__ = [ + "base", + "l2-inits/via_coordinator.init.env", + "configs/via_base.toml", +] + +[via_verifier] +# Interval between polling db for verification requests (in ms). +poll_interval = 10000 +# Coordinator server port. +port = 6060 +# Coordinator server url. +url = "http://0.0.0.0:6060" +# The signer private key. +private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" +# The verifiers public keys. +verifiers_pub_keys_str = [ + "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", + "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", +] +# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` +bridge_address_str = "bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv" +# The minimum required signers. +required_signers = 2 +# The verifier_mode can be simple verifier or coordinator. +verifier_mode = "COORDINATOR" diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index ce2ed419f..85e989e78 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -1 +1,26 @@ -__imports__ = [ "base", "l2-inits/via_verifier.init.env", "configs/via_base.toml" ] +__imports__ = [ + "base", + "l2-inits/via_verifier.init.env", + "configs/via_base.toml", +] + +[via_verifier] +# Interval between polling db for verification requests (in ms). +poll_interval = 10000 +# Coordinator server port. +port = 6060 +# Coordinator server url. +url = "http://0.0.0.0:6060" +# The signer private key. +private_key = "L3EGCjrX7ZTmUa2U7eL7akmBYoJB4FgNY8BpY8qwU5izy6k5D72m" +# The verifiers public keys. +verifiers_pub_keys_str = [ + "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", + "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", +] +# The bridge address. +bridge_address_str = "" +# The minimum required signers. +required_signers = 2 +# The verifier_mode can be simple verifier or coordinator. +verifier_mode = "VERIFIER" From cdb789a1da615431ab8f1bcd094657b16ccd59bd Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:11:54 +0100 Subject: [PATCH 121/212] feat: add verifier init logic to the infrastructure --- Makefile | 29 +++++++++++----------- docker-compose-via.yml | 9 ++++--- infrastructure/via/src/init.ts | 40 +++++++++++++++++++++++++----- infrastructure/via/src/types.ts | 5 ++++ infrastructure/via/src/verifier.ts | 11 +++----- 5 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 infrastructure/via/src/types.ts diff --git a/Makefile b/Makefile index 76e6fca89..c8b7a9f6e 100644 --- a/Makefile +++ b/Makefile @@ -9,14 +9,17 @@ CLI_TOOL = via CMD := $(firstword $(MAKECMDGOALS)) VIA_ENV ?= via DIFF ?= 0 +MODE ?= sequencer # Select the via env ifeq ($(CMD), via-verifier) VIA_ENV := via_verifier DIFF := 1 + MODE := verifier else ifeq ($(CMD), via-coordinator) VIA_ENV := via_coordinator DIFF := 2 + MODE := coordinator endif # Default target: Show help message @@ -54,19 +57,23 @@ help: # Run the basic setup workflow in sequence .PHONY: via -via: env config init transactions celestia bootstrap server-genesis server +via: base transactions celestia bootstrap server-genesis server # Run the full setup workflow in sequence .PHONY: all -all: env config init transactions celestia btc-explorer bootstrap server-genesis server +all: base transactions celestia btc-explorer bootstrap server-genesis server # Run the basic setup workflow in verifier .PHONY: via-verifier -via-verifier: env config verifier +via-verifier: base celestia verifier # Run the basic setup workflow in coordinator -.PHONY: via-verifier -via-coordinator: env config coordinator +.PHONY: via-coordinator +via-coordinator: base celestia verifier + +# Run minimal required setup +.PHONY: base +base: env config init # Run 'via env via' .PHONY: env @@ -90,7 +97,7 @@ init: @echo "------------------------------------------------------------------------------------" @echo "$(YELLOW)Initializing the project...$(RESET)" @echo "------------------------------------------------------------------------------------" - @$(CLI_TOOL) init + @$(CLI_TOOL) init --mode ${MODE} # Run 'via transactions' .PHONY: transactions @@ -144,18 +151,10 @@ server: .PHONY: verifier verifier: @echo "------------------------------------------------------------------------------------" - @echo "$(YELLOW)Running the verifier software...$(RESET)" + @echo "$(YELLOW)Running the verifier/coordinator software...$(RESET)" @echo "------------------------------------------------------------------------------------" @$(CLI_TOOL) verifier -# Run 'via verifier --coordinator' -.PHONY: coordinator -coordinator: - @echo "------------------------------------------------------------------------------------" - @echo "$(YELLOW)Running the coordinator software...$(RESET)" - @echo "------------------------------------------------------------------------------------" - @$(CLI_TOOL) verifier --coordinator - # Run 'via clean' .PHONY: clean clean: diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 9fe2321dd..a44e4f3b5 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -92,6 +92,7 @@ services: - VERIFIER_1_ADDRESS=bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv - VERIFIER_2_ADDRESS=bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4 - VERIFIER_3_ADDRESS=bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm + - BRIDGE_ADDRESS=bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv - RPC_ARGS=-chain=regtest -rpcconnect=bitcoind -rpcwait -rpcuser=rpcuser -rpcpassword=rpcpassword - SLEEP_SECONDS=5 @@ -113,10 +114,10 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia - - type: bind - source: ./volumes/celestia-keys - target: /root/.celestia-light-mocha-4/keys + target: /home/celestia:rw + # - type: bind + # source: ./volumes/celestia-keys + # target: /root/.celestia-light-mocha-4/keys command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip full.consensus.mocha-4.celestia-mocha.com --p2p.network mocha ports: - '26658:26658' diff --git a/infrastructure/via/src/init.ts b/infrastructure/via/src/init.ts index 2bc7e480c..0976dcc4f 100644 --- a/infrastructure/via/src/init.ts +++ b/infrastructure/via/src/init.ts @@ -9,9 +9,8 @@ import * as contract from './contract'; import * as db from './database'; import * as docker from './docker'; import * as env from './env'; -import * as config from './config'; import * as run from './run'; -// import * as server from './server'; +import { Mode } from './types'; import { createVolumes, up } from './up'; import path from 'path'; @@ -70,13 +69,24 @@ const initSetup = async ({ ]); }; -const initDatabase = async (shouldCheck: boolean = true): Promise => { - await announced('Drop postgres db', db.drop({ core: true, prover: true, verifier: true })); - await announced('Setup postgres db', db.setup({ core: true, prover: true, verifier: true }, shouldCheck)); +const initDatabase = async ( + shouldCheck: boolean = true, + core = true, + prover = true, + verifier = false +): Promise => { + await announced('Drop postgres db', db.drop({ core, prover, verifier })); + await announced('Setup postgres db', db.setup({ core, prover, verifier }, shouldCheck)); await announced('Clean rocksdb', clean(`db/${process.env.VIA_ENV!}`)); await announced('Clean backups', clean(`backups/${process.env.VIA_ENV!}`)); }; +const initVerifierSetup = async (skipEnvSetup: boolean): Promise => { + await announced(`Initializing the verifier'}`); + await announced('Checking environment', checkEnv()); + await initDatabase(true, false, false, true); +}; + // Deploys ERC20 and WETH tokens to localhost // ? // type DeployTestTokensOptions = { envFile?: string }; @@ -116,6 +126,7 @@ type InitDevCmdActionOptions = InitSetupOptions & { baseTokenName?: string; localLegacyBridgeTesting?: boolean; shouldCheckPostgres: boolean; // Whether to perform `cargo sqlx prepare --check` + mode: Mode; }; export const initDevCmdAction = async ({ skipEnvSetup, @@ -147,6 +158,22 @@ export const initDevCmdAction = async ({ } }; +export const initVerifierDevCmdAction = async ({ skipEnvSetup }: InitDevCmdActionOptions): Promise => { + await initVerifierSetup(skipEnvSetup); +}; + +const init = async (options: InitDevCmdActionOptions) => { + switch (options.mode) { + case Mode.SEQUENCER: + return await initDevCmdAction(options); + case Mode.VERIFIER: + case Mode.COORDINATOR: + return await initVerifierDevCmdAction(options); + default: + throw new Error('Invalid init mode'); + } +}; + // ########################### Command Definitions ########################### export const initCommand = new Command('init') .option('--skip-submodules-checkout') @@ -155,10 +182,11 @@ export const initCommand = new Command('init') .option('--base-token-name ', 'base token name') // ? // .option('--validium-mode', 'deploy contracts in Validium mode') .option('--run-observability', 'run observability suite') + .option('--mode [type]', 'init mode', Mode.SEQUENCER) .option( '--local-legacy-bridge-testing', 'used to test LegacyBridge compatibily. The chain will have the same id as the era chain id, while eraChainId in L2SharedBridge will be 0' ) .option('--should-check-postgres', 'Whether to perform cargo sqlx prepare --check during database setup', true) .description('Deploys the shared bridge and registers a hyperchain locally, as quickly as possible.') - .action(initDevCmdAction); + .action(init); diff --git a/infrastructure/via/src/types.ts b/infrastructure/via/src/types.ts new file mode 100644 index 000000000..b0153cf3a --- /dev/null +++ b/infrastructure/via/src/types.ts @@ -0,0 +1,5 @@ +export enum Mode { + SEQUENCER = 'sequencer', + VERIFIER = 'verifier', + COORDINATOR = 'coordinator' +} diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index c394397f3..693d62585 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -2,19 +2,14 @@ import { Command } from 'commander'; import * as utils from 'utils'; import * as env from './env'; -export async function verifier(isCoordinator: boolean) { +export async function verifier() { let options = ''; - console.log('Is Verifier Coordinator Instance', isCoordinator); - if (isCoordinator) { - options += '--coordinator'; - } - await utils.spawn(`cargo run --bin via_verifier -- ${options}`); + await utils.spawn(`cargo run --bin via_verifier`); } export const verifierCommand = new Command('verifier') .description('start via verifier node') - .option('--coordinator', 'start the verifier node as coordinator', false) .action(async (cmd: Command) => { cmd.chainName ? env.reload(cmd.chainName) : env.load(); - await verifier(cmd.coordinator); + await verifier(); }); From 871e7ffb2e5123ff1076c0a591ffacead1d8d45b Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:13:02 +0100 Subject: [PATCH 122/212] feat: add coordinator, verifier and da layers to the via verifier orchestration layer --- .../bin/verifier_server/src/config.rs | 19 ++++-- via_verifier/bin/verifier_server/src/main.rs | 15 +--- .../bin/verifier_server/src/node_builder.rs | 68 +++++++++++++++---- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/via_verifier/bin/verifier_server/src/config.rs b/via_verifier/bin/verifier_server/src/config.rs index 60a948842..a80bb05e9 100644 --- a/via_verifier/bin/verifier_server/src/config.rs +++ b/via_verifier/bin/verifier_server/src/config.rs @@ -11,7 +11,7 @@ use zksync_config::{ ProtectiveReadsWriterConfig, }, ApiConfig, DADispatcherConfig, DBConfig, ObjectStoreConfig, PostgresConfig, ViaBtcSenderConfig, - ViaBtcWatchConfig, ViaCelestiaConfig, + ViaBtcWatchConfig, ViaCelestiaConfig, ViaVerifierConfig, }; use zksync_core_leftovers::temp_config_store::{decode_yaml_repr, TempConfigStore}; use zksync_env_config::FromEnv; @@ -84,14 +84,25 @@ pub(crate) fn load_env_config() -> anyhow::Result { } // TODO: temporary solution, should be removed after the config is refactored -pub(crate) fn via_load_env_config( -) -> anyhow::Result<(ViaBtcWatchConfig, ViaBtcSenderConfig, ViaCelestiaConfig)> { +pub(crate) fn via_load_env_config() -> anyhow::Result<( + ViaBtcWatchConfig, + ViaBtcSenderConfig, + ViaCelestiaConfig, + ViaVerifierConfig, +)> { let btc_watch_config = ViaBtcWatchConfig::from_env().context("Failed to load BTC watch config")?; let btc_sender_config = ViaBtcSenderConfig::from_env().context("Failed to load BTC sender config")?; let celestia_config = ViaCelestiaConfig::from_env().context("Failed to load celestia config")?; + let verifier_config = + ViaVerifierConfig::from_env().context("Failed to load verifier config")?; - Ok((btc_watch_config, btc_sender_config, celestia_config)) + Ok(( + btc_watch_config, + btc_sender_config, + celestia_config, + verifier_config, + )) } diff --git a/via_verifier/bin/verifier_server/src/main.rs b/via_verifier/bin/verifier_server/src/main.rs index f76dc9544..1b02099d8 100644 --- a/via_verifier/bin/verifier_server/src/main.rs +++ b/via_verifier/bin/verifier_server/src/main.rs @@ -16,10 +16,6 @@ static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; #[derive(Debug, Parser)] #[command(author = "Via verifer", version, about = "Via verifer node", long_about = None)] struct Cli { - /// Run the verifier node as coordinator. - #[arg(long)] - coordinator: bool, - /// Path to the YAML config. If set, it will be used instead of env vars. #[arg(long)] config_path: Option, @@ -61,6 +57,7 @@ fn main() -> anyhow::Result<()> { via_general.via_btc_watch_config = Some(via_configs.0); via_general.via_btc_sender_config = Some(via_configs.1); via_general.via_celestia_config = Some(via_configs.2); + via_general.via_verifier_config = Some(via_configs.3); via_general } }; @@ -105,14 +102,8 @@ fn main() -> anyhow::Result<()> { .clone() .context("Observability config missing")?; - let node_builder = node_builder::ViaNodeBuilder::new( - opt.coordinator, - configs, - wallets, - secrets, - genesis, - contracts_config, - )?; + let node_builder = + node_builder::ViaNodeBuilder::new(configs, wallets, secrets, genesis, contracts_config)?; let observability_guard = { // Observability initialization should be performed within tokio context. diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 6b393f4e4..34bf3261c 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -1,12 +1,19 @@ use anyhow::Context; +use via_da_clients::celestia::wiring_layer::ViaCelestiaClientWiringLayer; use zksync_config::{ - configs::{wallets::Wallets, Secrets}, + configs::{via_verifier::VerifierMode, wallets::Wallets, Secrets}, ActorRole, ContractsConfig, GenesisConfig, ViaGeneralConfig, }; use zksync_node_framework::{ implementations::layers::{ - circuit_breaker_checker::CircuitBreakerCheckerLayer, healtcheck_server::HealthCheckLayer, - pools_layer::PoolsLayerBuilder, sigint::SigintHandlerLayer, + circuit_breaker_checker::CircuitBreakerCheckerLayer, + healtcheck_server::HealthCheckLayer, + pools_layer::PoolsLayerBuilder, + sigint::SigintHandlerLayer, + via_btc_watch::BtcWatchLayer, + via_verifier::{ + coordinator_api::ViaCoordinatorApiLayer, verifier::ViaWithdrawalVerifierLayer, + }, via_verifier_btc_watch::VerifierBtcWatchLayer, }, service::{ZkStackService, ZkStackServiceBuilder}, @@ -21,7 +28,7 @@ macro_rules! try_load_config { } pub struct ViaNodeBuilder { - coordinator: bool, + is_coordinator: bool, node: ZkStackServiceBuilder, configs: ViaGeneralConfig, wallets: Wallets, @@ -32,15 +39,16 @@ pub struct ViaNodeBuilder { impl ViaNodeBuilder { pub fn new( - coordinator: bool, via_general_config: ViaGeneralConfig, wallets: Wallets, secrets: Secrets, genesis_config: GenesisConfig, contracts_config: ContractsConfig, ) -> anyhow::Result { + let via_verifier_config = try_load_config!(via_general_config.via_verifier_config); + let is_coordinator = via_verifier_config.verifier_mode == VerifierMode::COORDINATOR; Ok(Self { - coordinator, + is_coordinator, node: ZkStackServiceBuilder::new().context("Cannot create ZkStackServiceBuilder")?, configs: via_general_config, wallets, @@ -59,6 +67,14 @@ impl ViaNodeBuilder { Ok(self) } + fn add_via_celestia_da_client_layer(mut self) -> anyhow::Result { + let celestia_config = try_load_config!(self.configs.via_celestia_config); + println!("{:?}", celestia_config); + self.node + .add_layer(ViaCelestiaClientWiringLayer::new(celestia_config)); + Ok(self) + } + fn add_healthcheck_layer(mut self) -> anyhow::Result { let healthcheck_config = try_load_config!(self.configs.api_config).healthcheck; self.node.add_layer(HealthCheckLayer(healthcheck_config)); @@ -96,14 +112,42 @@ impl ViaNodeBuilder { Ok(self) } - pub fn build(self) -> anyhow::Result { - Ok(self - .add_pools_layer()? + fn add_verifier_coordinator_api_layer(mut self) -> anyhow::Result { + let via_verifier_config = try_load_config!(self.configs.via_verifier_config); + let via_btc_sender_config = try_load_config!(self.configs.via_btc_sender_config); + self.node.add_layer(ViaCoordinatorApiLayer { + config: via_verifier_config, + btc_sender_config: via_btc_sender_config, + }); + Ok(self) + } + + fn add_withdrawal_verifier_task_layer(mut self) -> anyhow::Result { + let via_verifier_config = try_load_config!(self.configs.via_verifier_config); + let via_btc_sender_config = try_load_config!(self.configs.via_btc_sender_config); + self.node.add_layer(ViaWithdrawalVerifierLayer { + config: via_verifier_config, + btc_sender_config: via_btc_sender_config, + }); + Ok(self) + } + + pub fn build(mut self) -> anyhow::Result { + self = self .add_sigint_handler_layer()? .add_healthcheck_layer()? .add_circuit_breaker_checker_layer()? - .add_verifier_btc_watcher_layer()? - .node - .build()) + .add_pools_layer()?; + // .add_verifier_btc_watcher_layer()?; + + if self.is_coordinator { + self = self + .add_via_celestia_da_client_layer()? + .add_verifier_coordinator_api_layer()?; + } + + self = self.add_withdrawal_verifier_task_layer()?; + + Ok(self.node.build()) } } From bddf1d783347caa1d36063f0b8b36f6ebc1fdc8a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 09:40:50 +0100 Subject: [PATCH 123/212] fix: docker compose --- docker-compose-via.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index a44e4f3b5..890dead3a 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -114,7 +114,7 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia:rw + target: /home/celestia # - type: bind # source: ./volumes/celestia-keys # target: /root/.celestia-light-mocha-4/keys From 96cb1964ccf39fab8dde679a34335bb308992788 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:03:32 +0100 Subject: [PATCH 124/212] fix: use provided pubkeys to compute the bridge address instead of generating new ones --- via_verifier/lib/via_musig2/examples/key_generation_setup.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs index 8efd408dc..44f14f60c 100644 --- a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs +++ b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs @@ -82,8 +82,8 @@ fn main() -> Result<(), Box> { } let mut pubkeys = Vec::new(); - for _i in 2..args.len() { - let (_, public_key) = generate_keypair(); + for i in 2..args.len() { + let public_key = PublicKey::from_str(&args[i]).unwrap(); pubkeys.push(public_key); } From 28d071364f3f6b4a0d87041c085eb41028c61b4e Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:05:58 +0100 Subject: [PATCH 125/212] clean: remove comment --- via_verifier/lib/via_musig2/examples/key_generation_setup.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs index 44f14f60c..12fbd48fa 100644 --- a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs +++ b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs @@ -19,8 +19,6 @@ struct CoordinatorOutput { bridge_address: BitcoinAddress, } -// TODO: Add mechanism to validate generated address for bridge is valid and contain all contributors' pubkeys - fn generate_keypair() -> (SecretKey, PublicKey) { let mut rng = OsRng; let secp = Secp256k1::new(); From 40012f78d88754df85c86a2e07abd68045771a7b Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:35:56 +0100 Subject: [PATCH 126/212] clean: remove verifier config from the sequencer --- core/bin/via_server/src/config.rs | 20 ++++---------------- core/bin/via_server/src/main.rs | 1 - 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/core/bin/via_server/src/config.rs b/core/bin/via_server/src/config.rs index 1251a909a..427373973 100644 --- a/core/bin/via_server/src/config.rs +++ b/core/bin/via_server/src/config.rs @@ -11,7 +11,7 @@ use zksync_config::{ ProtectiveReadsWriterConfig, }, ApiConfig, DADispatcherConfig, DBConfig, EthConfig, GasAdjusterConfig, ObjectStoreConfig, - PostgresConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, ViaVerifierConfig, + PostgresConfig, ViaBtcSenderConfig, ViaBtcWatchConfig, ViaCelestiaConfig, }; use zksync_core_leftovers::temp_config_store::{decode_yaml_repr, TempConfigStore}; use zksync_env_config::FromEnv; @@ -84,26 +84,14 @@ pub(crate) fn load_env_config() -> anyhow::Result { } // TODO: temporary solution, should be removed after the config is refactored -pub(crate) fn via_load_env_config() -> anyhow::Result<( - ViaBtcWatchConfig, - ViaBtcSenderConfig, - ViaCelestiaConfig, - ViaVerifierConfig, -)> { +pub(crate) fn via_load_env_config( +) -> anyhow::Result<(ViaBtcWatchConfig, ViaBtcSenderConfig, ViaCelestiaConfig)> { let btc_watch_config = ViaBtcWatchConfig::from_env().context("Failed to load BTC watch config")?; let btc_sender_config = ViaBtcSenderConfig::from_env().context("Failed to load BTC sender config")?; let celestia_config = ViaCelestiaConfig::from_env().context("Failed to load celestia config")?; - // TODO: tmp - let verifier_config = - ViaVerifierConfig::from_env().context("Failed to load verifier config")?; - Ok(( - btc_watch_config, - btc_sender_config, - celestia_config, - verifier_config, - )) + Ok((btc_watch_config, btc_sender_config, celestia_config)) } diff --git a/core/bin/via_server/src/main.rs b/core/bin/via_server/src/main.rs index cadfbca0d..f2568296b 100644 --- a/core/bin/via_server/src/main.rs +++ b/core/bin/via_server/src/main.rs @@ -60,7 +60,6 @@ fn main() -> anyhow::Result<()> { via_general.via_btc_watch_config = Some(via_configs.0); via_general.via_btc_sender_config = Some(via_configs.1); via_general.via_celestia_config = Some(via_configs.2); - via_general.via_verifier_config = Some(via_configs.3); via_general } }; From f83f773d318087c2050802e96a2fa7b0be6897f6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:14:25 +0100 Subject: [PATCH 127/212] feat: migrate btc_sender dal from core to via_verifier --- ...919_add_verifier_vote_inscription.down.sql | 1 - ...91919_add_verifier_vote_inscription.up.sql | 8 - core/lib/dal/src/lib.rs | 8 - ...f3af3edce16051e8987a27ea207bfe9b65502.json | 82 ++++++ ...6857119c57c7ff5194a546d24fec0e3cf3059.json | 56 +++++ ...8cc9601afc6a4f86f930c9ceff02fae5c02dc.json | 58 +++++ ...d62244613761e41e811705611d75fbe48ad1a.json | 28 +++ ...7a23c11c6079a7d4f715a7387d9a96a91c52c.json | 60 +++++ ...1daff666fe04dd45246eb94c961eed1dba2d7.json | 15 ++ ...a2da09357ece059755139e698acbc050a7673.json | 22 ++ ...a233d81fc65d08215d6057e750ad72fbd7cce.json | 14 ++ ...8eef1a09c549c5c62c77b5527f771ae6370b0.json | 0 ...a4a2263af9c4aa330638ffdc8c380aafa6d3a.json | 0 via_verifier/lib/verifier_dal/Cargo.toml | 2 + ..._add_via_btc_inscription_requests.down.sql | 2 + ...23_add_via_btc_inscription_requests.up.sql | 34 +++ via_verifier/lib/verifier_dal/src/lib.rs | 16 +- .../lib/verifier_dal/src/models/mod.rs | 1 + .../models/storage_btc_inscription_request.rs | 62 +++++ .../lib/verifier_dal/src/via_blocks_dal.rs | 9 +- .../verifier_dal/src/via_btc_sender_dal.rs | 237 ++++++++++++++++++ 21 files changed, 692 insertions(+), 23 deletions(-) delete mode 100644 core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql delete mode 100644 core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-110825e736943e4ef68110e8d7af3af3edce16051e8987a27ea207bfe9b65502.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-2082d20e3b547a7385c174892d96857119c57c7ff5194a546d24fec0e3cf3059.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-2147add1c47a8b86de081f060458cc9601afc6a4f86f930c9ceff02fae5c02dc.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-3229aefe26d77c22cee31dd506cd62244613761e41e811705611d75fbe48ad1a.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-5644db74e4626d2c689b1a24c8b7a23c11c6079a7d4f715a7387d9a96a91c52c.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-7fe235092b7f64cb5c6755f1f571daff666fe04dd45246eb94c961eed1dba2d7.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-b78c21cb05f5d94f2dddaf1a216a233d81fc65d08215d6057e750ad72fbd7cce.json rename {core/lib/dal => via_verifier/lib/verifier_dal}/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json (100%) rename {core/lib/dal => via_verifier/lib/verifier_dal}/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json (100%) create mode 100644 via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.down.sql create mode 100644 via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.up.sql create mode 100644 via_verifier/lib/verifier_dal/src/models/mod.rs create mode 100644 via_verifier/lib/verifier_dal/src/models/storage_btc_inscription_request.rs rename core/lib/dal/src/via_verifier_blocks_dal.rs => via_verifier/lib/verifier_dal/src/via_blocks_dal.rs (91%) create mode 100644 via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs diff --git a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql deleted file mode 100644 index 5361eff01..000000000 --- a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE via_l1_batch_vote_inscription_request; \ No newline at end of file diff --git a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql b/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql deleted file mode 100644 index c53e8cce7..000000000 --- a/core/lib/dal/migrations/20241219091919_add_verifier_vote_inscription.up.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE "via_l1_batch_vote_inscription_request" ( - "l1_batch_number" bigint UNIQUE NOT NULL, - "vote_l1_batch_inscription_id" bigint UNIQUE NOT NULL, - "created_at" timestamp NOT NULL DEFAULT 'now()', - "updated_at" timestamp NOT NULL -); - -ALTER TABLE "via_l1_batch_vote_inscription_request" ADD FOREIGN KEY ("vote_l1_batch_inscription_id") REFERENCES "via_btc_inscriptions_request" ("id"); diff --git a/core/lib/dal/src/lib.rs b/core/lib/dal/src/lib.rs index 41c944ad5..7d914fa53 100644 --- a/core/lib/dal/src/lib.rs +++ b/core/lib/dal/src/lib.rs @@ -5,7 +5,6 @@ use btc_sender_dal::ViaBtcSenderDal; pub use sqlx::{types::BigDecimal, Error as SqlxError}; -use via_verifier_blocks_dal::ViaVerifierBlocksDal; use zksync_db_connection::connection::DbMarker; pub use zksync_db_connection::{ connection::{Connection, IsolationLevel}, @@ -67,7 +66,6 @@ pub mod transactions_web3_dal; pub mod via_blocks_dal; pub mod via_data_availability_dal; pub mod via_transactions_dal; -pub mod via_verifier_blocks_dal; pub mod via_votes_dal; pub mod vm_runner_dal; @@ -107,8 +105,6 @@ where fn btc_sender_dal(&mut self) -> ViaBtcSenderDal<'_, 'a>; - fn via_verifier_block_dal(&mut self) -> ViaVerifierBlocksDal<'_, 'a>; - fn events_dal(&mut self) -> EventsDal<'_, 'a>; fn events_web3_dal(&mut self) -> EventsWeb3Dal<'_, 'a>; @@ -208,10 +204,6 @@ impl<'a> CoreDal<'a> for Connection<'a, Core> { ViaBtcSenderDal { storage: self } } - fn via_verifier_block_dal(&mut self) -> ViaVerifierBlocksDal<'_, 'a> { - ViaVerifierBlocksDal { storage: self } - } - fn events_dal(&mut self) -> EventsDal<'_, 'a> { EventsDal { storage: self } } diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-110825e736943e4ef68110e8d7af3af3edce16051e8987a27ea207bfe9b65502.json b/via_verifier/lib/verifier_dal/.sqlx/query-110825e736943e4ef68110e8d7af3af3edce16051e8987a27ea207bfe9b65502.json new file mode 100644 index 000000000..1a0bcb627 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-110825e736943e4ef68110e8d7af3af3edce16051e8987a27ea207bfe9b65502.json @@ -0,0 +1,82 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n via_btc_inscriptions_request_history\n WHERE\n inscription_request_id = $1\n ORDER BY\n id DESC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "commit_tx_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "reveal_tx_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "inscription_request_id", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "signed_commit_tx", + "type_info": "Bytea" + }, + { + "ordinal": 5, + "name": "signed_reveal_tx", + "type_info": "Bytea" + }, + { + "ordinal": 6, + "name": "actual_fees", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "confirmed_at", + "type_info": "Timestamp" + }, + { + "ordinal": 8, + "name": "sent_at_block", + "type_info": "Int8" + }, + { + "ordinal": 9, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 10, + "name": "updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false + ] + }, + "hash": "110825e736943e4ef68110e8d7af3af3edce16051e8987a27ea207bfe9b65502" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-2082d20e3b547a7385c174892d96857119c57c7ff5194a546d24fec0e3cf3059.json b/via_verifier/lib/verifier_dal/.sqlx/query-2082d20e3b547a7385c174892d96857119c57c7ff5194a546d24fec0e3cf3059.json new file mode 100644 index 000000000..c6bf0d9f7 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-2082d20e3b547a7385c174892d96857119c57c7ff5194a546d24fec0e3cf3059.json @@ -0,0 +1,56 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n via_btc_inscriptions_request.*\n FROM\n via_btc_inscriptions_request\n JOIN via_btc_inscriptions_request_history ON via_btc_inscriptions_request.id = via_btc_inscriptions_request_history.inscription_request_id\n AND via_btc_inscriptions_request_history.sent_at_block IS NOT NULL\n AND via_btc_inscriptions_request.confirmed_inscriptions_request_history_id IS NULL\n AND via_btc_inscriptions_request_history.id = (\n SELECT\n id\n FROM\n via_btc_inscriptions_request_history\n WHERE\n inscription_request_id = via_btc_inscriptions_request.id\n AND via_btc_inscriptions_request_history.sent_at_block IS NOT NULL\n ORDER BY\n created_at DESC\n LIMIT\n 1\n )\n ORDER BY\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "request_type", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "inscription_message", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "predicted_fee", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "confirmed_inscriptions_request_history_id", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 6, + "name": "updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "2082d20e3b547a7385c174892d96857119c57c7ff5194a546d24fec0e3cf3059" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-2147add1c47a8b86de081f060458cc9601afc6a4f86f930c9ceff02fae5c02dc.json b/via_verifier/lib/verifier_dal/.sqlx/query-2147add1c47a8b86de081f060458cc9601afc6a4f86f930c9ceff02fae5c02dc.json new file mode 100644 index 000000000..17d7311da --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-2147add1c47a8b86de081f060458cc9601afc6a4f86f930c9ceff02fae5c02dc.json @@ -0,0 +1,58 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n via_btc_inscriptions_request.*\n FROM\n via_btc_inscriptions_request\n LEFT JOIN via_btc_inscriptions_request_history ON via_btc_inscriptions_request.id = via_btc_inscriptions_request_history.inscription_request_id\n WHERE\n via_btc_inscriptions_request_history.inscription_request_id IS NULL\n ORDER BY\n via_btc_inscriptions_request.id\n LIMIT\n $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "request_type", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "inscription_message", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "predicted_fee", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "confirmed_inscriptions_request_history_id", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 6, + "name": "updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "2147add1c47a8b86de081f060458cc9601afc6a4f86f930c9ceff02fae5c02dc" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-3229aefe26d77c22cee31dd506cd62244613761e41e811705611d75fbe48ad1a.json b/via_verifier/lib/verifier_dal/.sqlx/query-3229aefe26d77c22cee31dd506cd62244613761e41e811705611d75fbe48ad1a.json new file mode 100644 index 000000000..25653cf10 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-3229aefe26d77c22cee31dd506cd62244613761e41e811705611d75fbe48ad1a.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_btc_inscriptions_request_history (\n commit_tx_id,\n reveal_tx_id,\n inscription_request_id,\n signed_commit_tx,\n signed_reveal_tx,\n actual_fees,\n sent_at_block,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())\n RETURNING\n id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Int8", + "Bytea", + "Bytea", + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "3229aefe26d77c22cee31dd506cd62244613761e41e811705611d75fbe48ad1a" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-5644db74e4626d2c689b1a24c8b7a23c11c6079a7d4f715a7387d9a96a91c52c.json b/via_verifier/lib/verifier_dal/.sqlx/query-5644db74e4626d2c689b1a24c8b7a23c11c6079a7d4f715a7387d9a96a91c52c.json new file mode 100644 index 000000000..2e85bc0df --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-5644db74e4626d2c689b1a24c8b7a23c11c6079a7d4f715a7387d9a96a91c52c.json @@ -0,0 +1,60 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_btc_inscriptions_request (request_type, inscription_message, predicted_fee, created_at, updated_at)\n VALUES\n ($1, $2, $3, NOW(), NOW())\n RETURNING\n *\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "request_type", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "inscription_message", + "type_info": "Bytea" + }, + { + "ordinal": 3, + "name": "predicted_fee", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "confirmed_inscriptions_request_history_id", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "created_at", + "type_info": "Timestamp" + }, + { + "ordinal": 6, + "name": "updated_at", + "type_info": "Timestamp" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Bytea", + "Int8" + ] + }, + "nullable": [ + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "5644db74e4626d2c689b1a24c8b7a23c11c6079a7d4f715a7387d9a96a91c52c" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-7fe235092b7f64cb5c6755f1f571daff666fe04dd45246eb94c961eed1dba2d7.json b/via_verifier/lib/verifier_dal/.sqlx/query-7fe235092b7f64cb5c6755f1f571daff666fe04dd45246eb94c961eed1dba2d7.json new file mode 100644 index 000000000..1b93c7993 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-7fe235092b7f64cb5c6755f1f571daff666fe04dd45246eb94c961eed1dba2d7.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_btc_inscriptions_request\n SET\n updated_at = NOW(),\n confirmed_inscriptions_request_history_id = $2\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "7fe235092b7f64cb5c6755f1f571daff666fe04dd45246eb94c961eed1dba2d7" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json b/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json new file mode 100644 index 000000000..27c16afa8 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n COUNT(id) AS COUNT\n FROM\n via_btc_inscriptions_request_history\n WHERE\n inscription_request_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-b78c21cb05f5d94f2dddaf1a216a233d81fc65d08215d6057e750ad72fbd7cce.json b/via_verifier/lib/verifier_dal/.sqlx/query-b78c21cb05f5d94f2dddaf1a216a233d81fc65d08215d6057e750ad72fbd7cce.json new file mode 100644 index 000000000..ee5f7c934 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-b78c21cb05f5d94f2dddaf1a216a233d81fc65d08215d6057e750ad72fbd7cce.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_btc_inscriptions_request_history\n SET\n updated_at = NOW(),\n confirmed_at = NOW()\n WHERE\n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "b78c21cb05f5d94f2dddaf1a216a233d81fc65d08215d6057e750ad72fbd7cce" +} diff --git a/core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json b/via_verifier/lib/verifier_dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json similarity index 100% rename from core/lib/dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json rename to via_verifier/lib/verifier_dal/.sqlx/query-ca8a2d4afee25b6cd41bcb88af78eef1a09c549c5c62c77b5527f771ae6370b0.json diff --git a/core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json b/via_verifier/lib/verifier_dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json similarity index 100% rename from core/lib/dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json rename to via_verifier/lib/verifier_dal/.sqlx/query-dcc4dfd0b7fd4968ba8d7f26fe9a4a2263af9c4aa330638ffdc8c380aafa6d3a.json diff --git a/via_verifier/lib/verifier_dal/Cargo.toml b/via_verifier/lib/verifier_dal/Cargo.toml index 35c0406fe..b6442e39f 100644 --- a/via_verifier/lib/verifier_dal/Cargo.toml +++ b/via_verifier/lib/verifier_dal/Cargo.toml @@ -11,11 +11,13 @@ keywords.workspace = true categories.workspace = true [dependencies] +anyhow.workspace = true zksync_db_connection.workspace = true zksync_basic_types.workspace = true zksync_types.workspace = true thiserror.workspace = true +bitcoin = { version = "0.32.2" } strum = { workspace = true, features = ["derive"] } sqlx = { workspace = true, features = [ "runtime-tokio", diff --git a/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.down.sql b/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.down.sql new file mode 100644 index 000000000..f87e9b335 --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.down.sql @@ -0,0 +1,2 @@ +DROP TABLE via_btc_inscriptions_request_history; +DROP TABLE via_btc_inscriptions_request; \ No newline at end of file diff --git a/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.up.sql b/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.up.sql new file mode 100644 index 000000000..1b2a41839 --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20240906134623_add_via_btc_inscription_requests.up.sql @@ -0,0 +1,34 @@ +CREATE TABLE "via_btc_inscriptions_request" ( + "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + "request_type" varchar NOT NULL, + "inscription_message" BYTEA, + "predicted_fee" bigint, + "confirmed_inscriptions_request_history_id" bigint UNIQUE, + "created_at" timestamp NOT NULL DEFAULT 'now()', + "updated_at" timestamp NOT NULL +); + +CREATE TABLE "via_btc_inscriptions_request_history" ( + "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + "commit_tx_id" varchar UNIQUE NOT NULL, + "reveal_tx_id" varchar UNIQUE NOT NULL, + "inscription_request_id" bigint NOT NULL, + "signed_commit_tx" BYTEA NOT NULL, + "signed_reveal_tx" BYTEA NOT NULL, + "actual_fees" bigint NOT NULL, + "confirmed_at" timestamp DEFAULT null, + "sent_at_block" bigint NOT NULL, + "created_at" timestamp DEFAULT 'now()', + "updated_at" timestamp NOT NULL +); + +CREATE TABLE "via_l1_batch_vote_inscription_request" ( + "l1_batch_number" bigint UNIQUE NOT NULL, + "vote_l1_batch_inscription_id" bigint UNIQUE NOT NULL, + "created_at" timestamp NOT NULL DEFAULT 'now()', + "updated_at" timestamp NOT NULL +); + +ALTER TABLE "via_btc_inscriptions_request_history" ADD FOREIGN KEY ("inscription_request_id") REFERENCES "via_btc_inscriptions_request" ("id") ON DELETE CASCADE ON UPDATE NO ACTION; +ALTER TABLE "via_btc_inscriptions_request" ADD FOREIGN KEY ("confirmed_inscriptions_request_history_id") REFERENCES "via_btc_inscriptions_request_history" ("id"); +ALTER TABLE "via_l1_batch_vote_inscription_request" ADD FOREIGN KEY ("vote_l1_batch_inscription_id") REFERENCES "via_btc_inscriptions_request" ("id"); diff --git a/via_verifier/lib/verifier_dal/src/lib.rs b/via_verifier/lib/verifier_dal/src/lib.rs index 39af27f50..c5ee81787 100644 --- a/via_verifier/lib/verifier_dal/src/lib.rs +++ b/via_verifier/lib/verifier_dal/src/lib.rs @@ -11,8 +11,13 @@ pub use zksync_db_connection::{ error::{DalError, DalResult}, }; -use crate::via_votes_dal::ViaVotesDal; +use crate::{ + via_blocks_dal::ViaBlocksDal, via_btc_sender_dal::ViaBtcSenderDal, via_votes_dal::ViaVotesDal, +}; +pub mod models; +pub mod via_blocks_dal; +pub mod via_btc_sender_dal; pub mod via_votes_dal; #[cfg(test)] @@ -30,6 +35,8 @@ where Self: 'a, { fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a>; + fn via_btc_sender_dal(&mut self) -> ViaBtcSenderDal<'_, 'a>; + fn via_block_dal(&mut self) -> ViaBlocksDal<'_, 'a>; } #[derive(Clone, Debug)] @@ -44,4 +51,11 @@ impl<'a> VerifierDal<'a> for Connection<'a, Verifier> { fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a> { ViaVotesDal { storage: self } } + + fn via_btc_sender_dal(&mut self) -> ViaBtcSenderDal<'_, 'a> { + ViaBtcSenderDal { storage: self } + } + fn via_block_dal(&mut self) -> ViaBlocksDal<'_, 'a> { + ViaBlocksDal { storage: self } + } } diff --git a/via_verifier/lib/verifier_dal/src/models/mod.rs b/via_verifier/lib/verifier_dal/src/models/mod.rs new file mode 100644 index 000000000..c641ab7e2 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/models/mod.rs @@ -0,0 +1 @@ +pub mod storage_btc_inscription_request; diff --git a/via_verifier/lib/verifier_dal/src/models/storage_btc_inscription_request.rs b/via_verifier/lib/verifier_dal/src/models/storage_btc_inscription_request.rs new file mode 100644 index 000000000..baf0d71f3 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/models/storage_btc_inscription_request.rs @@ -0,0 +1,62 @@ +use std::str::FromStr; + +use bitcoin::Txid; +use sqlx::types::chrono::NaiveDateTime; +use zksync_types::btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}; + +#[derive(Debug, Clone)] +pub struct ViaStorageBtcInscriptionRequest { + pub id: i64, + pub request_type: String, + pub inscription_message: Option>, + pub predicted_fee: Option, + pub confirmed_inscriptions_request_history_id: Option, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, +} + +#[derive(Clone, Debug)] +pub struct ViaStorageBtcInscriptionRequestHistory { + pub id: i64, + pub commit_tx_id: String, + pub reveal_tx_id: String, + pub inscription_request_id: i64, + pub signed_commit_tx: Option>, + pub signed_reveal_tx: Option>, + pub actual_fees: i64, + pub sent_at_block: i64, + pub confirmed_at: Option, + pub created_at: Option, + pub updated_at: Option, +} + +impl From for ViaBtcInscriptionRequest { + fn from(req: ViaStorageBtcInscriptionRequest) -> ViaBtcInscriptionRequest { + ViaBtcInscriptionRequest { + id: req.id, + request_type: req.request_type, + inscription_message: req.inscription_message, + confirmed_inscriptions_request_history_id: req + .confirmed_inscriptions_request_history_id, + predicted_fee: req.predicted_fee, + created_at: req.created_at, + updated_at: req.updated_at, + } + } +} + +impl From for ViaBtcInscriptionRequestHistory { + fn from(history: ViaStorageBtcInscriptionRequestHistory) -> ViaBtcInscriptionRequestHistory { + ViaBtcInscriptionRequestHistory { + id: history.id, + commit_tx_id: Txid::from_str(&history.commit_tx_id).unwrap(), + reveal_tx_id: Txid::from_str(&history.reveal_tx_id).unwrap(), + inscription_request_id: history.inscription_request_id, + sent_at_block: history.sent_at_block, + signed_commit_tx: history.signed_commit_tx, + signed_reveal_tx: history.signed_reveal_tx, + actual_fees: history.actual_fees, + confirmed_at: history.confirmed_at, + } + } +} diff --git a/core/lib/dal/src/via_verifier_blocks_dal.rs b/via_verifier/lib/verifier_dal/src/via_blocks_dal.rs similarity index 91% rename from core/lib/dal/src/via_verifier_blocks_dal.rs rename to via_verifier/lib/verifier_dal/src/via_blocks_dal.rs index 3c1206d73..847055f7f 100644 --- a/core/lib/dal/src/via_verifier_blocks_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_blocks_dal.rs @@ -7,15 +7,14 @@ use zksync_types::{ via_verifier_btc_inscription_operations::ViaVerifierBtcInscriptionRequestType, L1BatchNumber, }; -pub use crate::models::storage_block::{L1BatchMetadataError, L1BatchWithOptionalMetadata}; -use crate::Core; +use crate::Verifier; #[derive(Debug)] -pub struct ViaVerifierBlocksDal<'a, 'c> { - pub(crate) storage: &'a mut Connection<'c, Core>, +pub struct ViaBlocksDal<'a, 'c> { + pub(crate) storage: &'a mut Connection<'c, Verifier>, } -impl ViaVerifierBlocksDal<'_, '_> { +impl ViaBlocksDal<'_, '_> { pub async fn insert_vote_l1_batch_inscription_request_id( &mut self, batch_number: L1BatchNumber, diff --git a/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs b/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs new file mode 100644 index 000000000..da63ed95a --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs @@ -0,0 +1,237 @@ +use anyhow::Context; +use zksync_db_connection::connection::Connection; +use zksync_types::btc_sender::{ViaBtcInscriptionRequest, ViaBtcInscriptionRequestHistory}; + +use crate::{ + models::storage_btc_inscription_request::{ + ViaStorageBtcInscriptionRequest, ViaStorageBtcInscriptionRequestHistory, + }, + Verifier, +}; + +#[derive(Debug)] +pub struct ViaBtcSenderDal<'a, 'c> { + pub(crate) storage: &'a mut Connection<'c, Verifier>, +} + +impl ViaBtcSenderDal<'_, '_> { + pub async fn via_save_btc_inscriptions_request( + &mut self, + inscription_request_type: String, + inscription_message: Vec, + predicted_fee: u64, + ) -> sqlx::Result { + let inscription_request = sqlx::query_as!( + ViaBtcInscriptionRequest, + r#" + INSERT INTO + via_btc_inscriptions_request (request_type, inscription_message, predicted_fee, created_at, updated_at) + VALUES + ($1, $2, $3, NOW(), NOW()) + RETURNING + * + "#, + inscription_request_type, + inscription_message, + predicted_fee as i64, + ) + .fetch_one(self.storage.conn()) + .await?; + Ok(inscription_request) + } + + pub async fn get_inflight_inscriptions( + &mut self, + ) -> sqlx::Result> { + let txs = sqlx::query_as!( + ViaStorageBtcInscriptionRequest, + r#" + SELECT + via_btc_inscriptions_request.* + FROM + via_btc_inscriptions_request + JOIN via_btc_inscriptions_request_history ON via_btc_inscriptions_request.id = via_btc_inscriptions_request_history.inscription_request_id + AND via_btc_inscriptions_request_history.sent_at_block IS NOT NULL + AND via_btc_inscriptions_request.confirmed_inscriptions_request_history_id IS NULL + AND via_btc_inscriptions_request_history.id = ( + SELECT + id + FROM + via_btc_inscriptions_request_history + WHERE + inscription_request_id = via_btc_inscriptions_request.id + AND via_btc_inscriptions_request_history.sent_at_block IS NOT NULL + ORDER BY + created_at DESC + LIMIT + 1 + ) + ORDER BY + id + "# + ) + .fetch_all(self.storage.conn()) + .await?; + Ok(txs.into_iter().map(|tx| tx.into()).collect()) + } + + pub async fn list_new_inscription_request( + &mut self, + limit: i64, + ) -> sqlx::Result> { + let txs = sqlx::query_as!( + ViaStorageBtcInscriptionRequest, + r#" + SELECT + via_btc_inscriptions_request.* + FROM + via_btc_inscriptions_request + LEFT JOIN via_btc_inscriptions_request_history ON via_btc_inscriptions_request.id = via_btc_inscriptions_request_history.inscription_request_id + WHERE + via_btc_inscriptions_request_history.inscription_request_id IS NULL + ORDER BY + via_btc_inscriptions_request.id + LIMIT + $1 + "#, + limit, + ) + .fetch_all(self.storage.conn()) + .await?; + Ok(txs.into_iter().map(|tx| tx.into()).collect()) + } + + #[allow(clippy::too_many_arguments)] + pub async fn insert_inscription_request_history( + &mut self, + commit_tx_id: String, + reveal_tx_id: String, + inscription_request_id: i64, + signed_commit_tx: Vec, + signed_reveal_tx: Vec, + actual_fees: i64, + sent_at_block: i64, + ) -> sqlx::Result> { + Ok(sqlx::query!( + r#" + INSERT INTO + via_btc_inscriptions_request_history ( + commit_tx_id, + reveal_tx_id, + inscription_request_id, + signed_commit_tx, + signed_reveal_tx, + actual_fees, + sent_at_block, + created_at, + updated_at + ) + VALUES + ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) + RETURNING + id + "#, + commit_tx_id, + reveal_tx_id, + inscription_request_id, + signed_commit_tx, + signed_reveal_tx, + actual_fees, + sent_at_block as i32 + ) + .fetch_optional(self.storage.conn()) + .await? + .map(|row| row.id as u32)) + } + + pub async fn get_last_inscription_request_history( + &mut self, + inscription_request_id: i64, + ) -> sqlx::Result> { + let inscription_request_history = sqlx::query_as!( + ViaStorageBtcInscriptionRequestHistory, + r#" + SELECT + * + FROM + via_btc_inscriptions_request_history + WHERE + inscription_request_id = $1 + ORDER BY + id DESC + LIMIT + 1 + "#, + inscription_request_id + ) + .fetch_optional(self.storage.conn()) + .await?; + + Ok(inscription_request_history.map(ViaBtcInscriptionRequestHistory::from)) + } + + pub async fn get_total_inscription_request_history( + &mut self, + inscription_request_id: i64, + ) -> sqlx::Result { + let total = sqlx::query!( + r#" + SELECT + COUNT(id) AS COUNT + FROM + via_btc_inscriptions_request_history + WHERE + inscription_request_id = $1 + "#, + inscription_request_id + ) + .fetch_one(self.storage.conn()) + .await?; + + // Return the count or 0 if no records were found + Ok(total.count.unwrap_or(0)) + } + + pub async fn confirm_inscription( + &mut self, + inscriptions_request_id: i64, + inscriptions_request_history_id: i64, + ) -> anyhow::Result<()> { + let mut transaction = self + .storage + .start_transaction() + .await + .context("start_transaction")?; + + sqlx::query!( + r#" + UPDATE via_btc_inscriptions_request_history + SET + updated_at = NOW(), + confirmed_at = NOW() + WHERE + id = $1 + "#, + inscriptions_request_history_id + ) + .execute(transaction.conn()) + .await?; + + sqlx::query!( + r#" + UPDATE via_btc_inscriptions_request + SET + updated_at = NOW(), + confirmed_inscriptions_request_history_id = $2 + WHERE + id = $1 + "#, + inscriptions_request_id, + inscriptions_request_history_id + ) + .execute(transaction.conn()) + .await?; + + transaction.commit().await.context("commit()") + } +} From 9729dc4d46c39e317fd17733e03a2d373f7b5b21 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:17:52 +0100 Subject: [PATCH 128/212] feat: migrate the verifier btc_sender node logic to via_verifier crate --- Cargo.lock | 27 ++ Cargo.toml | 2 + core/node/node_framework/Cargo.toml | 1 + .../layers/via_btc_sender/mod.rs | 1 + .../layers/via_btc_sender/vote.rs | 8 +- .../layers/via_btc_sender/vote_manager.rs | 100 ++++++++ core/node/via_btc_sender/src/lib.rs | 1 - core/node/via_btc_sender/src/tests/mod.rs | 1 - via_verifier/node/via_btc_sender/Cargo.toml | 34 +++ .../src/btc_inscription_manager.rs | 232 ++++++++++++++++++ .../src/btc_vote_inscription.rs | 16 +- .../node/via_btc_sender/src/config.rs | 2 + via_verifier/node/via_btc_sender/src/lib.rs | 5 + .../node/via_btc_sender/src/tests/mod.rs | 3 + .../node/via_btc_sender/src/tests/utils.rs | 37 +++ .../src/tests/vote_inscription_test.rs | 152 ++---------- 16 files changed, 476 insertions(+), 146 deletions(-) create mode 100644 core/node/node_framework/src/implementations/layers/via_btc_sender/vote_manager.rs create mode 100644 via_verifier/node/via_btc_sender/Cargo.toml create mode 100644 via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs rename {core => via_verifier}/node/via_btc_sender/src/btc_vote_inscription.rs (92%) create mode 100644 via_verifier/node/via_btc_sender/src/config.rs create mode 100644 via_verifier/node/via_btc_sender/src/lib.rs create mode 100644 via_verifier/node/via_btc_sender/src/tests/mod.rs create mode 100644 via_verifier/node/via_btc_sender/src/tests/utils.rs rename {core => via_verifier}/node/via_btc_sender/src/tests/vote_inscription_test.rs (61%) diff --git a/Cargo.lock b/Cargo.lock index 41ea6672f..fe3d71eb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9716,6 +9716,30 @@ dependencies = [ "zksync_vlog", ] +[[package]] +name = "via_verifier_btc_sender" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "bitcoin", + "chrono", + "hex", + "thiserror", + "tokio", + "tracing", + "via_btc_client", + "via_da_dispatcher", + "via_verifier_dal", + "zksync_config", + "zksync_contracts", + "zksync_l1_contract_interface", + "zksync_node_test_utils", + "zksync_object_store", + "zksync_types", +] + [[package]] name = "via_verifier_btc_watch" version = "0.1.0" @@ -9738,6 +9762,8 @@ dependencies = [ name = "via_verifier_dal" version = "0.1.0" dependencies = [ + "anyhow", + "bitcoin", "rand 0.8.5", "sqlx", "strum 0.26.3", @@ -11842,6 +11868,7 @@ dependencies = [ "via_da_dispatcher", "via_fee_model", "via_state_keeper", + "via_verifier_btc_sender", "via_verifier_btc_watch", "via_verifier_dal", "via_withdrawal_client", diff --git a/Cargo.toml b/Cargo.toml index 31f84410e..16911706c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,6 +102,7 @@ members = [ "via_verifier/node/withdrawal_service", "via_verifier/node/via_zk_verifier", "via_verifier/node/via_btc_watch", + "via_verifier/node/via_btc_sender", ] resolver = "2" @@ -341,3 +342,4 @@ via_verifier_dal = { version = "0.1.0", path = "via_verifier/lib/verifier_dal" } via_withdrawal_service = { version = "0.1.0", path = "via_verifier/node/withdrawal_service" } via_zk_verifier = { version = "0.1.0", path = "via_verifier/node/via_zk_verifier" } via_verifier_btc_watch = { version = "0.1.0", path = "via_verifier/node/via_btc_watch" } +via_verifier_btc_sender = { version = "0.1.0", path = "via_verifier/node/via_btc_sender" } diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index d6ab18b38..655b61ce9 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -68,6 +68,7 @@ via_withdrawal_client.workspace = true via_verifier_dal.workspace = true via_zk_verifier.workspace = true via_verifier_btc_watch.workspace = true +via_verifier_btc_sender.workspace = true pin-project-lite.workspace = true tracing.workspace = true thiserror.workspace = true diff --git a/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs b/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs index c3bd700d1..3ca69bc78 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_sender/mod.rs @@ -1,3 +1,4 @@ pub mod aggregator; pub mod manager; pub mod vote; +pub mod vote_manager; diff --git a/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs index fe75e8dc1..fe027b9cd 100644 --- a/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs +++ b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote.rs @@ -1,8 +1,8 @@ -use via_btc_sender::btc_vote_inscription::ViaVoteInscription; +use via_verifier_btc_sender::btc_vote_inscription::ViaVoteInscription; use zksync_config::ViaBtcSenderConfig; use crate::{ - implementations::resources::pools::{MasterPool, PoolResource}, + implementations::resources::pools::{PoolResource, VerifierPool}, service::StopReceiver, task::{Task, TaskId}, wiring_layer::{WiringError, WiringLayer}, @@ -20,7 +20,7 @@ pub struct ViaBtcVoteInscriptionLayer { #[derive(Debug, FromContext)] #[context(crate = crate)] pub struct Input { - pub master_pool: PoolResource, + pub master_pool: PoolResource, } #[derive(Debug, IntoContext)] @@ -46,7 +46,7 @@ impl WiringLayer for ViaBtcVoteInscriptionLayer { } async fn wire(self, input: Self::Input) -> Result { - // // Get resources. + // Get resources. let master_pool = input.master_pool.get().await.unwrap(); let via_vote_inscription = ViaVoteInscription::new(master_pool, self.config).await?; diff --git a/core/node/node_framework/src/implementations/layers/via_btc_sender/vote_manager.rs b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote_manager.rs new file mode 100644 index 000000000..0bd587046 --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/via_btc_sender/vote_manager.rs @@ -0,0 +1,100 @@ +use anyhow::Context; +use via_btc_client::{inscriber::Inscriber, types::NodeAuth}; +use via_btc_watch::BitcoinNetwork; +use via_verifier_btc_sender::btc_inscription_manager::ViaBtcInscriptionManager; +use zksync_config::ViaBtcSenderConfig; + +use crate::{ + implementations::resources::pools::{PoolResource, VerifierPool}, + service::StopReceiver, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, +}; + +/// Wiring layer for btc_sender to manage `inscriptions_requests` +/// +/// Responsible for initialization and running [`ViaBtcInscriptionTxManager`] component. The layer is responsible +/// to process inscription requests and create btc transactions. +/// +/// ## Requests resources +/// +/// - `PoolResource` +/// +/// ## Adds tasks +/// +/// - `ViaBtcInscriptionManager` +#[derive(Debug)] +pub struct ViaInscriptionManagerLayer { + pub config: ViaBtcSenderConfig, +} + +#[derive(Debug, FromContext)] +#[context(crate = crate)] +pub struct Input { + pub master_pool: PoolResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +pub struct Output { + #[context(task)] + pub via_btc_inscription_manager: ViaBtcInscriptionManager, +} + +impl ViaInscriptionManagerLayer { + pub fn new(config: ViaBtcSenderConfig) -> Self { + Self { config } + } +} + +#[async_trait::async_trait] +impl WiringLayer for ViaInscriptionManagerLayer { + type Input = Input; + type Output = Output; + + fn layer_name(&self) -> &'static str { + "via_btc_inscription_manager_layer" + } + + async fn wire(self, input: Self::Input) -> Result { + // Get resources. + let master_pool = input.master_pool.get().await.unwrap(); + + let network = BitcoinNetwork::from_core_arg(self.config.network()) + .map_err(|_| WiringError::Configuration("Wrong network in config".to_string()))?; + + let inscriber = Inscriber::new( + self.config.rpc_url(), + network, + NodeAuth::UserPass( + self.config.rpc_user().to_string(), + self.config.rpc_password().to_string(), + ), + self.config.private_key(), + None, + ) + .await + .context("Init inscriber")?; + + let via_btc_inscription_manager = + ViaBtcInscriptionManager::new(inscriber, master_pool, self.config) + .await + .unwrap(); + + Ok(Output { + via_btc_inscription_manager, + }) + } +} + +#[async_trait::async_trait] +impl Task for ViaBtcInscriptionManager { + fn id(&self) -> TaskId { + "via_btc_inscription_manager".into() + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + (*self).run(stop_receiver.0).await + } +} diff --git a/core/node/via_btc_sender/src/lib.rs b/core/node/via_btc_sender/src/lib.rs index 34c3cef36..67fbb4ab6 100644 --- a/core/node/via_btc_sender/src/lib.rs +++ b/core/node/via_btc_sender/src/lib.rs @@ -2,7 +2,6 @@ mod aggregated_operations; pub mod aggregator; pub mod btc_inscription_aggregator; pub mod btc_inscription_manager; -pub mod btc_vote_inscription; mod config; mod publish_criterion; #[cfg(test)] diff --git a/core/node/via_btc_sender/src/tests/mod.rs b/core/node/via_btc_sender/src/tests/mod.rs index 471ef77a0..786877161 100644 --- a/core/node/via_btc_sender/src/tests/mod.rs +++ b/core/node/via_btc_sender/src/tests/mod.rs @@ -4,4 +4,3 @@ mod btc_inscription_manager_test; mod publish_criterion_test; #[cfg(test)] mod utils; -mod vote_inscription_test; diff --git a/via_verifier/node/via_btc_sender/Cargo.toml b/via_verifier/node/via_btc_sender/Cargo.toml new file mode 100644 index 000000000..258df7a31 --- /dev/null +++ b/via_verifier/node/via_btc_sender/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "via_verifier_btc_sender" +description = "VIA Verifier Bitcoin Sender" +version.workspace = true +edition.workspace = true +authors = [ "VIA Protocol Team"] +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +via_btc_client.workspace = true +via_da_dispatcher.workspace = true +via_verifier_dal.workspace = true +zksync_config.workspace = true +zksync_object_store.workspace = true +zksync_l1_contract_interface.workspace = true +zksync_types.workspace = true +zksync_contracts.workspace = true +bitcoin = { version = "0.32.2", features = ["serde"] } +bincode = "1.3" + +tokio.workspace = true +anyhow.workspace = true +thiserror.workspace = true +async-trait.workspace = true +tracing.workspace = true +chrono.workspace = true +hex = "0.4" + +[dev-dependencies] +zksync_node_test_utils.workspace = true diff --git a/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs new file mode 100644 index 000000000..3b896b030 --- /dev/null +++ b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs @@ -0,0 +1,232 @@ +use anyhow::{Context, Result}; +use bincode::serialize; +use tokio::sync::watch; +use via_btc_client::{ + inscriber::Inscriber, + traits::Serializable, + types::{InscriptionConfig, InscriptionMessage}, +}; +use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; +use zksync_config::ViaBtcSenderConfig; +use zksync_types::btc_sender::ViaBtcInscriptionRequest; + +use crate::config::BLOCK_RESEND; + +#[derive(Debug)] +pub struct ViaBtcInscriptionManager { + inscriber: Inscriber, + config: ViaBtcSenderConfig, + pool: ConnectionPool, +} + +impl ViaBtcInscriptionManager { + pub async fn new( + inscriber: Inscriber, + pool: ConnectionPool, + config: ViaBtcSenderConfig, + ) -> anyhow::Result { + Ok(Self { + inscriber, + config, + pool, + }) + } + + pub async fn run(mut self, mut stop_receiver: watch::Receiver) -> anyhow::Result<()> { + let mut timer = tokio::time::interval(self.config.poll_interval()); + let pool = self.pool.clone(); + + while !*stop_receiver.borrow_and_update() { + tokio::select! { + _ = timer.tick() => { /* continue iterations */ } + _ = stop_receiver.changed() => break, + } + + let mut storage = pool.connection_tagged("via_btc_sender").await?; + + match self.loop_iteration(&mut storage).await { + Ok(()) => { + tracing::info!("Inscription manager task finished"); + } + Err(err) => { + tracing::error!("Failed to process btc_sender_inscription_manager: {err}"); + } + } + } + + tracing::info!("Stop signal received, btc_sender is shutting down"); + Ok(()) + } + + async fn loop_iteration( + &mut self, + storage: &mut Connection<'_, Verifier>, + ) -> Result<(), anyhow::Error> { + self.update_inscription_status_or_resend(storage).await?; + self.send_new_inscription_txs(storage).await?; + Ok(()) + } + + async fn update_inscription_status_or_resend( + &mut self, + storage: &mut Connection<'_, Verifier>, + ) -> anyhow::Result<()> { + let inflight_inscriptions = storage + .via_btc_sender_dal() + .get_inflight_inscriptions() + .await?; + + for inscription in inflight_inscriptions { + if let Some(last_inscription_history) = storage + .via_btc_sender_dal() + .get_last_inscription_request_history(inscription.id) + .await? + { + let is_confirmed = self + .inscriber + .get_client() + .await + .check_tx_confirmation( + &last_inscription_history.reveal_tx_id, + self.config.block_confirmations(), + ) + .await?; + + if is_confirmed { + storage + .via_btc_sender_dal() + .confirm_inscription(inscription.id, last_inscription_history.id) + .await?; + tracing::info!( + "Inscription confirmed {reveal_tx}", + reveal_tx = last_inscription_history.reveal_tx_id, + ); + } else { + let current_block = self + .inscriber + .get_client() + .await + .fetch_block_height() + .await + .context("context")?; + + if last_inscription_history.sent_at_block + BLOCK_RESEND as i64 + > current_block as i64 + { + continue; + } + + let number_inscription_request_history = storage + .via_btc_sender_dal() + .get_total_inscription_request_history(inscription.id) + .await?; + + let config = InscriptionConfig { + fee_multiplier: number_inscription_request_history as u64 + 1, + }; + + tracing::info!( + "Inscription {reveal_tx} stuck for more than {BLOCK_RESEND} block, retry sending the inscription.", + reveal_tx = last_inscription_history.reveal_tx_id + ); + + self.send_inscription_tx(storage, &inscription, config) + .await?; + } + } + } + + Ok(()) + } + + async fn send_new_inscription_txs( + &mut self, + storage: &mut Connection<'_, Verifier>, + ) -> anyhow::Result<()> { + let number_inflight_txs = storage + .via_btc_sender_dal() + .get_inflight_inscriptions() + .await? + .len(); + + tracing::debug!( + "Inflight inscriptions: {count}", + count = number_inflight_txs + ); + + let number_of_available_slots_for_inscription_txs = self + .config + .max_txs_in_flight() + .saturating_sub(number_inflight_txs as i64); + + tracing::debug!( + "Available slots to process inscriptions: {count}", + count = number_of_available_slots_for_inscription_txs + ); + + if number_of_available_slots_for_inscription_txs > 0 { + let list_new_inscription_request = storage + .via_btc_sender_dal() + .list_new_inscription_request(number_of_available_slots_for_inscription_txs) + .await?; + + for inscription in list_new_inscription_request { + self.send_inscription_tx(storage, &inscription, InscriptionConfig::default()) + .await?; + } + } + Ok(()) + } + + pub(crate) async fn send_inscription_tx( + &mut self, + storage: &mut Connection<'_, Verifier>, + tx: &ViaBtcInscriptionRequest, + config: InscriptionConfig, + ) -> anyhow::Result<()> { + let sent_at_block = self + .inscriber + .get_client() + .await + .fetch_block_height() + .await + .context("Error to fetch current block number")? as i64; + + let input = + InscriptionMessage::from_bytes(&tx.inscription_message.clone().unwrap_or_default()); + + let inscribe_info = self + .inscriber + .inscribe(input, config) + .await + .context("Sent inscription tx")?; + + let signed_commit_tx = + serialize(&inscribe_info.final_commit_tx.tx).context("Serilize the commit tx")?; + let signed_reveal_tx = + serialize(&inscribe_info.final_reveal_tx.tx).context("Serilize the reveal tx")?; + + let actual_fees = inscribe_info.reveal_tx_output_info._reveal_fee + + inscribe_info.commit_tx_output_info._commit_tx_fee; + + tracing::info!( + "New inscription created {commit_tx} {reveal_tx}", + commit_tx = inscribe_info.final_commit_tx.txid, + reveal_tx = inscribe_info.final_reveal_tx.txid, + ); + + storage + .via_btc_sender_dal() + .insert_inscription_request_history( + inscribe_info.final_commit_tx.txid.to_string(), + inscribe_info.final_reveal_tx.txid.to_string(), + tx.id, + signed_commit_tx, + signed_reveal_tx, + actual_fees.to_sat() as i64, + sent_at_block, + ) + .await?; + Ok(()) + } +} diff --git a/core/node/via_btc_sender/src/btc_vote_inscription.rs b/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs similarity index 92% rename from core/node/via_btc_sender/src/btc_vote_inscription.rs rename to via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs index cff564dba..4514997f8 100644 --- a/core/node/via_btc_sender/src/btc_vote_inscription.rs +++ b/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs @@ -5,21 +5,21 @@ use via_btc_client::{ traits::Serializable, types::{InscriptionMessage, ValidatorAttestationInput, Vote}, }; +use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; use zksync_config::ViaBtcSenderConfig; -use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_types::{ via_verifier_btc_inscription_operations::ViaVerifierBtcInscriptionRequestType, L1BatchNumber, }; #[derive(Debug)] pub struct ViaVoteInscription { - pool: ConnectionPool, + pool: ConnectionPool, config: ViaBtcSenderConfig, } impl ViaVoteInscription { pub async fn new( - pool: ConnectionPool, + pool: ConnectionPool, config: ViaBtcSenderConfig, ) -> anyhow::Result { Ok(Self { pool, config }) @@ -55,7 +55,7 @@ impl ViaVoteInscription { pub async fn loop_iteration( &mut self, - storage: &mut Connection<'_, Core>, + storage: &mut Connection<'_, Verifier>, ) -> anyhow::Result<()> { if let Some((l1_batch_number, vote, tx_id)) = self.get_voting_operation(storage).await? { tracing::info!("New voting operation ready to be processed"); @@ -63,7 +63,7 @@ impl ViaVoteInscription { let inscription_message = self.construct_voting_inscription_message(vote, tx_id)?; let inscription_request = transaction - .btc_sender_dal() + .via_btc_sender_dal() .via_save_btc_inscriptions_request( ViaVerifierBtcInscriptionRequestType::VoteOnchain.to_string(), InscriptionMessage::to_bytes(&inscription_message), @@ -73,7 +73,7 @@ impl ViaVoteInscription { .context("Via save btc inscriptions request")?; transaction - .via_verifier_block_dal() + .via_block_dal() .insert_vote_l1_batch_inscription_request_id( l1_batch_number, inscription_request.id, @@ -88,7 +88,7 @@ impl ViaVoteInscription { pub async fn get_voting_operation( &mut self, - storage: &mut Connection<'_, Core>, + storage: &mut Connection<'_, Verifier>, ) -> anyhow::Result)>> { if let Some(batch_number) = storage .via_votes_dal() @@ -97,7 +97,7 @@ impl ViaVoteInscription { { // Check if already created a voting inscription let exists = storage - .via_verifier_block_dal() + .via_block_dal() .check_vote_l1_batch_inscription_request_if_exists(batch_number) .await?; if exists { diff --git a/via_verifier/node/via_btc_sender/src/config.rs b/via_verifier/node/via_btc_sender/src/config.rs new file mode 100644 index 000000000..56ce5556d --- /dev/null +++ b/via_verifier/node/via_btc_sender/src/config.rs @@ -0,0 +1,2 @@ +// Number of blocks to wait before increasing the inscription fee. +pub const BLOCK_RESEND: u32 = 6; diff --git a/via_verifier/node/via_btc_sender/src/lib.rs b/via_verifier/node/via_btc_sender/src/lib.rs new file mode 100644 index 000000000..099f87cf9 --- /dev/null +++ b/via_verifier/node/via_btc_sender/src/lib.rs @@ -0,0 +1,5 @@ +pub mod btc_inscription_manager; +pub mod btc_vote_inscription; +mod config; +#[cfg(test)] +mod tests; diff --git a/via_verifier/node/via_btc_sender/src/tests/mod.rs b/via_verifier/node/via_btc_sender/src/tests/mod.rs new file mode 100644 index 000000000..bc4b47358 --- /dev/null +++ b/via_verifier/node/via_btc_sender/src/tests/mod.rs @@ -0,0 +1,3 @@ +#[cfg(test)] +mod utils; +mod vote_inscription_test; diff --git a/via_verifier/node/via_btc_sender/src/tests/utils.rs b/via_verifier/node/via_btc_sender/src/tests/utils.rs new file mode 100644 index 000000000..838e88a3b --- /dev/null +++ b/via_verifier/node/via_btc_sender/src/tests/utils.rs @@ -0,0 +1,37 @@ +use via_btc_client::inscriber::test_utils::{ + get_mock_inscriber_and_conditions, MockBitcoinOpsConfig, +}; +use via_verifier_dal::{ConnectionPool, Verifier}; +use zksync_config::{configs::via_btc_sender::ProofSendingMode, ViaBtcSenderConfig}; + +use crate::btc_inscription_manager::ViaBtcInscriptionManager; + +pub fn get_btc_sender_config( + max_aggregated_blocks_to_commit: i32, + max_aggregated_proofs_to_commit: i32, +) -> ViaBtcSenderConfig { + ViaBtcSenderConfig { + actor_role: "sender".to_string(), + network: "testnet".to_string(), + private_key: "0x0".to_string(), + rpc_password: "password".to_string(), + rpc_url: "password".to_string(), + rpc_user: "rpc".to_string(), + poll_interval: 5000, + da_identifier: "CELESTIA".to_string(), + max_aggregated_blocks_to_commit, + max_aggregated_proofs_to_commit, + max_txs_in_flight: 1, + proof_sending_mode: ProofSendingMode::SkipEveryProof, + block_confirmations: 0, + } +} + +pub async fn get_inscription_manager_mock( + pool: ConnectionPool, + config: ViaBtcSenderConfig, + mock_btc_ops_config: MockBitcoinOpsConfig, +) -> ViaBtcInscriptionManager { + let inscriber = get_mock_inscriber_and_conditions(mock_btc_ops_config); + Result::unwrap(ViaBtcInscriptionManager::new(inscriber, pool, config).await) +} diff --git a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs b/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs similarity index 61% rename from core/node/via_btc_sender/src/tests/vote_inscription_test.rs rename to via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs index bedf0a638..04fb2a776 100644 --- a/core/node/via_btc_sender/src/tests/vote_inscription_test.rs +++ b/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs @@ -1,44 +1,31 @@ #[cfg(test)] mod tests { - use chrono::Utc; use tokio::{sync::watch, time}; use via_btc_client::{ inscriber::test_utils::MockBitcoinOpsConfig, traits::Serializable, types::InscriptionMessage, }; + use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; use zksync_config::ViaBtcSenderConfig; - use zksync_contracts::BaseSystemContractsHashes; - use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; - use zksync_node_test_utils::l1_batch_metadata_to_commitment_artifacts; - use zksync_types::{ - block::{L1BatchHeader, L1BatchTreeData}, - commitment::L1BatchCommitmentArtifacts, - protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, - L1BatchNumber, ProtocolVersionId, H256, - }; + use zksync_types::{L1BatchNumber, H256}; use crate::{ btc_vote_inscription::ViaVoteInscription, - tests::utils::{ - create_l1_batch, default_l1_batch_metadata, generate_random_bytes, - get_btc_sender_config, get_inscription_manager_mock, - }, + tests::utils::{get_btc_sender_config, get_inscription_manager_mock}, }; pub struct ViaVoteInscriptionTest { pub aggregator: ViaVoteInscription, - pub storage: Connection<'static, Core>, + pub storage: Connection<'static, Verifier>, } impl ViaVoteInscriptionTest { pub async fn new( - protocol_version: ProtocolVersionId, - base_system_contracts_hashes: BaseSystemContractsHashes, - pool: ConnectionPool, + pool: ConnectionPool, mut config: Option, ) -> Self { - let mut storage = pool.connection().await.unwrap(); + let storage = pool.connection().await.unwrap(); if config.is_none() { config = Some(ViaBtcSenderConfig::for_tests()); @@ -47,98 +34,18 @@ mod tests { .await .unwrap(); - let timestamp = Utc::now().timestamp() as u64; - let protocol_version = zksync_types::ProtocolVersion { - l1_verifier_config: L1VerifierConfig { - recursion_scheduler_level_vk_hash: H256::random(), - }, - base_system_contracts_hashes, - timestamp, - tx: None, - version: ProtocolSemanticVersion { - minor: protocol_version, - patch: 0.into(), - }, - }; - - storage - .protocol_versions_dal() - .save_protocol_version_with_tx(&protocol_version) - .await - .unwrap(); - Self { aggregator, storage, } } - - pub async fn insert_l1_batch( - &mut self, - header: L1BatchHeader, - l1_commitment_artifacts: L1BatchCommitmentArtifacts, - ) { - self.storage - .blocks_dal() - .insert_mock_l1_batch(&header) - .await - .unwrap(); - - self.storage - .blocks_dal() - .save_l1_batch_tree_data( - header.number, - &L1BatchTreeData { - hash: H256::random(), - rollup_last_leaf_index: 1, - }, - ) - .await - .unwrap(); - - self.storage - .blocks_dal() - .save_l1_batch_commitment_artifacts(header.number, &l1_commitment_artifacts) - .await - .unwrap(); - - let time = Utc::now().naive_utc(); - - self.storage - .via_data_availability_dal() - .insert_l1_batch_da(header.number, "blob_id", time) - .await - .expect("insert_l1_batch_da"); - - let random_slice: &[u8] = &generate_random_bytes(32); - - self.storage - .via_data_availability_dal() - .save_l1_batch_inclusion_data(header.number, random_slice) - .await - .expect("save_l1_batch_inclusion_data"); - } } // Get the current operation (commitBatch or commitProof) to execute when there is no batches. Should return 'None' #[tokio::test] async fn test_get_next_ready_vote_operation() { - let pool = ConnectionPool::::test_pool().await; - let header = create_l1_batch(1); - let mut aggregator_test = ViaVoteInscriptionTest::new( - header.protocol_version.unwrap(), - header.base_system_contracts_hashes, - pool, - None, - ) - .await; - - aggregator_test - .insert_l1_batch( - header.clone(), - l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), - ) - .await; + let pool = ConnectionPool::::test_pool().await; + let mut aggregator_test = ViaVoteInscriptionTest::new(pool, None).await; let tx_id = H256::random(); let _ = aggregator_test @@ -184,7 +91,7 @@ mod tests { let inscriptions = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .list_new_inscription_request(10) .await .unwrap(); @@ -205,26 +112,13 @@ mod tests { #[tokio::test] async fn test_verifier_vote_inscription_manager() { - let pool = ConnectionPool::::test_pool().await; + let pool = ConnectionPool::::test_pool().await; let config = get_btc_sender_config(1, 1); let mut mock_btc_ops_config = MockBitcoinOpsConfig::default(); mock_btc_ops_config.set_block_height(1); - let header = create_l1_batch(1); - let mut aggregator_test = ViaVoteInscriptionTest::new( - header.protocol_version.unwrap(), - header.base_system_contracts_hashes, - pool.clone(), - None, - ) - .await; + let mut aggregator_test = ViaVoteInscriptionTest::new(pool.clone(), None).await; - aggregator_test - .insert_l1_batch( - header.clone(), - l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), - ) - .await; let tx_id = H256::random(); let _ = aggregator_test @@ -239,12 +133,12 @@ mod tests { .verify_votable_transaction(1, tx_id, true) .await; - run_aggregator(header, pool.clone()).await; + run_aggregator(pool.clone()).await; run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; let inflight_inscriptions_before = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .get_inflight_inscriptions() .await .unwrap(); @@ -253,7 +147,7 @@ mod tests { let last_inscription_history_before = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .get_last_inscription_request_history(inflight_inscriptions_before[0].id) .await .unwrap(); @@ -268,7 +162,7 @@ mod tests { let last_inscription_history_after = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .get_last_inscription_request_history(inflight_inscriptions_before[0].id) .await .unwrap(); @@ -288,7 +182,7 @@ mod tests { let inflight_inscriptions_after = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .get_inflight_inscriptions() .await .unwrap(); @@ -297,7 +191,7 @@ mod tests { let last_inscription_history_after = aggregator_test .storage - .btc_sender_dal() + .via_btc_sender_dal() .get_last_inscription_request_history(inflight_inscriptions_before[0].id) .await .unwrap(); @@ -311,7 +205,7 @@ mod tests { run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; } - async fn run_aggregator(header: L1BatchHeader, pool: ConnectionPool) { + async fn run_aggregator(pool: ConnectionPool) { { // Create an async channel to break the while loop afer 3 seconds. let (sender, receiver): (watch::Sender, watch::Receiver) = @@ -330,13 +224,7 @@ mod tests { } }); - let aggregator_test = ViaVoteInscriptionTest::new( - header.protocol_version.unwrap(), - header.base_system_contracts_hashes, - pool.clone(), - None, - ) - .await; + let aggregator_test = ViaVoteInscriptionTest::new(pool.clone(), None).await; aggregator_test.aggregator.run(receiver).await.unwrap(); if let Err(e) = toggle_handler.await { @@ -346,7 +234,7 @@ mod tests { } async fn run_manager( - pool: ConnectionPool, + pool: ConnectionPool, config: ViaBtcSenderConfig, mock_btc_ops_config: MockBitcoinOpsConfig, ) { From 85c1b46725fe32fe56f557e99cd72918c04096c5 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:18:25 +0100 Subject: [PATCH 129/212] feat: add verifer btc_sender --- .../bin/verifier_server/src/node_builder.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 34bf3261c..3e154c79c 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -10,6 +10,9 @@ use zksync_node_framework::{ healtcheck_server::HealthCheckLayer, pools_layer::PoolsLayerBuilder, sigint::SigintHandlerLayer, + via_btc_sender::{ + vote::ViaBtcVoteInscriptionLayer, vote_manager::ViaInscriptionManagerLayer, + }, via_btc_watch::BtcWatchLayer, via_verifier::{ coordinator_api::ViaCoordinatorApiLayer, verifier::ViaWithdrawalVerifierLayer, @@ -88,6 +91,15 @@ impl ViaNodeBuilder { Ok(self) } + fn add_btc_sender_layer(mut self) -> anyhow::Result { + let btc_sender_config = try_load_config!(self.configs.via_btc_sender_config); + self.node + .add_layer(ViaBtcVoteInscriptionLayer::new(btc_sender_config.clone())); + self.node + .add_layer(ViaInscriptionManagerLayer::new(btc_sender_config)); + Ok(self) + } + // VIA related layers fn add_verifier_btc_watcher_layer(mut self) -> anyhow::Result { let mut btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); @@ -137,7 +149,8 @@ impl ViaNodeBuilder { .add_sigint_handler_layer()? .add_healthcheck_layer()? .add_circuit_breaker_checker_layer()? - .add_pools_layer()?; + .add_pools_layer()? + .add_btc_sender_layer()?; // .add_verifier_btc_watcher_layer()?; if self.is_coordinator { From d524d85c4ad89a202654b5df35b98c99a2e92771 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 14 Jan 2025 18:21:59 +0100 Subject: [PATCH 130/212] feat: btc_watcher layer, zkp verification layer for verification bin --- core/bin/via_server/src/config.rs | 6 +++--- ...f7f7dc59a40e03457c442d14fa5c4d37182b.json} | 4 ++-- core/lib/dal/src/via_votes_dal.rs | 2 +- .../layers/via_verifier_btc_watch.rs | 1 + .../layers/via_zk_verification.rs | 4 ++-- docker-compose-via.yml | 2 +- infrastructure/via/src/bootstrap.ts | 8 +++++--- infrastructure/via/src/verifier.ts | 16 +++++++++++++++ .../bin/verifier_server/src/node_builder.rs | 20 +++++++++++++++---- 9 files changed, 47 insertions(+), 16 deletions(-) rename core/lib/dal/.sqlx/{query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json => query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json} (71%) diff --git a/core/bin/via_server/src/config.rs b/core/bin/via_server/src/config.rs index 1251a909a..3c3511be0 100644 --- a/core/bin/via_server/src/config.rs +++ b/core/bin/via_server/src/config.rs @@ -97,13 +97,13 @@ pub(crate) fn via_load_env_config() -> anyhow::Result<( let celestia_config = ViaCelestiaConfig::from_env().context("Failed to load celestia config")?; // TODO: tmp - let verifier_config = - ViaVerifierConfig::from_env().context("Failed to load verifier config")?; + // let verifier_config = + // ViaVerifierConfig::from_env().context("Failed to load verifier config")?; Ok(( btc_watch_config, btc_sender_config, celestia_config, - verifier_config, + ViaVerifierConfig::for_tests(), )) } diff --git a/core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json b/core/lib/dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json similarity index 71% rename from core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json rename to core/lib/dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json index 472334232..3f4dc4c6e 100644 --- a/core/lib/dal/.sqlx/query-39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9.json +++ b/core/lib/dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING\n ", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", "describe": { "columns": [], "parameters": { @@ -14,5 +14,5 @@ }, "nullable": [] }, - "hash": "39f6b255bf7129ece302bd6cc9e70265a6fe24abd28e629dd2fa1f9c400c29d9" + "hash": "aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b" } diff --git a/core/lib/dal/src/via_votes_dal.rs b/core/lib/dal/src/via_votes_dal.rs index b10fc584a..2c8f1cdc0 100644 --- a/core/lib/dal/src/via_votes_dal.rs +++ b/core/lib/dal/src/via_votes_dal.rs @@ -24,7 +24,7 @@ impl ViaVotesDal<'_, '_> { via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id) VALUES ($1, $2, $3, $4, $5) - ON CONFLICT (l1_batch_number, tx_id, blob_id) DO NOTHING + ON CONFLICT (l1_batch_number, tx_id) DO NOTHING "#, i64::from(l1_batch_number), tx_id.as_bytes(), diff --git a/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs index 6f4a50462..4c457909e 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs @@ -71,6 +71,7 @@ impl WiringLayer for VerifierBtcWatchLayer { .collect::, _>>()?; let btc_blocks_lag = self.btc_watch_config.btc_blocks_lag(); + tracing::error!("bootstrap_txids: {:?}", bootstrap_txids); let indexer = BtcIndexerResource::from( BitcoinInscriptionIndexer::new( self.btc_watch_config.rpc_url(), diff --git a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs index e48b38923..ab3f0d2a1 100644 --- a/core/node/node_framework/src/implementations/layers/via_zk_verification.rs +++ b/core/node/node_framework/src/implementations/layers/via_zk_verification.rs @@ -16,8 +16,8 @@ use crate::{ #[derive(Debug)] pub struct ViaBtcProofVerificationLayer { - config: ViaVerifierConfig, - btc_watcher_config: ViaBtcWatchConfig, + pub config: ViaVerifierConfig, + pub btc_watcher_config: ViaBtcWatchConfig, } #[derive(Debug, FromContext)] diff --git a/docker-compose-via.yml b/docker-compose-via.yml index a44e4f3b5..890dead3a 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -114,7 +114,7 @@ services: volumes: - type: bind source: ./volumes/celestia - target: /home/celestia:rw + target: /home/celestia # - type: bind # source: ./volumes/celestia-keys # target: /root/.celestia-light-mocha-4/keys diff --git a/infrastructure/via/src/bootstrap.ts b/infrastructure/via/src/bootstrap.ts index 584971309..9d5f2b707 100644 --- a/infrastructure/via/src/bootstrap.ts +++ b/infrastructure/via/src/bootstrap.ts @@ -23,7 +23,7 @@ async function updateEnvVariable(envFilePath: string, variableName: string, newV await fs.writeFile(envFilePath, newEnvContent, 'utf-8'); } -async function updateBootstrapTxidsEnv() { +export async function updateBootstrapTxidsEnv() { const txidsFilePath = path.join(process.env.VIA_HOME!, 'txids.via'); const txidsContent = await fs.readFile(txidsFilePath, 'utf8'); @@ -34,13 +34,15 @@ async function updateBootstrapTxidsEnv() { const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); + console.log(`Updating file ${envFilePath}`); + await updateEnvVariable(envFilePath, 'VIA_BTC_WATCH_BOOTSTRAP_TXIDS', newTxids); console.log(`Updated VIA_BTC_WATCH_BOOTSTRAP_TXIDS with: ${newTxids}`); try { - await fs.unlink(txidsFilePath); - console.log(`Deleted txids.via file.`); + // await fs.unlink(txidsFilePath); + console.log(`NOT Deleted txids.via file.`); } catch (error) { console.error(`Error deleting txids.via file`); } diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index 693d62585..e74f5de72 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -1,9 +1,23 @@ import { Command } from 'commander'; import * as utils from 'utils'; import * as env from './env'; +import { updateBootstrapTxidsEnv } from './bootstrap'; +import { updateEnvVariable } from './helpers'; +import path from 'path'; export async function verifier() { let options = ''; + await updateBootstrapTxidsEnv(); + + const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); + await updateEnvVariable(envFilePath, 'VIA_BTC_WATCH_ACTOR_ROLE', 'Verifier'); + + console.log(`Starting verifier node...`); + + env.reload(); + + await console.log(`Starting verifier node...`); + await utils.spawn(`cargo run --bin via_verifier`); } @@ -11,5 +25,7 @@ export const verifierCommand = new Command('verifier') .description('start via verifier node') .action(async (cmd: Command) => { cmd.chainName ? env.reload(cmd.chainName) : env.load(); + await env.load(); + env.get(true); await verifier(); }); diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 34bf3261c..05d810ea4 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -15,6 +15,7 @@ use zksync_node_framework::{ coordinator_api::ViaCoordinatorApiLayer, verifier::ViaWithdrawalVerifierLayer, }, via_verifier_btc_watch::VerifierBtcWatchLayer, + via_zk_verification::ViaBtcProofVerificationLayer, }, service::{ZkStackService, ZkStackServiceBuilder}, }; @@ -91,7 +92,6 @@ impl ViaNodeBuilder { // VIA related layers fn add_verifier_btc_watcher_layer(mut self) -> anyhow::Result { let mut btc_watch_config = try_load_config!(self.configs.via_btc_watch_config); - btc_watch_config.actor_role = ActorRole::Verifier; assert_eq!( btc_watch_config.actor_role, ActorRole::Verifier, @@ -132,18 +132,30 @@ impl ViaNodeBuilder { Ok(self) } + fn add_zkp_verification_layer(mut self) -> anyhow::Result { + let via_verifier_config = try_load_config!(self.configs.via_verifier_config); + let via_btc_watcher_config = try_load_config!(self.configs.via_btc_watch_config); + self.node.add_layer(ViaBtcProofVerificationLayer { + config: via_verifier_config, + btc_watcher_config: via_btc_watcher_config, + }); + Ok(self) + } + pub fn build(mut self) -> anyhow::Result { self = self .add_sigint_handler_layer()? .add_healthcheck_layer()? .add_circuit_breaker_checker_layer()? - .add_pools_layer()?; - // .add_verifier_btc_watcher_layer()?; + .add_pools_layer()? + .add_verifier_btc_watcher_layer()? + .add_withdrawal_verifier_task_layer()?; if self.is_coordinator { self = self .add_via_celestia_da_client_layer()? - .add_verifier_coordinator_api_layer()?; + .add_verifier_coordinator_api_layer()? + .add_zkp_verification_layer()?; } self = self.add_withdrawal_verifier_task_layer()?; From 425097d079dd10694955724e66fd8c722eb5fa62 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 15 Jan 2025 11:07:04 +0100 Subject: [PATCH 131/212] fix: infra --- .../src/implementations/layers/via_verifier_btc_watch.rs | 1 - infrastructure/via/src/env.ts | 9 +++++++++ infrastructure/via/src/verifier.ts | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs index 4c457909e..6f4a50462 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier_btc_watch.rs @@ -71,7 +71,6 @@ impl WiringLayer for VerifierBtcWatchLayer { .collect::, _>>()?; let btc_blocks_lag = self.btc_watch_config.btc_blocks_lag(); - tracing::error!("bootstrap_txids: {:?}", bootstrap_txids); let indexer = BtcIndexerResource::from( BitcoinInscriptionIndexer::new( self.btc_watch_config.rpc_url(), diff --git a/infrastructure/via/src/env.ts b/infrastructure/via/src/env.ts index 5b38d1e50..44bcf44c4 100644 --- a/infrastructure/via/src/env.ts +++ b/infrastructure/via/src/env.ts @@ -76,6 +76,15 @@ export function reload(environment?: string) { } } +export function load_from_file(environment?: string) { + environment = environment ?? get(); + const envFile = (process.env.ENV_FILE = `etc/env/target/${environment}.env`); + const env = dotenv.parse(fs.readFileSync(envFile)); + for (const envVar in env) { + process.env[envVar] = env[envVar]; + } +} + // loads environment variables export function load() { fs.mkdirSync('etc/env/target', { recursive: true }); diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index e74f5de72..1db6705a5 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -4,6 +4,7 @@ import * as env from './env'; import { updateBootstrapTxidsEnv } from './bootstrap'; import { updateEnvVariable } from './helpers'; import path from 'path'; +import {load_from_file} from "./env"; export async function verifier() { let options = ''; @@ -14,7 +15,7 @@ export async function verifier() { console.log(`Starting verifier node...`); - env.reload(); + env.load_from_file(); await console.log(`Starting verifier node...`); From 4a94b8541f2a3859702f56eeab1543bba560425d Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 15 Jan 2025 11:08:15 +0100 Subject: [PATCH 132/212] chore: fmt --- infrastructure/via/src/verifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index 1db6705a5..4a20d95a1 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -4,7 +4,7 @@ import * as env from './env'; import { updateBootstrapTxidsEnv } from './bootstrap'; import { updateEnvVariable } from './helpers'; import path from 'path'; -import {load_from_file} from "./env"; +import { load_from_file } from './env'; export async function verifier() { let options = ''; From 34093f2615bf768f1f1abd9731cbfda747f2e07d Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 15 Jan 2025 11:42:48 +0100 Subject: [PATCH 133/212] fix: review fix --- etc/env/configs/via_coordinator.toml | 3 +++ infrastructure/via/src/verifier.ts | 6 ------ via_verifier/bin/verifier_server/src/node_builder.rs | 8 +++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index 573cdc698..c92cdfe2c 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -24,3 +24,6 @@ bridge_address_str = "bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62s required_signers = 2 # The verifier_mode can be simple verifier or coordinator. verifier_mode = "COORDINATOR" + +[via_btc_watch] +actor_role = "Verifier" diff --git a/infrastructure/via/src/verifier.ts b/infrastructure/via/src/verifier.ts index 4a20d95a1..310899bbf 100644 --- a/infrastructure/via/src/verifier.ts +++ b/infrastructure/via/src/verifier.ts @@ -7,18 +7,12 @@ import path from 'path'; import { load_from_file } from './env'; export async function verifier() { - let options = ''; await updateBootstrapTxidsEnv(); - const envFilePath = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); - await updateEnvVariable(envFilePath, 'VIA_BTC_WATCH_ACTOR_ROLE', 'Verifier'); - console.log(`Starting verifier node...`); env.load_from_file(); - await console.log(`Starting verifier node...`); - await utils.spawn(`cargo run --bin via_verifier`); } diff --git a/via_verifier/bin/verifier_server/src/node_builder.rs b/via_verifier/bin/verifier_server/src/node_builder.rs index 05d810ea4..071547a44 100644 --- a/via_verifier/bin/verifier_server/src/node_builder.rs +++ b/via_verifier/bin/verifier_server/src/node_builder.rs @@ -149,13 +149,11 @@ impl ViaNodeBuilder { .add_circuit_breaker_checker_layer()? .add_pools_layer()? .add_verifier_btc_watcher_layer()? - .add_withdrawal_verifier_task_layer()?; + .add_via_celestia_da_client_layer()? + .add_zkp_verification_layer()?; if self.is_coordinator { - self = self - .add_via_celestia_da_client_layer()? - .add_verifier_coordinator_api_layer()? - .add_zkp_verification_layer()?; + self = self.add_verifier_coordinator_api_layer()? } self = self.add_withdrawal_verifier_task_layer()?; From 59265e332b48415fec85fc0981b34d5056a2e3a7 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:52:59 +0100 Subject: [PATCH 134/212] chore: update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 733a66811..f44fc9ad6 100644 --- a/.gitignore +++ b/.gitignore @@ -118,3 +118,5 @@ configs/* era-observability/ core/tests/ts-integration/deployments-zk .env + +*.via \ No newline at end of file From 4a708a14bc96ff3577c0dc8eaa092a9127a726b4 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 15 Jan 2025 15:40:15 +0100 Subject: [PATCH 135/212] feat: new via key --- .../02122b5b52d9dd736578baeeb056e4516e92a565.address | 1 + celestia-keys/keys/keyring-test/via.info | 1 + docker-compose-via.yml | 6 ++---- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 celestia-keys/keys/keyring-test/02122b5b52d9dd736578baeeb056e4516e92a565.address create mode 100644 celestia-keys/keys/keyring-test/via.info diff --git a/celestia-keys/keys/keyring-test/02122b5b52d9dd736578baeeb056e4516e92a565.address b/celestia-keys/keys/keyring-test/02122b5b52d9dd736578baeeb056e4516e92a565.address new file mode 100644 index 000000000..97fe3f4b6 --- /dev/null +++ b/celestia-keys/keys/keyring-test/02122b5b52d9dd736578baeeb056e4516e92a565.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNS0wMS0xNSAxNDoyMjo1MC41NDMzNTkwMDEgKzAwMDAgVVRDIG09KzAuMDU4MzU0MzM0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiQ1h1eFoxa1gxcTRJM1pWYyJ9.uNjZsbL9Hv8otbgUlksmWNCQFvLR6AOmas9qmny0B2TP5MJeFRWk7g.wyZbmsDqzNCv1H5M.CUcs61H8OmnLsY-jxmel8zhCNSXTKJsQJIrn7JBbK1XnJgpVgQ-KMkeQVp5T69GSL3KUfe2MjI2kCVeKcDytDsGy0ateEonhdO08Pg91X77phFVkBNFn1VtnCHaceyFC4zwf-zZ30gh8N4QKSuLQNdjI07BFs2q1swW-eCUF3TFryVxixyOYGpx_Juy2p_bLoyni1A4eip7I1BBvNRJ8fxYo9qqRB4mZwXIJIcxk8-3tiA.gjMUyxcmYXgIz5jnJ9gRMA \ No newline at end of file diff --git a/celestia-keys/keys/keyring-test/via.info b/celestia-keys/keys/keyring-test/via.info new file mode 100644 index 000000000..19426573a --- /dev/null +++ b/celestia-keys/keys/keyring-test/via.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNS0wMS0xNSAxNDoyMjo1MC41NDExNTQ1MDEgKzAwMDAgVVRDIG09KzAuMDU2MTQ5ODM0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiM2M2ZE5hZGtfZ2tlYTZpeCJ9.vZYYaf-uL3peWfxb6Hn4CZesAbXSgLeYXwMaeN_0h9gFuzr4XBALXg.qo8y1jMkqcJGbhDc.8KRkaeKDNlahLgJd3mvsjLODIlcJAeMh8ZBvIVVWcdY-O-GhR_HfXFyYquWGC0pjLuJaL49WoERrRWUjU61bGpsqMS0aGDI4kp8mZUFefs7ZH0knqfHbacpqgU-5VIbvvPQ4qGlrtSZfiCMNN_h53leFzy8W3QGU1icA-J63kjl_GvVagQ02eqoX9HnzlYlWl4nUNprnK2qvaxZ-OfDCPCDpd3ol0mqnKlAuR_dOJjgJdcwpYEK7k93qUbjRdjTOJP-j_GG8OnP-TuMb-btNhi08jcVmTdfJFW3MK1XBnpDMqVz0tTm5Wk0HWC_5rhPAyamPkFWegvTMDhuq7GfAYICxIdi5Rj5A1024zQZItTCgwezPgWpYRiqVD4TcesFbUHOkDaQI5kUyozOB3CtdlBWDePhM2vnoZMRP8ODHeXg-7rDwocNdqGu0.K8T_WIUoinYUDSewZpFGMQ \ No newline at end of file diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 890dead3a..155f99f49 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -115,10 +115,8 @@ services: - type: bind source: ./volumes/celestia target: /home/celestia - # - type: bind - # source: ./volumes/celestia-keys - # target: /root/.celestia-light-mocha-4/keys - command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip full.consensus.mocha-4.celestia-mocha.com --p2p.network mocha + - ./celestia-keys/keys:/home/celestia/keys + command: celestia light start --headers.trusted-hash ${VIA_CELESTIA_CLIENT_TRUSTED_BLOCK_HASH} --core.ip full.consensus.mocha-4.celestia-mocha.com --p2p.network mocha --keyring.backend test --keyring.keyname via ports: - '26658:26658' environment: From ac447168c9d11254b251f919fca8e039407d955e Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 15 Jan 2025 15:43:29 +0100 Subject: [PATCH 136/212] fix: updated .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f44fc9ad6..21679c61a 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,6 @@ era-observability/ core/tests/ts-integration/deployments-zk .env -*.via \ No newline at end of file +*.via + +celestia-keys/* \ No newline at end of file From 8bcbe043ae2d8a0e3aeb28a28304ab1924ea059d Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 16 Jan 2025 15:08:01 +0330 Subject: [PATCH 137/212] Fix(musig2): fix withdrawal example --- docker-compose-via.yml | 2 +- .../examples/key_generation_setup.rs | 4 +- .../lib/via_musig2/examples/withdrawal.rs | 353 ++++++++++-------- 3 files changed, 196 insertions(+), 163 deletions(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 155f99f49..79409c870 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -92,7 +92,7 @@ services: - VERIFIER_1_ADDRESS=bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv - VERIFIER_2_ADDRESS=bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4 - VERIFIER_3_ADDRESS=bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm - - BRIDGE_ADDRESS=bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv + - BRIDGE_ADDRESS=bcrt1pcx974cg2w66cqhx67zadf85t8k4sd2wp68l8x8agd3aj4tuegsgsz97amg - RPC_ARGS=-chain=regtest -rpcconnect=bitcoind -rpcwait -rpcuser=rpcuser -rpcpassword=rpcpassword - SLEEP_SECONDS=5 diff --git a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs index 12fbd48fa..7105ce698 100644 --- a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs +++ b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs @@ -80,8 +80,8 @@ fn main() -> Result<(), Box> { } let mut pubkeys = Vec::new(); - for i in 2..args.len() { - let public_key = PublicKey::from_str(&args[i]).unwrap(); + for pubkey_str in args.iter().skip(2) { + let public_key = PublicKey::from_str(pubkey_str).unwrap(); pubkeys.push(public_key); } diff --git a/via_verifier/lib/via_musig2/examples/withdrawal.rs b/via_verifier/lib/via_musig2/examples/withdrawal.rs index 108609ac6..dd22c393a 100644 --- a/via_verifier/lib/via_musig2/examples/withdrawal.rs +++ b/via_verifier/lib/via_musig2/examples/withdrawal.rs @@ -1,220 +1,253 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Demonstrate creating a transaction that spends to and from p2tr outputs with musig2. + +use std::str::FromStr; + use bitcoin::{ - absolute, hashes::Hash, - sighash::{Prevouts, SighashCache}, - taproot::TaprootSpendInfo, - Address as BitcoinAddress, Amount, Network, OutPoint, TapSighashType, Transaction, TxIn, TxOut, - Witness, XOnlyPublicKey, -}; -// use bitcoincore_rpc::Auth; -use musig2::{ - verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, SecNonceSpices, + key::Keypair, + locktime::absolute, + secp256k1::{Secp256k1, SecretKey}, + sighash::{Prevouts, SighashCache, TapSighashType}, + transaction, Address, Amount, Network, PrivateKey, ScriptBuf, Sequence, TapTweakHash, + Transaction, TxIn, TxOut, Witness, }; -use rand::{rngs::OsRng, Rng}; -use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; +use musig2::{secp::Scalar, KeyAggContext}; +use rand::Rng; +use secp256k1_musig2::schnorr::Signature; +use via_btc_client::{inscriber::Inscriber, types::NodeAuth}; + +const RPC_URL: &str = "http://0.0.0.0:18443"; +const RPC_USERNAME: &str = "rpcuser"; +const RPC_PASSWORD: &str = "rpcpassword"; +const NETWORK: Network = Network::Regtest; +const PK: &str = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm"; +const SPEND_AMOUNT: Amount = Amount::from_sat(5_000_000); #[tokio::main] async fn main() -> Result<(), Box> { - // ------------------------------------------- - // Setup: Create secret and public keys for three participants - // ------------------------------------------- - let mut rng = OsRng; - let secret_key_1 = SecretKey::new(&mut rng); - let secret_key_2 = SecretKey::new(&mut rng); - let secret_key_3 = SecretKey::new(&mut rng); - let secp = Secp256k1::new(); - let public_key_1 = PublicKey::from_secret_key(&secp, &secret_key_1); - let public_key_2 = PublicKey::from_secret_key(&secp, &secret_key_2); - let public_key_3 = PublicKey::from_secret_key(&secp, &secret_key_3); + + // Get a keypair we control. In a real application these would come from a stored secret. + let private_key_1 = + PrivateKey::from_wif("cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R").unwrap(); + + let private_key_2 = + PrivateKey::from_wif("cUWA5dZXc6NwLovW3Kr9DykfY5ysFigKZM5Annzty7J8a43Fe2YF").unwrap(); + + let private_key_3 = + PrivateKey::from_wif("cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm").unwrap(); + + let secret_key_1 = SecretKey::from_slice(&private_key_1.inner.secret_bytes()).unwrap(); + let secret_key_2 = SecretKey::from_slice(&private_key_2.inner.secret_bytes()).unwrap(); + let secret_key_3 = SecretKey::from_slice(&private_key_3.inner.secret_bytes()).unwrap(); + + let keypair_1 = Keypair::from_secret_key(&secp, &secret_key_1); + let keypair_2 = Keypair::from_secret_key(&secp, &secret_key_2); + let keypair_3 = Keypair::from_secret_key(&secp, &secret_key_3); + + let (internal_key_1, parity_1) = keypair_1.x_only_public_key(); + let (internal_key_2, parity_2) = keypair_2.x_only_public_key(); + let (internal_key_3, parity_3) = keypair_3.x_only_public_key(); // ------------------------------------------- // Key aggregation (MuSig2) // ------------------------------------------- - let pubkeys = vec![public_key_1, public_key_2, public_key_3]; - let key_agg_ctx = KeyAggContext::new(pubkeys)?; - let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); - - // Convert to x-only pubkey for Taproot address - let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); - let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; - // Create a P2TR address from the aggregated x-only public key - let secp_btc = bitcoin::secp256k1::Secp256k1::new(); - let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); - let tweaked_key = tap_info.output_key(); - let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); - println!("Aggregated taproot address: {}", address); + let pubkeys = vec![ + musig2::secp256k1::PublicKey::from_slice(&internal_key_1.public_key(parity_1).serialize()) + .unwrap(), + musig2::secp256k1::PublicKey::from_slice(&internal_key_2.public_key(parity_2).serialize()) + .unwrap(), + musig2::secp256k1::PublicKey::from_slice(&internal_key_3.public_key(parity_3).serialize()) + .unwrap(), + ]; - // ------------------------------------------- - // Connect to Bitcoin node (adjust RPC credentials and URL) - // ------------------------------------------- - // NOTE: Update these with real RPC credentials and URL - let _rpc_url = "http://127.0.0.1:18443"; - let _rpc_user = "user"; - let _rpc_pass = "pass"; + let mut musig_key_agg_cache = KeyAggContext::new(pubkeys)?; + + let agg_pubkey = musig_key_agg_cache.aggregated_pubkey::(); + let (xonly_agg_key, _) = agg_pubkey.x_only_public_key(); + + // Convert to bitcoin XOnlyPublicKey first + let internal_key = bitcoin::XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + + // Calculate taproot tweak + let tap_tweak = TapTweakHash::from_key_and_tweak(internal_key, None); + let tweak = tap_tweak.to_scalar(); + let tweak_bytes = tweak.to_be_bytes(); + let tweak = secp256k1_musig2::Scalar::from_be_bytes(tweak_bytes).unwrap(); - // let client = BitcoinClient::new(rpc_url, Network::Regtest, Auth::UserPass(rpc_user.into(), rpc_pass.into()))?; + // Apply tweak to the key aggregation context before signing + musig_key_agg_cache = musig_key_agg_cache.with_xonly_tweak(tweak)?; + + // Use internal_key for address creation + let address = Address::p2tr(&secp, internal_key, None, NETWORK); + + println!("address: {}", address); // ------------------------------------------- - // Instead of fetching UTXOs from node, use a fake constant UTXO for demonstration - // Comment out real fetching code + // Connect to Bitcoin node (adjust RPC credentials and URL) // ------------------------------------------- - // let utxos = client.fetch_utxos(&address).await?; - // if utxos.is_empty() { - // eprintln!("No UTXOs found for this address. Please fund it first."); - // return Ok(()); - // } - - // We'll use a fake UTXO here - let fake_utxo_txid = bitcoin::Txid::from_slice(&[0x11; 32]).unwrap(); // just a dummy 32-byte txid - let fake_vout = 0; - let fake_utxo_amount = Amount::from_btc(1.0).unwrap(); // 1 BTC in the fake utxo - let fake_utxo = (fake_utxo_txid, fake_vout, fake_utxo_amount); + let inscriber = Inscriber::new( + RPC_URL, + NETWORK, + NodeAuth::UserPass(RPC_USERNAME.to_string(), RPC_PASSWORD.to_string()), + PK, + None, + ) + .await?; + let client = inscriber.get_client().await; // ------------------------------------------- - // Create a transaction spending this fake UTXO + // Fetching UTXOs from node // ------------------------------------------- - let send_amount = Amount::from_btc(0.1).unwrap(); // amount to send - let fee_amount = Amount::from_btc(0.0001).unwrap(); - let change_amount = fake_utxo_amount - send_amount - fee_amount; - - // The recipient address - for demonstration let's send to the same aggregated address - // or another regtest address. - let recipient_address = address.clone(); - let change_address = address.clone(); - - let txin = TxIn { - previous_output: OutPoint { - txid: fake_utxo.0, - vout: fake_utxo.1, - }, - sequence: bitcoin::Sequence(0xFFFFFFFF), - witness: Witness::new(), - script_sig: bitcoin::Script::new().into(), + let utxos = client.fetch_utxos(&address).await?; + + // Get an unspent output that is locked to the key above that we control. + // In a real application these would come from the chain. + let (dummy_out_point, dummy_utxo) = utxos[0].clone(); + + let change_amount = dummy_utxo.value - SPEND_AMOUNT; + + // Get an address to send to. + let address = receivers_address(); + + // The input for the transaction we are constructing. + let input = TxIn { + previous_output: dummy_out_point, // The dummy output we are spending. + script_sig: ScriptBuf::default(), // For a p2tr script_sig is empty. + sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: Witness::default(), // Filled in after signing. }; - let txout_recipient = TxOut { - value: send_amount, - script_pubkey: recipient_address.script_pubkey(), + // The spend output is locked to a key controlled by the receiver. + let spend = TxOut { + value: SPEND_AMOUNT, + script_pubkey: address.script_pubkey(), }; - let txout_change = TxOut { + // The change output is locked to a key controlled by us. + let change = TxOut { value: change_amount, - script_pubkey: change_address.script_pubkey(), + script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key, None), // Change comes back to us. }; + // The transaction we want to sign and broadcast. let mut unsigned_tx = Transaction { - version: bitcoin::transaction::Version(2), - lock_time: absolute::LockTime::ZERO, - input: vec![txin], - output: vec![txout_recipient, txout_change], + version: transaction::Version::TWO, // Post BIP-68. + lock_time: absolute::LockTime::ZERO, // Ignore the locktime. + input: vec![input], // Input goes into index 0. + output: vec![spend, change], // Outputs, order does not matter. }; + let input_index = 0; - // ------------------------------------------- - // Compute the BIP341 sighash for signing - // ------------------------------------------- - let mut sighash_cache = SighashCache::new(&unsigned_tx); - let sighash_type = TapSighashType::All; - - // For taproot key spend (no script): - let sighash = sighash_cache.taproot_key_spend_signature_hash( - 0, - &Prevouts::All(&[TxOut { - value: fake_utxo_amount, - script_pubkey: recipient_address.script_pubkey(), - }]), - sighash_type, - )?; + // Get the sighash to sign. + let sighash_type = TapSighashType::Default; + let prevouts = vec![dummy_utxo]; + let prevouts = Prevouts::All(&prevouts); - let message = sighash; // This 32-byte hash is what we will sign using MuSig2 + let mut sighasher = SighashCache::new(&mut unsigned_tx); + let sighash = sighasher + .taproot_key_spend_signature_hash(input_index, &prevouts, sighash_type) + .expect("failed to construct sighash"); // ------------------------------------------- - // MuSig2 Nonce Exchange and Partial Signatures + // MuSig2 Signing Process // ------------------------------------------- - // First round: generate public nonces + use musig2::{FirstRound, SecNonceSpices}; + use rand::thread_rng; + + // Convert bitcoin::SecretKey to musig2::SecretKey for each participant + let secret_key_1 = musig2::secp256k1::SecretKey::from_slice(&secret_key_1[..]).unwrap(); + let secret_key_2 = musig2::secp256k1::SecretKey::from_slice(&secret_key_2[..]).unwrap(); + let secret_key_3 = musig2::secp256k1::SecretKey::from_slice(&secret_key_3[..]).unwrap(); + + // First round: Generate nonces let mut first_round_1 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), + musig_key_agg_cache.clone(), // Use tweaked context + thread_rng().gen::<[u8; 32]>(), 0, SecNonceSpices::new() .with_seckey(secret_key_1) - .with_message(&message), + .with_message(&sighash.to_byte_array()), )?; let mut first_round_2 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), + musig_key_agg_cache.clone(), + thread_rng().gen::<[u8; 32]>(), 1, SecNonceSpices::new() .with_seckey(secret_key_2) - .with_message(&message), + .with_message(&sighash.to_byte_array()), )?; let mut first_round_3 = FirstRound::new( - key_agg_ctx.clone(), - rand::thread_rng().gen::<[u8; 32]>(), + musig_key_agg_cache.clone(), + thread_rng().gen::<[u8; 32]>(), 2, SecNonceSpices::new() .with_seckey(secret_key_3) - .with_message(&message), + .with_message(&sighash.to_byte_array()), )?; - // Get public nonces - let pub_nonce_1 = first_round_1.our_public_nonce(); - let pub_nonce_2 = first_round_2.our_public_nonce(); - let pub_nonce_3 = first_round_3.our_public_nonce(); + // Exchange nonces + let nonce_1 = first_round_1.our_public_nonce(); + let nonce_2 = first_round_2.our_public_nonce(); + let nonce_3 = first_round_3.our_public_nonce(); - // Exchange nonces between participants - first_round_1.receive_nonce(1, pub_nonce_2.clone())?; - first_round_1.receive_nonce(2, pub_nonce_3.clone())?; - - first_round_2.receive_nonce(0, pub_nonce_1.clone())?; - first_round_2.receive_nonce(2, pub_nonce_3.clone())?; - - first_round_3.receive_nonce(0, pub_nonce_1.clone())?; - first_round_3.receive_nonce(1, pub_nonce_2.clone())?; + first_round_1.receive_nonce(1, nonce_2.clone())?; + first_round_1.receive_nonce(2, nonce_3.clone())?; + first_round_2.receive_nonce(0, nonce_1.clone())?; + first_round_2.receive_nonce(2, nonce_3.clone())?; + first_round_3.receive_nonce(0, nonce_1.clone())?; + first_round_3.receive_nonce(1, nonce_2.clone())?; // Second round: Create partial signatures - let mut second_round_1 = first_round_1.finalize(secret_key_1, &message)?; - let second_round_2 = first_round_2.finalize(secret_key_2, &message)?; - let second_round_3 = first_round_3.finalize(secret_key_3, &message)?; - - // Get partial signatures - let _partial_sig_1: PartialSignature = second_round_1.our_signature(); - let partial_sig_2: PartialSignature = second_round_2.our_signature(); - let partial_sig_3: PartialSignature = second_round_3.our_signature(); - - // One participant collects all partial signatures - second_round_1.receive_signature(1, partial_sig_2)?; - second_round_1.receive_signature(2, partial_sig_3)?; - - // Final aggregate MuSig2 signature - let final_signature: CompactSignature = second_round_1.finalize()?; - - // Verify the signature (optional sanity check) - match verify_single(aggregated_pubkey, final_signature, message) { - Ok(_) => println!("MuSig2 signature verified successfully!"), - Err(e) => println!("MuSig2 signature verification failed: {:?}", e), - } - - // ------------------------------------------- - // Insert the final signature into the transaction witness - // ------------------------------------------- - let mut final_sig_with_hashtype = final_signature.serialize().to_vec(); - final_sig_with_hashtype.push(sighash_type as u8); // For SIGHASH_DEFAULT this is 0x00 + let binding = sighash.to_byte_array(); + let mut second_round_1 = first_round_1.finalize(secret_key_1, &binding)?; + let binding = sighash.to_byte_array(); + let second_round_2 = first_round_2.finalize(secret_key_2, &binding)?; + let binding = sighash.to_byte_array(); + let second_round_3 = first_round_3.finalize(secret_key_3, &binding)?; + // Combine partial signatures + let partial_sig_2: [u8; 32] = second_round_2.our_signature(); + let partial_sig_3: [u8; 32] = second_round_3.our_signature(); + + second_round_1.receive_signature(1, Scalar::from_slice(&partial_sig_2).unwrap())?; + second_round_1.receive_signature(2, Scalar::from_slice(&partial_sig_3).unwrap())?; + + let final_signature: Signature = second_round_1.finalize()?; + + // Update the witness stack with the aggregated signature + let signature = bitcoin::taproot::Signature { + signature: bitcoin::secp256k1::schnorr::Signature::from_slice( + &final_signature.to_byte_array(), + )?, + sighash_type, + }; + *sighasher.witness_mut(input_index).unwrap() = Witness::p2tr_key_spend(&signature); - // For a key-path spend in taproot, the witness is just the signature - unsigned_tx.input[0].witness = Witness::from(vec![final_sig_with_hashtype]); + // Get the signed transaction + let tx = sighasher.into_transaction(); - // ------------------------------------------- - // Print the signed raw transaction (in hex) - // ------------------------------------------- - let signed_raw_tx = bitcoin::consensus::encode::serialize_hex(&unsigned_tx); - println!("Signed raw transaction (hex): {}", signed_raw_tx); + // BOOM! Transaction signed and ready to broadcast. + println!("{:#?}", tx); - // NOTE: In real scenario, you could broadcast this transaction using the Bitcoin node RPC: - // client.broadcast_raw_tx(&signed_raw_tx).await?; - // Here we just printed it. + let tx_hex = bitcoin::consensus::encode::serialize_hex(&tx); + let res = client.broadcast_signed_transaction(&tx_hex).await?; + println!("res: {:?}", res); Ok(()) } + +/// A dummy address for the receiver. +/// +/// We lock the spend output to the key associated with this address. +/// +/// (FWIW this is an arbitrary mainnet address from block 805222.) +fn receivers_address() -> Address { + Address::from_str("bc1p0dq0tzg2r780hldthn5mrznmpxsxc0jux5f20fwj0z3wqxxk6fpqm7q0va") + .expect("a valid address") + .require_network(Network::Bitcoin) + .expect("valid address for mainnet") +} From 1b932106414a0a25c580b4782fda15c2eddcd6ac Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 16 Jan 2025 15:22:59 +0330 Subject: [PATCH 138/212] Fix(musig2): fund bridge address in regtest and apply fee in change amount --- docker-compose-via.yml | 4 ++++ via_verifier/lib/via_musig2/examples/withdrawal.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 79409c870..10abb654e 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -54,6 +54,10 @@ services: bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${VERIFIER_1_ADDRESS} 300 echo "Sent 300 BTC to VERIFIER_1_ADDRESS: $${VERIFIER_1_ADDRESS}" + echo "BRIDGE_ADDRESS: $${BRIDGE_ADDRESS}" + bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${BRIDGE_ADDRESS} 300 + echo "Sent 300 BTC to BRIDGE_ADDRESS: $${BRIDGE_ADDRESS}" + echo "VERIFIER_2_ADDRESS: $${VERIFIER_2_ADDRESS}" bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${VERIFIER_2_ADDRESS} 300 echo "Sent 300 BTC to VERIFIER_2_ADDRESS: $${VERIFIER_2_ADDRESS}" diff --git a/via_verifier/lib/via_musig2/examples/withdrawal.rs b/via_verifier/lib/via_musig2/examples/withdrawal.rs index dd22c393a..908e607ed 100644 --- a/via_verifier/lib/via_musig2/examples/withdrawal.rs +++ b/via_verifier/lib/via_musig2/examples/withdrawal.rs @@ -107,7 +107,7 @@ async fn main() -> Result<(), Box> { // In a real application these would come from the chain. let (dummy_out_point, dummy_utxo) = utxos[0].clone(); - let change_amount = dummy_utxo.value - SPEND_AMOUNT; + let change_amount = dummy_utxo.value - SPEND_AMOUNT - Amount::from_sat(1000); // Get an address to send to. let address = receivers_address(); From d7a4e5d5a717e39c614ccc6f5c82eabe5e624b4b Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Thu, 16 Jan 2025 14:26:43 +0100 Subject: [PATCH 139/212] fix: converting txid from H256, verifier config --- etc/env/configs/via_verifier.toml | 3 +++ .../src/btc_vote_inscription.rs | 20 ++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index 85e989e78..77b0102c1 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -24,3 +24,6 @@ bridge_address_str = "" required_signers = 2 # The verifier_mode can be simple verifier or coordinator. verifier_mode = "VERIFIER" + +[via_btc_watch] +actor_role = "Verifier" diff --git a/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs b/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs index 4514997f8..bbb315d59 100644 --- a/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs +++ b/via_verifier/node/via_btc_sender/src/btc_vote_inscription.rs @@ -124,15 +124,25 @@ impl ViaVoteInscription { vote: bool, tx_id: Vec, ) -> anyhow::Result { - let mut attestation = Vote::NotOk; + let attestation = if vote { Vote::Ok } else { Vote::NotOk }; + + // Convert H256 bytes to Txid + let txid = Self::h256_to_txid(&tx_id)?; - if vote { - attestation = Vote::Ok; - } let input = ValidatorAttestationInput { - reference_txid: Txid::from_slice(&tx_id)?, + reference_txid: txid, attestation, }; Ok(InscriptionMessage::ValidatorAttestation(input)) } + + /// Converts H256 bytes (from the DB) to a Txid by reversing the byte order. + fn h256_to_txid(h256_bytes: &[u8]) -> anyhow::Result { + if h256_bytes.len() != 32 { + return Err(anyhow::anyhow!("H256 must be 32 bytes")); + } + let mut reversed_bytes = h256_bytes.to_vec(); + reversed_bytes.reverse(); + Txid::from_slice(&reversed_bytes).context("Failed to convert H256 to Txid") + } } From 1d939b4360f341999f380be9295a681d067f55af Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:48:02 +0100 Subject: [PATCH 140/212] fix: set the correct verifiers wallets --- core/lib/via_btc_client/examples/bootstrap.rs | 27 +++++++++++-------- core/lib/via_btc_client/examples/deposit.rs | 7 ++--- etc/env/configs/via_coordinator.toml | 10 +++---- etc/env/configs/via_verifier.toml | 8 +++--- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/core/lib/via_btc_client/examples/bootstrap.rs b/core/lib/via_btc_client/examples/bootstrap.rs index d88d88f4b..27a93d409 100644 --- a/core/lib/via_btc_client/examples/bootstrap.rs +++ b/core/lib/via_btc_client/examples/bootstrap.rs @@ -49,8 +49,11 @@ async fn main() -> Result<()> { let rpc_password = args[4].clone(); // Regtest verifier keys + // pubkey: 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b let verifier_1_private_key = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm".to_string(); + // pubkey: 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662 let verifier_2_private_key = "cQ4UHjdsGWFMcQ8zXcaSr7m4Kxq9x7g9EKqguTaFH7fA34mZAnqW".to_string(); + // pubkey: 03cf1b1c7ad2952a99e6e2d12d52437f41f867c30eceef1bf88f402296424d6eb8 let verifier_3_private_key = "cS9UbUKKepDjthBFPBDBe5vGVjNXXygCN75kPWmNKk7HTPV8p6he".to_string(); let sequencer_p2wpkh_address = "bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56" @@ -61,8 +64,10 @@ async fn main() -> Result<()> { .parse::>()?; let verifier_3_p2wpkh_address = "bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm" .parse::>()?; - let bridge_p2wpkh_mpc_address = "bcrt1qdrzjq2mwlhrnhan94em5sl032zd95m73ud8ddw" - .parse::>()?; + // cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662 + let bridge_p2wpkh_mpc_address = + "bcrt1paf9ewekz080f4vluhm0sau7wn3f7uuxcngh9ffyram4q7qjsx4cqsa23tj" + .parse::>()?; let mut verifier_inscribers: Vec = vec![ create_inscriber( @@ -81,14 +86,14 @@ async fn main() -> Result<()> { network, ) .await?, - create_inscriber( - &verifier_3_private_key, - &rpc_url, - &rpc_username, - &rpc_password, - network, - ) - .await?, + // create_inscriber( + // &verifier_3_private_key, + // &rpc_url, + // &rpc_username, + // &rpc_password, + // network, + // ) + // .await?, ]; // Bootstrapping message @@ -97,7 +102,7 @@ async fn main() -> Result<()> { verifier_p2wpkh_addresses: vec![ verifier_1_p2wpkh_address, verifier_2_p2wpkh_address, - verifier_3_p2wpkh_address, + // verifier_3_p2wpkh_address, ], bridge_p2wpkh_mpc_address, bootloader_hash: H256::zero(), diff --git a/core/lib/via_btc_client/examples/deposit.rs b/core/lib/via_btc_client/examples/deposit.rs index 4be2b10eb..4b8832b57 100644 --- a/core/lib/via_btc_client/examples/deposit.rs +++ b/core/lib/via_btc_client/examples/deposit.rs @@ -51,9 +51,10 @@ async fn main() -> Result<()> { let rpc_username = args[6].clone(); let rpc_password = args[7].clone(); - let bridge_p2wpkh_mpc_address = "bcrt1qdrzjq2mwlhrnhan94em5sl032zd95m73ud8ddw" - .parse::>()? - .require_network(network)?; + let bridge_p2wpkh_mpc_address = + "bcrt1paf9ewekz080f4vluhm0sau7wn3f7uuxcngh9ffyram4q7qjsx4cqsa23tj" + .parse::>()? + .require_network(network)?; // Load the previous context from the file if it exists let context = load_context_from_file(CONTEXT_FILE)?; diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index c92cdfe2c..c2c5e1a08 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -12,14 +12,14 @@ port = 6060 # Coordinator server url. url = "http://0.0.0.0:6060" # The signer private key. -private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" +private_key = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm" # The verifiers public keys. verifiers_pub_keys_str = [ - "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", - "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", + "03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b", + "02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662", ] -# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` -bridge_address_str = "bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv" +# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662` +bridge_address_str = "bcrt1paf9ewekz080f4vluhm0sau7wn3f7uuxcngh9ffyram4q7qjsx4cqsa23tj" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index 77b0102c1..703687b41 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -12,14 +12,14 @@ port = 6060 # Coordinator server url. url = "http://0.0.0.0:6060" # The signer private key. -private_key = "L3EGCjrX7ZTmUa2U7eL7akmBYoJB4FgNY8BpY8qwU5izy6k5D72m" +private_key = "cQ4UHjdsGWFMcQ8zXcaSr7m4Kxq9x7g9EKqguTaFH7fA34mZAnqW" # The verifiers public keys. verifiers_pub_keys_str = [ - "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", - "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", + "03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b", + "02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662", ] # The bridge address. -bridge_address_str = "" +bridge_address_str = "bcrt1paf9ewekz080f4vluhm0sau7wn3f7uuxcngh9ffyram4q7qjsx4cqsa23tj" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. From 90494806cd808fd6ae4a410a8f267ee3526bcb7e Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:59:03 +0100 Subject: [PATCH 141/212] chore: update the bridge address --- docker-compose-via.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 155f99f49..e3270e3ea 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -92,7 +92,7 @@ services: - VERIFIER_1_ADDRESS=bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv - VERIFIER_2_ADDRESS=bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4 - VERIFIER_3_ADDRESS=bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm - - BRIDGE_ADDRESS=bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv + - BRIDGE_ADDRESS=bcrt1paf9ewekz080f4vluhm0sau7wn3f7uuxcngh9ffyram4q7qjsx4cqsa23tj - RPC_ARGS=-chain=regtest -rpcconnect=bitcoind -rpcwait -rpcuser=rpcuser -rpcpassword=rpcpassword - SLEEP_SECONDS=5 From e0471a9f8d9ca1514a31e37b20e99503b5b88ae5 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 16 Jan 2025 17:53:04 +0330 Subject: [PATCH 142/212] Fix(musig2): add taproot tweak to verifier_musig2 lib --- .../lib/via_musig2/examples/withdrawal.rs | 2 -- via_verifier/lib/via_musig2/src/lib.rs | 33 ++++++++++++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/via_verifier/lib/via_musig2/examples/withdrawal.rs b/via_verifier/lib/via_musig2/examples/withdrawal.rs index 908e607ed..3576159fe 100644 --- a/via_verifier/lib/via_musig2/examples/withdrawal.rs +++ b/via_verifier/lib/via_musig2/examples/withdrawal.rs @@ -205,9 +205,7 @@ async fn main() -> Result<(), Box> { // Second round: Create partial signatures let binding = sighash.to_byte_array(); let mut second_round_1 = first_round_1.finalize(secret_key_1, &binding)?; - let binding = sighash.to_byte_array(); let second_round_2 = first_round_2.finalize(secret_key_2, &binding)?; - let binding = sighash.to_byte_array(); let second_round_3 = first_round_3.finalize(secret_key_3, &binding)?; // Combine partial signatures let partial_sig_2: [u8; 32] = second_round_2.our_signature(); diff --git a/via_verifier/lib/via_musig2/src/lib.rs b/via_verifier/lib/via_musig2/src/lib.rs index 841261ab0..91617db46 100644 --- a/via_verifier/lib/via_musig2/src/lib.rs +++ b/via_verifier/lib/via_musig2/src/lib.rs @@ -1,5 +1,6 @@ use std::fmt; +use bitcoin::TapTweakHash; use musig2::{ verify_single, CompactSignature, FirstRound, KeyAggContext, PartialSignature, PubNonce, SecNonceSpices, SecondRound, @@ -34,7 +35,7 @@ impl std::error::Error for MusigError {} /// Represents a single signer in the MuSig2 protocol pub struct Signer { secret_key: SecretKey, - _public_key: PublicKey, + public_key: PublicKey, signer_index: usize, key_agg_ctx: KeyAggContext, first_round: Option, @@ -47,7 +48,7 @@ pub struct Signer { impl fmt::Debug for Signer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Signer") - .field("_public_key", &self._public_key) + .field("public_key", &self.public_key) .field("signer_index", &self.signer_index) .field("key_agg_ctx", &self.key_agg_ctx) .field("message", &self.message) @@ -77,14 +78,36 @@ impl Signer { )); } - let key_agg_ctx = + let mut musig_key_agg_cache = KeyAggContext::new(all_pubkeys).map_err(|e| MusigError::Musig2Error(e.to_string()))?; + let agg_pubkey = musig_key_agg_cache.aggregated_pubkey::(); + let (xonly_agg_key, _) = agg_pubkey.x_only_public_key(); + + // Convert to bitcoin XOnlyPublicKey first + let internal_key = bitcoin::XOnlyPublicKey::from_slice(&xonly_agg_key.serialize()) + .map_err(|e| { + MusigError::Musig2Error(format!( + "Failed to convert to bitcoin XOnlyPublicKey: {}", + e + )) + })?; + + // Calculate taproot tweak + let tap_tweak = TapTweakHash::from_key_and_tweak(internal_key, None); + let tweak = tap_tweak.to_scalar(); + let tweak_bytes = tweak.to_be_bytes(); + let musig2_compatible_tweak = secp256k1_musig2::Scalar::from_be_bytes(tweak_bytes).unwrap(); + // Apply tweak to the key aggregation context before signing + musig_key_agg_cache = musig_key_agg_cache + .with_xonly_tweak(musig2_compatible_tweak) + .map_err(|e| MusigError::Musig2Error(format!("Failed to apply tweak: {}", e)))?; + Ok(Self { secret_key, - _public_key: public_key, + public_key, signer_index, - key_agg_ctx, + key_agg_ctx: musig_key_agg_cache, first_round: None, second_round: None, message: Vec::new(), From 0175fac440c8a7bd3c01507c510ea9370e2350d8 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 16 Jan 2025 18:01:38 +0330 Subject: [PATCH 143/212] Fix(musig2): fix address generation in key_generation_setup --- .../examples/key_generation_setup.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs index 7105ce698..6c79d334c 100644 --- a/via_verifier/lib/via_musig2/examples/key_generation_setup.rs +++ b/via_verifier/lib/via_musig2/examples/key_generation_setup.rs @@ -1,6 +1,6 @@ use std::{env, str::FromStr}; -use bitcoin::{taproot::TaprootSpendInfo, Address as BitcoinAddress, Network, XOnlyPublicKey}; +use bitcoin::{Address as BitcoinAddress, Network}; use musig2::KeyAggContext; use rand::rngs::OsRng; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; @@ -30,16 +30,18 @@ fn generate_keypair() -> (SecretKey, PublicKey) { fn create_bridge_address( pubkeys: Vec, ) -> Result> { - let key_agg_ctx: KeyAggContext = KeyAggContext::new(pubkeys)?; - let aggregated_pubkey: PublicKey = key_agg_ctx.aggregated_pubkey(); + let secp = bitcoin::secp256k1::Secp256k1::new(); - let (xonly_agg_key, _parity) = aggregated_pubkey.x_only_public_key(); - let xonly_pub = XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + let musig_key_agg_cache = KeyAggContext::new(pubkeys)?; - let secp_btc = bitcoin::secp256k1::Secp256k1::new(); - let tap_info = TaprootSpendInfo::new_key_spend(&secp_btc, xonly_pub, None); - let tweaked_key = tap_info.output_key(); - let address = BitcoinAddress::p2tr(&secp_btc, tweaked_key.into(), None, Network::Regtest); + let agg_pubkey = musig_key_agg_cache.aggregated_pubkey::(); + let (xonly_agg_key, _) = agg_pubkey.x_only_public_key(); + + // Convert to bitcoin XOnlyPublicKey first + let internal_key = bitcoin::XOnlyPublicKey::from_slice(&xonly_agg_key.serialize())?; + + // Use internal_key for address creation + let address = BitcoinAddress::p2tr(&secp, internal_key, None, Network::Regtest); Ok(address) } From a5c02923ed48b1a140ea83562b8d88ab7c308573 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:06:03 +0100 Subject: [PATCH 144/212] fix: the bridge address validation address to p2tr --- core/lib/via_btc_client/src/indexer/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index fc43776d1..85dc6ac6c 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -507,7 +507,7 @@ impl MessageParser { .iter() .find(|output| { if let Some(address) = self.bridge_address.as_ref() { - output.script_pubkey.is_p2wpkh() + output.script_pubkey.is_p2tr() && output.script_pubkey == address.script_pubkey() } else { tracing::error!("Bridge address not found"); From fd0d023a6ac780194c6378993c8c60401557b143 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Fri, 17 Jan 2025 05:12:48 +0330 Subject: [PATCH 145/212] Fix(musig2): update bridge address in confige and sequencer logic --- core/lib/via_btc_client/DEV.md | 2 +- core/lib/via_btc_client/examples/bootstrap.rs | 4 ++-- core/lib/via_btc_client/examples/deposit.rs | 4 ++-- core/lib/via_btc_client/src/indexer/mod.rs | 8 ++------ core/lib/via_btc_client/src/indexer/parser.rs | 2 +- core/lib/via_btc_client/src/inscriber/script_builder.rs | 2 +- core/lib/via_btc_client/src/types.rs | 2 +- etc/env/configs/via_coordinator.toml | 3 ++- etc/env/configs/via_verifier.toml | 7 +++++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/lib/via_btc_client/DEV.md b/core/lib/via_btc_client/DEV.md index 238dd25d1..cdb285c8d 100644 --- a/core/lib/via_btc_client/DEV.md +++ b/core/lib/via_btc_client/DEV.md @@ -96,7 +96,7 @@ Votable : No | OP_PUSHBYTES_32 b"verifier_5_p2wpkh_address" | | OP_PUSHBYTES_32 b"verifier_6_p2wpkh_address" | | OP_PUSHBYTES_32 b"verifier_7_p2wpkh_address" | -| OP_PUSHBYTES_32 b"bridge_p2wpkh_mpc_address" | +| OP_PUSHBYTES_32 b"bridge_musig2_address" | | OP_PUSHBYTES_32 b"Str('bootloader_hash')" | | OP_PUSHBYTES_32 b"Str('abstract_account_hash')" | | OP_ENDIF | diff --git a/core/lib/via_btc_client/examples/bootstrap.rs b/core/lib/via_btc_client/examples/bootstrap.rs index d88d88f4b..61ae0d629 100644 --- a/core/lib/via_btc_client/examples/bootstrap.rs +++ b/core/lib/via_btc_client/examples/bootstrap.rs @@ -61,7 +61,7 @@ async fn main() -> Result<()> { .parse::>()?; let verifier_3_p2wpkh_address = "bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm" .parse::>()?; - let bridge_p2wpkh_mpc_address = "bcrt1qdrzjq2mwlhrnhan94em5sl032zd95m73ud8ddw" + let bridge_musig2_address = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" .parse::>()?; let mut verifier_inscribers: Vec = vec![ @@ -99,7 +99,7 @@ async fn main() -> Result<()> { verifier_2_p2wpkh_address, verifier_3_p2wpkh_address, ], - bridge_p2wpkh_mpc_address, + bridge_musig2_address, bootloader_hash: H256::zero(), abstract_account_hash: H256::random(), }; diff --git a/core/lib/via_btc_client/examples/deposit.rs b/core/lib/via_btc_client/examples/deposit.rs index 4be2b10eb..663fd3a5e 100644 --- a/core/lib/via_btc_client/examples/deposit.rs +++ b/core/lib/via_btc_client/examples/deposit.rs @@ -51,7 +51,7 @@ async fn main() -> Result<()> { let rpc_username = args[6].clone(); let rpc_password = args[7].clone(); - let bridge_p2wpkh_mpc_address = "bcrt1qdrzjq2mwlhrnhan94em5sl032zd95m73ud8ddw" + let bridge_musig2_address = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" .parse::>()? .require_network(network)?; @@ -87,7 +87,7 @@ async fn main() -> Result<()> { InscriptionMessage::L1ToL2Message(input), InscriptionConfig::default(), Some(Recipient { - address: bridge_p2wpkh_mpc_address, + address: bridge_musig2_address, amount: Amount::from_btc(amount)?, }), ) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 4f6ad7044..2a5b400bf 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -306,7 +306,7 @@ impl BitcoinInscriptionIndexer { let bridge_address = sb .input - .bridge_p2wpkh_mpc_address + .bridge_musig2_address .require_network(network) .unwrap(); state.bridge_address = Some(bridge_address); @@ -591,11 +591,7 @@ mod tests { common: get_test_common_fields(), input: types::SystemBootstrappingInput { start_block_height: 0, - bridge_p2wpkh_mpc_address: indexer - .bridge_address - .clone() - .as_unchecked() - .to_owned(), + bridge_musig2_address: indexer.bridge_address.clone().as_unchecked().to_owned(), verifier_p2wpkh_addresses: vec![], bootloader_hash: H256::zero(), abstract_account_hash: H256::zero(), diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index fc43776d1..cde6acb6b 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -279,7 +279,7 @@ impl MessageParser { common: common_fields.clone(), input: SystemBootstrappingInput { start_block_height, - bridge_p2wpkh_mpc_address: network_unchecked_bridge_address, + bridge_musig2_address: network_unchecked_bridge_address, verifier_p2wpkh_addresses: network_unchecked_verifier_addresses, bootloader_hash, abstract_account_hash, diff --git a/core/lib/via_btc_client/src/inscriber/script_builder.rs b/core/lib/via_btc_client/src/inscriber/script_builder.rs index b00ab0b6e..7418df5ea 100644 --- a/core/lib/via_btc_client/src/inscriber/script_builder.rs +++ b/core/lib/via_btc_client/src/inscriber/script_builder.rs @@ -232,7 +232,7 @@ impl InscriptionData { } let bridge_address = input - .bridge_p2wpkh_mpc_address + .bridge_musig2_address .clone() .require_network(network)?; let bridge_address_encoded = Self::encode_push_bytes(bridge_address.to_string().as_bytes()); diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index bdcc75c59..7263173d2 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -74,7 +74,7 @@ pub struct CommonFields { pub struct SystemBootstrappingInput { pub start_block_height: u32, pub verifier_p2wpkh_addresses: Vec>, - pub bridge_p2wpkh_mpc_address: BitcoinAddress, + pub bridge_musig2_address: BitcoinAddress, pub bootloader_hash: H256, pub abstract_account_hash: H256, } diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index c92cdfe2c..ce3529641 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -19,7 +19,8 @@ verifiers_pub_keys_str = [ "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", ] # The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` -bridge_address_str = "bcrt1plt2vht9q56x66alsyz2sc59pt3nuuh2vde3kgakju00nk3pyc62sr4tsyv" +# also update the bridge address in the via_btc_client/examples/deposit.rs +bridge_address_str = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index 77b0102c1..b7c6acf2d 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -18,8 +18,11 @@ verifiers_pub_keys_str = [ "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", ] -# The bridge address. -bridge_address_str = "" + +# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` +# also update the bridge address in the via_btc_client/examples/deposit.rs + +bridge_address_str = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. From 3c755c728a6ea0489cf53b98f43fdebb6017eeab Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Fri, 17 Jan 2025 05:15:42 +0330 Subject: [PATCH 146/212] Fix(musig2): change variable name in docker compose --- docker-compose-via.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose-via.yml b/docker-compose-via.yml index 10abb654e..e17c6dbca 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -54,9 +54,9 @@ services: bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${VERIFIER_1_ADDRESS} 300 echo "Sent 300 BTC to VERIFIER_1_ADDRESS: $${VERIFIER_1_ADDRESS}" - echo "BRIDGE_ADDRESS: $${BRIDGE_ADDRESS}" - bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${BRIDGE_ADDRESS} 300 - echo "Sent 300 BTC to BRIDGE_ADDRESS: $${BRIDGE_ADDRESS}" + echo "BRIDGE_TEST_ADDRESS: $${BRIDGE_TEST_ADDRESS}" + bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${BRIDGE_TEST_ADDRESS} 300 + echo "Sent 300 BTC to BRIDGE_TEST_ADDRESS: $${BRIDGE_TEST_ADDRESS}" echo "VERIFIER_2_ADDRESS: $${VERIFIER_2_ADDRESS}" bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${VERIFIER_2_ADDRESS} 300 @@ -96,7 +96,7 @@ services: - VERIFIER_1_ADDRESS=bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv - VERIFIER_2_ADDRESS=bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4 - VERIFIER_3_ADDRESS=bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm - - BRIDGE_ADDRESS=bcrt1pcx974cg2w66cqhx67zadf85t8k4sd2wp68l8x8agd3aj4tuegsgsz97amg + - BRIDGE_TEST_ADDRESS=bcrt1pcx974cg2w66cqhx67zadf85t8k4sd2wp68l8x8agd3aj4tuegsgsz97amg - RPC_ARGS=-chain=regtest -rpcconnect=bitcoind -rpcwait -rpcuser=rpcuser -rpcpassword=rpcpassword - SLEEP_SECONDS=5 From bd2aee0390083014125e706db57beef2226aa9e4 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:10:21 +0100 Subject: [PATCH 147/212] fix: insert empty transaction id when no withdrawals in a batch --- .../node/withdrawal_service/src/coordinator/api_impl.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 1f38b93ac..9c6ef1223 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -113,7 +113,12 @@ impl RestApi { .await .unwrap() .via_votes_dal() - .mark_vote_transaction_as_processed_withdrawals(H256::zero(), l1_block_number) + .mark_vote_transaction_as_processed_withdrawals( + H256::zero(), + block_number.clone(), + ) + .await + .unwrap(); } } From db5fd0aceb0ad98e31aec9384bd8f20f3fd772b0 Mon Sep 17 00:00:00 2001 From: Danijel Radakovic <129277218+danijelTxFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:42:32 +0100 Subject: [PATCH 148/212] build: dockerize the devnet-2 server (#97) --- .dockerignore | 2 ++ docker/server/Dockerfile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index c32286be6..eababae16 100644 --- a/.dockerignore +++ b/.dockerignore @@ -47,3 +47,5 @@ contracts/.git !etc/env/consensus_secrets.yaml !etc/env/consensus_config.yaml !rust-toolchain + +!via_verifier \ No newline at end of file diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile index 6e2915986..c5b88591d 100644 --- a/docker/server/Dockerfile +++ b/docker/server/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /usr/src/via COPY . . -RUN apt-get update && apt-get install -y protobuf-compiler && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y protobuf-compiler git && rm -rf /var/lib/apt/lists/* RUN cargo build --release #--features=rocksdb/io-uring <-- investigate what is this FROM debian:bookworm-slim From 792d8f6b2b4b5277807bf41c94e0fcc339c49b32 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:19:40 +0100 Subject: [PATCH 149/212] fix: verifier dal migration --- infrastructure/via/src/database.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/via/src/database.ts b/infrastructure/via/src/database.ts index a57b20341..e32929dc5 100644 --- a/infrastructure/via/src/database.ts +++ b/infrastructure/via/src/database.ts @@ -22,7 +22,7 @@ export interface DbOpts { function getDals(opts: DbOpts): Map { let dals = new Map(); - if (!opts.prover && !opts.core) { + if (!opts.prover && !opts.core && !opts.verifier) { dals.set(DalPath.CoreDal, process.env.DATABASE_URL!); if (process.env.DATABASE_PROVER_URL) { dals.set(DalPath.ProverDal, process.env.DATABASE_PROVER_URL); From a71c3d0bda91311047e80c50bb342ced51c3d634 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Fri, 17 Jan 2025 13:51:59 +0330 Subject: [PATCH 150/212] apply PR #95 Changes --- core/lib/via_btc_client/examples/bootstrap.rs | 30 +++++++++++-------- core/lib/via_btc_client/examples/deposit.rs | 2 +- core/lib/via_btc_client/src/indexer/parser.rs | 2 +- etc/env/configs/via_base.toml | 9 +++--- etc/env/configs/via_coordinator.toml | 12 ++++---- etc/env/configs/via_verifier.toml | 12 ++++---- 6 files changed, 39 insertions(+), 28 deletions(-) diff --git a/core/lib/via_btc_client/examples/bootstrap.rs b/core/lib/via_btc_client/examples/bootstrap.rs index 61ae0d629..4af3a360f 100644 --- a/core/lib/via_btc_client/examples/bootstrap.rs +++ b/core/lib/via_btc_client/examples/bootstrap.rs @@ -49,9 +49,13 @@ async fn main() -> Result<()> { let rpc_password = args[4].clone(); // Regtest verifier keys + // pubkey: 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b let verifier_1_private_key = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm".to_string(); + // pubkey: 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662 let verifier_2_private_key = "cQ4UHjdsGWFMcQ8zXcaSr7m4Kxq9x7g9EKqguTaFH7fA34mZAnqW".to_string(); - let verifier_3_private_key = "cS9UbUKKepDjthBFPBDBe5vGVjNXXygCN75kPWmNKk7HTPV8p6he".to_string(); + // pubkey: 03cf1b1c7ad2952a99e6e2d12d52437f41f867c30eceef1bf88f402296424d6eb8 + let _verifier_3_private_key = + "cS9UbUKKepDjthBFPBDBe5vGVjNXXygCN75kPWmNKk7HTPV8p6he".to_string(); let sequencer_p2wpkh_address = "bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56" .parse::>()?; @@ -59,9 +63,11 @@ async fn main() -> Result<()> { .parse::>()?; let verifier_2_p2wpkh_address = "bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4" .parse::>()?; - let verifier_3_p2wpkh_address = "bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm" + let _verifier_3_p2wpkh_address = "bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm" .parse::>()?; - let bridge_musig2_address = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" + + // cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662 + let bridge_musig2_address = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" .parse::>()?; let mut verifier_inscribers: Vec = vec![ @@ -81,14 +87,14 @@ async fn main() -> Result<()> { network, ) .await?, - create_inscriber( - &verifier_3_private_key, - &rpc_url, - &rpc_username, - &rpc_password, - network, - ) - .await?, + // create_inscriber( + // &verifier_3_private_key, + // &rpc_url, + // &rpc_username, + // &rpc_password, + // network, + // ) + // .await?, ]; // Bootstrapping message @@ -97,7 +103,7 @@ async fn main() -> Result<()> { verifier_p2wpkh_addresses: vec![ verifier_1_p2wpkh_address, verifier_2_p2wpkh_address, - verifier_3_p2wpkh_address, + // verifier_3_p2wpkh_address, ], bridge_musig2_address, bootloader_hash: H256::zero(), diff --git a/core/lib/via_btc_client/examples/deposit.rs b/core/lib/via_btc_client/examples/deposit.rs index 663fd3a5e..bf3464f2a 100644 --- a/core/lib/via_btc_client/examples/deposit.rs +++ b/core/lib/via_btc_client/examples/deposit.rs @@ -51,7 +51,7 @@ async fn main() -> Result<()> { let rpc_username = args[6].clone(); let rpc_password = args[7].clone(); - let bridge_musig2_address = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" + let bridge_musig2_address = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" .parse::>()? .require_network(network)?; diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index cde6acb6b..9369eeaa3 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -507,7 +507,7 @@ impl MessageParser { .iter() .find(|output| { if let Some(address) = self.bridge_address.as_ref() { - output.script_pubkey.is_p2wpkh() + output.script_pubkey.is_p2tr() && output.script_pubkey == address.script_pubkey() } else { tracing::error!("Bridge address not found"); diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml index 57dea7ef2..0b83639d9 100644 --- a/etc/env/configs/via_base.toml +++ b/etc/env/configs/via_base.toml @@ -1,4 +1,7 @@ [via_btc_watch] +# Number of blocks that we should wait before processing the new blocks. +# For local regtest we should wait for 0 blocks. +# But for mainnet we should wait for 3 blocks. confirmations_for_btc_msg = 0 btc_node_poll_interval = 1000 rpc_url = "http://0.0.0.0:18443" @@ -7,10 +10,8 @@ rpc_password = "rpcpassword" network = "regtest" bootstrap_txids = [] actor_role = "Sequencer" -# Number of blocks that we should wait before processing the new blocks. -# For local regtest we should wait for 0 blocks. -# But for mainnet we should wait for 3 blocks. -btc_blocks_lag = 0 +# Number of blocks that we should check when restarting the service. +btc_blocks_lag = 1000 [via_btc_sender] poll_interval = 1000 diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index ce3529641..d49049bc0 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -12,15 +12,15 @@ port = 6060 # Coordinator server url. url = "http://0.0.0.0:6060" # The signer private key. -private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" +private_key = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm" # The verifiers public keys. verifiers_pub_keys_str = [ - "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", - "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", + "03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b", + "02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662", ] -# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` +# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662` # also update the bridge address in the via_btc_client/examples/deposit.rs -bridge_address_str = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" +bridge_address_str = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. @@ -28,3 +28,5 @@ verifier_mode = "COORDINATOR" [via_btc_watch] actor_role = "Verifier" +# Number of blocks that we should check when restarting the service. +btc_blocks_lag = 1000 diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index b7c6acf2d..6acbb405c 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -12,17 +12,17 @@ port = 6060 # Coordinator server url. url = "http://0.0.0.0:6060" # The signer private key. -private_key = "L3EGCjrX7ZTmUa2U7eL7akmBYoJB4FgNY8BpY8qwU5izy6k5D72m" +private_key = "cQ4UHjdsGWFMcQ8zXcaSr7m4Kxq9x7g9EKqguTaFH7fA34mZAnqW" # The verifiers public keys. verifiers_pub_keys_str = [ - "0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11", - "02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc", + "03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b", + "02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662", ] -# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 0216d3ee537b26e65c4651cea9d066048eb083d40aeb11eb26644517a8f41bba11 02ffa48031b415a78769b47d325a53f2f83610e8e7b47d864d945f216b1ab7c2dc` +# The bridge address. Run the following cmd: `cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662` # also update the bridge address in the via_btc_client/examples/deposit.rs -bridge_address_str = "bcrt1p3w832gamavyl3w8y6ev9mv6sdw7nl4d8yj4psxls4vcxrrqpcd0stcngwh" +bridge_address_str = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" # The minimum required signers. required_signers = 2 # The verifier_mode can be simple verifier or coordinator. @@ -30,3 +30,5 @@ verifier_mode = "VERIFIER" [via_btc_watch] actor_role = "Verifier" +# Number of blocks that we should check when restarting the service. +btc_blocks_lag = 1000 From bccb130843e3fb3dc1f13974f10c6f9596e20479 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:15:39 +0100 Subject: [PATCH 151/212] fix: parse the BTC value to 18 decimals --- infrastructure/via/src/token.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/infrastructure/via/src/token.ts b/infrastructure/via/src/token.ts index 6f2bd3c81..7ad483168 100644 --- a/infrastructure/via/src/token.ts +++ b/infrastructure/via/src/token.ts @@ -80,11 +80,11 @@ async function withdraw(amount: number, receiverL1Address: string, userL2Private const contract = new Contract(L2_BASE_TOKEN, abi, wallet) as any; let balance = await contract.balanceOf(wallet.address); - console.log('Balance before withdraw', ethers.formatUnits(balance, 8)); - const tx = await contract.connect(wallet).withdraw(btcAddress, { value: ethers.parseUnits(String(amount), 8) }); + console.log('Balance before withdraw', ethers.formatEther(String(balance))); + const tx = await contract.connect(wallet).withdraw(btcAddress, { value: ethers.parseEther(String(amount)) }); await tx.wait(); balance = await contract.balanceOf(wallet.address); - console.log('Balance after withdraw', ethers.formatUnits(balance, 8)); + console.log('Balance after withdraw', ethers.formatEther(String(balance))); } export const command = new Command('token').description('Bridge BTC L2<>L1'); From 60aed2239336cc376aa20182761af0cf3de17e3a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:26:42 +0100 Subject: [PATCH 152/212] chore: update the contracts hash --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index cd3c930a1..2fe62059d 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit cd3c930a1d6bbe37f7a3bf39589703898654fe38 +Subproject commit 2fe62059d9f9ee4270e0e5ac4e1fcb8b046e8b7d From 7055e80df24b0584adf36b1615b92b3778ccd283 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:55:48 +0100 Subject: [PATCH 153/212] chore: update config --- etc/env/base/contracts.toml | 4 ++-- etc/env/file_based/genesis.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index b5cc2a796..167feb1bf 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -26,8 +26,8 @@ RECURSION_NODE_LEVEL_VK_HASH = "0x1186ec268d49f1905f8d9c1e9d39fc33e98c74f91d91a2 RECURSION_LEAF_LEVEL_VK_HASH = "0x101e08b00193e529145ee09823378ef51a3bc8966504064f1f6ba3f1ba863210" RECURSION_CIRCUITS_SET_VKS_HASH = "0x18c1639094f58177409186e8c48d9f577c9410901d2f1d486b3e7d6cf553ae4c" GENESIS_TX_HASH = "0xb99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e" -GENESIS_ROOT = "0x55cc43e53c79bfdc738ca7aa7a7677ed0c50d07ae3d72181da42ac897af8bdd5" -GENESIS_BATCH_COMMITMENT = "0x9ad49644e4f8c9a3642db6033df1bb89b5f7d4e156ba9e48296d323d453f69f1" +GENESIS_ROOT = "0xe411a1602b4ef98bc064de599dab18b940172b2a564e781f52ad2650cbcf72c5" +GENESIS_BATCH_COMMITMENT = "0xfaa108d80b92837c172f156fe5f0f0d85c23c70442a30834f75d6a57a50bb73b" PRIORITY_TX_MAX_GAS_LIMIT = 72000000 DEPLOY_L2_BRIDGE_COUNTERPART_GAS_LIMIT = 10000000 GENESIS_ROLLUP_LEAF_INDEX = "54" diff --git a/etc/env/file_based/genesis.yaml b/etc/env/file_based/genesis.yaml index 50ee75852..d498cb866 100644 --- a/etc/env/file_based/genesis.yaml +++ b/etc/env/file_based/genesis.yaml @@ -1,6 +1,6 @@ -genesis_root: 0x55cc43e53c79bfdc738ca7aa7a7677ed0c50d07ae3d72181da42ac897af8bdd5 +genesis_root: 0xe411a1602b4ef98bc064de599dab18b940172b2a564e781f52ad2650cbcf72c5 genesis_rollup_leaf_index: 54 -genesis_batch_commitment: 0x9ad49644e4f8c9a3642db6033df1bb89b5f7d4e156ba9e48296d323d453f69f1 +genesis_batch_commitment: 0xfaa108d80b92837c172f156fe5f0f0d85c23c70442a30834f75d6a57a50bb73b genesis_protocol_semantic_version: '0.26.0' # deprecated genesis_protocol_version: 26 From c07153300b6672daaa4155a48ba0a4f69e7916da Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sat, 18 Jan 2025 11:22:32 +0100 Subject: [PATCH 154/212] fix: the votable transaction column name and add store the pubdata blob_id --- core/lib/via_btc_client/examples/bootstrap.rs | 4 +-- core/lib/via_btc_client/examples/deposit.rs | 1 - ...30743de219ffd56015380a713ee0fd1fcce0.json} | 5 +-- ...65dd1b36c6d94d1c307d66d2133d2277f62a7.json | 32 +++++++++++++++++++ ...a074871ce49f2c81be801c233032ec1d046ba.json | 32 ------------------- .../20250112053854_create_via_votes.up.up.sql | 3 +- .../lib/verifier_dal/src/tests/mod.rs | 3 +- .../lib/verifier_dal/src/via_votes_dal.rs | 29 +++++++++++------ .../src/tests/vote_inscription_test.rs | 18 +++++++++-- 9 files changed, 75 insertions(+), 52 deletions(-) rename via_verifier/lib/verifier_dal/.sqlx/{query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json => query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json} (56%) create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-bac043d7cb5f1b9cee546a34fa265dd1b36c6d94d1c307d66d2133d2277f62a7.json delete mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json diff --git a/core/lib/via_btc_client/examples/bootstrap.rs b/core/lib/via_btc_client/examples/bootstrap.rs index 8f22e781d..4af3a360f 100644 --- a/core/lib/via_btc_client/examples/bootstrap.rs +++ b/core/lib/via_btc_client/examples/bootstrap.rs @@ -57,7 +57,6 @@ async fn main() -> Result<()> { let _verifier_3_private_key = "cS9UbUKKepDjthBFPBDBe5vGVjNXXygCN75kPWmNKk7HTPV8p6he".to_string(); - let sequencer_p2wpkh_address = "bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56" .parse::>()?; let verifier_1_p2wpkh_address = "bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv" @@ -66,12 +65,11 @@ async fn main() -> Result<()> { .parse::>()?; let _verifier_3_p2wpkh_address = "bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm" .parse::>()?; - + // cargo run --example key_generation_setup coordinator 03d8e2443ef58aa80fb6256bf3b94d2ecf9117f19cb17661ec60ad35fd84ff4a8b 02043f839b8ecd9ffd79f26ec7d05750555cd0d1e0777cfc84a29b7e38e6324662 let bridge_musig2_address = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" .parse::>()?; - let mut verifier_inscribers: Vec = vec![ create_inscriber( &verifier_1_private_key, diff --git a/core/lib/via_btc_client/examples/deposit.rs b/core/lib/via_btc_client/examples/deposit.rs index d992ee8ae..bf3464f2a 100644 --- a/core/lib/via_btc_client/examples/deposit.rs +++ b/core/lib/via_btc_client/examples/deposit.rs @@ -55,7 +55,6 @@ async fn main() -> Result<()> { .parse::>()? .require_network(network)?; - // Load the previous context from the file if it exists let context = load_context_from_file(CONTEXT_FILE)?; diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json b/via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json similarity index 56% rename from via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json rename to via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json index 3f4dc4c6e..eb02d266b 100644 --- a/via_verifier/lib/verifier_dal/.sqlx/query-aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b.json +++ b/via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", + "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, pubdata_reveal_tx_id, pubdata_blob_id)\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", "describe": { "columns": [], "parameters": { @@ -9,10 +9,11 @@ "Bytea", "Varchar", "Varchar", + "Varchar", "Varchar" ] }, "nullable": [] }, - "hash": "aaed24343bdc5ea2e69e03d8e735f7f7dc59a40e03457c442d14fa5c4d37182b" + "hash": "32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0" } diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-bac043d7cb5f1b9cee546a34fa265dd1b36c6d94d1c307d66d2133d2277f62a7.json b/via_verifier/lib/verifier_dal/.sqlx/query-bac043d7cb5f1b9cee546a34fa265dd1b36c6d94d1c307d66d2133d2277f62a7.json new file mode 100644 index 000000000..77dc305a2 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-bac043d7cb5f1b9cee546a34fa265dd1b36c6d94d1c307d66d2133d2277f62a7.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_batch_number,\n pubdata_blob_id,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n ORDER BY\n l1_batch_number ASC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "pubdata_blob_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "bac043d7cb5f1b9cee546a34fa265dd1b36c6d94d1c307d66d2133d2277f62a7" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json b/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json deleted file mode 100644 index 3e41688ab..000000000 --- a/via_verifier/lib/verifier_dal/.sqlx/query-ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n l1_batch_number,\n blob_id,\n proof_tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n ORDER BY\n l1_batch_number ASC\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "l1_batch_number", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "blob_id", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "proof_tx_id", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "ea244d902835a929b3871ba74a5a074871ce49f2c81be801c233032ec1d046ba" -} diff --git a/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql index 1fdfa1484..a000a61cf 100644 --- a/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql +++ b/via_verifier/lib/verifier_dal/migrations/20250112053854_create_via_votes.up.up.sql @@ -3,7 +3,8 @@ CREATE TABLE IF NOT EXISTS via_votable_transactions ( tx_id BYTEA, da_identifier VARCHAR NOT NULL, blob_id VARCHAR NOT NULL, - proof_tx_id VARCHAR NOT NULL, + pubdata_blob_id VARCHAR NOT NULL, + pubdata_reveal_tx_id VARCHAR NOT NULL, withdrawal_tx_id BYTEA, is_finalized BOOLEAN NOT NULL DEFAULT FALSE, is_verified BOOLEAN NOT NULL DEFAULT FALSE, diff --git a/via_verifier/lib/verifier_dal/src/tests/mod.rs b/via_verifier/lib/verifier_dal/src/tests/mod.rs index 0d868c8ac..f29b90636 100644 --- a/via_verifier/lib/verifier_dal/src/tests/mod.rs +++ b/via_verifier/lib/verifier_dal/src/tests/mod.rs @@ -34,7 +34,8 @@ async fn test_via_vote_workflow() { tx_id, "test_da_id".to_string(), "test_blob_id".to_string(), - "test_proof_tx_id".to_string(), + "test_pubdata_tx_id".to_string(), + "test_pubdata_blob_id".to_string(), ) .await .unwrap(); diff --git a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs index fde6f6c90..a157c7d88 100644 --- a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs @@ -16,21 +16,30 @@ impl ViaVotesDal<'_, '_> { tx_id: H256, da_identifier: String, blob_id: String, - proof_tx_id: String, + pubdata_reveal_tx_id: String, + pubdata_blob_id: String, ) -> DalResult<()> { sqlx::query!( r#" INSERT INTO - via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, proof_tx_id) + via_votable_transactions ( + l1_batch_number, + tx_id, + da_identifier, + blob_id, + pubdata_reveal_tx_id, + pubdata_blob_id + ) VALUES - ($1, $2, $3, $4, $5) + ($1, $2, $3, $4, $5, $6) ON CONFLICT (l1_batch_number, tx_id) DO NOTHING "#, i64::from(l1_batch_number), tx_id.as_bytes(), da_identifier, blob_id, - proof_tx_id + pubdata_reveal_tx_id, + pubdata_blob_id ) .instrument("insert_votable_transaction") .fetch_optional(self.storage) @@ -280,13 +289,13 @@ impl ViaVotesDal<'_, '_> { } pub async fn get_finalized_blocks_and_non_processed_withdrawals( &mut self, - ) -> DalResult> { + ) -> DalResult)>> { let rows = sqlx::query!( r#" SELECT l1_batch_number, - blob_id, - proof_tx_id + pubdata_blob_id, + tx_id FROM via_votable_transactions WHERE @@ -301,10 +310,10 @@ impl ViaVotesDal<'_, '_> { .fetch_all(self.storage) .await?; - // Map the rows into a Vec<(l1_batch_number, blob_id, proof_tx_id)> - let result: Vec<(i64, String, String)> = rows + // Map the rows into a Vec<(l1_batch_number, pubdata_blob_id, tx_id)> + let result: Vec<(i64, String, Vec)> = rows .into_iter() - .map(|r| (r.l1_batch_number, r.blob_id, r.proof_tx_id)) + .map(|r| (r.l1_batch_number, r.pubdata_blob_id, r.tx_id)) .collect(); Ok(result) diff --git a/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs b/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs index 04fb2a776..f01abb668 100644 --- a/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs +++ b/via_verifier/node/via_btc_sender/src/tests/vote_inscription_test.rs @@ -51,7 +51,14 @@ mod tests { let _ = aggregator_test .storage .via_votes_dal() - .insert_votable_transaction(1, tx_id, "".to_string(), "".to_string(), "".to_string()) + .insert_votable_transaction( + 1, + tx_id, + "".to_string(), + "".to_string(), + "".to_string(), + "".to_string(), + ) .await; let op = aggregator_test @@ -124,7 +131,14 @@ mod tests { let _ = aggregator_test .storage .via_votes_dal() - .insert_votable_transaction(1, tx_id, "".to_string(), "".to_string(), "".to_string()) + .insert_votable_transaction( + 1, + tx_id, + "".to_string(), + "".to_string(), + "".to_string(), + "".to_string(), + ) .await; let _ = aggregator_test From 7a7f1fda80fea293d21e1f257452cb4178490620 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sat, 18 Jan 2025 11:23:50 +0100 Subject: [PATCH 155/212] fix: store the pubdata blob id --- .../src/message_processors/mod.rs | 8 ++++++- .../src/message_processors/verifier.rs | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/via_verifier/node/via_btc_watch/src/message_processors/mod.rs b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs index 0c84c751b..7e3e297ba 100644 --- a/via_verifier/node/via_btc_watch/src/message_processors/mod.rs +++ b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs @@ -1,7 +1,7 @@ pub(crate) use verifier::VerifierMessageProcessor; use via_btc_client::{ indexer::BitcoinInscriptionIndexer, - types::{BitcoinTxid, FullInscriptionMessage}, + types::{BitcoinTxid, FullInscriptionMessage, IndexerError}, }; use via_verifier_dal::{Connection, Verifier}; use zksync_types::H256; @@ -16,6 +16,12 @@ pub(super) enum MessageProcessorError { DatabaseError(String), } +impl From for MessageProcessorError { + fn from(err: IndexerError) -> Self { + MessageProcessorError::Internal(err.into()) + } +} + #[async_trait::async_trait] pub(super) trait MessageProcessor: 'static + std::fmt::Debug + Send + Sync { async fn process_messages( diff --git a/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs index 1156476f4..656d09e6f 100644 --- a/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs +++ b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs @@ -44,6 +44,27 @@ impl MessageProcessor for VerifierMessageProcessor { let tx_id = convert_txid_to_h256(proof_msg.common.tx_id); + let pubdata_msgs = indexer + .parse_transaction(&proof_msg.input.l1_batch_reveal_txid) + .await?; + + if pubdata_msgs.len() != 1 { + return Err(MessageProcessorError::Internal(anyhow::Error::msg( + "Invalid pubdata msg lenght", + ))); + } + + let inscription = pubdata_msgs[0].clone(); + + let l1_batch_da_ref_inscription = match inscription { + FullInscriptionMessage::L1BatchDAReference(da_msg) => da_msg, + _ => { + return Err(MessageProcessorError::Internal(anyhow::Error::msg( + "Invalid inscription type", + ))) + } + }; + votes_dal .insert_votable_transaction( l1_batch_number.0, @@ -51,6 +72,7 @@ impl MessageProcessor for VerifierMessageProcessor { proof_msg.input.da_identifier.clone(), proof_msg.input.blob_id.clone(), proof_msg.input.l1_batch_reveal_txid.to_string(), + l1_batch_da_ref_inscription.input.blob_id, ) .await .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; From 99b4473cdda354b6a1d5712bdbdcdbb9cda43d09 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sat, 18 Jan 2025 12:35:30 +0100 Subject: [PATCH 156/212] refactorfeat: improve the error handling for the coordinator rest api --- Cargo.lock | 1 + .../node/withdrawal_service/Cargo.toml | 1 + .../src/coordinator/api_impl.rs | 89 ++++++++++--------- .../src/coordinator/error.rs | 60 +++++++++++++ .../withdrawal_service/src/coordinator/mod.rs | 1 + 5 files changed, 108 insertions(+), 44 deletions(-) create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/error.rs diff --git a/Cargo.lock b/Cargo.lock index fe3d71eb3..d6e208521 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9811,6 +9811,7 @@ dependencies = [ "secp256k1 0.30.0", "serde", "serde_json", + "thiserror", "tokio", "tower-http", "tracing", diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index d6e8b492d..050a4c172 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -31,5 +31,6 @@ secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = [ ] } musig2 = "0.2.0" base64 = "0.21" +thiserror = "1.0.57" [dev-dependencies] diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 9c6ef1223..0d4b17142 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -15,7 +15,7 @@ use via_btc_client::{traits::Serializable, withdrawal_builder::WithdrawalRequest use via_verifier_dal::VerifierDal; use zksync_types::H256; -use super::api_decl::RestApi; +use super::{api_decl::RestApi, error::ApiError}; use crate::{ types::{NoncePair, PartialSignaturePair, SigningSession, SigningSessionResponse}, utils::{decode_signature, encode_signature}, @@ -28,23 +28,11 @@ fn ok_json(data: T) -> Response { .unwrap() } -fn bad_request(message: &str) -> Response { - Response::builder() - .status(axum::http::StatusCode::BAD_REQUEST) - .body(message.to_string()) - .unwrap() -} - -fn not_found(message: &str) -> Response { - Response::builder() - .status(axum::http::StatusCode::NOT_FOUND) - .body(message.to_string()) - .unwrap() -} - impl RestApi { #[instrument(skip(self_))] - pub async fn new_session(State(self_): State>) -> Response { + pub async fn new_session( + State(self_): State>, + ) -> anyhow::Result, ApiError> { let mut l1_block_number: i64; { @@ -56,16 +44,14 @@ impl RestApi { let withdrawal_tx = self_ .master_connection_pool .connection_tagged("coordinator api") - .await - .unwrap() + .await? .via_votes_dal() .get_vote_transaction_withdrawal_tx(l1_block_number) - .await - .unwrap(); + .await?; if withdrawal_tx.is_none() { // The withdrawal process is in progress - return ok_json(l1_block_number); + return Ok(ok_json(l1_block_number)); } } @@ -84,24 +70,21 @@ impl RestApi { if l1_block_number != 0 { self_.reset_session().await; } - return not_found("No block found for processing withdrawals"); + return Ok(ok_json("No block found for processing withdrawals")); } let mut withdrawals_to_process: Vec = Vec::new(); let mut proof_txid = Txid::all_zeros(); - for (block_number, blob_id, proof_tx) in blocks.iter() { + for (block_number, blob_id, proof_tx_id) in blocks.iter() { let withdrawals = self_ .withdrawal_client .get_withdrawals(blob_id) .await - .context("Error to get withdrawals") - .unwrap(); + .context("Error to get withdrawals from DA")?; if !withdrawals.is_empty() { - proof_txid = Txid::from_slice(proof_tx.as_bytes()) - .context("Invalid proof id") - .unwrap(); + proof_txid = Self::h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; break; @@ -110,29 +93,36 @@ impl RestApi { _ = self_ .master_connection_pool .connection_tagged("coordinator") - .await - .unwrap() + .await? .via_votes_dal() .mark_vote_transaction_as_processed_withdrawals( H256::zero(), block_number.clone(), ) .await - .unwrap(); + .context("Error to mark a vote transaction as processed")?; } } if withdrawals_to_process.is_empty() { self_.reset_session().await; - return not_found("There are no withdrawals to process"); + return Ok(ok_json("There are no withdrawals to process")); } - let unsigned_tx = self_ + let unsigned_tx_result = self_ .withdrawal_builder .create_unsigned_withdrawal_tx(withdrawals_to_process, proof_txid) - .await - .context("Error to create a unsigned withdrawal transaction") - .unwrap(); + .await; + + let unsigned_tx = match unsigned_tx_result { + Ok(unsigned_tx) => unsigned_tx, + Err(err) => { + tracing::info!("Invalid unsigned tx: {err}"); + return Err(ApiError::InternalServerError( + "Invalid unsigned tx".to_string(), + )); + } + }; let mut sighash_cache = SighashCache::new(&unsigned_tx.tx); let sighash_type = TapSighashType::All; @@ -158,7 +148,7 @@ impl RestApi { *session = new_sesssion; } - return ok_json(l1_block_number); + return Ok(ok_json(l1_block_number)); } #[instrument(skip(self_))] @@ -184,16 +174,16 @@ impl RestApi { pub async fn submit_nonce( State(self_): State>, Json(nonce_pair): Json, - ) -> Response { + ) -> anyhow::Result, ApiError> { let decoded_nonce = match base64::engine::general_purpose::STANDARD.decode(&nonce_pair.nonce) { Ok(nonce) => nonce, - Err(_) => return bad_request("Invalid nonce pair"), + Err(_) => return Err(ApiError::BadRequest("Invalid nonce pair".to_string())), }; let pub_nonce = match PubNonce::from_bytes(&decoded_nonce) { Ok(nonce) => nonce, - Err(_) => return bad_request("Invalid pub nonce"), + Err(_) => return Err(ApiError::BadRequest("Invalid pub nonce".to_string())), }; let mut session = self_.state.signing_session.write().await; @@ -202,17 +192,17 @@ impl RestApi { .received_nonces .insert(nonce_pair.signer_index, pub_nonce); - ok_json("Success") + Ok(ok_json("Success")) } #[instrument(skip(self_))] pub async fn submit_partial_signature( State(self_): State>, Json(sig_pair): Json, - ) -> Response { + ) -> anyhow::Result, ApiError> { let partial_sig = match decode_signature(sig_pair.signature) { Ok(sig) => sig, - Err(_) => return bad_request("Invalid signature"), + Err(_) => return Err(ApiError::BadRequest("Invalid signature".to_string())), }; { @@ -222,7 +212,7 @@ impl RestApi { .received_sigs .insert(sig_pair.signer_index, partial_sig); } - ok_json("Success") + Ok(ok_json("Success")) } #[instrument(skip(self_))] @@ -254,4 +244,15 @@ impl RestApi { let mut session = self.state.signing_session.write().await; *session = SigningSession::default(); } + + // Todo: move this logic in a helper crate as it's used in multiple crates. + /// Converts H256 bytes (from the DB) to a Txid by reversing the byte order. + fn h256_to_txid(h256_bytes: &[u8]) -> anyhow::Result { + if h256_bytes.len() != 32 { + return Err(anyhow::anyhow!("H256 must be 32 bytes")); + } + let mut reversed_bytes = h256_bytes.to_vec(); + reversed_bytes.reverse(); + Txid::from_slice(&reversed_bytes).context("Failed to convert H256 to Txid") + } } diff --git a/via_verifier/node/withdrawal_service/src/coordinator/error.rs b/via_verifier/node/withdrawal_service/src/coordinator/error.rs new file mode 100644 index 000000000..b1b0dbb6c --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/error.rs @@ -0,0 +1,60 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use serde::Serialize; +use thiserror::Error; +use tracing::error; +use via_verifier_dal::DalError; + +// Custom error type for API-specific errors +#[derive(Error, Debug)] +pub enum ApiError { + #[error("Invalid input: {0}")] + BadRequest(String), + #[error("Unexpected error: {0}")] + InternalServerError(String), +} + +impl From for ApiError { + fn from(error: anyhow::Error) -> Self { + ApiError::InternalServerError(error.to_string()) + } +} + +impl From for ApiError { + fn from(error: DalError) -> Self { + ApiError::InternalServerError(error.to_string()) + } +} + +impl IntoResponse for ApiError { + fn into_response(self) -> Response { + let (status, error_response) = match self { + ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, ErrorResponse::new(&msg)), + ApiError::InternalServerError(msg) => { + (StatusCode::INTERNAL_SERVER_ERROR, ErrorResponse::new(&msg)) + } + }; + + let response = Json(error_response).into_response(); + (status, response).into_response() + } +} + +// Struct for standardized error responses +#[derive(Serialize)] +struct ErrorResponse { + error: String, + message: String, +} + +impl ErrorResponse { + fn new(message: &E) -> Self { + Self { + error: "Coordinator API Error".to_string(), + message: message.to_string(), + } + } +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/mod.rs b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs index 63c0a9149..cb001f217 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/mod.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs @@ -1,3 +1,4 @@ pub mod api; mod api_decl; mod api_impl; +mod error; From 22897f14c86f85b829909ebb8c9ed4a3bbf9f530 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:40:27 +0100 Subject: [PATCH 157/212] fixfix: update the verifier dal migration files --- ...f30743de219ffd56015380a713ee0fd1fcce0.json | 19 ------------------- ...6f71979a3e3826c8cb240c0f1e37bc1bbbdf9.json | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-e1237653c8bb6b8df57852f48136f71979a3e3826c8cb240c0f1e37bc1bbbdf9.json diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json b/via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json deleted file mode 100644 index eb02d266b..000000000 --- a/via_verifier/lib/verifier_dal/.sqlx/query-32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_votable_transactions (l1_batch_number, tx_id, da_identifier, blob_id, pubdata_reveal_tx_id, pubdata_blob_id)\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Varchar", - "Varchar", - "Varchar", - "Varchar" - ] - }, - "nullable": [] - }, - "hash": "32aa4bea1feff592ceaae7c10f8f30743de219ffd56015380a713ee0fd1fcce0" -} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-e1237653c8bb6b8df57852f48136f71979a3e3826c8cb240c0f1e37bc1bbbdf9.json b/via_verifier/lib/verifier_dal/.sqlx/query-e1237653c8bb6b8df57852f48136f71979a3e3826c8cb240c0f1e37bc1bbbdf9.json new file mode 100644 index 000000000..57ef4050b --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-e1237653c8bb6b8df57852f48136f71979a3e3826c8cb240c0f1e37bc1bbbdf9.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_votable_transactions (\n l1_batch_number,\n tx_id,\n da_identifier,\n blob_id,\n pubdata_reveal_tx_id,\n pubdata_blob_id\n )\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (l1_batch_number, tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Varchar", + "Varchar", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "e1237653c8bb6b8df57852f48136f71979a3e3826c8cb240c0f1e37bc1bbbdf9" +} From 728373ea703171424999f003d53bd0af367757da Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Sat, 18 Jan 2025 14:33:38 +0100 Subject: [PATCH 158/212] chore: inscrease the pooling time for btc_sender and btc_watch --- etc/env/configs/via_base.toml | 4 ++-- etc/env/configs/via_coordinator.toml | 3 +++ etc/env/configs/via_verifier.toml | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml index 0b83639d9..a30a0bfdb 100644 --- a/etc/env/configs/via_base.toml +++ b/etc/env/configs/via_base.toml @@ -3,7 +3,7 @@ # For local regtest we should wait for 0 blocks. # But for mainnet we should wait for 3 blocks. confirmations_for_btc_msg = 0 -btc_node_poll_interval = 1000 +btc_node_poll_interval = 10000 rpc_url = "http://0.0.0.0:18443" rpc_user = "rpcuser" rpc_password = "rpcpassword" @@ -14,7 +14,7 @@ actor_role = "Sequencer" btc_blocks_lag = 1000 [via_btc_sender] -poll_interval = 1000 +poll_interval = 10000 private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" max_aggregated_blocks_to_commit = 1 max_aggregated_proofs_to_commit = 1 diff --git a/etc/env/configs/via_coordinator.toml b/etc/env/configs/via_coordinator.toml index d49049bc0..5509beea3 100644 --- a/etc/env/configs/via_coordinator.toml +++ b/etc/env/configs/via_coordinator.toml @@ -30,3 +30,6 @@ verifier_mode = "COORDINATOR" actor_role = "Verifier" # Number of blocks that we should check when restarting the service. btc_blocks_lag = 1000 + +[via_btc_sender] +private_key = "cRaUbRSn8P8cXUcg6cMZ7oTZ1wbDjktYTsbdGw62tuqqD9ttQWMm" diff --git a/etc/env/configs/via_verifier.toml b/etc/env/configs/via_verifier.toml index 6acbb405c..b59d10c47 100644 --- a/etc/env/configs/via_verifier.toml +++ b/etc/env/configs/via_verifier.toml @@ -32,3 +32,6 @@ verifier_mode = "VERIFIER" actor_role = "Verifier" # Number of blocks that we should check when restarting the service. btc_blocks_lag = 1000 + +[via_btc_sender] +private_key = "cQ4UHjdsGWFMcQ8zXcaSr7m4Kxq9x7g9EKqguTaFH7fA34mZAnqW" From 62c4245845635862a56eb297551f62a345e04182 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:24:44 +0100 Subject: [PATCH 159/212] fix: the transaction fee to include the reveal and commit txs --- .../src/inscriber/internal_type.rs | 2 +- core/lib/via_btc_client/src/inscriber/mod.rs | 62 ++++++++++++++----- core/lib/via_btc_client/src/types.rs | 2 +- .../src/btc_inscription_aggregator.rs | 2 +- .../src/btc_inscription_manager.rs | 2 +- .../src/btc_inscription_manager.rs | 2 +- 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/core/lib/via_btc_client/src/inscriber/internal_type.rs b/core/lib/via_btc_client/src/inscriber/internal_type.rs index 6ea40ad63..d79778435 100644 --- a/core/lib/via_btc_client/src/inscriber/internal_type.rs +++ b/core/lib/via_btc_client/src/inscriber/internal_type.rs @@ -13,7 +13,7 @@ pub struct CommitTxOutputRes { pub commit_tx_change_output: TxOut, pub commit_tx_tapscript_output: TxOut, pub commit_tx_fee_rate: u64, - pub _commit_tx_fee: Amount, + pub commit_tx_fee: Amount, } #[derive(Debug)] diff --git a/core/lib/via_btc_client/src/inscriber/mod.rs b/core/lib/via_btc_client/src/inscriber/mod.rs index cc5434000..5823aa376 100644 --- a/core/lib/via_btc_client/src/inscriber/mod.rs +++ b/core/lib/via_btc_client/src/inscriber/mod.rs @@ -45,6 +45,10 @@ const REVEAL_TX_FEE_INPUT_INDEX: u32 = 0; const REVEAL_TX_TAPSCRIPT_REVEAL_INDEX: u32 = 1; const FEE_RATE_INCREASE_PER_PENDING_TX: u64 = 5; // percentage +/// The fee percentage amount reduced from the commit transaction and added to the reveal transaction. +const FEE_RATE_DECREASE_COMMIT_TX: u64 = 20; +/// The additional fee percentage added to the base reveal transaction fee serves as an incentive for the minter to include commit and reveal transactions. +const FEE_RATE_INCENTIVE: u64 = 5; const COMMIT_TX_P2TR_OUTPUT_COUNT: u32 = 1; const COMMIT_TX_P2WPKH_OUTPUT_COUNT: u32 = 1; @@ -114,7 +118,6 @@ impl Inscriber { .prepare_commit_tx_output( &commit_tx_input_info, inscription_data.script_pubkey.clone(), - config, ) .await?; @@ -127,7 +130,13 @@ impl Inscriber { )?; let reveal_tx_output_info = self - .prepare_reveal_tx_output(&reveal_tx_input_info, &inscription_data, recipient) + .prepare_reveal_tx_output( + &reveal_tx_input_info, + &inscription_data, + config, + recipient, + commit_tx_output_info.commit_tx_fee, + ) .await?; let final_reveal_tx = self.sign_reveal_tx( @@ -336,7 +345,6 @@ impl Inscriber { &self, tx_input_data: &CommitTxInputRes, inscription_pubkey: ScriptBuf, - config: InscriptionConfig, ) -> Result { debug!("Preparing commit transaction output"); let inscription_commitment_output = TxOut { @@ -344,16 +352,9 @@ impl Inscriber { script_pubkey: inscription_pubkey, }; - let mut fee_rate = self.get_fee_rate().await?; - let pending_tx_in_context = self.context.fifo_queue.len(); - - // increase fee rate based on pending transactions in context - - let increase_factor = (FEE_RATE_INCREASE_PER_PENDING_TX * config.fee_multiplier) - * pending_tx_in_context as u64; - fee_rate += fee_rate * increase_factor / 100; + let fee_rate = self.get_fee_rate().await?; - let fee_amount = InscriberFeeCalculator::estimate_fee( + let mut fee_amount = InscriberFeeCalculator::estimate_fee( tx_input_data.inputs_count, COMMIT_TX_P2TR_INPUT_COUNT, COMMIT_TX_P2WPKH_OUTPUT_COUNT, @@ -361,6 +362,8 @@ impl Inscriber { vec![], fee_rate, )?; + let fee_amount_before_decrease = fee_amount; + fee_amount -= (fee_amount * FEE_RATE_DECREASE_COMMIT_TX) / 100; let commit_tx_change_output_value = tx_input_data .unlocked_value @@ -384,7 +387,7 @@ impl Inscriber { commit_tx_change_output, commit_tx_tapscript_output: inscription_commitment_output, commit_tx_fee_rate: fee_rate, - _commit_tx_fee: fee_amount, + commit_tx_fee: fee_amount_before_decrease, }; Ok(res) @@ -395,7 +398,7 @@ impl Inscriber { debug!("Getting fee rate"); let res = self.client.get_fee_rate(FEE_RATE_CONF_TARGET).await?; debug!("Fee rate obtained: {}", res); - Ok(res) + Ok(std::cmp::max(res, 1)) } #[instrument(skip(self, input, output), target = "bitcoin_inscriber")] @@ -557,20 +560,45 @@ impl Inscriber { &self, tx_input_data: &RevealTxInputRes, inscription_data: &InscriptionData, + config: InscriptionConfig, recipient: Option, + commit_tx_fee: Amount, ) -> Result { debug!("Preparing reveal transaction output"); let fee_rate = self.get_fee_rate().await?; + let pending_tx_in_context = self.context.fifo_queue.len(); + + let mut reveal_tx_p2wpkh_output_count = REVEAL_TX_P2WPKH_OUTPUT_COUNT; + let mut reveal_tx_p2tr_output_count = REVEAL_TX_P2TR_OUTPUT_COUNT; + + if let Some(r) = &recipient { + if r.address.script_pubkey().is_p2tr() { + reveal_tx_p2tr_output_count += 1; + } else { + reveal_tx_p2wpkh_output_count += 1; + }; + } - let fee_amount = InscriberFeeCalculator::estimate_fee( + let mut fee_amount = InscriberFeeCalculator::estimate_fee( REVEAL_TX_P2WPKH_INPUT_COUNT, REVEAL_TX_P2TR_INPUT_COUNT, - REVEAL_TX_P2WPKH_OUTPUT_COUNT + recipient.as_ref().map_or(0, |_| 1), - REVEAL_TX_P2TR_OUTPUT_COUNT, + reveal_tx_p2wpkh_output_count, + reveal_tx_p2tr_output_count, vec![inscription_data.script_size], fee_rate, )?; + // increase fee rate based on pending transactions in context + let retry_factor = FEE_RATE_INCREASE_PER_PENDING_TX * config.fee_multiplier; + + let txs_stuck_factor = FEE_RATE_INCREASE_PER_PENDING_TX * pending_tx_in_context as u64; + + let increase_factor = retry_factor + txs_stuck_factor + FEE_RATE_INCENTIVE; + + fee_amount += (fee_amount * increase_factor) / 100; + // Add the fee amount removed from the commit tx to reveal + fee_amount += (commit_tx_fee * FEE_RATE_DECREASE_COMMIT_TX) / 100; + let recipient_amount = recipient.as_ref().map_or(Amount::ZERO, |r| r.amount); let reveal_change_amount = tx_input_data diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index 7263173d2..90f44c927 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -141,7 +141,7 @@ pub struct InscriptionConfig { impl Default for InscriptionConfig { fn default() -> Self { - InscriptionConfig { fee_multiplier: 1 } + InscriptionConfig { fee_multiplier: 0 } } } diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index 8bd70d338..dd2661909 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -99,7 +99,7 @@ impl ViaBtcInscriptionAggregator { .context("Via get inscriber info")?; let prediction_fee = inscribe_info.reveal_tx_output_info._reveal_fee - + inscribe_info.commit_tx_output_info._commit_tx_fee; + + inscribe_info.commit_tx_output_info.commit_tx_fee; let inscription_request = transaction .btc_sender_dal() diff --git a/core/node/via_btc_sender/src/btc_inscription_manager.rs b/core/node/via_btc_sender/src/btc_inscription_manager.rs index eb46dd7a1..349718039 100644 --- a/core/node/via_btc_sender/src/btc_inscription_manager.rs +++ b/core/node/via_btc_sender/src/btc_inscription_manager.rs @@ -204,7 +204,7 @@ impl ViaBtcInscriptionManager { serialize(&inscribe_info.final_reveal_tx.tx).context("Serilize the reveal tx")?; let actual_fees = inscribe_info.reveal_tx_output_info._reveal_fee - + inscribe_info.commit_tx_output_info._commit_tx_fee; + + inscribe_info.commit_tx_output_info.commit_tx_fee; tracing::info!( "New inscription created {commit_tx} {reveal_tx}", diff --git a/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs index 3b896b030..7f1508353 100644 --- a/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs +++ b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs @@ -207,7 +207,7 @@ impl ViaBtcInscriptionManager { serialize(&inscribe_info.final_reveal_tx.tx).context("Serilize the reveal tx")?; let actual_fees = inscribe_info.reveal_tx_output_info._reveal_fee - + inscribe_info.commit_tx_output_info._commit_tx_fee; + + inscribe_info.commit_tx_output_info.commit_tx_fee; tracing::info!( "New inscription created {commit_tx} {reveal_tx}", From 9ad88cdafc4015923534c54e0447dcb726e18766 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Tue, 21 Jan 2025 11:40:09 +0100 Subject: [PATCH 160/212] chore: decrease the pooling time for btc sender and watch --- etc/env/configs/via_base.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/env/configs/via_base.toml b/etc/env/configs/via_base.toml index a30a0bfdb..ad23f1bca 100644 --- a/etc/env/configs/via_base.toml +++ b/etc/env/configs/via_base.toml @@ -3,7 +3,7 @@ # For local regtest we should wait for 0 blocks. # But for mainnet we should wait for 3 blocks. confirmations_for_btc_msg = 0 -btc_node_poll_interval = 10000 +btc_node_poll_interval = 2000 rpc_url = "http://0.0.0.0:18443" rpc_user = "rpcuser" rpc_password = "rpcpassword" @@ -14,7 +14,7 @@ actor_role = "Sequencer" btc_blocks_lag = 1000 [via_btc_sender] -poll_interval = 10000 +poll_interval = 2000 private_key = "cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R" max_aggregated_blocks_to_commit = 1 max_aggregated_proofs_to_commit = 1 From 30ea8ec7240572613d7355dc89b5b225e3c734e4 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 21 Jan 2025 20:48:14 +0100 Subject: [PATCH 161/212] fix: server restart, update via cli, minor logs changes --- core/node/via_btc_sender/src/aggregator.rs | 11 +++++----- .../src/btc_inscription_manager.rs | 4 +--- infrastructure/via/src/env.ts | 20 ++++++++++++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/core/node/via_btc_sender/src/aggregator.rs b/core/node/via_btc_sender/src/aggregator.rs index aa2270f27..e992a890b 100644 --- a/core/node/via_btc_sender/src/aggregator.rs +++ b/core/node/via_btc_sender/src/aggregator.rs @@ -81,14 +81,15 @@ impl ViaAggregator { ) .await?; - tracing::debug!( - "Found {} l1 batches ready for commit", - ready_for_commit_l1_batches.len() - ); + if !ready_for_commit_l1_batches.is_empty() { + tracing::debug!( + "Found {} l1 batches ready for commit", + ready_for_commit_l1_batches.len() + ); + } validate_l1_batch_sequence(&ready_for_commit_l1_batches); - tracing::debug!("Extracting ready subrange"); if let Some(l1_batches) = extract_ready_subrange( &mut self.commit_l1_block_criteria, ready_for_commit_l1_batches, diff --git a/core/node/via_btc_sender/src/btc_inscription_manager.rs b/core/node/via_btc_sender/src/btc_inscription_manager.rs index 349718039..dafe2f865 100644 --- a/core/node/via_btc_sender/src/btc_inscription_manager.rs +++ b/core/node/via_btc_sender/src/btc_inscription_manager.rs @@ -45,9 +45,7 @@ impl ViaBtcInscriptionManager { let mut storage = pool.connection_tagged("via_btc_sender").await?; match self.loop_iteration(&mut storage).await { - Ok(()) => { - tracing::info!("Inscription manager task finished"); - } + Ok(()) => {} Err(err) => { tracing::error!("Failed to process btc_sender_inscription_manager: {err}"); } diff --git a/infrastructure/via/src/env.ts b/infrastructure/via/src/env.ts index 44bcf44c4..747034c48 100644 --- a/infrastructure/via/src/env.ts +++ b/infrastructure/via/src/env.ts @@ -46,7 +46,7 @@ export async function gitHooks() { } } -export function set(environment: string, print: boolean = false) { +export function set(environment: string, print: boolean = false, soft: boolean = false) { if (!fs.existsSync(`etc/env/target/${environment}.env`) && !fs.existsSync(`etc/env/configs/${environment}.toml`)) { console.error( `Unknown environment: ${environment}.\nCreate an environment file etc/env/target/${environment}.env or etc/env/configs/${environment}.toml` @@ -60,7 +60,11 @@ export function set(environment: string, print: boolean = false) { // No .env file found - we should compile it! config.compileConfig(environment); } - reload(); + + // Only reload if we did NOT pass the --soft flag + if (!soft) { + reload(environment); + } get(print); } @@ -150,8 +154,14 @@ export function mergeInitToEnv() { } export const command = new Command('env') - .arguments('[env_name]') .description('get or set via environment') - .action((environment?: string) => { - environment ? set(environment, true) : get(true); + .option('--soft', 'Skip reloading the environment') + .action((cmd: Command) => { + // If user typed `cli env dev --soft`, then: + // cmd.args[0] = 'dev' + // cmd.soft = true + const environment = cmd.args[0]; + const { soft } = cmd.opts(); + + environment ? set(environment, /*print=*/ true, soft) : get(/*print=*/ true); }); From 3e9e5a3a13bef27252ee40dd355023bda68d6f3b Mon Sep 17 00:00:00 2001 From: danijelTxFusion Date: Wed, 22 Jan 2025 00:10:29 +0100 Subject: [PATCH 162/212] build: add Dockerfile for via-verifier --- docker/via-verifier/Dockerfile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docker/via-verifier/Dockerfile diff --git a/docker/via-verifier/Dockerfile b/docker/via-verifier/Dockerfile new file mode 100644 index 000000000..bcb139440 --- /dev/null +++ b/docker/via-verifier/Dockerfile @@ -0,0 +1,22 @@ +# Will work locally only after prior contracts build +# syntax=docker/dockerfile:experimental +FROM matterlabs/zksync-build-base:latest AS builder + +WORKDIR /usr/src/via + +COPY . . + +RUN apt-get update && apt-get install -y protobuf-compiler && rm -rf /var/lib/apt/lists/* +RUN cargo build --release + +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y curl libpq5 liburing-dev ca-certificates && \ + rm -rf /var/lib/apt/lists/* +ENV PATH=$PATH:/usr/local/bin + +EXPOSE 6060 + +COPY --from=builder /usr/src/via/target/release/via_verifier /usr/bin + +ENTRYPOINT ["via_verifier"] From c6cf8337e2cbc303ae95021b028445c9acb40df0 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 23 Jan 2025 13:30:47 +0330 Subject: [PATCH 163/212] feat(logic): add first step filter for transaction in btc block --- core/lib/via_btc_client/src/indexer/mod.rs | 32 +++++-- core/lib/via_btc_client/src/indexer/parser.rs | 90 ++++++++++--------- core/lib/via_btc_client/src/types.rs | 8 +- .../src/coordinator/api_impl.rs | 9 +- 4 files changed, 80 insertions(+), 59 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 2a5b400bf..fe6756f69 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Arc}; -use bitcoin::{Address, BlockHash, Network, Txid}; +use bitcoin::{Address, BlockHash, Network, Transaction as BitcoinTransaction, Txid}; use bitcoincore_rpc::Auth; use tracing::{debug, error, info, instrument, warn}; @@ -140,20 +140,40 @@ impl BitcoinInscriptionIndexer { let block = self.client.fetch_block(block_height as u128).await?; - let messages: Vec<_> = block + let important_txs: Vec<_> = block .txdata + .iter() + .filter(|tx| self.is_transaction_involving_important_addresses(tx)) + .collect(); + + let parsed_messages: Vec<_> = important_txs .iter() .flat_map(|tx| self.parser.parse_transaction(tx, block_height)) - // TODO: Implement message validation - // .filter(|message| self.is_valid_message(message)) + .collect(); + + let valid_messages: Vec<_> = parsed_messages + .into_iter() + .filter(|message| self.is_valid_message(message)) .collect(); debug!( "Processed {} valid messages in block {}", - messages.len(), + valid_messages.len(), block_height ); - Ok(messages) + Ok(valid_messages) + } + + fn is_transaction_involving_important_addresses(&self, tx: &BitcoinTransaction) -> bool { + tx.output.iter().any(|output| { + let script_pubkey = &output.script_pubkey; + script_pubkey == &self.sequencer_address.script_pubkey() + || script_pubkey == &self.bridge_address.script_pubkey() + || self + .verifier_addresses + .iter() + .any(|addr| script_pubkey == &addr.script_pubkey()) + }) } #[instrument(skip(self), target = "bitcoin_indexer")] diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index 9369eeaa3..3eba1d98e 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -12,10 +12,10 @@ use zksync_types::{Address as EVMAddress, L1BatchNumber}; use crate::{ types, types::{ - CommonFields, FullInscriptionMessage as Message, L1BatchDAReference, - L1BatchDAReferenceInput, L1ToL2Message, L1ToL2MessageInput, ProofDAReference, - ProofDAReferenceInput, ProposeSequencer, ProposeSequencerInput, SystemBootstrapping, - SystemBootstrappingInput, ValidatorAttestation, ValidatorAttestationInput, Vote, + CommonFields, FullInscriptionMessage, L1BatchDAReference, L1BatchDAReferenceInput, + L1ToL2Message, L1ToL2MessageInput, ProofDAReference, ProofDAReferenceInput, + ProposeSequencer, ProposeSequencerInput, SystemBootstrapping, SystemBootstrappingInput, + ValidatorAttestation, ValidatorAttestationInput, Vote, }, }; @@ -43,7 +43,11 @@ impl MessageParser { } #[instrument(skip(self, tx), target = "bitcoin_indexer::parser")] - pub fn parse_transaction(&mut self, tx: &Transaction, block_height: u32) -> Vec { + pub fn parse_transaction( + &mut self, + tx: &Transaction, + block_height: u32, + ) -> Vec { // parsing btc address let mut sender_addresses: Option
= None; for input in tx.input.iter() { @@ -74,7 +78,7 @@ impl MessageParser { tx: &Transaction, block_height: u32, address: Address, - ) -> Option { + ) -> Option { let witness = &input.witness; if witness.len() < MIN_WITNESS_LENGTH { return None; @@ -138,7 +142,7 @@ impl MessageParser { tx: &Transaction, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { let message_type = instructions.get(1)?; match message_type { @@ -200,7 +204,7 @@ impl MessageParser { &mut self, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_SYSTEM_BOOTSTRAPPING_INSTRUCTIONS { warn!("Insufficient instructions for system bootstrapping"); return None; @@ -275,16 +279,18 @@ impl MessageParser { debug!("Parsed abstract account hash"); - Some(Message::SystemBootstrapping(SystemBootstrapping { - common: common_fields.clone(), - input: SystemBootstrappingInput { - start_block_height, - bridge_musig2_address: network_unchecked_bridge_address, - verifier_p2wpkh_addresses: network_unchecked_verifier_addresses, - bootloader_hash, - abstract_account_hash, + Some(FullInscriptionMessage::SystemBootstrapping( + SystemBootstrapping { + common: common_fields.clone(), + input: SystemBootstrappingInput { + start_block_height, + bridge_musig2_address: network_unchecked_bridge_address, + verifier_p2wpkh_addresses: network_unchecked_verifier_addresses, + bootloader_hash, + abstract_account_hash, + }, }, - })) + )) } #[instrument( @@ -295,7 +301,7 @@ impl MessageParser { &self, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_PROPOSE_SEQUENCER_INSTRUCTIONS { warn!("Insufficient instructions for propose sequencer"); return None; @@ -316,7 +322,7 @@ impl MessageParser { debug!("Parsed sequencer address"); - Some(Message::ProposeSequencer(ProposeSequencer { + Some(FullInscriptionMessage::ProposeSequencer(ProposeSequencer { common: common_fields.clone(), input: ProposeSequencerInput { sequencer_new_p2wpkh_address: sequencer_address.as_unchecked().clone(), @@ -332,7 +338,7 @@ impl MessageParser { &self, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_VALIDATOR_ATTESTATION_INSTRUCTIONS { warn!("Insufficient instructions for validator attestation"); return None; @@ -373,13 +379,15 @@ impl MessageParser { debug!("Parsed attestation: {:?}", attestation); - Some(Message::ValidatorAttestation(ValidatorAttestation { - common: common_fields.clone(), - input: ValidatorAttestationInput { - reference_txid, - attestation, + Some(FullInscriptionMessage::ValidatorAttestation( + ValidatorAttestation { + common: common_fields.clone(), + input: ValidatorAttestationInput { + reference_txid, + attestation, + }, }, - })) + )) } #[instrument( @@ -390,7 +398,7 @@ impl MessageParser { &self, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_L1_BATCH_DA_REFERENCE_INSTRUCTIONS { warn!("Insufficient instructions for L1 batch DA reference"); return None; @@ -419,15 +427,17 @@ impl MessageParser { .to_string(); debug!("Parsed blob ID: {}", blob_id); - Some(Message::L1BatchDAReference(L1BatchDAReference { - common: common_fields.clone(), - input: L1BatchDAReferenceInput { - l1_batch_hash, - l1_batch_index, - da_identifier, - blob_id, + Some(FullInscriptionMessage::L1BatchDAReference( + L1BatchDAReference { + common: common_fields.clone(), + input: L1BatchDAReferenceInput { + l1_batch_hash, + l1_batch_index, + da_identifier, + blob_id, + }, }, - })) + )) } #[instrument( @@ -438,7 +448,7 @@ impl MessageParser { &self, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_PROOF_DA_REFERENCE_INSTRUCTIONS { warn!("Insufficient instructions for proof DA reference"); return None; @@ -466,7 +476,7 @@ impl MessageParser { .to_string(); debug!("Parsed blob ID: {}", blob_id); - Some(Message::ProofDAReference(ProofDAReference { + Some(FullInscriptionMessage::ProofDAReference(ProofDAReference { common: common_fields.clone(), input: ProofDAReferenceInput { l1_batch_reveal_txid, @@ -485,7 +495,7 @@ impl MessageParser { tx: &Transaction, instructions: &[Instruction], common_fields: &CommonFields, - ) -> Option { + ) -> Option { if instructions.len() < MIN_L1_TO_L2_MESSAGE_INSTRUCTIONS { warn!("Insufficient instructions for L1 to L2 message"); return None; @@ -518,7 +528,7 @@ impl MessageParser { .unwrap_or(Amount::ZERO); debug!("Parsed amount: {}", amount); - Some(Message::L1ToL2Message(L1ToL2Message { + Some(FullInscriptionMessage::L1ToL2Message(L1ToL2Message { common: common_fields.clone(), amount, input: L1ToL2MessageInput { @@ -590,7 +600,7 @@ mod tests { let mut parser = MessageParser::new(network); let tx = setup_test_transaction(); - if let Some(Message::SystemBootstrapping(bootstrapping)) = + if let Some(FullInscriptionMessage::SystemBootstrapping(bootstrapping)) = parser.parse_transaction(&tx, 0).pop() { assert_eq!(bootstrapping.input.start_block_height, 10); diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index 90f44c927..643983d66 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -134,17 +134,11 @@ impl Serializable for InscriptionMessage { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct InscriptionConfig { pub fee_multiplier: u64, } -impl Default for InscriptionConfig { - fn default() -> Self { - InscriptionConfig { fee_multiplier: 0 } - } -} - #[derive(Debug)] pub struct Recipient { pub address: BitcoinAddress, diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 0d4b17142..ec790e1a7 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -84,21 +84,18 @@ impl RestApi { .context("Error to get withdrawals from DA")?; if !withdrawals.is_empty() { - proof_txid = Self::h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; + proof_txid = Self::h256_to_txid(proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; break; } else { // If there is no withdrawals to process in a batch, update the status and mark it as processed - _ = self_ + self_ .master_connection_pool .connection_tagged("coordinator") .await? .via_votes_dal() - .mark_vote_transaction_as_processed_withdrawals( - H256::zero(), - block_number.clone(), - ) + .mark_vote_transaction_as_processed_withdrawals(H256::zero(), *block_number) .await .context("Error to mark a vote transaction as processed")?; } From a7235243537b2596611adbe7c54bcbb2e32d1d50 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 23 Jan 2025 15:13:54 +0100 Subject: [PATCH 164/212] fix: verifier task logic to start a new session when the previous one is processed --- .../src/withdrawal_builder/mod.rs | 2 +- .../src/coordinator/api_impl.rs | 6 +- .../withdrawal_service/src/verifier/mod.rs | 96 +++++++++++++------ 3 files changed, 72 insertions(+), 32 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs index 8f96a1125..9e4264db9 100644 --- a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs @@ -100,7 +100,7 @@ impl WithdrawalBuilder { let available_utxos = self.get_available_utxos().await?; // Get fee rate - let fee_rate = self.client.get_fee_rate(1).await?; + let fee_rate = std::cmp::max(self.client.get_fee_rate(1).await?, 1); // Estimate initial fee with approximate input count // We'll estimate high initially to avoid underestimating diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 0d4b17142..2e624a38d 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -59,12 +59,10 @@ impl RestApi { let blocks = self_ .master_connection_pool .connection_tagged("coordinator") - .await - .unwrap() + .await? .via_votes_dal() .get_finalized_blocks_and_non_processed_withdrawals() - .await - .unwrap(); + .await?; if blocks.is_empty() { if l1_block_number != 0 { diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 40e7a2375..89dad1827 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::{Context, Result}; -use bitcoin::{hashes::Hash, TapSighashType, Witness}; +use bitcoin::{hashes::Hash, TapSighashType, Txid, Witness}; use musig2::{CompactSignature, PartialSignature}; use reqwest::{header, Client, StatusCode}; use tokio::sync::watch; @@ -73,19 +73,48 @@ impl ViaWithdrawalVerifier { } async fn loop_iteration(&mut self) -> Result<(), anyhow::Error> { - if self.config.verifier_mode == VerifierMode::COORDINATOR { - self.create_new_session().await?; + let mut session_info = self.get_session().await?; + if self.config.verifier_mode == VerifierMode::COORDINATOR { tracing::info!("create a new session"); - self.build_and_broadcast_final_transaction().await?; + + if !session_info.l1_block_number == 0 { + let withdrawal_txid = self + .master_connection_pool + .connection_tagged("coordinator task") + .await? + .via_votes_dal() + .get_vote_transaction_withdrawal_tx(session_info.l1_block_number) + .await?; + + // Check if the previous batch musig2 transaction was minted before start a new session. + if let Some(tx) = withdrawal_txid { + let tx_id = Txid::from_slice(&tx)?; + let is_confirmed = self.btc_client.check_tx_confirmation(&tx_id, 2).await?; + if !is_confirmed { + return Ok(()); + } + } + } + + self.create_new_session().await?; } - let session_info = self.get_session().await?; + session_info = self.get_session().await?; if session_info.l1_block_number == 0 { tracing::info!("Empty session, nothing to process"); return Ok(()); } + if self.config.verifier_mode == VerifierMode::COORDINATOR { + if self + .build_and_broadcast_final_transaction(&session_info) + .await? + { + return Ok(()); + } + } + let session_signature = self.get_session_signatures().await?; let session_nonces = self.get_session_nonces().await?; let verifier_index = self.signer.signer_index(); @@ -93,16 +122,16 @@ impl ViaWithdrawalVerifier { if session_signature.contains_key(&verifier_index) && session_nonces.contains_key(&verifier_index) { - // The verifier already sent his nonce and partial signature return Ok(()); } - // Reinit the signer incase the coordinator lost his in memory data + // Reinit the signer, when a new session is created by the coordinator. if !session_signature.contains_key(&verifier_index) && !session_nonces.contains_key(&verifier_index) && (self.signer.has_created_partial_sig() || self.signer.has_submitted_nonce()) { - _ = self.reinit_signer(); + self.reinit_signer()?; + return Ok(()); } if session_info.received_nonces < session_info.required_signers { @@ -210,31 +239,31 @@ impl ViaWithdrawalVerifier { } async fn create_new_session(&mut self) -> anyhow::Result<()> { - let session_info = self.get_session().await?; - if session_info.l1_block_number == 0 { - let url = format!("{}/session/new", self.config.url,); - let resp = self - .client - .post(&url) - .header(header::CONTENT_TYPE, "application/json") - .send() - .await?; - - if !resp.status().is_success() {} + let url = format!("{}/session/new", self.config.url); + let resp = self + .client + .post(&url) + .header(header::CONTENT_TYPE, "application/json") + .send() + .await?; + + if !resp.status().is_success() { + self.reinit_signer()?; } Ok(()) } - async fn create_final_signature(&mut self) -> anyhow::Result<()> { + async fn create_final_signature( + &mut self, + session_info: &SigningSessionResponse, + ) -> anyhow::Result<()> { if self.final_sig.is_some() { return Ok(()); } - let session_info = self.get_session().await?; if session_info.received_partial_signatures >= session_info.required_signers { let signatures = self.get_session_signatures().await?; for (&i, sig) in &signatures { - println!("1"); if self.signer.signer_index() != i { self.signer.receive_partial_signature(i, *sig)?; } @@ -269,9 +298,11 @@ impl ViaWithdrawalVerifier { bitcoin::consensus::encode::serialize_hex(&unsigned_tx.tx) } - async fn build_and_broadcast_final_transaction(&mut self) -> anyhow::Result<()> { - let session_info = self.get_session().await?; - self.create_final_signature() + async fn build_and_broadcast_final_transaction( + &mut self, + session_info: &SigningSessionResponse, + ) -> anyhow::Result { + self.create_final_signature(session_info) .await .context("Error create final signature")?; @@ -285,8 +316,9 @@ impl ViaWithdrawalVerifier { .await?; if withdrawal_txid.is_some() { - return Ok(()); + return Ok(false); } + let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session_info.unsigned_tx); let signed_tx = self.sign_transaction(unsigned_tx.clone(), musig2_signature); @@ -304,7 +336,17 @@ impl ViaWithdrawalVerifier { session_info.l1_block_number, ) .await?; + + tracing::info!( + "New withdrawal transaction processed, l1 batch {} musig2 tx_id {}", + session_info.l1_block_number, + txid + ); + + self.reinit_signer()?; + + return Ok(true); } - Ok(()) + Ok(false) } } From 2606d285846cf8d46b066f8aec535291cd4030b9 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 23 Jan 2025 19:53:22 +0100 Subject: [PATCH 165/212] fix: if condition and reduce the confirmation block to 1 --- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 89dad1827..b72447910 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -78,7 +78,7 @@ impl ViaWithdrawalVerifier { if self.config.verifier_mode == VerifierMode::COORDINATOR { tracing::info!("create a new session"); - if !session_info.l1_block_number == 0 { + if session_info.l1_block_number != 0 { let withdrawal_txid = self .master_connection_pool .connection_tagged("coordinator task") @@ -87,10 +87,11 @@ impl ViaWithdrawalVerifier { .get_vote_transaction_withdrawal_tx(session_info.l1_block_number) .await?; + // TODO: refactore the transaction confirmation for the musig2, and implement utxo manager like in the inscriber // Check if the previous batch musig2 transaction was minted before start a new session. if let Some(tx) = withdrawal_txid { let tx_id = Txid::from_slice(&tx)?; - let is_confirmed = self.btc_client.check_tx_confirmation(&tx_id, 2).await?; + let is_confirmed = self.btc_client.check_tx_confirmation(&tx_id, 1).await?; if !is_confirmed { return Ok(()); } From 6aa8fa11c9500723750a64b73c2ca46d0cb69e21 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:41:08 +0100 Subject: [PATCH 166/212] feat: add restart cmds --- Makefile | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c8b7a9f6e..ec4facdce 100644 --- a/Makefile +++ b/Makefile @@ -16,10 +16,16 @@ ifeq ($(CMD), via-verifier) VIA_ENV := via_verifier DIFF := 1 MODE := verifier +else ifeq ($(CMD), via-restart) + VIA_ENV := via +else ifeq ($(CMD), via-restart-verifier) + VIA_ENV := via_verifier else ifeq ($(CMD), via-coordinator) VIA_ENV := via_coordinator DIFF := 2 MODE := coordinator +else ifeq ($(CMD), via-restart-coordinator) + VIA_ENV := via_coordinator endif # Default target: Show help message @@ -55,6 +61,10 @@ help: # Default target: Redirect to help .DEFAULT_GOAL := help +# Restart the sequence +.PHONY: via-restart +via-restart: env server + # Run the basic setup workflow in sequence .PHONY: via via: base transactions celestia bootstrap server-genesis server @@ -67,10 +77,18 @@ all: base transactions celestia btc-explorer bootstrap server-genesis server .PHONY: via-verifier via-verifier: base celestia verifier -# Run the basic setup workflow in coordinator +# Restart the verifier +.PHONY: via-restart-verifier +via-restart-verifier: env verifier + +# Run the basic setup workflow for the coordinator .PHONY: via-coordinator via-coordinator: base celestia verifier +# Restart the coordinator +.PHONY: via-restart-coordinator +via-restart-coordinator: env verifier + # Run minimal required setup .PHONY: base base: env config init From c6f98837fe1bcf680f6036e6274caabc39300aa5 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:54:25 +0100 Subject: [PATCH 167/212] feat: add soft reload config --- Makefile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ec4facdce..d1198c0a8 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ help: # Restart the sequence .PHONY: via-restart -via-restart: env server +via-restart: env-soft server # Run the basic setup workflow in sequence .PHONY: via @@ -79,7 +79,7 @@ via-verifier: base celestia verifier # Restart the verifier .PHONY: via-restart-verifier -via-restart-verifier: env verifier +via-restart-verifier: env-soft verifier # Run the basic setup workflow for the coordinator .PHONY: via-coordinator @@ -87,7 +87,7 @@ via-coordinator: base celestia verifier # Restart the coordinator .PHONY: via-restart-coordinator -via-restart-coordinator: env verifier +via-restart-coordinator: env-soft verifier # Run minimal required setup .PHONY: base @@ -99,7 +99,15 @@ env: @echo "------------------------------------------------------------------------------------" @echo "$(YELLOW)Setting the environment...$(RESET)" @echo "------------------------------------------------------------------------------------" - @$(CLI_TOOL) env ${VIA_ENV} + @$(CLI_TOOL) env ${VIA_ENV} + +# Run 'via env via --soft' +.PHONY: env-soft +env-soft: + @echo "------------------------------------------------------------------------------------" + @echo "$(YELLOW)Setting the environment...$(RESET)" + @echo "------------------------------------------------------------------------------------" + @$(CLI_TOOL) env ${VIA_ENV} --soft # Run 'via config compile' .PHONY: config From ace4fc881ad5ed9a7e51d2d8b8bdce5ca49fb72c Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sat, 25 Jan 2025 10:38:55 +0330 Subject: [PATCH 168/212] feat(indexer): improve indexer input tx filter --- core/lib/via_btc_client/src/indexer/mod.rs | 20 ++++++++++++++++--- core/lib/via_btc_client/src/indexer/parser.rs | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index fe6756f69..ac64c720d 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -139,6 +139,7 @@ impl BitcoinInscriptionIndexer { } let block = self.client.fetch_block(block_height as u128).await?; + // TODO: check block header is belong to a valid chain of blocks (reorg detection and management) let important_txs: Vec<_> = block .txdata @@ -165,7 +166,18 @@ impl BitcoinInscriptionIndexer { } fn is_transaction_involving_important_addresses(&self, tx: &BitcoinTransaction) -> bool { - tx.output.iter().any(|output| { + // We only care about the transactions that sequencer, verifiers are sending and the bridge is receiving + + let is_important_sender = tx.input.iter().any(|input| { + if let Some(btc_address) = self.parser.parse_p2wpkh(&input.witness) { + btc_address == self.sequencer_address + || self.verifier_addresses.contains(&btc_address) + } else { + false + } + }); + + let is_important_receiver = tx.output.iter().any(|output| { let script_pubkey = &output.script_pubkey; script_pubkey == &self.sequencer_address.script_pubkey() || script_pubkey == &self.bridge_address.script_pubkey() @@ -173,7 +185,9 @@ impl BitcoinInscriptionIndexer { .verifier_addresses .iter() .any(|addr| script_pubkey == &addr.script_pubkey()) - }) + }); + + is_important_sender || is_important_receiver } #[instrument(skip(self), target = "bitcoin_indexer")] @@ -313,7 +327,7 @@ impl BitcoinInscriptionIndexer { debug!("Processing SystemBootstrapping message"); // convert the verifier addresses to the correct network - // scince the bootstrap message should run on the bootstrapping phase of sequencer + // since the bootstrap message should run on the bootstrapping phase of sequencer // i consume it's ok to using unwrap let verifier_addresses = sb .input diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index 3eba1d98e..0e116500c 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -122,7 +122,7 @@ impl MessageParser { } #[instrument(skip(self), target = "bitcoin_indexer::parser")] - fn parse_p2wpkh(&mut self, witness: &Witness) -> Option
{ + pub fn parse_p2wpkh(&self, witness: &Witness) -> Option
{ if witness.len() == 2 { let public_key = bitcoin::PublicKey::from_slice(&witness[1]).ok()?; let cm_pk = CompressedPublicKey::try_from(public_key).ok()?; From d96e22c9fc4e7ace73e6353192f7db4ce9930b35 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Sat, 25 Jan 2025 12:48:50 +0330 Subject: [PATCH 169/212] feat(indexer): seperate system message and bridge message flow in indexer --- core/lib/via_btc_client/src/indexer/mod.rs | 142 ++++++++++++------ core/lib/via_btc_client/src/indexer/parser.rs | 35 ++++- 2 files changed, 132 insertions(+), 45 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index ac64c720d..67b1ba1ca 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -94,7 +94,7 @@ impl BitcoinInscriptionIndexer { for txid in bootstrap_txids { debug!("Processing bootstrap transaction: {}", txid); let tx = client.get_transaction(&txid).await?; - let messages = parser.parse_transaction(&tx, 0); + let messages = parser.parse_system_transaction(&tx, 0); for message in messages { Self::process_bootstrap_message(&mut bootstrap_state, message, txid, network); @@ -141,21 +141,48 @@ impl BitcoinInscriptionIndexer { let block = self.client.fetch_block(block_height as u128).await?; // TODO: check block header is belong to a valid chain of blocks (reorg detection and management) - let important_txs: Vec<_> = block - .txdata - .iter() - .filter(|tx| self.is_transaction_involving_important_addresses(tx)) - .collect(); + // let important_txs: Vec<_> = block + // .txdata + // .iter() + // .filter(|tx| self.is_transaction_involving_important_addresses(tx)) + // .collect(); - let parsed_messages: Vec<_> = important_txs - .iter() - .flat_map(|tx| self.parser.parse_transaction(tx, block_height)) - .collect(); + // let system transaction + // let bridge transaction + // parse system transaction + // parse bridge transaction - let valid_messages: Vec<_> = parsed_messages - .into_iter() - .filter(|message| self.is_valid_message(message)) - .collect(); + let mut valid_messages = Vec::new(); + + let (system_tx, bridge_tx) = self.extract_important_transactions(&block.txdata); + + if let Some(system_tx) = system_tx { + let parsed_messages: Vec<_> = system_tx + .iter() + .flat_map(|tx| self.parser.parse_system_transaction(tx, block_height)) + .collect(); + + let messages: Vec<_> = parsed_messages + .into_iter() + .filter(|message| self.is_valid_system_message(message)) + .collect(); + + valid_messages.extend(messages); + } + + if let Some(bridge_tx) = bridge_tx { + let parsed_messages: Vec<_> = bridge_tx + .iter() + .flat_map(|tx| self.parser.parse_bridge_transaction(tx, block_height)) + .collect(); + + let messages: Vec<_> = parsed_messages + .into_iter() + .filter(|message| self.is_valid_bridge_message(message)) + .collect(); + + valid_messages.extend(messages); + } debug!( "Processed {} valid messages in block {}", @@ -165,29 +192,53 @@ impl BitcoinInscriptionIndexer { Ok(valid_messages) } - fn is_transaction_involving_important_addresses(&self, tx: &BitcoinTransaction) -> bool { + fn extract_important_transactions( + &self, + transactions: &[BitcoinTransaction], + ) -> ( + Option>, + Option>, + ) { // We only care about the transactions that sequencer, verifiers are sending and the bridge is receiving + let system_txs: Vec = transactions + .iter() + .filter(|tx| { + tx.input.iter().any(|input| { + if let Some(btc_address) = self.parser.parse_p2wpkh(&input.witness) { + btc_address == self.sequencer_address + || self.verifier_addresses.contains(&btc_address) + } else { + false + } + }) + }) + .cloned() + .collect(); - let is_important_sender = tx.input.iter().any(|input| { - if let Some(btc_address) = self.parser.parse_p2wpkh(&input.witness) { - btc_address == self.sequencer_address - || self.verifier_addresses.contains(&btc_address) - } else { - false - } - }); + let bridge_txs: Vec = transactions + .iter() + .filter(|tx| { + tx.output.iter().any(|output| { + let script_pubkey = &output.script_pubkey; + script_pubkey == &self.bridge_address.script_pubkey() + }) + }) + .cloned() + .collect(); - let is_important_receiver = tx.output.iter().any(|output| { - let script_pubkey = &output.script_pubkey; - script_pubkey == &self.sequencer_address.script_pubkey() - || script_pubkey == &self.bridge_address.script_pubkey() - || self - .verifier_addresses - .iter() - .any(|addr| script_pubkey == &addr.script_pubkey()) - }); + let system_txs = if !system_txs.is_empty() { + Some(system_txs) + } else { + None + }; + + let bridge_txs = if !bridge_txs.is_empty() { + Some(bridge_txs) + } else { + None + }; - is_important_sender || is_important_receiver + (system_txs, bridge_txs) } #[instrument(skip(self), target = "bitcoin_indexer")] @@ -245,7 +296,7 @@ impl BitcoinInscriptionIndexer { tx: &Txid, ) -> BitcoinIndexerResult> { let tx = self.client.get_transaction(tx).await?; - Ok(self.parser.parse_transaction(&tx, 0)) + Ok(self.parser.parse_system_transaction(&tx, 0)) } } @@ -287,7 +338,7 @@ impl BitcoinInscriptionIndexer { } #[instrument(skip(self, message), target = "bitcoin_indexer")] - fn is_valid_message(&self, message: &FullInscriptionMessage) -> bool { + fn is_valid_system_message(&self, message: &FullInscriptionMessage) -> bool { match message { FullInscriptionMessage::ProposeSequencer(m) => { self.verifier_addresses.contains(&m.common.p2wpkh_address) @@ -315,6 +366,13 @@ impl BitcoinInscriptionIndexer { } } + fn is_valid_bridge_message(&self, message: &FullInscriptionMessage) -> bool { + match message { + FullInscriptionMessage::L1ToL2Message(m) => self.is_valid_l1_to_l2_transfer(m), + _ => false, + } + } + #[instrument(skip(state, message), target = "bitcoin_indexer")] fn process_bootstrap_message( state: &mut BootstrapState, @@ -394,7 +452,7 @@ impl BitcoinInscriptionIndexer { txid: &Txid, ) -> anyhow::Result { let a = self.client.get_transaction(txid).await?; - let b = self.parser.parse_transaction(&a, 0); + let b = self.parser.parse_system_transaction(&a, 0); let msg = b .first() .ok_or_else(|| anyhow::anyhow!("No message found"))?; @@ -410,7 +468,7 @@ impl BitcoinInscriptionIndexer { txid: &Txid, ) -> anyhow::Result { let a = self.client.get_transaction(txid).await?; - let b = self.parser.parse_transaction(&a, 0); + let b = self.parser.parse_system_transaction(&a, 0); let msg = b .first() .ok_or_else(|| anyhow::anyhow!("No message found"))?; @@ -574,7 +632,7 @@ mod tests { .to_owned(), }, }); - assert!(!indexer.is_valid_message(&propose_sequencer)); + assert!(!indexer.is_valid_system_message(&propose_sequencer)); let validator_attestation = FullInscriptionMessage::ValidatorAttestation(types::ValidatorAttestation { @@ -584,7 +642,7 @@ mod tests { attestation: Vote::Ok, }, }); - assert!(!indexer.is_valid_message(&validator_attestation)); + assert!(!indexer.is_valid_system_message(&validator_attestation)); let l1_batch_da_reference = FullInscriptionMessage::L1BatchDAReference(types::L1BatchDAReference { @@ -603,7 +661,7 @@ mod tests { }, }); // We didn't vote for the sequencer yet, so this message is invalid - assert!(indexer.is_valid_message(&l1_batch_da_reference)); + assert!(indexer.is_valid_system_message(&l1_batch_da_reference)); let l1_to_l2_message = FullInscriptionMessage::L1ToL2Message(L1ToL2Message { common: get_test_common_fields(), @@ -618,7 +676,7 @@ mod tests { script_pubkey: indexer.bridge_address.script_pubkey(), }], }); - assert!(indexer.is_valid_message(&l1_to_l2_message)); + assert!(indexer.is_valid_bridge_message(&l1_to_l2_message)); let system_bootstrapping = FullInscriptionMessage::SystemBootstrapping(types::SystemBootstrapping { @@ -631,7 +689,7 @@ mod tests { abstract_account_hash: H256::zero(), }, }); - assert!(indexer.is_valid_message(&system_bootstrapping)); + assert!(indexer.is_valid_system_message(&system_bootstrapping)); } #[tokio::test] diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index 0e116500c..497177cce 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -43,7 +43,36 @@ impl MessageParser { } #[instrument(skip(self, tx), target = "bitcoin_indexer::parser")] - pub fn parse_transaction( + pub fn parse_system_transaction( + &mut self, + tx: &Transaction, + block_height: u32, + ) -> Vec { + // parsing btc address + let mut sender_addresses: Option
= None; + for input in tx.input.iter() { + let witness = &input.witness; + if let Some(btc_address) = self.parse_p2wpkh(witness) { + sender_addresses = Some(btc_address); + } + } + + match sender_addresses { + Some(address) => { + // parsing messages + tx.input + .iter() + .filter_map(|input| self.parse_input(input, tx, block_height, address.clone())) + .collect() + } + None => { + vec![] + } + } + } + + #[instrument(skip(self, tx), target = "bitcoin_indexer::parser")] + pub fn parse_bridge_transaction( &mut self, tx: &Transaction, block_height: u32, @@ -589,7 +618,7 @@ mod tests { let mut parser = MessageParser::new(network); let tx = setup_test_transaction(); - let messages = parser.parse_transaction(&tx, 0); + let messages = parser.parse_system_transaction(&tx, 0); assert_eq!(messages.len(), 1); } @@ -601,7 +630,7 @@ mod tests { let tx = setup_test_transaction(); if let Some(FullInscriptionMessage::SystemBootstrapping(bootstrapping)) = - parser.parse_transaction(&tx, 0).pop() + parser.parse_system_transaction(&tx, 0).pop() { assert_eq!(bootstrapping.input.start_block_height, 10); assert_eq!(bootstrapping.input.verifier_p2wpkh_addresses.len(), 1); From d3c2fe911dcfb8405df5efd6cd45660ce4e5bbdd Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Sun, 26 Jan 2025 12:05:41 +0100 Subject: [PATCH 170/212] fix: protocol version --- prover/crates/lib/prover_fri_types/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prover/crates/lib/prover_fri_types/src/lib.rs b/prover/crates/lib/prover_fri_types/src/lib.rs index c14bc1905..f89e45ac1 100644 --- a/prover/crates/lib/prover_fri_types/src/lib.rs +++ b/prover/crates/lib/prover_fri_types/src/lib.rs @@ -28,8 +28,8 @@ pub mod keys; pub mod queue; // THESE VALUES SHOULD BE UPDATED ON ANY PROTOCOL UPGRADE OF PROVERS -pub const PROVER_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version24; -pub const PROVER_PROTOCOL_PATCH: VersionPatch = VersionPatch(2); +pub const PROVER_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version26; +pub const PROVER_PROTOCOL_PATCH: VersionPatch = VersionPatch(0); pub const PROVER_PROTOCOL_SEMANTIC_VERSION: ProtocolSemanticVersion = ProtocolSemanticVersion { minor: PROVER_PROTOCOL_VERSION, patch: PROVER_PROTOCOL_PATCH, From f0a24b31fc410e7fce39baad9b5f1b0b8441aab0 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:13:24 +0100 Subject: [PATCH 171/212] feat(verifier_dal): add a logic to fetch a votable transaction per l1 batch --- ...0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json | 28 ++++++++++++++++ .../lib/verifier_dal/src/via_votes_dal.rs | 33 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json b/via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json new file mode 100644 index 000000000..5093aa470 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n pubdata_blob_id,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n AND l1_batch_number = $1\n LIMIT 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "pubdata_blob_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "tx_id", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9" +} diff --git a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs index a157c7d88..83d132d94 100644 --- a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs @@ -287,6 +287,39 @@ impl ViaVotesDal<'_, '_> { Ok(result) } + + pub async fn get_finalized_block_and_non_processed_withdrawal( + &mut self, + l1_batch_number: i64, + ) -> DalResult)>> { + // Query the database to fetch the desired row + let result = sqlx::query!( + r#" + SELECT + pubdata_blob_id, + tx_id + FROM + via_votable_transactions + WHERE + is_finalized = TRUE + AND is_verified = TRUE + AND withdrawal_tx_id IS NULL + AND l1_batch_number = $1 + LIMIT + 1 + "#, + l1_batch_number + ) + .instrument("get_finalized_block_and_non_processed_withdrawal") + .fetch_optional(&mut self.storage) // Use fetch_optional to handle None results + .await?; + + // Map the result into the desired output format + let mapped_result = result.map(|row| (row.pubdata_blob_id, row.tx_id)); + + Ok(mapped_result) + } + pub async fn get_finalized_blocks_and_non_processed_withdrawals( &mut self, ) -> DalResult)>> { From 6c0a9208722925e8b7a2f01533ca509b0846bca1 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:14:34 +0100 Subject: [PATCH 172/212] feat(verifier): amake the create_op_return_script public --- core/lib/via_btc_client/src/withdrawal_builder/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs index 9e4264db9..ef61d68fd 100644 --- a/core/lib/via_btc_client/src/withdrawal_builder/mod.rs +++ b/core/lib/via_btc_client/src/withdrawal_builder/mod.rs @@ -127,7 +127,7 @@ impl WithdrawalBuilder { .ok_or_else(|| anyhow::anyhow!("Input amount overflow"))?; // Create OP_RETURN output with proof txid - let op_return_data = self.create_op_return_script(proof_txid)?; + let op_return_data = WithdrawalBuilder::create_op_return_script(proof_txid)?; let op_return_output = TxOut { value: Amount::ZERO, script_pubkey: op_return_data, @@ -260,7 +260,7 @@ impl WithdrawalBuilder { } // Helper function to create OP_RETURN script - fn create_op_return_script(&self, proof_txid: Txid) -> Result { + pub fn create_op_return_script(proof_txid: Txid) -> Result { let mut data = Vec::with_capacity(OP_RETURN_PREFIX.len() + 32); data.extend_from_slice(OP_RETURN_PREFIX); data.extend_from_slice(&proof_txid.as_raw_hash().to_byte_array()); From edb33d687eb3565ae3d2f82213f15e8b3c200be0 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:15:55 +0100 Subject: [PATCH 173/212] feat(verifier): add logic to verify the unsigned transaction --- .../layers/via_verifier/verifier.rs | 11 +- .../src/coordinator/api_impl.rs | 19 +-- .../node/withdrawal_service/src/utils.rs | 12 +- .../withdrawal_service/src/verifier/mod.rs | 115 +++++++++++++++++- 4 files changed, 136 insertions(+), 21 deletions(-) diff --git a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs index 111cecbff..f9dc3ef08 100644 --- a/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs +++ b/core/node/node_framework/src/implementations/layers/via_verifier/verifier.rs @@ -3,11 +3,15 @@ use std::{str::FromStr, sync::Arc}; use anyhow::Context; use via_btc_client::{client::BitcoinClient, types::NodeAuth}; use via_btc_watch::BitcoinNetwork; +use via_withdrawal_client::client::WithdrawalClient; use via_withdrawal_service::verifier::ViaWithdrawalVerifier; use zksync_config::{ViaBtcSenderConfig, ViaVerifierConfig}; use crate::{ - implementations::resources::pools::{PoolResource, VerifierPool}, + implementations::resources::{ + da_client::DAClientResource, + pools::{PoolResource, VerifierPool}, + }, service::StopReceiver, task::{Task, TaskId}, wiring_layer::{WiringError, WiringLayer}, @@ -25,6 +29,7 @@ pub struct ViaWithdrawalVerifierLayer { #[context(crate = crate)] pub struct Input { pub master_pool: PoolResource, + pub client: DAClientResource, } #[derive(IntoContext)] @@ -56,8 +61,10 @@ impl WiringLayer for ViaWithdrawalVerifierLayer { .context("Error to init the btc client for verifier task")?, ); + let withdrawal_client = WithdrawalClient::new(input.client.0, network); + let via_withdrawal_verifier_task = - ViaWithdrawalVerifier::new(master_pool, btc_client, self.config) + ViaWithdrawalVerifier::new(master_pool, btc_client, withdrawal_client, self.config) .await .context("Error to init the via withdrawal verifier")?; diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 2e624a38d..07181e8fd 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -18,7 +18,7 @@ use zksync_types::H256; use super::{api_decl::RestApi, error::ApiError}; use crate::{ types::{NoncePair, PartialSignaturePair, SigningSession, SigningSessionResponse}, - utils::{decode_signature, encode_signature}, + utils::{decode_signature, encode_signature, h256_to_txid}, }; fn ok_json(data: T) -> Response { @@ -75,14 +75,14 @@ impl RestApi { let mut proof_txid = Txid::all_zeros(); for (block_number, blob_id, proof_tx_id) in blocks.iter() { - let withdrawals = self_ + let withdrawals: Vec = self_ .withdrawal_client .get_withdrawals(blob_id) .await .context("Error to get withdrawals from DA")?; if !withdrawals.is_empty() { - proof_txid = Self::h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; + proof_txid = h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; break; @@ -131,7 +131,7 @@ impl RestApi { } let sighash = sighash_cache .taproot_key_spend_signature_hash(0, &Prevouts::All(&txout_list), sighash_type) - .unwrap(); + .context("Error taproot_key_spend_signature_hash")?; let new_sesssion = SigningSession { l1_block_number, @@ -242,15 +242,4 @@ impl RestApi { let mut session = self.state.signing_session.write().await; *session = SigningSession::default(); } - - // Todo: move this logic in a helper crate as it's used in multiple crates. - /// Converts H256 bytes (from the DB) to a Txid by reversing the byte order. - fn h256_to_txid(h256_bytes: &[u8]) -> anyhow::Result { - if h256_bytes.len() != 32 { - return Err(anyhow::anyhow!("H256 must be 32 bytes")); - } - let mut reversed_bytes = h256_bytes.to_vec(); - reversed_bytes.reverse(); - Txid::from_slice(&reversed_bytes).context("Failed to convert H256 to Txid") - } } diff --git a/via_verifier/node/withdrawal_service/src/utils.rs b/via_verifier/node/withdrawal_service/src/utils.rs index dc8b906ec..49d39adee 100644 --- a/via_verifier/node/withdrawal_service/src/utils.rs +++ b/via_verifier/node/withdrawal_service/src/utils.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use anyhow::Context; use base64::Engine; -use bitcoin::PrivateKey; +use bitcoin::{hashes::Hash, PrivateKey, Txid}; use musig2::{BinaryEncoding, PartialSignature, PubNonce}; use secp256k1_musig2::{PublicKey, Secp256k1, SecretKey}; use via_musig2::Signer; @@ -69,3 +69,13 @@ pub fn decode_nonce(nonce_pair: NoncePair) -> anyhow::Result { let pub_nonce = PubNonce::from_bytes(&decoded_nonce)?; Ok(pub_nonce) } + +/// Converts H256 bytes (from the DB) to a Txid by reversing the byte order. +pub(crate) fn h256_to_txid(h256_bytes: &[u8]) -> anyhow::Result { + if h256_bytes.len() != 32 { + return Err(anyhow::anyhow!("H256 must be 32 bytes")); + } + let mut reversed_bytes = h256_bytes.to_vec(); + reversed_bytes.reverse(); + Txid::from_slice(&reversed_bytes).context("Failed to convert H256 to Txid") +} diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index b72447910..a5f793130 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,22 +1,29 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::{Context, Result}; -use bitcoin::{hashes::Hash, TapSighashType, Txid, Witness}; +use bitcoin::{ + hashes::Hash, + sighash::{Prevouts, SighashCache}, + Amount, TapSighashType, Txid, Witness, +}; use musig2::{CompactSignature, PartialSignature}; use reqwest::{header, Client, StatusCode}; use tokio::sync::watch; use via_btc_client::{ traits::{BitcoinOps, Serializable}, - withdrawal_builder::UnsignedWithdrawalTx, + withdrawal_builder::{UnsignedWithdrawalTx, WithdrawalBuilder}, }; use via_musig2::{verify_signature, Signer}; use via_verifier_dal::{ConnectionPool, Verifier, VerifierDal}; +use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::{VerifierMode, ViaVerifierConfig}; use zksync_types::H256; use crate::{ types::{NoncePair, PartialSignaturePair, SigningSessionResponse}, - utils::{decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer}, + utils::{ + decode_nonce, decode_signature, encode_nonce, encode_signature, get_signer, h256_to_txid, + }, }; pub struct ViaWithdrawalVerifier { @@ -24,6 +31,7 @@ pub struct ViaWithdrawalVerifier { btc_client: Arc, config: ViaVerifierConfig, client: Client, + withdrawal_client: WithdrawalClient, signer: Signer, final_sig: Option, } @@ -32,6 +40,7 @@ impl ViaWithdrawalVerifier { pub async fn new( master_connection_pool: ConnectionPool, btc_client: Arc, + withdrawal_client: WithdrawalClient, config: ViaVerifierConfig, ) -> anyhow::Result { let signer = get_signer( @@ -44,6 +53,7 @@ impl ViaWithdrawalVerifier { btc_client, signer, client: Client::new(), + withdrawal_client, config, final_sig: None, }) @@ -138,6 +148,10 @@ impl ViaWithdrawalVerifier { if session_info.received_nonces < session_info.required_signers { let message = hex::decode(&session_info.message_to_sign)?; + if !self.verify_message(&session_info).await? { + anyhow::bail!("Error when verify the session message"); + } + if self.signer.has_not_started() { self.signer.start_signing_session(message)?; } @@ -165,6 +179,101 @@ impl ViaWithdrawalVerifier { Ok(session_info) } + async fn verify_message(&self, session: &SigningSessionResponse) -> anyhow::Result { + // Get the l1 batches finilized but withdrawals not yet processed + if let Some((blob_id, proof_tx_id)) = self + .master_connection_pool + .connection_tagged("verifier") + .await? + .via_votes_dal() + .get_finalized_block_and_non_processed_withdrawal(session.l1_block_number) + .await? + { + if !self + ._verify_withdrawals(&session, &blob_id, proof_tx_id) + .await? + { + return Ok(false); + } + + return self._verify_sighash(&session).await; + } + Ok(false) + } + async fn _verify_withdrawals( + &self, + session: &SigningSessionResponse, + blob_id: &str, + proof_tx_id: Vec, + ) -> anyhow::Result { + let withdrawals = self.withdrawal_client.get_withdrawals(blob_id).await?; + let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session.unsigned_tx); + + let len = withdrawals.len(); + if len == 0 { + tracing::error!( + "Invalid session, there are no withdrawals to process, l1 batch: {}", + session.l1_block_number + ); + return Ok(false); + } + if len + 2 != unsigned_tx.tx.output.len() { + // Log an error + return Ok(false); + } + + // Verify if all withdrawals are included with valid amount. + for (i, (_, txout)) in unsigned_tx.utxos.iter().enumerate() { + let req = &withdrawals[i]; + if req.amount != txout.value || req.address.script_pubkey() != txout.script_pubkey { + tracing::error!("Invalid request withdrawal, id: {i}"); + return Ok(false); + } + } + + // Verify the OP return + let tx_id = h256_to_txid(&proof_tx_id)?; + let op_return_data = WithdrawalBuilder::create_op_return_script(tx_id)?; + let (_, op_return_tx_out) = &unsigned_tx.utxos[len - 2]; + + if op_return_tx_out.script_pubkey.to_string() != op_return_data.to_string() + || op_return_tx_out.value != Amount::ZERO + { + tracing::error!( + "Invalid op return data for l1 batch: {}", + session.l1_block_number + ); + return Ok(false); + } + + Ok(true) + } + + async fn _verify_sighash(&self, session: &SigningSessionResponse) -> anyhow::Result { + // Verify the sighash + let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session.unsigned_tx); + let mut sighash_cache = SighashCache::new(&unsigned_tx.tx); + + let sighash_type = TapSighashType::All; + let mut txout_list = Vec::with_capacity(unsigned_tx.utxos.len()); + + for (_, txout) in unsigned_tx.utxos.clone() { + txout_list.push(txout); + } + let sighash = sighash_cache + .taproot_key_spend_signature_hash(0, &Prevouts::All(&txout_list), sighash_type) + .context("Error taproot_key_spend_signature_hash")?; + + if session.message_to_sign != sighash.to_string() { + tracing::error!( + "Invalid transaction sighash for session with block id {}", + session.l1_block_number + ); + return Ok(false); + } + Ok(true) + } + async fn get_session_nonces(&self) -> anyhow::Result> { // We need to fetch all nonces from the coordinator let nonces_url = format!("{}/session/nonce", self.config.url); From bef4be4880a2560f772cb66b86c84bb7f0ca3921 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 23 Jan 2025 10:56:33 +0100 Subject: [PATCH 174/212] fix: verifier message validation --- ...5e871be4ac71acac33d4662af5cfc4c6bff9.json} | 4 ++-- .../withdrawal_service/src/verifier/mod.rs | 21 ++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) rename via_verifier/lib/verifier_dal/.sqlx/{query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json => query-4f3219a13e972e4c7b13af9d22c55e871be4ac71acac33d4662af5cfc4c6bff9.json} (83%) diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json b/via_verifier/lib/verifier_dal/.sqlx/query-4f3219a13e972e4c7b13af9d22c55e871be4ac71acac33d4662af5cfc4c6bff9.json similarity index 83% rename from via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json rename to via_verifier/lib/verifier_dal/.sqlx/query-4f3219a13e972e4c7b13af9d22c55e871be4ac71acac33d4662af5cfc4c6bff9.json index 5093aa470..8ccbb4649 100644 --- a/via_verifier/lib/verifier_dal/.sqlx/query-400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9.json +++ b/via_verifier/lib/verifier_dal/.sqlx/query-4f3219a13e972e4c7b13af9d22c55e871be4ac71acac33d4662af5cfc4c6bff9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n pubdata_blob_id,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n AND l1_batch_number = $1\n LIMIT 1\n ", + "query": "\n SELECT\n pubdata_blob_id,\n tx_id\n FROM\n via_votable_transactions\n WHERE\n is_finalized = TRUE\n AND is_verified = TRUE\n AND withdrawal_tx_id IS NULL\n AND l1_batch_number = $1\n LIMIT\n 1\n ", "describe": { "columns": [ { @@ -24,5 +24,5 @@ false ] }, - "hash": "400d78a27c5a126ea6f56f159cd0a6b4fb1d6b5870bbbfe7f2e43a94dc2cb2b9" + "hash": "4f3219a13e972e4c7b13af9d22c55e871be4ac71acac33d4662af5cfc4c6bff9" } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index a5f793130..0c9b3eb2d 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -223,18 +223,32 @@ impl ViaWithdrawalVerifier { } // Verify if all withdrawals are included with valid amount. - for (i, (_, txout)) in unsigned_tx.utxos.iter().enumerate() { + for (i, txout) in unsigned_tx + .tx + .output + .iter() + .enumerate() + .take(unsigned_tx.tx.output.len().saturating_sub(2)) + { let req = &withdrawals[i]; if req.amount != txout.value || req.address.script_pubkey() != txout.script_pubkey { - tracing::error!("Invalid request withdrawal, id: {i}"); + tracing::error!( + "Invalid request withdrawal for batch {}, index: {}", + session.l1_block_number, + i + ); return Ok(false); } } + tracing::info!( + "All request withdrawals for batch {} are valid", + session.l1_block_number + ); // Verify the OP return let tx_id = h256_to_txid(&proof_tx_id)?; let op_return_data = WithdrawalBuilder::create_op_return_script(tx_id)?; - let (_, op_return_tx_out) = &unsigned_tx.utxos[len - 2]; + let op_return_tx_out = &unsigned_tx.tx.output[unsigned_tx.tx.output.len() - 2]; if op_return_tx_out.script_pubkey.to_string() != op_return_data.to_string() || op_return_tx_out.value != Amount::ZERO @@ -271,6 +285,7 @@ impl ViaWithdrawalVerifier { ); return Ok(false); } + tracing::info!("Sighash for batch {} is valid", session.l1_block_number); Ok(true) } From ea0892c8d443d27c6e616422578531f5377fd6ab Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:10:37 +0100 Subject: [PATCH 175/212] fix: group withdrawals before validation --- .../withdrawal_service/src/verifier/mod.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 0c9b3eb2d..cbf2a9d94 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -209,7 +209,18 @@ impl ViaWithdrawalVerifier { let withdrawals = self.withdrawal_client.get_withdrawals(blob_id).await?; let unsigned_tx = UnsignedWithdrawalTx::from_bytes(&session.unsigned_tx); - let len = withdrawals.len(); + // Group withdrawals by address and sum amounts + let mut grouped_withdrawals: HashMap = HashMap::new(); + for w in &withdrawals { + let key = w.address.script_pubkey().to_string(); + *grouped_withdrawals.entry(key).or_insert(Amount::ZERO) = grouped_withdrawals + .get(&key) + .unwrap_or(&Amount::ZERO) + .checked_add(w.amount) + .ok_or_else(|| anyhow::anyhow!("Withdrawal amount overflow when grouping"))?; + } + + let len = grouped_withdrawals.len(); if len == 0 { tracing::error!( "Invalid session, there are no withdrawals to process, l1 batch: {}", @@ -222,7 +233,7 @@ impl ViaWithdrawalVerifier { return Ok(false); } - // Verify if all withdrawals are included with valid amount. + // Verify if all grouped_withdrawals are included with valid amount. for (i, txout) in unsigned_tx .tx .output @@ -230,8 +241,8 @@ impl ViaWithdrawalVerifier { .enumerate() .take(unsigned_tx.tx.output.len().saturating_sub(2)) { - let req = &withdrawals[i]; - if req.amount != txout.value || req.address.script_pubkey() != txout.script_pubkey { + let amount = &grouped_withdrawals[&txout.script_pubkey.to_string()]; + if amount != &txout.value { tracing::error!( "Invalid request withdrawal for batch {}, index: {}", session.l1_block_number, From 5f8df3d6a4f4c74d804308ea915ea45e21900b4f Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 28 Jan 2025 13:32:21 +0330 Subject: [PATCH 176/212] feat(indexer): impl base method for op_return --- core/lib/via_btc_client/src/indexer/mod.rs | 72 ++++----- core/lib/via_btc_client/src/indexer/parser.rs | 148 +++++++++++++++--- core/lib/via_btc_client/src/types.rs | 2 +- 3 files changed, 162 insertions(+), 60 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 67b1ba1ca..651ccbcc9 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -140,17 +140,7 @@ impl BitcoinInscriptionIndexer { let block = self.client.fetch_block(block_height as u128).await?; // TODO: check block header is belong to a valid chain of blocks (reorg detection and management) - - // let important_txs: Vec<_> = block - // .txdata - // .iter() - // .filter(|tx| self.is_transaction_involving_important_addresses(tx)) - // .collect(); - - // let system transaction - // let bridge transaction - // parse system transaction - // parse bridge transaction + // TODO: deal with malicious sequencer, verifiers from being able to make trouble by sending invalid messages / valid messages with invalid data let mut valid_messages = Vec::new(); @@ -340,29 +330,31 @@ impl BitcoinInscriptionIndexer { #[instrument(skip(self, message), target = "bitcoin_indexer")] fn is_valid_system_message(&self, message: &FullInscriptionMessage) -> bool { match message { - FullInscriptionMessage::ProposeSequencer(m) => { - self.verifier_addresses.contains(&m.common.p2wpkh_address) - } - FullInscriptionMessage::ValidatorAttestation(m) => { - self.verifier_addresses.contains(&m.common.p2wpkh_address) - } - FullInscriptionMessage::L1BatchDAReference(m) => { - m.common.p2wpkh_address == self.sequencer_address - } - FullInscriptionMessage::ProofDAReference(m) => { - m.common.p2wpkh_address == self.sequencer_address - } - FullInscriptionMessage::L1ToL2Message(m) => { - // TODO: also check sender address - let is_valid = - m.amount > bitcoin::Amount::ZERO && self.is_valid_l1_to_l2_transfer(m); - debug!("L1ToL2Message validity: {}", is_valid); - is_valid - } + FullInscriptionMessage::ProposeSequencer(m) => m + .common + .p2wpkh_address + .as_ref() + .map_or(false, |addr| self.verifier_addresses.contains(addr)), + FullInscriptionMessage::ValidatorAttestation(m) => m + .common + .p2wpkh_address + .as_ref() + .map_or(false, |addr| self.verifier_addresses.contains(addr)), + FullInscriptionMessage::L1BatchDAReference(m) => m + .common + .p2wpkh_address + .as_ref() + .map_or(false, |addr| addr == &self.sequencer_address), + FullInscriptionMessage::ProofDAReference(m) => m + .common + .p2wpkh_address + .as_ref() + .map_or(false, |addr| addr == &self.sequencer_address), FullInscriptionMessage::SystemBootstrapping(_) => { debug!("SystemBootstrapping message is always valid"); true } + _ => false, } } @@ -408,7 +400,12 @@ impl BitcoinInscriptionIndexer { } FullInscriptionMessage::ProposeSequencer(ps) => { debug!("Processing ProposeSequencer message"); - if state.verifier_addresses.contains(&ps.common.p2wpkh_address) { + let p2wpkh_address = ps + .common + .p2wpkh_address + .as_ref() + .expect("ProposeSequencer message must have a p2wpkh address"); + if state.verifier_addresses.contains(p2wpkh_address) { let sequencer_address = ps .input .sequencer_new_p2wpkh_address @@ -419,14 +416,19 @@ impl BitcoinInscriptionIndexer { } } FullInscriptionMessage::ValidatorAttestation(va) => { - if state.verifier_addresses.contains(&va.common.p2wpkh_address) + let p2wpkh_address = va + .common + .p2wpkh_address + .as_ref() + .expect("ValidatorAttestation message must have a p2wpkh address"); + if state.verifier_addresses.contains(p2wpkh_address) && state.proposed_sequencer.is_some() { if let Some(proposed_txid) = state.proposed_sequencer_txid { if va.input.reference_txid == proposed_txid { state .sequencer_votes - .insert(va.common.p2wpkh_address, va.input.attestation); + .insert(p2wpkh_address.clone(), va.input.attestation); } } } @@ -533,7 +535,7 @@ mod tests { encoded_public_key: bitcoin::script::PushBytesBuf::from([0u8; 32]), block_height: 0, tx_id: Txid::all_zeros(), - p2wpkh_address: get_test_addr(), + p2wpkh_address: Some(get_test_addr()), } } @@ -651,7 +653,7 @@ mod tests { encoded_public_key: bitcoin::script::PushBytesBuf::from([0u8; 32]), block_height: 0, tx_id: Txid::all_zeros(), - p2wpkh_address: get_test_addr(), + p2wpkh_address: Some(get_test_addr()), }, input: types::L1BatchDAReferenceInput { l1_batch_hash: zksync_basic_types::H256::zero(), diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index 497177cce..b94871123 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -3,7 +3,7 @@ use bitcoin::{ hashes::Hash, script::{Instruction, PushBytesBuf}, taproot::{ControlBlock, Signature as TaprootSignature}, - Address, Amount, CompressedPublicKey, Network, ScriptBuf, Transaction, Txid, Witness, + Address, Amount, CompressedPublicKey, Network, ScriptBuf, Transaction, TxOut, Txid, Witness, }; use tracing::{debug, instrument, warn}; use zksync_basic_types::H256; @@ -62,7 +62,9 @@ impl MessageParser { // parsing messages tx.input .iter() - .filter_map(|input| self.parse_input(input, tx, block_height, address.clone())) + .filter_map(|input| { + self.parse_system_input(input, tx, block_height, address.clone()) + }) .collect() } None => { @@ -77,31 +79,40 @@ impl MessageParser { tx: &Transaction, block_height: u32, ) -> Vec { - // parsing btc address - let mut sender_addresses: Option
= None; - for input in tx.input.iter() { - let witness = &input.witness; - if let Some(btc_address) = self.parse_p2wpkh(witness) { - sender_addresses = Some(btc_address); + let mut messages = Vec::new(); + + // Find bridge output and amount first + let bridge_output = match tx.output.iter().find(|output| { + if let Some(bridge_addr) = &self.bridge_address { + output.script_pubkey == bridge_addr.script_pubkey() + } else { + false } + }) { + Some(output) => output, + None => return messages, // Not a bridge transaction + }; + + // Try to parse as inscription-based deposit first + if let Some(inscription_message) = + self.parse_inscription_deposit(tx, block_height, bridge_output) + { + messages.push(inscription_message); + return messages; } - match sender_addresses { - Some(address) => { - // parsing messages - tx.input - .iter() - .filter_map(|input| self.parse_input(input, tx, block_height, address.clone())) - .collect() - } - None => { - vec![] - } + // If not an inscription, try to parse as OP_RETURN based deposit + if let Some(op_return_message) = + self.parse_op_return_deposit(tx, block_height, bridge_output) + { + messages.push(op_return_message); } + + messages } #[instrument(skip(self, input, tx), target = "bitcoin_indexer::parser")] - fn parse_input( + fn parse_system_input( &mut self, input: &bitcoin::TxIn, tx: &Transaction, @@ -144,10 +155,10 @@ impl MessageParser { encoded_public_key: PushBytesBuf::from(public_key.serialize()), block_height, tx_id: tx.compute_ntxid().into(), - p2wpkh_address: address, + p2wpkh_address: Some(address), }; - self.parse_message(tx, &instructions[via_index..], &common_fields) + self.parse_system_message(tx, &instructions[via_index..], &common_fields) } #[instrument(skip(self), target = "bitcoin_indexer::parser")] @@ -166,7 +177,7 @@ impl MessageParser { skip(self, tx, instructions, common_fields), target = "bitcoin_indexer::parser" )] - fn parse_message( + fn parse_system_message( &mut self, tx: &Transaction, instructions: &[Instruction], @@ -210,7 +221,7 @@ impl MessageParser { self.parse_l1_to_l2_message(tx, instructions, common_fields) } Instruction::PushBytes(bytes) => { - warn!("Unknown message type"); + warn!("Unknown message type for system transaction parser"); warn!( "first instruction: {:?}", String::from_utf8(bytes.as_bytes().to_vec()) @@ -568,6 +579,95 @@ impl MessageParser { tx_outputs: tx.output.clone(), })) } + + fn parse_inscription_deposit( + &self, + tx: &Transaction, + block_height: u32, + bridge_output: &TxOut, + ) -> Option { + // Try to find any witness data that contains a valid inscription + for input in tx.input.iter() { + let witness = &input.witness; + if witness.len() < MIN_WITNESS_LENGTH { + continue; + } + + // Parse signature and control block + let signature = TaprootSignature::from_slice(&witness[0]).ok()?; + let script = ScriptBuf::from_bytes(witness[1].to_vec()); + let control_block = ControlBlock::decode(&witness[2]).ok()?; + + let instructions: Vec<_> = script.instructions().filter_map(Result::ok).collect(); + let via_index = find_via_inscription_protocol(&instructions)?; + + // Try to parse p2wpkh address if possible, but make it optional + let p2wpkh_address = self.parse_p2wpkh(witness); + + let common_fields = CommonFields { + schnorr_signature: signature, + encoded_public_key: PushBytesBuf::from(control_block.internal_key.serialize()), + block_height, + tx_id: tx.compute_ntxid().into(), + p2wpkh_address, + }; + + // Parse L1ToL2Message from instructions + return self.parse_l1_to_l2_message(tx, &instructions[via_index..], &common_fields); + } + + None + } + + fn parse_op_return_deposit( + &self, + tx: &Transaction, + block_height: u32, + bridge_output: &TxOut, + ) -> Option { + // Find OP_RETURN output + let op_return_output = tx + .output + .iter() + .find(|output| output.script_pubkey.is_op_return())?; + + // Parse OP_RETURN data + let op_return_data = op_return_output.script_pubkey.as_bytes(); + if op_return_data.len() < 2 { + return None; + } + + // Parse receiver address from OP_RETURN data + let receiver_l2_address = EVMAddress::from_slice(&op_return_data[2..22])?; + + let input = L1ToL2MessageInput { + receiver_l2_address, + l2_contract_address: EVMAddress::zero(), + call_data: vec![], + }; + + // Try to parse p2wpkh address from the first input if possible + let p2wpkh_address = tx + .input + .first() + .and_then(|input| self.parse_p2wpkh(&input.witness)); + + // Create common fields with empty signature for OP_RETURN + let common_fields = CommonFields { + schnorr_signature: TaprootSignature::from_slice(&[0; 64]).ok()?, + encoded_public_key: PushBytesBuf::new(), + block_height, + tx_id: tx.compute_ntxid().into(), + p2wpkh_address, + }; + + Some(FullInscriptionMessage::L1ToL2Message(L1ToL2Message { + common: common_fields, + amount: bridge_output.value, + input, + tx_outputs: tx.output.clone(), + })) + } } #[instrument(skip(instructions), target = "bitcoin_indexer::parser")] diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index 643983d66..3cda21997 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -67,7 +67,7 @@ pub struct CommonFields { pub encoded_public_key: PushBytesBuf, pub block_height: u32, pub tx_id: Txid, - pub p2wpkh_address: BitcoinAddress, + pub p2wpkh_address: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] From b9fe34a052008e584d90a4edea3aa9cd33bcc973 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 28 Jan 2025 14:23:17 +0330 Subject: [PATCH 177/212] feat(indexer): update common fields type and adopt indexer and votable with new type --- core/lib/via_btc_client/src/indexer/parser.rs | 8 +++----- core/node/via_btc_watch/src/message_processors/votable.rs | 8 +++++++- .../node/via_btc_watch/src/message_processors/verifier.rs | 8 +++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/parser.rs b/core/lib/via_btc_client/src/indexer/parser.rs index b94871123..833634eab 100644 --- a/core/lib/via_btc_client/src/indexer/parser.rs +++ b/core/lib/via_btc_client/src/indexer/parser.rs @@ -94,9 +94,7 @@ impl MessageParser { }; // Try to parse as inscription-based deposit first - if let Some(inscription_message) = - self.parse_inscription_deposit(tx, block_height, bridge_output) - { + if let Some(inscription_message) = self.parse_inscription_deposit(tx, block_height) { messages.push(inscription_message); return messages; } @@ -584,7 +582,6 @@ impl MessageParser { &self, tx: &Transaction, block_height: u32, - bridge_output: &TxOut, ) -> Option { // Try to find any witness data that contains a valid inscription for input in tx.input.iter() { @@ -638,7 +635,8 @@ impl MessageParser { } // Parse receiver address from OP_RETURN data - let receiver_l2_address = EVMAddress::from_slice(&op_return_data[2..22])?; + + let receiver_l2_address = EVMAddress::from_slice(&op_return_data[2..22]); let input = L1ToL2MessageInput { receiver_l2_address, diff --git a/core/node/via_btc_watch/src/message_processors/votable.rs b/core/node/via_btc_watch/src/message_processors/votable.rs index 5164de85f..9a3a7dc8a 100644 --- a/core/node/via_btc_watch/src/message_processors/votable.rs +++ b/core/node/via_btc_watch/src/message_processors/votable.rs @@ -104,11 +104,17 @@ impl MessageProcessor for VotableMessageProcessor { attestation_msg.input.attestation, via_btc_client::types::Vote::Ok ); + + let p2wpkh_address = attestation_msg + .common + .p2wpkh_address + .as_ref() + .expect("ValidatorAttestation message must have a p2wpkh address"); votes_dal .insert_vote( l1_batch_number.0, reference_txid, - &attestation_msg.common.p2wpkh_address.to_string(), + &p2wpkh_address.to_string(), is_ok, ) .await diff --git a/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs index 656d09e6f..56055469f 100644 --- a/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs +++ b/via_verifier/node/via_btc_watch/src/message_processors/verifier.rs @@ -96,11 +96,17 @@ impl MessageProcessor for VerifierMessageProcessor { attestation_msg.input.attestation, via_btc_client::types::Vote::Ok ); + + let p2wpkh_address = attestation_msg + .common + .p2wpkh_address + .as_ref() + .expect("ValidatorAttestation message must have a p2wpkh address"); votes_dal .insert_vote( l1_batch_number.0, reference_txid, - &attestation_msg.common.p2wpkh_address.to_string(), + &p2wpkh_address.to_string(), is_ok, ) .await From f3f31a89b3148edf4441da6104c5d9803933ad60 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 28 Jan 2025 12:20:27 +0100 Subject: [PATCH 178/212] DEBUG: NEEDS TO REVERT - logs for da_dispatcher --- .../via_da_dispatcher/src/da_dispatcher.rs | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/core/node/via_da_dispatcher/src/da_dispatcher.rs b/core/node/via_da_dispatcher/src/da_dispatcher.rs index be2dd2bbc..9cc6a5e4f 100644 --- a/core/node/via_da_dispatcher/src/da_dispatcher.rs +++ b/core/node/via_da_dispatcher/src/da_dispatcher.rs @@ -203,15 +203,18 @@ impl ViaDataAvailabilityDispatcher { async fn dispatch_real_proofs(&self) -> anyhow::Result<()> { let mut conn = self.pool.connection_tagged("da_dispatcher").await?; + tracing::error!("dispatch_real_proofs started"); let proofs = conn .via_data_availability_dal() .get_ready_for_da_dispatch_proofs(self.config.max_rows_to_dispatch() as usize) .await?; + tracing::error!("dispatch_real_proofs got proofs : {:?}", proofs); drop(conn); for proof in proofs { // fetch the proof from object store + tracing::error!("dispatch_real_proofs proof : {:?}", proof); let proof_data = match self.load_real_proof_operation(proof.l1_batch_number).await { Some(proof) => proof, None => { @@ -220,7 +223,11 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!("proof_data : {:?}", proof_data); + let serelize_proof = proof_data.into_tokens(); + + tracing::error!("serelize_proof : {:?}", serelize_proof); // iterate over tokens and convert them to bytes let mut proof_bytes = Vec::new(); for token in serelize_proof { @@ -230,6 +237,8 @@ impl ViaDataAvailabilityDispatcher { // concatenate all bytes let final_proof = proof_bytes.into_iter().flatten().collect::>(); + tracing::error!("final_proof : {:?}", final_proof); + let dispatch_latency = METRICS.proof_dispatch_latency.start(); let dispatch_response = retry(self.config.max_retries(), proof.l1_batch_number, || { @@ -279,6 +288,7 @@ impl ViaDataAvailabilityDispatcher { ) -> Option { let mut storage = self.pool.connection_tagged("da_dispatcher").await.ok()?; + tracing::error!("load_real_proof_operation started"); let previous_proven_batch_number = match storage.blocks_dal().get_last_l1_batch_with_prove_tx().await { Ok(batch_number) => batch_number, @@ -288,6 +298,10 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!( + "previous_proven_batch_number : {:?}", + previous_proven_batch_number + ); let minor_version = match storage .blocks_dal() .get_batch_protocol_version_id(batch_to_prove) @@ -303,6 +317,8 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!("minor version : {:?}", minor_version); + let latest_semantic_version = match storage .protocol_versions_dal() .latest_semantic_version() @@ -315,11 +331,15 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!("latest_semantic_version : {:?}", latest_semantic_version); + let l1_verifier_config = storage .protocol_versions_dal() .l1_verifier_config_for_version(latest_semantic_version) .await?; + tracing::error!("l1 verifier config: {:?}", l1_verifier_config); + let allowed_patch_versions = match storage .protocol_versions_dal() .get_patch_versions_for_vk( @@ -346,6 +366,8 @@ impl ViaDataAvailabilityDispatcher { }) .collect(); + tracing::error!("allowed_versions : {:?}", allowed_versions); + let proof = match self .load_wrapped_fri_proofs_for_range(batch_to_prove, &allowed_versions) .await @@ -357,6 +379,8 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!("proof : {:?}", proof); + let previous_proven_batch_metadata = match storage .blocks_dal() .get_l1_batch_metadata(previous_proven_batch_number) @@ -380,6 +404,11 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!( + "previous_proven_batch_metadata : {:?}", + previous_proven_batch_metadata + ); + let metadata_for_batch_being_proved = match storage .blocks_dal() .get_l1_batch_metadata(batch_to_prove) @@ -403,6 +432,11 @@ impl ViaDataAvailabilityDispatcher { } }; + tracing::error!( + "metadata_for_batch_being_proved : {:?}", + metadata_for_batch_being_proved + ); + Some(ProveBatches { prev_l1_batch: previous_proven_batch_metadata, l1_batches: vec![metadata_for_batch_being_proved], @@ -520,10 +554,21 @@ impl ViaDataAvailabilityDispatcher { l1_batch_number: L1BatchNumber, allowed_versions: &[ProtocolSemanticVersion], ) -> Option { + tracing::error!("load_wrapped_fri_proofs_for_range started"); for version in allowed_versions { match self.blob_store.get((l1_batch_number, *version)).await { - Ok(proof) => return Some(proof), - Err(ObjectStoreError::KeyNotFound(_)) => continue, // Proof is not ready yet. + Ok(proof) => { + tracing::error!("load_wrapped_fri_proofs_for_range proof : {:?}", proof); + return Some(proof); + } + Err(ObjectStoreError::KeyNotFound(_)) => { + tracing::error!( + "KeyNotFound for loading proof for batch {} and version {:?}", + l1_batch_number.0, + version + ); + continue; + } // Proof is not ready yet. Err(err) => { tracing::error!( "Failed to load proof for batch {} and version {:?}: {}", @@ -536,16 +581,27 @@ impl ViaDataAvailabilityDispatcher { } } + tracing::error!("load_wrapped_fri_proofs_for_range failed"); + // Check for deprecated file naming if patch 0 is allowed. let is_patch_0_present = allowed_versions.iter().any(|v| v.patch.0 == 0); + tracing::error!("is_patch_0_present : {:?}", is_patch_0_present); if is_patch_0_present { match self .blob_store .get_by_encoded_key(format!("l1_batch_proof_{}.bin", l1_batch_number)) .await { - Ok(proof) => return Some(proof), - Err(ObjectStoreError::KeyNotFound(_)) => (), + Ok(proof) => { + tracing::error!("load_wrapped_fri_proofs_for_range proof : {:?}", proof); + return Some(proof); + } + Err(ObjectStoreError::KeyNotFound(_)) => { + tracing::error!( + "KeyNotFound for loading proof for batch {}", + l1_batch_number.0 + ); + } Err(err) => { tracing::error!( "Failed to load proof for batch {} from deprecated naming: {}", From 82386bdaeee930aebe5844633cbcedad0b3b23e1 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 28 Jan 2025 13:24:29 +0100 Subject: [PATCH 179/212] fix: da_dispatcher real final proof fix --- .../via_da_dispatcher/src/da_dispatcher.rs | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/core/node/via_da_dispatcher/src/da_dispatcher.rs b/core/node/via_da_dispatcher/src/da_dispatcher.rs index 9cc6a5e4f..659ac0540 100644 --- a/core/node/via_da_dispatcher/src/da_dispatcher.rs +++ b/core/node/via_da_dispatcher/src/da_dispatcher.rs @@ -13,7 +13,7 @@ use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_l1_contract_interface::{i_executor::methods::ProveBatches, Tokenize}; use zksync_object_store::{ObjectStore, ObjectStoreError}; use zksync_prover_interface::outputs::L1BatchProofForL1; -use zksync_types::{protocol_version::ProtocolSemanticVersion, L1BatchNumber}; +use zksync_types::{ethabi::Token, protocol_version::ProtocolSemanticVersion, L1BatchNumber}; use crate::metrics::METRICS; @@ -228,14 +228,9 @@ impl ViaDataAvailabilityDispatcher { let serelize_proof = proof_data.into_tokens(); tracing::error!("serelize_proof : {:?}", serelize_proof); - // iterate over tokens and convert them to bytes - let mut proof_bytes = Vec::new(); - for token in serelize_proof { - proof_bytes.extend(token.into_bytes()); - } // concatenate all bytes - let final_proof = proof_bytes.into_iter().flatten().collect::>(); + let final_proof = flatten_tokens(&serelize_proof); tracing::error!("final_proof : {:?}", final_proof); @@ -742,6 +737,48 @@ impl ViaDataAvailabilityDispatcher { } } +/// Recursively flattens all `Token` variants into a single `Vec`. +fn flatten_tokens(tokens: &[Token]) -> Vec { + let mut out = Vec::new(); + for token in tokens { + match token { + Token::Uint(u) => { + let mut buf = [0u8; 32]; + u.to_big_endian(&mut buf); + out.extend_from_slice(&buf); + } + Token::FixedBytes(fixed_bytes) => { + out.extend_from_slice(fixed_bytes); + } + Token::Array(arr) | Token::FixedArray(arr) | Token::Tuple(arr) => { + out.extend(flatten_tokens(arr)); + } + // not used in the prover + Token::Bool(b) => { + out.push(if *b { 1 } else { 0 }); + } + Token::Address(a) => { + out.extend_from_slice(a.as_bytes()); + } + Token::Int(i) => { + let mut buf = [0u8; 32]; + i.to_big_endian(&mut buf); + out.extend_from_slice(&buf); + } + Token::Bytes(bytes) => { + out.extend_from_slice(bytes); + } + Token::String(s) => { + let str_bytes = s.as_bytes(); + let len_u32 = str_bytes.len() as u32; + out.extend_from_slice(&len_u32.to_be_bytes()); + out.extend_from_slice(str_bytes); + } + } + } + out +} + async fn retry( max_retries: u16, batch_number: L1BatchNumber, From 168d60bb30f13e744c600159a2b7e1c73c65f5fb Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Tue, 28 Jan 2025 15:26:41 +0100 Subject: [PATCH 180/212] fix: bincode serialize --- .../via_da_dispatcher/src/da_dispatcher.rs | 182 +++++------------- 1 file changed, 46 insertions(+), 136 deletions(-) diff --git a/core/node/via_da_dispatcher/src/da_dispatcher.rs b/core/node/via_da_dispatcher/src/da_dispatcher.rs index 659ac0540..4ef437058 100644 --- a/core/node/via_da_dispatcher/src/da_dispatcher.rs +++ b/core/node/via_da_dispatcher/src/da_dispatcher.rs @@ -10,10 +10,10 @@ use zksync_da_client::{ DataAvailabilityClient, }; use zksync_dal::{ConnectionPool, Core, CoreDal}; -use zksync_l1_contract_interface::{i_executor::methods::ProveBatches, Tokenize}; +use zksync_l1_contract_interface::i_executor::methods::ProveBatches; use zksync_object_store::{ObjectStore, ObjectStoreError}; use zksync_prover_interface::outputs::L1BatchProofForL1; -use zksync_types::{ethabi::Token, protocol_version::ProtocolSemanticVersion, L1BatchNumber}; +use zksync_types::{protocol_version::ProtocolSemanticVersion, L1BatchNumber}; use crate::metrics::METRICS; @@ -203,19 +203,16 @@ impl ViaDataAvailabilityDispatcher { async fn dispatch_real_proofs(&self) -> anyhow::Result<()> { let mut conn = self.pool.connection_tagged("da_dispatcher").await?; - tracing::error!("dispatch_real_proofs started"); let proofs = conn .via_data_availability_dal() .get_ready_for_da_dispatch_proofs(self.config.max_rows_to_dispatch() as usize) .await?; - tracing::error!("dispatch_real_proofs got proofs : {:?}", proofs); drop(conn); for proof in proofs { // fetch the proof from object store - tracing::error!("dispatch_real_proofs proof : {:?}", proof); - let proof_data = match self.load_real_proof_operation(proof.l1_batch_number).await { + let final_proof = match self.load_real_proof_operation(proof.l1_batch_number).await { Some(proof) => proof, None => { tracing::error!("Failed to load proof for batch {}", proof.l1_batch_number.0); @@ -223,17 +220,6 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!("proof_data : {:?}", proof_data); - - let serelize_proof = proof_data.into_tokens(); - - tracing::error!("serelize_proof : {:?}", serelize_proof); - - // concatenate all bytes - let final_proof = flatten_tokens(&serelize_proof); - - tracing::error!("final_proof : {:?}", final_proof); - let dispatch_latency = METRICS.proof_dispatch_latency.start(); let dispatch_response = retry(self.config.max_retries(), proof.l1_batch_number, || { @@ -277,13 +263,9 @@ impl ViaDataAvailabilityDispatcher { } /// Loads a real proof operation for a given L1 batch number. - async fn load_real_proof_operation( - &self, - batch_to_prove: L1BatchNumber, - ) -> Option { + async fn load_real_proof_operation(&self, batch_to_prove: L1BatchNumber) -> Option> { let mut storage = self.pool.connection_tagged("da_dispatcher").await.ok()?; - tracing::error!("load_real_proof_operation started"); let previous_proven_batch_number = match storage.blocks_dal().get_last_l1_batch_with_prove_tx().await { Ok(batch_number) => batch_number, @@ -293,10 +275,6 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!( - "previous_proven_batch_number : {:?}", - previous_proven_batch_number - ); let minor_version = match storage .blocks_dal() .get_batch_protocol_version_id(batch_to_prove) @@ -312,8 +290,6 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!("minor version : {:?}", minor_version); - let latest_semantic_version = match storage .protocol_versions_dal() .latest_semantic_version() @@ -326,15 +302,11 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!("latest_semantic_version : {:?}", latest_semantic_version); - let l1_verifier_config = storage .protocol_versions_dal() .l1_verifier_config_for_version(latest_semantic_version) .await?; - tracing::error!("l1 verifier config: {:?}", l1_verifier_config); - let allowed_patch_versions = match storage .protocol_versions_dal() .get_patch_versions_for_vk( @@ -361,8 +333,6 @@ impl ViaDataAvailabilityDispatcher { }) .collect(); - tracing::error!("allowed_versions : {:?}", allowed_versions); - let proof = match self .load_wrapped_fri_proofs_for_range(batch_to_prove, &allowed_versions) .await @@ -374,8 +344,6 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!("proof : {:?}", proof); - let previous_proven_batch_metadata = match storage .blocks_dal() .get_l1_batch_metadata(previous_proven_batch_number) @@ -399,11 +367,6 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!( - "previous_proven_batch_metadata : {:?}", - previous_proven_batch_metadata - ); - let metadata_for_batch_being_proved = match storage .blocks_dal() .get_l1_batch_metadata(batch_to_prove) @@ -427,17 +390,14 @@ impl ViaDataAvailabilityDispatcher { } }; - tracing::error!( - "metadata_for_batch_being_proved : {:?}", - metadata_for_batch_being_proved - ); - - Some(ProveBatches { + let res = ProveBatches { prev_l1_batch: previous_proven_batch_metadata, l1_batches: vec![metadata_for_batch_being_proved], proofs: vec![proof], should_verify: true, - }) + }; + + serialize_prove_batches(&res) } async fn prepare_dummy_proof_operation( @@ -508,62 +468,21 @@ impl ViaDataAvailabilityDispatcher { should_verify: false, }; - let prev_l1_batch_bytes = bincode::serialize(&res.prev_l1_batch) - .map_err(|e| { - tracing::error!("Failed to serialize prev_l1_batch: {}", e); - None::> - }) - .ok()?; - let l1_batches_bytes = bincode::serialize(&res.l1_batches) - .map_err(|e| { - tracing::error!("Failed to serialize l1_batches: {}", e); - None::> - }) - .ok()?; - let proofs_bytes = bincode::serialize(&res.proofs) - .map_err(|e| { - tracing::error!("Failed to serialize proofs: {}", e); - None::> - }) - .ok()?; - let should_verify = bincode::serialize(&res.should_verify) - .map_err(|e| { - tracing::error!("Failed to serialize should_verify: {}", e); - None::> - }) - .ok()?; - - let final_proof = [ - prev_l1_batch_bytes, - l1_batches_bytes, - proofs_bytes, - should_verify, - ] - .concat(); - - Some(final_proof) + serialize_prove_batches(&res) } + /// Loads wrapped FRI proofs for a given L1 batch number and allowed protocol versions. pub async fn load_wrapped_fri_proofs_for_range( &self, l1_batch_number: L1BatchNumber, allowed_versions: &[ProtocolSemanticVersion], ) -> Option { - tracing::error!("load_wrapped_fri_proofs_for_range started"); for version in allowed_versions { match self.blob_store.get((l1_batch_number, *version)).await { Ok(proof) => { - tracing::error!("load_wrapped_fri_proofs_for_range proof : {:?}", proof); return Some(proof); } - Err(ObjectStoreError::KeyNotFound(_)) => { - tracing::error!( - "KeyNotFound for loading proof for batch {} and version {:?}", - l1_batch_number.0, - version - ); - continue; - } // Proof is not ready yet. + Err(ObjectStoreError::KeyNotFound(_)) => continue, // Proof is not ready yet. Err(err) => { tracing::error!( "Failed to load proof for batch {} and version {:?}: {}", @@ -576,11 +495,8 @@ impl ViaDataAvailabilityDispatcher { } } - tracing::error!("load_wrapped_fri_proofs_for_range failed"); - // Check for deprecated file naming if patch 0 is allowed. let is_patch_0_present = allowed_versions.iter().any(|v| v.patch.0 == 0); - tracing::error!("is_patch_0_present : {:?}", is_patch_0_present); if is_patch_0_present { match self .blob_store @@ -588,7 +504,6 @@ impl ViaDataAvailabilityDispatcher { .await { Ok(proof) => { - tracing::error!("load_wrapped_fri_proofs_for_range proof : {:?}", proof); return Some(proof); } Err(ObjectStoreError::KeyNotFound(_)) => { @@ -737,46 +652,41 @@ impl ViaDataAvailabilityDispatcher { } } -/// Recursively flattens all `Token` variants into a single `Vec`. -fn flatten_tokens(tokens: &[Token]) -> Vec { - let mut out = Vec::new(); - for token in tokens { - match token { - Token::Uint(u) => { - let mut buf = [0u8; 32]; - u.to_big_endian(&mut buf); - out.extend_from_slice(&buf); - } - Token::FixedBytes(fixed_bytes) => { - out.extend_from_slice(fixed_bytes); - } - Token::Array(arr) | Token::FixedArray(arr) | Token::Tuple(arr) => { - out.extend(flatten_tokens(arr)); - } - // not used in the prover - Token::Bool(b) => { - out.push(if *b { 1 } else { 0 }); - } - Token::Address(a) => { - out.extend_from_slice(a.as_bytes()); - } - Token::Int(i) => { - let mut buf = [0u8; 32]; - i.to_big_endian(&mut buf); - out.extend_from_slice(&buf); - } - Token::Bytes(bytes) => { - out.extend_from_slice(bytes); - } - Token::String(s) => { - let str_bytes = s.as_bytes(); - let len_u32 = str_bytes.len() as u32; - out.extend_from_slice(&len_u32.to_be_bytes()); - out.extend_from_slice(str_bytes); - } - } - } - out +fn serialize_prove_batches(prove_batches: &ProveBatches) -> Option> { + let prev_l1_batch_bytes = bincode::serialize(&prove_batches.prev_l1_batch) + .map_err(|e| { + tracing::error!("Failed to serialize prev_l1_batch: {}", e); + None::> + }) + .ok()?; + let l1_batches_bytes = bincode::serialize(&prove_batches.l1_batches) + .map_err(|e| { + tracing::error!("Failed to serialize l1_batches: {}", e); + None::> + }) + .ok()?; + let proofs_bytes = bincode::serialize(&prove_batches.proofs) + .map_err(|e| { + tracing::error!("Failed to serialize proofs: {}", e); + None::> + }) + .ok()?; + let should_verify = bincode::serialize(&prove_batches.should_verify) + .map_err(|e| { + tracing::error!("Failed to serialize should_verify: {}", e); + None::> + }) + .ok()?; + + Some( + [ + prev_l1_batch_bytes, + l1_batches_bytes, + proofs_bytes, + should_verify, + ] + .concat(), + ) } async fn retry( From a7f64aa5603484993e3c0d35ff7f5d8f9fe28432 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 28 Jan 2025 19:00:30 +0330 Subject: [PATCH 181/212] feat(indexer): update is_valid_amount to is_valid_l1_to_l2_transfer method --- core/lib/via_btc_client/src/indexer/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 651ccbcc9..dedb4a700 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Arc}; -use bitcoin::{Address, BlockHash, Network, Transaction as BitcoinTransaction, Txid}; +use bitcoin::{Address, Amount, BlockHash, Network, Transaction as BitcoinTransaction, Txid}; use bitcoincore_rpc::Auth; use tracing::{debug, error, info, instrument, warn}; @@ -441,12 +441,26 @@ impl BitcoinInscriptionIndexer { #[instrument(skip(self, message), target = "bitcoin_indexer")] fn is_valid_l1_to_l2_transfer(&self, message: &L1ToL2Message) -> bool { - let is_valid = message + let is_valid_receiver = message .tx_outputs .iter() .any(|output| output.script_pubkey == self.bridge_address.script_pubkey()); - debug!("L1ToL2Message transfer validity: {}", is_valid); - is_valid + debug!("L1ToL2Message transfer validity: {}", is_valid_receiver); + + let total_bridge_amount = message + .tx_outputs + .iter() + .filter(|output| output.script_pubkey == self.bridge_address.script_pubkey()) + .map(|output| output.value) + .sum::(); + + let is_valid_amount = message.amount == total_bridge_amount; + debug!( + "Amount validation: message amount = {}, total bridge outputs = {}", + message.amount, total_bridge_amount + ); + + is_valid_receiver && is_valid_amount } async fn get_l1_batch_number_from_proof_tx_id( From 3ff9cf7775d7270b082c376bd4bf2521eb002a25 Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 29 Jan 2025 11:51:24 +0100 Subject: [PATCH 182/212] fix: vk path for verifier --- .../lib/via_verification/src/utils.rs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/via_verifier/lib/via_verification/src/utils.rs b/via_verifier/lib/via_verification/src/utils.rs index 41808a299..cc1347346 100644 --- a/via_verifier/lib/via_verification/src/utils.rs +++ b/via_verifier/lib/via_verification/src/utils.rs @@ -68,19 +68,30 @@ pub async fn load_verification_key( pub async fn load_verification_key_without_l1_check( protocol_version: String, ) -> Result, VerificationError> { - let file_path = format!( - "core/lib/via_verification/keys/protocol_version/{}/scheduler_key.json", - protocol_version - ); - let base_dir = env::var("VIA_HOME").map_err(|e| VerificationError::Other(e.to_string()))?; - let base_path = PathBuf::from(base_dir); - let file = base_path.join(&file_path); + let key_path = match env::var("VIA_VK_KEY_PATH") { + Ok(path) => { + let file_path = format!("protocol_version/{}/scheduler_key.json", protocol_version); + let base_path = PathBuf::from(path); + base_path.join(&file_path) + } + Err(_) => { + // from VIA_HOME + let base_dir = + env::var("VIA_HOME").map_err(|e| VerificationError::Other(e.to_string()))?; + let base_path = PathBuf::from(base_dir); + let file_path = format!( + "via_verifier/lib/via_verification/keys/protocol_version/{}/scheduler_key.json", + protocol_version + ); + base_path.join(&file_path) + } + }; // Load the verification key from the specified file. - let verification_key_content = fs::read_to_string(file).map_err(|e| { + let verification_key_content = fs::read_to_string(key_path.clone()).map_err(|e| { VerificationError::Other(format!( - "Failed to read verification key from {}: {}", - file_path, e + "Failed to read verification key from {:?}: {}", + key_path, e )) })?; let vk_inner: VerificationKey = From 157a996b61c49b7c4290661ba8a15f86a5c114de Mon Sep 17 00:00:00 2001 From: Steph Sinyakov Date: Wed, 29 Jan 2025 13:19:55 +0100 Subject: [PATCH 183/212] chore: add log with verification result --- via_verifier/node/via_zk_verifier/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/via_verifier/node/via_zk_verifier/src/lib.rs b/via_verifier/node/via_zk_verifier/src/lib.rs index d1411851b..189cc2302 100644 --- a/via_verifier/node/via_zk_verifier/src/lib.rs +++ b/via_verifier/node/via_zk_verifier/src/lib.rs @@ -256,7 +256,11 @@ impl ViaVerifier { via_verification::utils::load_verification_key_without_l1_check(protocol_version) .await?; - Ok(via_proof.verify(vk_inner)?) + let is_valid = via_proof.verify(vk_inner)?; + + tracing::info!("Proof verification result: {}", is_valid); + + Ok(is_valid) } } } From c1ba8b0b7607b724dc826b815e9f0cc80f5f2068 Mon Sep 17 00:00:00 2001 From: danijelTxFusion Date: Wed, 29 Jan 2025 13:47:22 +0100 Subject: [PATCH 184/212] build: add verification keys to verifier image --- docker/via-verifier/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker/via-verifier/Dockerfile b/docker/via-verifier/Dockerfile index bcb139440..925004f44 100644 --- a/docker/via-verifier/Dockerfile +++ b/docker/via-verifier/Dockerfile @@ -17,6 +17,11 @@ ENV PATH=$PATH:/usr/local/bin EXPOSE 6060 +ARG PROTOCOL_VERSION=26 +COPY --from=builder /usr/src/via/via_verifier/lib/via_verification/keys/protocol_version/${PROTOCOL_VERSION}/scheduler_key.json \ + /keys/protocol_version/${PROTOCOL_VERSION}/scheduler_key.json +ENV VIA_VK_KEY_PATH=/keys + COPY --from=builder /usr/src/via/target/release/via_verifier /usr/bin ENTRYPOINT ["via_verifier"] From 8987333961b8d59a44725ef91ac34c642518f1f0 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:39:28 +0100 Subject: [PATCH 185/212] feat: add logs to the coordinator --- .../src/coordinator/api_impl.rs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 2e624a38d..59f2ffa0e 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -74,6 +74,11 @@ impl RestApi { let mut withdrawals_to_process: Vec = Vec::new(); let mut proof_txid = Txid::all_zeros(); + tracing::info!( + "Found {} finalized unprocessed L1 batch(es) with withdrawals waiting to be processed", + blocks.len() + ); + for (block_number, blob_id, proof_tx_id) in blocks.iter() { let withdrawals = self_ .withdrawal_client @@ -85,6 +90,11 @@ impl RestApi { proof_txid = Self::h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; + tracing::info!( + "L1 batch {} includes withdrawal requests {}", + block_number.clone(), + withdrawals_to_process.len() + ); break; } else { // If there is no withdrawals to process in a batch, update the status and mark it as processed @@ -99,6 +109,10 @@ impl RestApi { ) .await .context("Error to mark a vote transaction as processed")?; + tracing::info!( + "There is no withdrawal to process in l1 batch {}", + block_number.clone() + ); } } @@ -107,6 +121,12 @@ impl RestApi { return Ok(ok_json("There are no withdrawals to process")); } + tracing::info!( + "Found withdrawals in the l1 batch {}, total withdrawals: {}", + l1_block_number, + withdrawals_to_process.len() + ); + let unsigned_tx_result = self_ .withdrawal_builder .create_unsigned_withdrawal_tx(withdrawals_to_process, proof_txid) @@ -115,7 +135,7 @@ impl RestApi { let unsigned_tx = match unsigned_tx_result { Ok(unsigned_tx) => unsigned_tx, Err(err) => { - tracing::info!("Invalid unsigned tx: {err}"); + tracing::error!("Invalid unsigned tx for batch {l1_block_number}: {err}"); return Err(ApiError::InternalServerError( "Invalid unsigned tx".to_string(), )); @@ -146,6 +166,8 @@ impl RestApi { *session = new_sesssion; } + tracing::info!("New session created for l1 batch {}", l1_block_number); + return Ok(ok_json(l1_block_number)); } From 8f02c68499f2027dc338d194ad246a61be214328 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:46:52 +0100 Subject: [PATCH 186/212] clean: delete unnecessary log --- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index b72447910..4b1a3f7bd 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -59,9 +59,7 @@ impl ViaWithdrawalVerifier { } match self.loop_iteration().await { - Ok(()) => { - tracing::info!("Verifier withdrawal task finished"); - } + Ok(()) => {} Err(err) => { tracing::error!("Failed to process verifier withdrawal task: {err}"); } From d8db2231f554dd63a83b78196b631d74d5e1a775 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 08:45:49 +0330 Subject: [PATCH 187/212] fix(withdrawal_service): fix clippy error --- .../node/withdrawal_service/src/coordinator/api_impl.rs | 9 +++------ via_verifier/node/withdrawal_service/src/verifier/mod.rs | 9 ++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 59f2ffa0e..233977814 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -87,7 +87,7 @@ impl RestApi { .context("Error to get withdrawals from DA")?; if !withdrawals.is_empty() { - proof_txid = Self::h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; + proof_txid = Self::h256_to_txid(proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; tracing::info!( @@ -98,15 +98,12 @@ impl RestApi { break; } else { // If there is no withdrawals to process in a batch, update the status and mark it as processed - _ = self_ + self_ .master_connection_pool .connection_tagged("coordinator") .await? .via_votes_dal() - .mark_vote_transaction_as_processed_withdrawals( - H256::zero(), - block_number.clone(), - ) + .mark_vote_transaction_as_processed_withdrawals(H256::zero(), *block_number) .await .context("Error to mark a vote transaction as processed")?; tracing::info!( diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 4b1a3f7bd..e96cf6be0 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -105,13 +105,12 @@ impl ViaWithdrawalVerifier { return Ok(()); } - if self.config.verifier_mode == VerifierMode::COORDINATOR { - if self + if self.config.verifier_mode == VerifierMode::COORDINATOR + && self .build_and_broadcast_final_transaction(&session_info) .await? - { - return Ok(()); - } + { + return Ok(()); } let session_signature = self.get_session_signatures().await?; From f0ffa880ac016546329f24b8bcba5a66670a2778 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 09:08:47 +0330 Subject: [PATCH 188/212] feat(withdrawal_service): impl auth module --- Cargo.lock | 1 + .../node/withdrawal_service/Cargo.toml | 1 + .../node/withdrawal_service/src/auth.rs | 76 +++++++++++++++++++ .../node/withdrawal_service/src/lib.rs | 4 +- 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 via_verifier/node/withdrawal_service/src/auth.rs diff --git a/Cargo.lock b/Cargo.lock index d6e208521..fbaff3b02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9811,6 +9811,7 @@ dependencies = [ "secp256k1 0.30.0", "serde", "serde_json", + "sha2 0.10.8", "thiserror", "tokio", "tower-http", diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index 050a4c172..d2f5f6aa7 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -32,5 +32,6 @@ secp256k1_musig2 = { package = "secp256k1", version = "0.30.0", features = [ musig2 = "0.2.0" base64 = "0.21" thiserror = "1.0.57" +sha2.workspace = true [dev-dependencies] diff --git a/via_verifier/node/withdrawal_service/src/auth.rs b/via_verifier/node/withdrawal_service/src/auth.rs new file mode 100644 index 000000000..6bf97744e --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/auth.rs @@ -0,0 +1,76 @@ +use anyhow::Context; +use base64::Engine; +use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; +use serde::Serialize; +use sha2::{Digest, Sha256}; + +/// Signs a request payload using the verifier's private key. +pub fn sign_request(payload: &T, secret_key: &SecretKey) -> anyhow::Result { + let secp = Secp256k1::new(); + + // Serialize and hash the payload. + let payload_bytes = serde_json::to_vec(payload).context("Failed to serialize payload")?; + let hash = Sha256::digest(&payload_bytes); + let message = Message::from_digest_slice(hash.as_ref()).context("Hash is not 32 bytes")?; + + // Sign the message. + let sig = secp.sign_ecdsa(&message, secret_key); + // Encode the compact 64-byte signature in base64. + let sig_bytes = sig.serialize_compact(); + Ok(base64::engine::general_purpose::STANDARD.encode(sig_bytes)) +} + +/// Verifies a request signature using the verifier's public key. +pub fn verify_signature( + payload: &T, + signature_b64: &str, + public_key: &PublicKey, +) -> anyhow::Result { + let secp = Secp256k1::new(); + + // Decode the base64 signature. + let sig_bytes = base64::engine::general_purpose::STANDARD + .decode(signature_b64) + .context("Failed to decode base64 signature")?; + let sig = bitcoin::secp256k1::ecdsa::Signature::from_compact(&sig_bytes) + .context("Failed to parse signature from compact form")?; + + // Serialize and hash the payload. + let payload_bytes = serde_json::to_vec(payload).context("Failed to serialize payload")?; + let hash = Sha256::digest(&payload_bytes); + let message = Message::from_digest_slice(hash.as_ref()).context("Hash is not 32 bytes")?; + + // Verify the signature. + Ok(secp.verify_ecdsa(&message, &sig, public_key).is_ok()) +} + +#[cfg(test)] +mod tests { + use bitcoin::secp256k1::rand::rngs::OsRng; + use serde_json::json; + + use super::*; + + #[test] + fn test_signature_verification() { + let secp = Secp256k1::new(); + let (secret_key, public_key) = secp.generate_keypair(&mut OsRng); + + let payload = json!({ + "test": "data", + "number": 123 + }); + + // Sign the payload. + let signature = sign_request(&payload, &secret_key).expect("Signature generation failed"); + + // Verify the signature. + assert!(verify_signature(&payload, &signature, &public_key) + .expect("Signature verification failed")); + + // Verify that a wrong public key does not verify. + let (_, wrong_public_key) = secp.generate_keypair(&mut OsRng); + assert!(!verify_signature(&payload, &signature, &wrong_public_key) + .expect("Verification with wrong key unexpectedly succeeded")); + } +} diff --git a/via_verifier/node/withdrawal_service/src/lib.rs b/via_verifier/node/withdrawal_service/src/lib.rs index 101e452e7..20e491d51 100644 --- a/via_verifier/node/withdrawal_service/src/lib.rs +++ b/via_verifier/node/withdrawal_service/src/lib.rs @@ -1,4 +1,6 @@ pub mod coordinator; +pub mod verifier; + +mod auth; mod types; mod utils; -pub mod verifier; From dc153320782521938416d634b1fc1b90eec926bb Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 09:56:52 +0330 Subject: [PATCH 189/212] feat(withdrawal_service): impl new headrs in verifier (sender) side --- Cargo.lock | 1 + .../node/withdrawal_service/Cargo.toml | 1 + .../withdrawal_service/src/verifier/mod.rs | 67 ++++++++++++++++--- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbaff3b02..aef0e691c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9805,6 +9805,7 @@ dependencies = [ "axum 0.7.9", "base64 0.21.7", "bitcoin", + "chrono", "hex", "musig2", "reqwest 0.12.7", diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index d2f5f6aa7..0c3d7fe00 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -33,5 +33,6 @@ musig2 = "0.2.0" base64 = "0.21" thiserror = "1.0.57" sha2.workspace = true +chrono.workspace = true [dev-dependencies] diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index e96cf6be0..c4ae30cc3 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, str::FromStr, sync::Arc}; use anyhow::{Context, Result}; use bitcoin::{hashes::Hash, TapSighashType, Txid, Witness}; @@ -152,9 +152,43 @@ impl ViaWithdrawalVerifier { Ok(()) } + fn create_request_headers( + &self, + body: Option<&impl serde::Serialize>, + ) -> anyhow::Result { + let mut headers = header::HeaderMap::new(); + let timestamp = chrono::Utc::now().timestamp().to_string(); + let verifier_index = self.signer.signer_index().to_string(); + + let secret_key = bitcoin::secp256k1::SecretKey::from_str(&self.config.private_key)?; + + // Create signature based on whether there's a body + let signature = if let Some(data) = body { + // Sign the request body directly + crate::auth::sign_request(data, &secret_key)? + } else { + // Sign timestamp + verifier_index as a JSON object + let payload = serde_json::json!({ + "timestamp": timestamp, + "verifier_index": verifier_index, + }); + crate::auth::sign_request(&payload, &secret_key)? + }; + + headers.insert("X-Timestamp", header::HeaderValue::from_str(×tamp)?); + headers.insert( + "X-Verifier-Index", + header::HeaderValue::from_str(&verifier_index)?, + ); + headers.insert("X-Signature", header::HeaderValue::from_str(&signature)?); + + Ok(headers) + } + async fn get_session(&self) -> anyhow::Result { let url = format!("{}/session", self.config.url); - let resp = self.client.get(&url).send().await?; + let headers = self.create_request_headers(None::<&()>)?; + let resp = self.client.get(&url).headers(headers).send().await?; if resp.status().as_u16() != StatusCode::OK.as_u16() { anyhow::bail!("Error to fetch the session"); } @@ -163,9 +197,9 @@ impl ViaWithdrawalVerifier { } async fn get_session_nonces(&self) -> anyhow::Result> { - // We need to fetch all nonces from the coordinator let nonces_url = format!("{}/session/nonce", self.config.url); - let resp = self.client.get(&nonces_url).send().await?; + let headers = self.create_request_headers(None::<&()>)?; + let resp = self.client.get(&nonces_url).headers(headers).send().await?; let nonces: HashMap = resp.json().await?; Ok(nonces) } @@ -178,7 +212,14 @@ impl ViaWithdrawalVerifier { let nonce_pair = encode_nonce(self.signer.signer_index(), nonce).unwrap(); let url = format!("{}/session/nonce", self.config.url); - let res = self.client.post(&url).json(&nonce_pair).send().await?; + let headers = self.create_request_headers(Some(&nonce_pair))?; + let res = self + .client + .post(&url) + .headers(headers) + .json(&nonce_pair) + .send() + .await?; if res.status().is_success() { self.signer.mark_nonce_submitted(); @@ -189,7 +230,8 @@ impl ViaWithdrawalVerifier { async fn get_session_signatures(&self) -> anyhow::Result> { let url = format!("{}/session/signature", self.config.url); - let resp = self.client.get(&url).send().await?; + let headers = self.create_request_headers(None::<&()>)?; + let resp = self.client.get(&url).headers(headers).send().await?; let signatures: HashMap = resp.json().await?; let mut partial_sigs: HashMap = HashMap::new(); for (idx, sig) in signatures { @@ -218,8 +260,15 @@ impl ViaWithdrawalVerifier { let partial_sig = self.signer.create_partial_signature()?; let sig_pair = encode_signature(self.signer.signer_index(), partial_sig)?; - let url = format!("{}/session/signature", self.config.url,); - let resp = self.client.post(&url).json(&sig_pair).send().await?; + let url = format!("{}/session/signature", self.config.url); + let headers = self.create_request_headers(Some(&sig_pair))?; + let resp = self + .client + .post(&url) + .headers(headers) + .json(&sig_pair) + .send() + .await?; if resp.status().is_success() { self.signer.mark_partial_sig_submitted(); } @@ -238,9 +287,11 @@ impl ViaWithdrawalVerifier { async fn create_new_session(&mut self) -> anyhow::Result<()> { let url = format!("{}/session/new", self.config.url); + let headers = self.create_request_headers(None::<&()>)?; let resp = self .client .post(&url) + .headers(headers) .header(header::CONTENT_TYPE, "application/json") .send() .await?; From 5a514efc6cab21bd2eaf719546673c8f4df9e184 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 10:13:36 +0330 Subject: [PATCH 190/212] feat(withdrawal_service): impl auth middleware --- .../src/coordinator/api_decl.rs | 17 +++- .../src/coordinator/auth_middleware.rs | 81 +++++++++++++++++++ .../src/coordinator/error.rs | 3 + .../withdrawal_service/src/coordinator/mod.rs | 1 + .../node/withdrawal_service/src/types.rs | 1 + 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs index f84aa8296..30d783a95 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -1,5 +1,6 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; +use axum::middleware; use tokio::sync::RwLock; use tower_http::cors::CorsLayer; use via_btc_client::withdrawal_builder::WithdrawalBuilder; @@ -7,7 +8,10 @@ use via_verifier_dal::{ConnectionPool, Verifier}; use via_withdrawal_client::client::WithdrawalClient; use zksync_config::configs::via_verifier::ViaVerifierConfig; -use crate::types::{SigningSession, ViaWithdrawalState}; +use crate::{ + coordinator::auth_middleware, + types::{SigningSession, ViaWithdrawalState}, +}; pub struct RestApi { pub master_connection_pool: ConnectionPool, @@ -26,6 +30,11 @@ impl RestApi { let state = ViaWithdrawalState { signing_session: Arc::new(RwLock::new(SigningSession::default())), required_signers: config.required_signers, + verifiers_pub_keys: config + .verifiers_pub_keys_str + .iter() + .map(|s| bitcoin::secp256k1::PublicKey::from_str(s).unwrap()) + .collect(), }; Ok(Self { master_connection_pool, @@ -49,7 +58,9 @@ impl RestApi { ) .route("/nonce", axum::routing::post(Self::submit_nonce)) .route("/nonce", axum::routing::get(Self::get_nonces)) - .layer(CorsLayer::permissive()); + .layer(CorsLayer::permissive()) + .layer(middleware::from_fn(auth_middleware::extract_body)) + .layer(middleware::from_fn(auth_middleware::auth_middleware)); axum::Router::new() .nest("/session", router) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs new file mode 100644 index 000000000..05c008fbd --- /dev/null +++ b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs @@ -0,0 +1,81 @@ +use std::sync::Arc; + +use axum::{body::Bytes, extract::Request, middleware::Next, response::Response}; +use serde_json::Value; + +use crate::coordinator::{api_decl::RestApi, error::ApiError}; + +pub async fn auth_middleware(request: Request, next: Next) -> Result { + let headers = request.headers(); + + // Extract required headers + let timestamp = headers + .get("X-Timestamp") + .and_then(|h| h.to_str().ok()) + .ok_or_else(|| ApiError::Unauthorized("Missing timestamp header".into()))?; + + let verifier_index = headers + .get("X-Verifier-Index") + .and_then(|h| h.to_str().ok()) + .and_then(|s| s.parse::().ok()) + .ok_or_else(|| ApiError::Unauthorized("Missing or invalid verifier index".into()))?; + + let signature = headers + .get("X-Signature") + .and_then(|h| h.to_str().ok()) + .ok_or_else(|| ApiError::Unauthorized("Missing signature header".into()))?; + + // Get state from request extensions + let state = request + .extensions() + .get::>() + .ok_or_else(|| ApiError::InternalServerError("Missing state".into()))?; + + // Validate verifier index + if verifier_index >= state.state.verifiers_pub_keys.len() { + return Err(ApiError::Unauthorized("Invalid verifier index".into())); + } + + // Get the public key for this verifier + let public_key = &state.state.verifiers_pub_keys[verifier_index]; + + // Create verification payload based on request method and body + let payload = if request.method().is_safe() { + // For GET requests, verify timestamp + verifier_index + serde_json::json!({ + "timestamp": timestamp, + "verifier_index": verifier_index.to_string(), + }) + } else { + // For POST/PUT requests, verify the body + let body_bytes = request + .extensions() + .get::() + .ok_or_else(|| ApiError::InternalServerError("Missing request body".into()))?; + + serde_json::from_slice::(body_bytes) + .map_err(|_| ApiError::BadRequest("Invalid JSON body".into()))? + }; + + // Verify the signature + if !crate::auth::verify_signature(&payload, signature, public_key) + .map_err(|_| ApiError::InternalServerError("Signature verification failed".into()))? + { + return Err(ApiError::Unauthorized("Invalid signature".into())); + } + + Ok(next.run(request).await) +} + +// Helper function to extract body as bytes +pub async fn extract_body(request: Request, next: Next) -> Result { + let (parts, body) = request.into_parts(); + let bytes = axum::body::to_bytes(body, usize::MAX) + .await + .map_err(|_| ApiError::InternalServerError("Failed to read body".into()))?; + + let mut request = Request::from_parts(parts, axum::body::Body::empty()); + request.extensions_mut().insert(bytes); + + Ok(next.run(request).await) +} diff --git a/via_verifier/node/withdrawal_service/src/coordinator/error.rs b/via_verifier/node/withdrawal_service/src/coordinator/error.rs index b1b0dbb6c..36a60179b 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/error.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/error.rs @@ -13,6 +13,8 @@ use via_verifier_dal::DalError; pub enum ApiError { #[error("Invalid input: {0}")] BadRequest(String), + #[error("Unauthorized: {0}")] + Unauthorized(String), #[error("Unexpected error: {0}")] InternalServerError(String), } @@ -33,6 +35,7 @@ impl IntoResponse for ApiError { fn into_response(self) -> Response { let (status, error_response) = match self { ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, ErrorResponse::new(&msg)), + ApiError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, ErrorResponse::new(&msg)), ApiError::InternalServerError(msg) => { (StatusCode::INTERNAL_SERVER_ERROR, ErrorResponse::new(&msg)) } diff --git a/via_verifier/node/withdrawal_service/src/coordinator/mod.rs b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs index cb001f217..3a5fbd0b0 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/mod.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/mod.rs @@ -1,4 +1,5 @@ pub mod api; mod api_decl; mod api_impl; +mod auth_middleware; mod error; diff --git a/via_verifier/node/withdrawal_service/src/types.rs b/via_verifier/node/withdrawal_service/src/types.rs index e2f6703f8..20f6afccf 100644 --- a/via_verifier/node/withdrawal_service/src/types.rs +++ b/via_verifier/node/withdrawal_service/src/types.rs @@ -9,6 +9,7 @@ use via_btc_client::withdrawal_builder::UnsignedWithdrawalTx; pub struct ViaWithdrawalState { pub signing_session: Arc>, pub required_signers: usize, + pub verifiers_pub_keys: Vec, } #[derive(Default, Debug, Clone)] From ade33ca47a75c2823eda4a77a1e030f78a015e4e Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 10:30:12 +0330 Subject: [PATCH 191/212] fix clippy warning in btc_client lib --- core/lib/via_btc_client/src/types.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index 90f44c927..643983d66 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -134,17 +134,11 @@ impl Serializable for InscriptionMessage { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct InscriptionConfig { pub fee_multiplier: u64, } -impl Default for InscriptionConfig { - fn default() -> Self { - InscriptionConfig { fee_multiplier: 0 } - } -} - #[derive(Debug)] pub struct Recipient { pub address: BitcoinAddress, From 775770f084d158587481b8398d523d603af23ec3 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 12:41:39 +0330 Subject: [PATCH 192/212] fix middleware state issue --- Cargo.lock | 1 + .../node/withdrawal_service/Cargo.toml | 1 + .../src/coordinator/api_decl.rs | 20 +++++--- .../src/coordinator/auth_middleware.rs | 51 ++++++++++--------- .../withdrawal_service/src/verifier/mod.rs | 20 ++++++-- 5 files changed, 59 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aef0e691c..b63481a5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9815,6 +9815,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "tokio", + "tower 0.4.13", "tower-http", "tracing", "uuid 1.10.0", diff --git a/via_verifier/node/withdrawal_service/Cargo.toml b/via_verifier/node/withdrawal_service/Cargo.toml index 0c3d7fe00..883c378ff 100644 --- a/via_verifier/node/withdrawal_service/Cargo.toml +++ b/via_verifier/node/withdrawal_service/Cargo.toml @@ -22,6 +22,7 @@ anyhow.workspace = true axum.workspace = true tokio = { workspace = true, features = ["time"] } tower-http = { workspace = true, features = ["cors"] } +tower = { workspace = true } tracing.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs index 30d783a95..d33353a08 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_decl.rs @@ -45,6 +45,15 @@ impl RestApi { } pub fn into_router(self) -> axum::Router<()> { + // Wrap the API state in an Arc. + let shared_state = Arc::new(self); + + // Create middleware layers using from_fn_with_state. + let auth_mw = + middleware::from_fn_with_state(shared_state.clone(), auth_middleware::auth_middleware); + let body_mw = + middleware::from_fn_with_state(shared_state.clone(), auth_middleware::extract_body); + let router = axum::Router::new() .route("/new", axum::routing::post(Self::new_session)) .route("/", axum::routing::get(Self::get_session)) @@ -58,12 +67,11 @@ impl RestApi { ) .route("/nonce", axum::routing::post(Self::submit_nonce)) .route("/nonce", axum::routing::get(Self::get_nonces)) - .layer(CorsLayer::permissive()) - .layer(middleware::from_fn(auth_middleware::extract_body)) - .layer(middleware::from_fn(auth_middleware::auth_middleware)); + .route_layer(body_mw) + .route_layer(auth_mw) + .with_state(shared_state.clone()) + .layer(CorsLayer::permissive()); - axum::Router::new() - .nest("/session", router) - .with_state(Arc::new(self)) + axum::Router::new().nest("/session", router) } } diff --git a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs index 05c008fbd..f9b91616b 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs @@ -1,14 +1,23 @@ use std::sync::Arc; -use axum::{body::Bytes, extract::Request, middleware::Next, response::Response}; +use axum::{ + body::{self, Body, Bytes}, + extract::{Request, State}, + middleware::Next, + response::Response, +}; use serde_json::Value; use crate::coordinator::{api_decl::RestApi, error::ApiError}; -pub async fn auth_middleware(request: Request, next: Next) -> Result { +pub async fn auth_middleware( + State(state): State>, + request: Request, + next: Next, +) -> Result { let headers = request.headers(); - // Extract required headers + // Extract required headers. let timestamp = headers .get("X-Timestamp") .and_then(|h| h.to_str().ok()) @@ -25,39 +34,32 @@ pub async fn auth_middleware(request: Request, next: Next) -> Result>() - .ok_or_else(|| ApiError::InternalServerError("Missing state".into()))?; - - // Validate verifier index + // Validate the verifier index. if verifier_index >= state.state.verifiers_pub_keys.len() { return Err(ApiError::Unauthorized("Invalid verifier index".into())); } - // Get the public key for this verifier + // Get the public key for this verifier. let public_key = &state.state.verifiers_pub_keys[verifier_index]; - // Create verification payload based on request method and body + // Create verification payload based on request method. let payload = if request.method().is_safe() { - // For GET requests, verify timestamp + verifier_index + // For GET requests, verify timestamp + verifier_index. serde_json::json!({ "timestamp": timestamp, "verifier_index": verifier_index.to_string(), }) } else { - // For POST/PUT requests, verify the body + // For POST/PUT requests, verify the body. let body_bytes = request .extensions() .get::() .ok_or_else(|| ApiError::InternalServerError("Missing request body".into()))?; - serde_json::from_slice::(body_bytes) .map_err(|_| ApiError::BadRequest("Invalid JSON body".into()))? }; - // Verify the signature + // Verify the signature. if !crate::auth::verify_signature(&payload, signature, public_key) .map_err(|_| ApiError::InternalServerError("Signature verification failed".into()))? { @@ -67,15 +69,16 @@ pub async fn auth_middleware(request: Request, next: Next) -> Result Result { +pub async fn extract_body( + State(_state): State>, + request: Request, + next: Next, +) -> Result { let (parts, body) = request.into_parts(); - let bytes = axum::body::to_bytes(body, usize::MAX) + let bytes = body::to_bytes(body, usize::MAX) .await .map_err(|_| ApiError::InternalServerError("Failed to read body".into()))?; - - let mut request = Request::from_parts(parts, axum::body::Body::empty()); - request.extensions_mut().insert(bytes); - - Ok(next.run(request).await) + let mut req = Request::from_parts(parts, Body::empty()); + req.extensions_mut().insert(bytes); + Ok(next.run(req).await) } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index c4ae30cc3..1441f8ced 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, str::FromStr, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; use anyhow::{Context, Result}; use bitcoin::{hashes::Hash, TapSighashType, Txid, Witness}; @@ -160,7 +160,8 @@ impl ViaWithdrawalVerifier { let timestamp = chrono::Utc::now().timestamp().to_string(); let verifier_index = self.signer.signer_index().to_string(); - let secret_key = bitcoin::secp256k1::SecretKey::from_str(&self.config.private_key)?; + let private_key = bitcoin::PrivateKey::from_wif(&self.config.private_key)?; + let secret_key = private_key.inner; // Create signature based on whether there's a body let signature = if let Some(data) = body { @@ -188,9 +189,20 @@ impl ViaWithdrawalVerifier { async fn get_session(&self) -> anyhow::Result { let url = format!("{}/session", self.config.url); let headers = self.create_request_headers(None::<&()>)?; - let resp = self.client.get(&url).headers(headers).send().await?; + let resp = self + .client + .get(&url) + .headers(headers.clone()) + .send() + .await?; if resp.status().as_u16() != StatusCode::OK.as_u16() { - anyhow::bail!("Error to fetch the session"); + anyhow::bail!( + "Error to fetch the session, status: {}, url: {}, headers: {:?}, resp: {:?}", + resp.status(), + url, + headers, + resp.text().await? + ); } let session_info: SigningSessionResponse = resp.json().await?; Ok(session_info) From 793446f9940fa656e2fb22a2f1a94f6080580866 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 14:40:31 +0330 Subject: [PATCH 193/212] fix middleware message validation issue --- .../src/coordinator/auth_middleware.rs | 13 ++-- .../withdrawal_service/src/verifier/mod.rs | 67 ++++++++++++++++--- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs index f9b91616b..a41be455e 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs @@ -42,15 +42,20 @@ pub async fn auth_middleware( // Get the public key for this verifier. let public_key = &state.state.verifiers_pub_keys[verifier_index]; - // Create verification payload based on request method. - let payload = if request.method().is_safe() { - // For GET requests, verify timestamp + verifier_index. + // Create verification payload based on request method and body content + let payload = if request.method().is_safe() + || request + .extensions() + .get::() + .map_or(true, |b| b.is_empty()) + { + // For GET requests or empty body requests, verify timestamp + verifier_index serde_json::json!({ "timestamp": timestamp, "verifier_index": verifier_index.to_string(), }) } else { - // For POST/PUT requests, verify the body. + // For POST/PUT requests with non-empty body, verify the body let body_bytes = request .extensions() .get::() diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 1441f8ced..eb2adb7b8 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -211,7 +211,22 @@ impl ViaWithdrawalVerifier { async fn get_session_nonces(&self) -> anyhow::Result> { let nonces_url = format!("{}/session/nonce", self.config.url); let headers = self.create_request_headers(None::<&()>)?; - let resp = self.client.get(&nonces_url).headers(headers).send().await?; + let resp = self + .client + .get(&nonces_url) + .headers(headers.clone()) + .send() + .await?; + + if resp.status().as_u16() != StatusCode::OK.as_u16() { + anyhow::bail!( + "Error to fetch the session nonces, status: {}, url: {}, headers: {:?}, resp: {:?}", + resp.status(), + nonces_url, + headers, + resp.text().await? + ); + } let nonces: HashMap = resp.json().await?; Ok(nonces) } @@ -228,22 +243,44 @@ impl ViaWithdrawalVerifier { let res = self .client .post(&url) - .headers(headers) + .headers(headers.clone()) .json(&nonce_pair) .send() .await?; if res.status().is_success() { self.signer.mark_nonce_submitted(); - return Ok(()); + Ok(()) + } else { + anyhow::bail!( + "Failed to submit nonce, response: {}, url: {}, headers: {:?}, body: {:?} ", + res.text().await?, + url, + headers, + nonce_pair + ); } - Ok(()) } async fn get_session_signatures(&self) -> anyhow::Result> { let url = format!("{}/session/signature", self.config.url); let headers = self.create_request_headers(None::<&()>)?; - let resp = self.client.get(&url).headers(headers).send().await?; + let resp = self + .client + .get(&url) + .headers(headers.clone()) + .send() + .await?; + + if resp.status().as_u16() != StatusCode::OK.as_u16() { + anyhow::bail!( + "Error to fetch the session signatures, status: {}, url: {}, headers: {:?}, resp: {:?}", + resp.status(), + url, + headers, + resp.text().await? + ); + } let signatures: HashMap = resp.json().await?; let mut partial_sigs: HashMap = HashMap::new(); for (idx, sig) in signatures { @@ -277,14 +314,22 @@ impl ViaWithdrawalVerifier { let resp = self .client .post(&url) - .headers(headers) + .headers(headers.clone()) .json(&sig_pair) .send() .await?; if resp.status().is_success() { self.signer.mark_partial_sig_submitted(); + Ok(()) + } else { + anyhow::bail!( + "Failed to submit partial signature, response: {}, url: {}, headers: {:?}, body: {:?} ", + resp.text().await?, + url, + headers, + sig_pair + ); } - Ok(()) } fn reinit_signer(&mut self) -> anyhow::Result<()> { @@ -303,12 +348,18 @@ impl ViaWithdrawalVerifier { let resp = self .client .post(&url) - .headers(headers) + .headers(headers.clone()) .header(header::CONTENT_TYPE, "application/json") .send() .await?; if !resp.status().is_success() { + tracing::warn!( + "Failed to create a new session, response: {}, url: {}, headers: {:?}", + resp.text().await?, + url, + headers + ); self.reinit_signer()?; } Ok(()) From 7e38bbf67ba6f301451e243d781a55352db70ad7 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 15:49:02 +0330 Subject: [PATCH 194/212] change error message --- .../node/withdrawal_service/src/coordinator/api_impl.rs | 6 +++++- .../withdrawal_service/src/coordinator/auth_middleware.rs | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index 233977814..af7adcc87 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -219,7 +219,11 @@ impl RestApi { ) -> anyhow::Result, ApiError> { let partial_sig = match decode_signature(sig_pair.signature) { Ok(sig) => sig, - Err(_) => return Err(ApiError::BadRequest("Invalid signature".to_string())), + Err(_) => { + return Err(ApiError::BadRequest( + "Invalid partial signature submitted".to_string(), + )) + } }; { diff --git a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs index a41be455e..42bc6fe6a 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs @@ -68,7 +68,9 @@ pub async fn auth_middleware( if !crate::auth::verify_signature(&payload, signature, public_key) .map_err(|_| ApiError::InternalServerError("Signature verification failed".into()))? { - return Err(ApiError::Unauthorized("Invalid signature".into())); + return Err(ApiError::Unauthorized( + "Invalid authentication signature".into(), + )); } Ok(next.run(request).await) From de3b5d3daba1291b68f7fb3fe702248f6a25f672 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Mon, 3 Feb 2025 17:26:49 +0330 Subject: [PATCH 195/212] remove request body from payload and rely only on timestamp and verifier index --- .../src/coordinator/auth_middleware.rs | 47 ++++++++----------- .../withdrawal_service/src/verifier/mod.rs | 35 +++++--------- 2 files changed, 32 insertions(+), 50 deletions(-) diff --git a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs index 42bc6fe6a..3e34a796c 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/auth_middleware.rs @@ -1,12 +1,11 @@ use std::sync::Arc; use axum::{ - body::{self, Body, Bytes}, + body::{self, Body}, extract::{Request, State}, middleware::Next, response::Response, }; -use serde_json::Value; use crate::coordinator::{api_decl::RestApi, error::ApiError}; @@ -17,7 +16,7 @@ pub async fn auth_middleware( ) -> Result { let headers = request.headers(); - // Extract required headers. + // Extract required headers let timestamp = headers .get("X-Timestamp") .and_then(|h| h.to_str().ok()) @@ -34,37 +33,29 @@ pub async fn auth_middleware( .and_then(|h| h.to_str().ok()) .ok_or_else(|| ApiError::Unauthorized("Missing signature header".into()))?; - // Validate the verifier index. + // Validate the verifier index if verifier_index >= state.state.verifiers_pub_keys.len() { return Err(ApiError::Unauthorized("Invalid verifier index".into())); } - // Get the public key for this verifier. + let timestamp_now = chrono::Utc::now().timestamp(); + let timestamp_diff = timestamp_now - timestamp.parse::().unwrap(); + + //Todo: move this to config + if timestamp_diff > 10 { + return Err(ApiError::Unauthorized("Timestamp is too old".into())); + } + + // Get the public key for this verifier let public_key = &state.state.verifiers_pub_keys[verifier_index]; - // Create verification payload based on request method and body content - let payload = if request.method().is_safe() - || request - .extensions() - .get::() - .map_or(true, |b| b.is_empty()) - { - // For GET requests or empty body requests, verify timestamp + verifier_index - serde_json::json!({ - "timestamp": timestamp, - "verifier_index": verifier_index.to_string(), - }) - } else { - // For POST/PUT requests with non-empty body, verify the body - let body_bytes = request - .extensions() - .get::() - .ok_or_else(|| ApiError::InternalServerError("Missing request body".into()))?; - serde_json::from_slice::(body_bytes) - .map_err(|_| ApiError::BadRequest("Invalid JSON body".into()))? - }; + // verify timestamp + verifier_index + let payload = serde_json::json!({ + "timestamp": timestamp, + "verifier_index": verifier_index.to_string(), + }); - // Verify the signature. + // Verify the signature if !crate::auth::verify_signature(&payload, signature, public_key) .map_err(|_| ApiError::InternalServerError("Signature verification failed".into()))? { @@ -85,7 +76,7 @@ pub async fn extract_body( let bytes = body::to_bytes(body, usize::MAX) .await .map_err(|_| ApiError::InternalServerError("Failed to read body".into()))?; - let mut req = Request::from_parts(parts, Body::empty()); + let mut req = Request::from_parts(parts, Body::from(bytes.clone())); req.extensions_mut().insert(bytes); Ok(next.run(req).await) } diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index eb2adb7b8..a31df8bab 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -152,10 +152,7 @@ impl ViaWithdrawalVerifier { Ok(()) } - fn create_request_headers( - &self, - body: Option<&impl serde::Serialize>, - ) -> anyhow::Result { + fn create_request_headers(&self) -> anyhow::Result { let mut headers = header::HeaderMap::new(); let timestamp = chrono::Utc::now().timestamp().to_string(); let verifier_index = self.signer.signer_index().to_string(); @@ -163,18 +160,12 @@ impl ViaWithdrawalVerifier { let private_key = bitcoin::PrivateKey::from_wif(&self.config.private_key)?; let secret_key = private_key.inner; - // Create signature based on whether there's a body - let signature = if let Some(data) = body { - // Sign the request body directly - crate::auth::sign_request(data, &secret_key)? - } else { - // Sign timestamp + verifier_index as a JSON object - let payload = serde_json::json!({ - "timestamp": timestamp, - "verifier_index": verifier_index, - }); - crate::auth::sign_request(&payload, &secret_key)? - }; + // Sign timestamp + verifier_index as a JSON object + let payload = serde_json::json!({ + "timestamp": timestamp, + "verifier_index": verifier_index, + }); + let signature = crate::auth::sign_request(&payload, &secret_key)?; headers.insert("X-Timestamp", header::HeaderValue::from_str(×tamp)?); headers.insert( @@ -188,7 +179,7 @@ impl ViaWithdrawalVerifier { async fn get_session(&self) -> anyhow::Result { let url = format!("{}/session", self.config.url); - let headers = self.create_request_headers(None::<&()>)?; + let headers = self.create_request_headers()?; let resp = self .client .get(&url) @@ -210,7 +201,7 @@ impl ViaWithdrawalVerifier { async fn get_session_nonces(&self) -> anyhow::Result> { let nonces_url = format!("{}/session/nonce", self.config.url); - let headers = self.create_request_headers(None::<&()>)?; + let headers = self.create_request_headers()?; let resp = self .client .get(&nonces_url) @@ -239,7 +230,7 @@ impl ViaWithdrawalVerifier { let nonce_pair = encode_nonce(self.signer.signer_index(), nonce).unwrap(); let url = format!("{}/session/nonce", self.config.url); - let headers = self.create_request_headers(Some(&nonce_pair))?; + let headers = self.create_request_headers()?; let res = self .client .post(&url) @@ -264,7 +255,7 @@ impl ViaWithdrawalVerifier { async fn get_session_signatures(&self) -> anyhow::Result> { let url = format!("{}/session/signature", self.config.url); - let headers = self.create_request_headers(None::<&()>)?; + let headers = self.create_request_headers()?; let resp = self .client .get(&url) @@ -310,7 +301,7 @@ impl ViaWithdrawalVerifier { let sig_pair = encode_signature(self.signer.signer_index(), partial_sig)?; let url = format!("{}/session/signature", self.config.url); - let headers = self.create_request_headers(Some(&sig_pair))?; + let headers = self.create_request_headers()?; let resp = self .client .post(&url) @@ -344,7 +335,7 @@ impl ViaWithdrawalVerifier { async fn create_new_session(&mut self) -> anyhow::Result<()> { let url = format!("{}/session/new", self.config.url); - let headers = self.create_request_headers(None::<&()>)?; + let headers = self.create_request_headers()?; let resp = self .client .post(&url) From b9d030c028853c08bbb7e7a7bdbc3b0134638853 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 4 Feb 2025 11:19:38 +0330 Subject: [PATCH 196/212] add op_return based deposit example --- core/lib/via_btc_client/Cargo.toml | 4 + .../examples/deposit_opreturn.rs | 133 ++++++++++++++++++ docker-compose-via.yml | 5 + infrastructure/via/src/token.ts | 41 ++++++ 4 files changed, 183 insertions(+) create mode 100644 core/lib/via_btc_client/examples/deposit_opreturn.rs diff --git a/core/lib/via_btc_client/Cargo.toml b/core/lib/via_btc_client/Cargo.toml index 6f2b4a791..0c6a7c272 100644 --- a/core/lib/via_btc_client/Cargo.toml +++ b/core/lib/via_btc_client/Cargo.toml @@ -69,3 +69,7 @@ path = "examples/verify_batch.rs" [[example]] name = "fee_history" path = "examples/fee_history.rs" + +[[example]] +name = "deposit_opreturn" +path = "examples/deposit_opreturn.rs" diff --git a/core/lib/via_btc_client/examples/deposit_opreturn.rs b/core/lib/via_btc_client/examples/deposit_opreturn.rs new file mode 100644 index 000000000..bf3464f2a --- /dev/null +++ b/core/lib/via_btc_client/examples/deposit_opreturn.rs @@ -0,0 +1,133 @@ +use std::{ + env, + fs::File, + io::{Read, Write}, + str::FromStr, +}; + +use anyhow::{Context, Result}; +use bitcoin::{address::NetworkUnchecked, Amount}; +use tracing::info; +use via_btc_client::{ + inscriber::Inscriber, + types::{ + BitcoinAddress, BitcoinNetwork, InscriberContext, InscriptionConfig, InscriptionMessage, + L1ToL2MessageInput, NodeAuth, Recipient, + }, +}; +use zksync_types::Address as EVMAddress; + +const CONTEXT_FILE: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/depositor_inscriber_context.json" +); + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); + + let args: Vec = env::args().collect(); + let mut amount = args[1].parse::()?; + let fees: f64 = 0.03; + amount += fees; + + let receiver_l2_address = EVMAddress::from_str(&args[2])?; + info!( + "Depositing {} BTC to receiver L2 address {}", + amount, receiver_l2_address + ); + + let depositor_private_key = args[3].clone(); + info!( + "Depositor L1 private key: {}...{}", + &depositor_private_key[..4], + &depositor_private_key[depositor_private_key.len() - 4..] + ); + + let network: BitcoinNetwork = args[4].parse().expect("Invalid network value"); + let rpc_url = args[5].clone(); + let rpc_username = args[6].clone(); + let rpc_password = args[7].clone(); + + let bridge_musig2_address = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" + .parse::>()? + .require_network(network)?; + + // Load the previous context from the file if it exists + let context = load_context_from_file(CONTEXT_FILE)?; + + let mut inscriber = Inscriber::new( + &rpc_url, + network, + NodeAuth::UserPass(rpc_username, rpc_password), + &depositor_private_key, + context, + ) + .await + .context("Failed to create Depositor Inscriber")?; + + info!( + "Depositor L1 balance: {}", + inscriber + .get_balance() + .await + .context("Failed to get balance")? + ); + + let input = L1ToL2MessageInput { + receiver_l2_address, + l2_contract_address: EVMAddress::zero(), + call_data: vec![], + }; + + let deposit_info = inscriber + .inscribe_with_recipient( + InscriptionMessage::L1ToL2Message(input), + InscriptionConfig::default(), + Some(Recipient { + address: bridge_musig2_address, + amount: Amount::from_btc(amount)?, + }), + ) + .await?; + + info!("Deposit tx sent: {:?}", deposit_info.final_reveal_tx.txid); + info!( + "Depositor change response: {:?}", + deposit_info.reveal_tx_output_info.reveal_tx_change_output + ); + info!( + "Recipient response: {:?}", + deposit_info + .reveal_tx_output_info + .recipient_tx_output + .unwrap() + ); + + // Save the updated context to the file after the inscription + save_context_to_file(&inscriber.get_context_snapshot()?, CONTEXT_FILE)?; + + Ok(()) +} + +// Utility function to save the context to a file +fn save_context_to_file(context: &InscriberContext, file_path: &str) -> Result<()> { + let serialized_context = serde_json::to_string(context)?; + let mut file = File::create(file_path)?; + file.write_all(serialized_context.as_bytes())?; + Ok(()) +} + +// Utility function to load the context from a file +fn load_context_from_file(file_path: &str) -> Result> { + if let Ok(mut file) = File::open(file_path) { + let mut data = String::new(); + file.read_to_string(&mut data)?; + let context: InscriberContext = serde_json::from_str(&data)?; + Ok(Some(context)) + } else { + Ok(None) + } +} diff --git a/docker-compose-via.yml b/docker-compose-via.yml index e17c6dbca..4e1214024 100644 --- a/docker-compose-via.yml +++ b/docker-compose-via.yml @@ -50,6 +50,10 @@ services: bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${TEST_ADDRESS} 300 echo "Sent 300 BTC to TEST_ADDRESS: $${TEST_ADDRESS}" + echo "TEST_ADDRESS_OP_RETURN: $${TEST_ADDRESS_OP_RETURN}" + bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${TEST_ADDRESS_OP_RETURN} 100 + echo "Sent 100 BTC to TEST_ADDRESS_OP_RETURN: $${TEST_ADDRESS_OP_RETURN}" + echo "VERIFIER_1_ADDRESS: $${VERIFIER_1_ADDRESS}" bitcoin-cli $${RPC_ARGS} -rpcwallet=Alice sendtoaddress $${VERIFIER_1_ADDRESS} 300 echo "Sent 300 BTC to VERIFIER_1_ADDRESS: $${VERIFIER_1_ADDRESS}" @@ -93,6 +97,7 @@ services: environment: - BITCOIN_DATA=/home/bitcoin/.bitcoin - TEST_ADDRESS=bcrt1qx2lk0unukm80qmepjp49hwf9z6xnz0s73k9j56 + - TEST_ADDRESS_OP_RETURN=bcrt1qu7z4qrlwl33qqz8duph0k7hv8trvgx8dt8jzfz - VERIFIER_1_ADDRESS=bcrt1qw2mvkvm6alfhe86yf328kgvr7mupdx4vln7kpv - VERIFIER_2_ADDRESS=bcrt1qk8mkhrmgtq24nylzyzejznfzws6d98g4kmuuh4 - VERIFIER_3_ADDRESS=bcrt1q23lgaa90s85jvtl6dsrkvn0g949cwjkwuyzwdm diff --git a/infrastructure/via/src/token.ts b/infrastructure/via/src/token.ts index 7ad483168..fe29fb162 100644 --- a/infrastructure/via/src/token.ts +++ b/infrastructure/via/src/token.ts @@ -4,6 +4,7 @@ import { ethers } from 'ethers'; import * as utils from 'utils'; const DEFAULT_DEPOSITOR_PRIVATE_KEY = 'cVZduZu265sWeAqFYygoDEE1FZ7wV9rpW5qdqjRkUehjaUMWLT1R'; +const DEFAULT_DEPOSITOR_PRIVATE_KEY_OP_RETURN = 'cQa1WGJQWT5suej9XZRBoAe4JsFtvswq5N3LWu7QboLJuZJewJSp'; const DEFAULT_NETWORK = 'regtest'; const DEFAULT_RPC_URL = 'http://0.0.0.0:18443'; const DEFAULT_RPC_USERNAME = 'rpcuser'; @@ -33,6 +34,24 @@ async function deposit( ); } +async function depositWithOpReturn( + amount: number, + receiverL2Address: string, + senderPrivateKey: string, + network: String, + rcpUrl: string, + rpcUsername: string, + rpcPassword: string +) { + if (isNaN(amount)) { + console.error('Error: Invalid deposit amount. Please provide a valid number.'); + return; + } + process.chdir(`${process.env.VIA_HOME}`); + await utils.spawn( + `cargo run --example deposit_opreturn -- ${amount} ${receiverL2Address} ${senderPrivateKey} ${network} ${rcpUrl} ${rpcUsername} ${rpcPassword}` + ); +} async function withdraw(amount: number, receiverL1Address: string, userL2PrivateKey: string, rpcUrl: string) { if (isNaN(amount)) { console.error('Error: Invalid withdraw amount. Please provide a valid number.'); @@ -110,6 +129,28 @@ command ) ); +command + .command('deposit-with-op-return') + .description('deposit BTC to l2 with op-return') + .requiredOption('--amount ', 'amount of BTC to deposit', parseFloat) + .requiredOption('--receiver-l2-address ', 'receiver l2 address') + .option('--sender-private-key ', 'sender private key', DEFAULT_DEPOSITOR_PRIVATE_KEY) + .option('--network ', 'network', DEFAULT_NETWORK) + .option('--rpc-url ', 'RPC URL', DEFAULT_RPC_URL) + .option('--rpc-username ', 'RPC username', DEFAULT_RPC_USERNAME) + .option('--rpc-password ', 'RPC password', DEFAULT_RPC_PASSWORD) + .action((cmd: Command) => + depositWithOpReturn( + cmd.amount, + cmd.receiverL2Address, + cmd.senderPrivateKey, + cmd.network, + cmd.rpcUrl, + cmd.rpcUsername, + cmd.rpcPassword + ) + ); + command .command('withdraw') .description('withdraw BTC to l1') From b3f8199bbe2c42fd3987bbd92e00492f180a8e15 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 4 Feb 2025 12:09:16 +0330 Subject: [PATCH 197/212] impl op_return example --- .../examples/deposit_opreturn.rs | 199 ++++++++++-------- 1 file changed, 112 insertions(+), 87 deletions(-) diff --git a/core/lib/via_btc_client/examples/deposit_opreturn.rs b/core/lib/via_btc_client/examples/deposit_opreturn.rs index bf3464f2a..c3c5e65e0 100644 --- a/core/lib/via_btc_client/examples/deposit_opreturn.rs +++ b/core/lib/via_btc_client/examples/deposit_opreturn.rs @@ -1,38 +1,34 @@ -use std::{ - env, - fs::File, - io::{Read, Write}, - str::FromStr, +use std::{env, str::FromStr}; + +use anyhow::Result; +use bitcoin::{ + absolute, + address::NetworkUnchecked, + consensus::encode::serialize_hex, + secp256k1::{Message, Secp256k1}, + sighash::{EcdsaSighashType, SighashCache}, + transaction, Address, Amount, CompressedPublicKey, PrivateKey, ScriptBuf, Sequence, + Transaction, TxIn, TxOut, Witness, }; - -use anyhow::{Context, Result}; -use bitcoin::{address::NetworkUnchecked, Amount}; use tracing::info; use via_btc_client::{ - inscriber::Inscriber, - types::{ - BitcoinAddress, BitcoinNetwork, InscriberContext, InscriptionConfig, InscriptionMessage, - L1ToL2MessageInput, NodeAuth, Recipient, - }, + client::BitcoinClient, + traits::BitcoinOps, + types::{BitcoinAddress, NodeAuth}, }; use zksync_types::Address as EVMAddress; -const CONTEXT_FILE: &str = concat!( - env!("CARGO_MANIFEST_DIR"), - "/depositor_inscriber_context.json" -); - #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .init(); - let args: Vec = env::args().collect(); - let mut amount = args[1].parse::()?; - let fees: f64 = 0.03; - amount += fees; + let secp = Secp256k1::new(); + let args: Vec = env::args().collect(); + let amount = Amount::from_btc(args[1].parse::()?)?; + let fees = Amount::from_btc(0.03)?; let receiver_l2_address = EVMAddress::from_str(&args[2])?; info!( "Depositing {} BTC to receiver L2 address {}", @@ -46,88 +42,117 @@ async fn main() -> Result<()> { &depositor_private_key[depositor_private_key.len() - 4..] ); - let network: BitcoinNetwork = args[4].parse().expect("Invalid network value"); + let network: bitcoin::Network = args[4].parse().expect("Invalid network value"); let rpc_url = args[5].clone(); let rpc_username = args[6].clone(); let rpc_password = args[7].clone(); + let private_key = + PrivateKey::from_wif(&depositor_private_key).map_err(|e| anyhow::anyhow!(e.to_string()))?; + let pk = private_key.inner.public_key(&secp); + let compressed_pk = CompressedPublicKey::from_private_key(&secp, &private_key) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + let address = Address::p2wpkh(&compressed_pk, network); + let bridge_musig2_address = "bcrt1p3s7m76wp5seprjy4gdxuxrr8pjgd47q5s8lu9vefxmp0my2p4t9qh6s8kq" .parse::>()? .require_network(network)?; - // Load the previous context from the file if it exists - let context = load_context_from_file(CONTEXT_FILE)?; - - let mut inscriber = Inscriber::new( + let client = BitcoinClient::new( &rpc_url, network, NodeAuth::UserPass(rpc_username, rpc_password), - &depositor_private_key, - context, - ) - .await - .context("Failed to create Depositor Inscriber")?; + )?; + + // Fetch UTXOs available at our address. + let all_utxos = client.fetch_utxos(&address).await?; + + // Select only the UTXOs needed to cover the total amount (amount + fees) + let total_needed = amount + fees; + let mut selected_utxos = Vec::new(); + let mut input_amount = Amount::from_sat(0); + for (outpoint, txout) in all_utxos.into_iter() { + selected_utxos.push((outpoint, txout)); + input_amount += selected_utxos.last().unwrap().1.value; + if input_amount >= total_needed { + break; + } + } - info!( - "Depositor L1 balance: {}", - inscriber - .get_balance() - .await - .context("Failed to get balance")? - ); + if input_amount < total_needed { + return Err(anyhow::anyhow!("Insufficient funds")); + } + + // Create transaction inputs from the selected UTXOs. + let tx_inputs: Vec = selected_utxos + .iter() + .map(|(outpoint, _)| TxIn { + previous_output: *outpoint, + script_sig: ScriptBuf::new(), + sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: Witness::new(), + }) + .collect(); + + // Create transaction outputs. + let mut outputs = Vec::new(); + // Output to bridge address. + outputs.push(TxOut { + value: amount, + script_pubkey: bridge_musig2_address.script_pubkey(), + }); + // OP_RETURN output with L2 address. + outputs.push(TxOut { + value: Amount::from_sat(0), + script_pubkey: ScriptBuf::new_op_return(receiver_l2_address.to_fixed_bytes()), + }); + // Change output (if any). + let change_amount = input_amount - total_needed; + if change_amount > Amount::from_sat(0) { + outputs.push(TxOut { + value: change_amount, + script_pubkey: address.script_pubkey(), + }); + } - let input = L1ToL2MessageInput { - receiver_l2_address, - l2_contract_address: EVMAddress::zero(), - call_data: vec![], + let mut tx = Transaction { + version: transaction::Version::TWO, + lock_time: absolute::LockTime::ZERO, + input: tx_inputs, + output: outputs, }; - let deposit_info = inscriber - .inscribe_with_recipient( - InscriptionMessage::L1ToL2Message(input), - InscriptionConfig::default(), - Some(Recipient { - address: bridge_musig2_address, - amount: Amount::from_btc(amount)?, - }), - ) - .await?; - - info!("Deposit tx sent: {:?}", deposit_info.final_reveal_tx.txid); - info!( - "Depositor change response: {:?}", - deposit_info.reveal_tx_output_info.reveal_tx_change_output - ); - info!( - "Recipient response: {:?}", - deposit_info - .reveal_tx_output_info - .recipient_tx_output - .unwrap() - ); + let sighash_type = EcdsaSighashType::All; + let mut cache = SighashCache::new(&mut tx); + for (i, (_, utxo)) in selected_utxos.iter().enumerate() { + let sighash = cache + .p2wpkh_signature_hash(i, &utxo.script_pubkey, utxo.value, sighash_type) + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + + let msg = Message::from(sighash); + let signature = secp.sign_ecdsa(&msg, &private_key.inner); + + // Create a Bitcoin ECDSA signature with sighash type + let signature = bitcoin::ecdsa::Signature { + signature, + sighash_type, + }; + + // Set the witness using p2wpkh helper + cache + .witness_mut(i) + .ok_or_else(|| anyhow::anyhow!("Failed to get witness")) + .map(|witness| *witness = Witness::p2wpkh(&signature, &pk))?; + } - // Save the updated context to the file after the inscription - save_context_to_file(&inscriber.get_context_snapshot()?, CONTEXT_FILE)?; + let tx = cache.into_transaction(); + // -------------------------------- - Ok(()) -} + // Broadcast transaction + let tx_hex = serialize_hex(&tx); + let txid = client.broadcast_signed_transaction(&tx_hex).await?; -// Utility function to save the context to a file -fn save_context_to_file(context: &InscriberContext, file_path: &str) -> Result<()> { - let serialized_context = serde_json::to_string(context)?; - let mut file = File::create(file_path)?; - file.write_all(serialized_context.as_bytes())?; - Ok(()) -} + info!("Transaction broadcasted with txid: {}", txid); -// Utility function to load the context from a file -fn load_context_from_file(file_path: &str) -> Result> { - if let Ok(mut file) = File::open(file_path) { - let mut data = String::new(); - file.read_to_string(&mut data)?; - let context: InscriberContext = serde_json::from_str(&data)?; - Ok(Some(context)) - } else { - Ok(None) - } + Ok(()) } From 140dbd3128143ba050ae03a8f16c02a38e53a2db Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 4 Feb 2025 12:32:18 +0330 Subject: [PATCH 198/212] change celestia fetch header url --- infrastructure/via/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/via/src/config.ts b/infrastructure/via/src/config.ts index b23aa3a66..8dd293d4e 100644 --- a/infrastructure/via/src/config.ts +++ b/infrastructure/via/src/config.ts @@ -201,7 +201,7 @@ const fetchCelestiaTrustedHash = async () => { let environment = process.env.VIA_ENV!; const l2InitFile = `etc/env/l2-inits/${environment}.init.env`; - const response = await (await fetch('http://public-celestia-mocha4-consensus.numia.xyz:26657/header')).json(); + const response = await (await fetch('http://celestia-testnet-consensus.itrocket.net:26657/header')).json(); const { last_block_id, height } = response.result.header; const envFilePath1 = path.join(process.env.VIA_HOME!, `etc/env/target/${process.env.VIA_ENV}.env`); From 67b4a1acd0a7b8efaa3b5318a01410ed30191c96 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Tue, 4 Feb 2025 12:48:37 +0330 Subject: [PATCH 199/212] reduce fee on op_return depsoit example --- core/lib/via_btc_client/examples/deposit_opreturn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/via_btc_client/examples/deposit_opreturn.rs b/core/lib/via_btc_client/examples/deposit_opreturn.rs index c3c5e65e0..23c42a450 100644 --- a/core/lib/via_btc_client/examples/deposit_opreturn.rs +++ b/core/lib/via_btc_client/examples/deposit_opreturn.rs @@ -28,7 +28,7 @@ async fn main() -> Result<()> { let args: Vec = env::args().collect(); let amount = Amount::from_btc(args[1].parse::()?)?; - let fees = Amount::from_btc(0.03)?; + let fees = Amount::from_btc(0.0001)?; let receiver_l2_address = EVMAddress::from_str(&args[2])?; info!( "Depositing {} BTC to receiver L2 address {}", From 2e7f66b816c6b9ab155989a0fbea79454b23075f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:59:33 +0100 Subject: [PATCH 200/212] remove: retry logic from btc_sender --- ...a2da09357ece059755139e698acbc050a7673.json | 22 -------------- core/lib/dal/src/btc_sender_dal.rs | 22 -------------- core/lib/via_btc_client/examples/bootstrap.rs | 19 ++++-------- core/lib/via_btc_client/examples/deposit.rs | 5 ++-- core/lib/via_btc_client/examples/inscriber.rs | 16 +++++----- .../via_btc_client/examples/verify_batch.rs | 10 ++----- core/lib/via_btc_client/src/inscriber/mod.rs | 26 ++++------------- core/lib/via_btc_client/src/types.rs | 11 ------- .../src/btc_inscription_aggregator.rs | 8 ++--- .../src/btc_inscription_manager.rs | 29 ++++--------------- ...a2da09357ece059755139e698acbc050a7673.json | 22 -------------- .../verifier_dal/src/via_btc_sender_dal.rs | 22 -------------- .../src/btc_inscription_manager.rs | 28 ++++-------------- 13 files changed, 34 insertions(+), 206 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json delete mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json diff --git a/core/lib/dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json b/core/lib/dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json deleted file mode 100644 index 27c16afa8..000000000 --- a/core/lib/dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n COUNT(id) AS COUNT\n FROM\n via_btc_inscriptions_request_history\n WHERE\n inscription_request_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "count", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - null - ] - }, - "hash": "939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673" -} diff --git a/core/lib/dal/src/btc_sender_dal.rs b/core/lib/dal/src/btc_sender_dal.rs index 0c3ec63a8..d22af890f 100644 --- a/core/lib/dal/src/btc_sender_dal.rs +++ b/core/lib/dal/src/btc_sender_dal.rs @@ -171,28 +171,6 @@ impl ViaBtcSenderDal<'_, '_> { Ok(inscription_request_history.map(ViaBtcInscriptionRequestHistory::from)) } - pub async fn get_total_inscription_request_history( - &mut self, - inscription_request_id: i64, - ) -> sqlx::Result { - let total = sqlx::query!( - r#" - SELECT - COUNT(id) AS COUNT - FROM - via_btc_inscriptions_request_history - WHERE - inscription_request_id = $1 - "#, - inscription_request_id - ) - .fetch_one(self.storage.conn()) - .await?; - - // Return the count or 0 if no records were found - Ok(total.count.unwrap_or(0)) - } - pub async fn confirm_inscription( &mut self, inscriptions_request_id: i64, diff --git a/core/lib/via_btc_client/examples/bootstrap.rs b/core/lib/via_btc_client/examples/bootstrap.rs index 4af3a360f..9ee8eba0b 100644 --- a/core/lib/via_btc_client/examples/bootstrap.rs +++ b/core/lib/via_btc_client/examples/bootstrap.rs @@ -10,8 +10,8 @@ use tracing::info; use via_btc_client::{ inscriber::Inscriber, types::{ - BitcoinAddress, BitcoinNetwork, InscriptionConfig, InscriptionMessage, NodeAuth, - ProposeSequencerInput, SystemBootstrappingInput, ValidatorAttestationInput, Vote, + BitcoinAddress, BitcoinNetwork, InscriptionMessage, NodeAuth, ProposeSequencerInput, + SystemBootstrappingInput, ValidatorAttestationInput, Vote, }, }; use zksync_basic_types::H256; @@ -110,10 +110,7 @@ async fn main() -> Result<()> { abstract_account_hash: H256::random(), }; let bootstrap_info = verifier_inscribers[0] - .inscribe( - InscriptionMessage::SystemBootstrapping(input), - InscriptionConfig::default(), - ) + .inscribe(InscriptionMessage::SystemBootstrapping(input)) .await?; info!( "Bootstrapping tx sent: {:?}", @@ -127,10 +124,7 @@ async fn main() -> Result<()> { sequencer_new_p2wpkh_address: sequencer_p2wpkh_address, }; let propose_info = verifier_inscribers[1] - .inscribe( - InscriptionMessage::ProposeSequencer(input), - InscriptionConfig::default(), - ) + .inscribe(InscriptionMessage::ProposeSequencer(input)) .await?; info!( "Propose sequencer tx sent: {:?}", @@ -149,10 +143,7 @@ async fn main() -> Result<()> { for (i, inscriber) in verifier_inscribers.iter_mut().enumerate() { let validator_info = inscriber - .inscribe( - InscriptionMessage::ValidatorAttestation(input.clone()), - InscriptionConfig::default(), - ) + .inscribe(InscriptionMessage::ValidatorAttestation(input.clone())) .await?; info!( "Validator {} attestation tx sent: {:?}", diff --git a/core/lib/via_btc_client/examples/deposit.rs b/core/lib/via_btc_client/examples/deposit.rs index bf3464f2a..82a74544b 100644 --- a/core/lib/via_btc_client/examples/deposit.rs +++ b/core/lib/via_btc_client/examples/deposit.rs @@ -11,8 +11,8 @@ use tracing::info; use via_btc_client::{ inscriber::Inscriber, types::{ - BitcoinAddress, BitcoinNetwork, InscriberContext, InscriptionConfig, InscriptionMessage, - L1ToL2MessageInput, NodeAuth, Recipient, + BitcoinAddress, BitcoinNetwork, InscriberContext, InscriptionMessage, L1ToL2MessageInput, + NodeAuth, Recipient, }, }; use zksync_types::Address as EVMAddress; @@ -85,7 +85,6 @@ async fn main() -> Result<()> { let deposit_info = inscriber .inscribe_with_recipient( InscriptionMessage::L1ToL2Message(input), - InscriptionConfig::default(), Some(Recipient { address: bridge_musig2_address, amount: Amount::from_btc(amount)?, diff --git a/core/lib/via_btc_client/examples/inscriber.rs b/core/lib/via_btc_client/examples/inscriber.rs index e147541e1..647ac1b71 100644 --- a/core/lib/via_btc_client/examples/inscriber.rs +++ b/core/lib/via_btc_client/examples/inscriber.rs @@ -1,7 +1,7 @@ use anyhow::{Context, Result}; use via_btc_client::{ inscriber::Inscriber, - types::{self as inscribe_types, BitcoinNetwork, InscriptionConfig, NodeAuth}, + types::{self as inscribe_types, BitcoinNetwork, NodeAuth}, }; #[tokio::main] @@ -40,10 +40,9 @@ async fn main() -> Result<()> { }; let inscribe_info = inscriber_instance - .inscribe( - inscribe_types::InscriptionMessage::L1BatchDAReference(l1_da_batch_ref), - InscriptionConfig::default(), - ) + .inscribe(inscribe_types::InscriptionMessage::L1BatchDAReference( + l1_da_batch_ref, + )) .await .context("Failed to inscribe L1BatchDAReference")?; @@ -58,10 +57,9 @@ async fn main() -> Result<()> { }; let _da_proof_ref_reveal_txid = inscriber_instance - .inscribe( - inscribe_types::InscriptionMessage::ProofDAReference(l1_da_proof_ref), - InscriptionConfig::default(), - ) + .inscribe(inscribe_types::InscriptionMessage::ProofDAReference( + l1_da_proof_ref, + )) .await .context("Failed to inscribe ProofDAReference")?; diff --git a/core/lib/via_btc_client/examples/verify_batch.rs b/core/lib/via_btc_client/examples/verify_batch.rs index 422863a89..fb984ca91 100644 --- a/core/lib/via_btc_client/examples/verify_batch.rs +++ b/core/lib/via_btc_client/examples/verify_batch.rs @@ -5,10 +5,7 @@ use bitcoin::Txid; use tracing::info; use via_btc_client::{ inscriber::Inscriber, - types::{ - BitcoinNetwork, InscriptionConfig, InscriptionMessage, NodeAuth, ValidatorAttestationInput, - Vote, - }, + types::{BitcoinNetwork, InscriptionMessage, NodeAuth, ValidatorAttestationInput, Vote}, }; const RPC_URL: &str = "http://0.0.0.0:18443"; @@ -63,10 +60,7 @@ async fn main() -> Result<()> { for (i, inscriber) in verifier_inscribers.iter_mut().enumerate() { let validator_info = inscriber - .inscribe( - InscriptionMessage::ValidatorAttestation(input.clone()), - InscriptionConfig::default(), - ) + .inscribe(InscriptionMessage::ValidatorAttestation(input.clone())) .await?; info!( "Validator {} attestation tx sent: {:?}", diff --git a/core/lib/via_btc_client/src/inscriber/mod.rs b/core/lib/via_btc_client/src/inscriber/mod.rs index 5823aa376..7b0cb7baa 100644 --- a/core/lib/via_btc_client/src/inscriber/mod.rs +++ b/core/lib/via_btc_client/src/inscriber/mod.rs @@ -27,7 +27,7 @@ use crate::{ }, signer::KeyManager, traits::{BitcoinOps, BitcoinSigner}, - types::{BitcoinNetwork, InscriberContext, InscriptionConfig, InscriptionMessage, Recipient}, + types::{BitcoinNetwork, InscriberContext, InscriptionMessage, Recipient}, }; mod fee; @@ -101,7 +101,6 @@ impl Inscriber { pub async fn prepare_inscribe( &mut self, input: &InscriptionMessage, - config: InscriptionConfig, recipient: Option, ) -> Result { self.sync_context_with_blockchain().await?; @@ -133,7 +132,6 @@ impl Inscriber { .prepare_reveal_tx_output( &reveal_tx_input_info, &inscription_data, - config, recipient, commit_tx_output_info.commit_tx_fee, ) @@ -158,13 +156,12 @@ impl Inscriber { pub async fn inscribe_with_recipient( &mut self, input: InscriptionMessage, - config: InscriptionConfig, recipient: Option, ) -> Result { info!("Starting inscription process"); let inscriber_info = self - .prepare_inscribe(&input, config, recipient) + .prepare_inscribe(&input, recipient) .await .context("Error prepare inscriber infos")?; @@ -181,12 +178,8 @@ impl Inscriber { } #[instrument(skip(self, input), target = "bitcoin_inscriber")] - pub async fn inscribe( - &mut self, - input: InscriptionMessage, - config: InscriptionConfig, - ) -> Result { - self.inscribe_with_recipient(input, config, None).await + pub async fn inscribe(&mut self, input: InscriptionMessage) -> Result { + self.inscribe_with_recipient(input, None).await } #[instrument(skip(self), target = "bitcoin_inscriber")] @@ -560,7 +553,6 @@ impl Inscriber { &self, tx_input_data: &RevealTxInputRes, inscription_data: &InscriptionData, - config: InscriptionConfig, recipient: Option, commit_tx_fee: Amount, ) -> Result { @@ -588,12 +580,9 @@ impl Inscriber { fee_rate, )?; - // increase fee rate based on pending transactions in context - let retry_factor = FEE_RATE_INCREASE_PER_PENDING_TX * config.fee_multiplier; - let txs_stuck_factor = FEE_RATE_INCREASE_PER_PENDING_TX * pending_tx_in_context as u64; - let increase_factor = retry_factor + txs_stuck_factor + FEE_RATE_INCENTIVE; + let increase_factor = txs_stuck_factor + FEE_RATE_INCENTIVE; fee_amount += (fee_amount * increase_factor) / 100; // Add the fee amount removed from the commit tx to reveal @@ -975,10 +964,7 @@ mod tests { let inscribe_message = InscriptionMessage::L1BatchDAReference(l1_da_batch_ref); - let res = inscriber - .inscribe(inscribe_message, InscriptionConfig::default()) - .await - .unwrap(); + let res = inscriber.inscribe(inscribe_message).await.unwrap(); assert_ne!(res.final_commit_tx.txid, Txid::all_zeros()); assert_ne!(res.final_reveal_tx.txid, Txid::all_zeros()); diff --git a/core/lib/via_btc_client/src/types.rs b/core/lib/via_btc_client/src/types.rs index 90f44c927..26adbab75 100644 --- a/core/lib/via_btc_client/src/types.rs +++ b/core/lib/via_btc_client/src/types.rs @@ -134,17 +134,6 @@ impl Serializable for InscriptionMessage { } } -#[derive(Debug)] -pub struct InscriptionConfig { - pub fee_multiplier: u64, -} - -impl Default for InscriptionConfig { - fn default() -> Self { - InscriptionConfig { fee_multiplier: 0 } - } -} - #[derive(Debug)] pub struct Recipient { pub address: BitcoinAddress, diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index dd2661909..e40ff92dd 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -2,11 +2,7 @@ use std::str::FromStr; use anyhow::{Context, Result}; use tokio::sync::watch; -use via_btc_client::{ - inscriber::Inscriber, - traits::Serializable, - types::{InscriptionConfig, InscriptionMessage}, -}; +use via_btc_client::{inscriber::Inscriber, traits::Serializable, types::InscriptionMessage}; use zksync_config::ViaBtcSenderConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; @@ -94,7 +90,7 @@ impl ViaBtcInscriptionAggregator { // Estimate the tx fee to execute the inscription request. let inscribe_info = self .inscriber - .prepare_inscribe(&inscription_message, InscriptionConfig::default(), None) + .prepare_inscribe(&inscription_message, None) .await .context("Via get inscriber info")?; diff --git a/core/node/via_btc_sender/src/btc_inscription_manager.rs b/core/node/via_btc_sender/src/btc_inscription_manager.rs index dafe2f865..5d1cac3ca 100644 --- a/core/node/via_btc_sender/src/btc_inscription_manager.rs +++ b/core/node/via_btc_sender/src/btc_inscription_manager.rs @@ -1,11 +1,7 @@ use anyhow::{Context, Result}; use bincode::serialize; use tokio::sync::watch; -use via_btc_client::{ - inscriber::Inscriber, - traits::Serializable, - types::{InscriptionConfig, InscriptionMessage}, -}; +use via_btc_client::{inscriber::Inscriber, traits::Serializable, types::InscriptionMessage}; use zksync_config::ViaBtcSenderConfig; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; use zksync_types::btc_sender::ViaBtcInscriptionRequest; @@ -110,23 +106,10 @@ impl ViaBtcInscriptionManager { { continue; } - - let number_inscription_request_history = storage - .btc_sender_dal() - .get_total_inscription_request_history(inscription.id) - .await?; - - let config = InscriptionConfig { - fee_multiplier: number_inscription_request_history as u64 + 1, - }; - - tracing::info!( - "Inscription {reveal_tx} stuck for more than {BLOCK_RESEND} block, retry sending the inscription.", + tracing::warn!( + "Inscription {reveal_tx} stuck for more than {BLOCK_RESEND} block.", reveal_tx = last_inscription_history.reveal_tx_id ); - - self.send_inscription_tx(storage, &inscription, config) - .await?; } } } @@ -166,8 +149,7 @@ impl ViaBtcInscriptionManager { .await?; for inscription in list_new_inscription_request { - self.send_inscription_tx(storage, &inscription, InscriptionConfig::default()) - .await?; + self.send_inscription_tx(storage, &inscription).await?; } } Ok(()) @@ -177,7 +159,6 @@ impl ViaBtcInscriptionManager { &mut self, storage: &mut Connection<'_, Core>, tx: &ViaBtcInscriptionRequest, - config: InscriptionConfig, ) -> anyhow::Result<()> { let sent_at_block = self .inscriber @@ -192,7 +173,7 @@ impl ViaBtcInscriptionManager { let inscribe_info = self .inscriber - .inscribe(input, config) + .inscribe(input) .await .context("Sent inscription tx")?; diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json b/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json deleted file mode 100644 index 27c16afa8..000000000 --- a/via_verifier/lib/verifier_dal/.sqlx/query-939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n COUNT(id) AS COUNT\n FROM\n via_btc_inscriptions_request_history\n WHERE\n inscription_request_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "count", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - null - ] - }, - "hash": "939ac2a27e3844db1e4606e2338a2da09357ece059755139e698acbc050a7673" -} diff --git a/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs b/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs index da63ed95a..dd2535ae3 100644 --- a/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_btc_sender_dal.rs @@ -170,28 +170,6 @@ impl ViaBtcSenderDal<'_, '_> { Ok(inscription_request_history.map(ViaBtcInscriptionRequestHistory::from)) } - pub async fn get_total_inscription_request_history( - &mut self, - inscription_request_id: i64, - ) -> sqlx::Result { - let total = sqlx::query!( - r#" - SELECT - COUNT(id) AS COUNT - FROM - via_btc_inscriptions_request_history - WHERE - inscription_request_id = $1 - "#, - inscription_request_id - ) - .fetch_one(self.storage.conn()) - .await?; - - // Return the count or 0 if no records were found - Ok(total.count.unwrap_or(0)) - } - pub async fn confirm_inscription( &mut self, inscriptions_request_id: i64, diff --git a/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs index 7f1508353..ddbffaec0 100644 --- a/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs +++ b/via_verifier/node/via_btc_sender/src/btc_inscription_manager.rs @@ -1,11 +1,7 @@ use anyhow::{Context, Result}; use bincode::serialize; use tokio::sync::watch; -use via_btc_client::{ - inscriber::Inscriber, - traits::Serializable, - types::{InscriptionConfig, InscriptionMessage}, -}; +use via_btc_client::{inscriber::Inscriber, traits::Serializable, types::InscriptionMessage}; use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; use zksync_config::ViaBtcSenderConfig; use zksync_types::btc_sender::ViaBtcInscriptionRequest; @@ -116,22 +112,10 @@ impl ViaBtcInscriptionManager { continue; } - let number_inscription_request_history = storage - .via_btc_sender_dal() - .get_total_inscription_request_history(inscription.id) - .await?; - - let config = InscriptionConfig { - fee_multiplier: number_inscription_request_history as u64 + 1, - }; - - tracing::info!( - "Inscription {reveal_tx} stuck for more than {BLOCK_RESEND} block, retry sending the inscription.", + tracing::warn!( + "Inscription {reveal_tx} stuck for more than {BLOCK_RESEND} block.", reveal_tx = last_inscription_history.reveal_tx_id ); - - self.send_inscription_tx(storage, &inscription, config) - .await?; } } } @@ -171,8 +155,7 @@ impl ViaBtcInscriptionManager { .await?; for inscription in list_new_inscription_request { - self.send_inscription_tx(storage, &inscription, InscriptionConfig::default()) - .await?; + self.send_inscription_tx(storage, &inscription).await?; } } Ok(()) @@ -182,7 +165,6 @@ impl ViaBtcInscriptionManager { &mut self, storage: &mut Connection<'_, Verifier>, tx: &ViaBtcInscriptionRequest, - config: InscriptionConfig, ) -> anyhow::Result<()> { let sent_at_block = self .inscriber @@ -197,7 +179,7 @@ impl ViaBtcInscriptionManager { let inscribe_info = self .inscriber - .inscribe(input, config) + .inscribe(input) .await .context("Sent inscription tx")?; From 33246d82b90b111af1d225a98245b0e4e2c187a8 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 6 Feb 2025 07:24:02 +0100 Subject: [PATCH 201/212] test: clean up tests --- .../src/inscriber/test_utils.rs | 11 +- .../src/tests/btc_inscription_manager_test.rs | 124 ------------------ 2 files changed, 10 insertions(+), 125 deletions(-) diff --git a/core/lib/via_btc_client/src/inscriber/test_utils.rs b/core/lib/via_btc_client/src/inscriber/test_utils.rs index 3b922da91..abc03f8d3 100644 --- a/core/lib/via_btc_client/src/inscriber/test_utils.rs +++ b/core/lib/via_btc_client/src/inscriber/test_utils.rs @@ -86,7 +86,16 @@ impl BitcoinOps for MockBitcoinOps { } async fn fetch_utxos(&self, _address: &Address) -> BitcoinClientResult> { - BitcoinClientResult::Ok(self.utxos.clone()) + BitcoinClientResult::Ok(vec![( + OutPoint { + txid: Txid::all_zeros(), + vout: 0, + }, + TxOut { + value: Amount::from_btc(1.0).unwrap(), + script_pubkey: _address.script_pubkey(), + }, + )]) } async fn check_tx_confirmation( diff --git a/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs b/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs index 1ef829a78..b77f8d8cd 100644 --- a/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs +++ b/core/node/via_btc_sender/src/tests/btc_inscription_manager_test.rs @@ -27,130 +27,6 @@ mod tests { run_manager(pool, config, MockBitcoinOpsConfig::default()).await; } - #[tokio::test] - async fn test_btc_inscription_manager_run_one_inscription_request_with_retry() { - let pool = ConnectionPool::::test_pool().await; - let config = get_btc_sender_config(1, 1); - let mut mock_btc_ops_config = MockBitcoinOpsConfig::default(); - mock_btc_ops_config.set_block_height(1); - - let number_of_batches = 1; - let mut protocol_version: Option = None; - let mut base_system_contracts_hashes: Option = None; - let mut l1_headers = vec![]; - - for batch_number in 1..number_of_batches + 1 { - let header: L1BatchHeader = via_create_l1_batch(batch_number); - l1_headers.push(header.clone()); - - if protocol_version.is_none() { - protocol_version = header.protocol_version; - } - if base_system_contracts_hashes.is_none() { - base_system_contracts_hashes = Some(header.base_system_contracts_hashes); - } - } - - let mut aggregator_test = ViaAggregatorTest::new( - protocol_version.unwrap(), - base_system_contracts_hashes.unwrap(), - pool.clone(), - Some(config.clone()), - ) - .await; - - for header in l1_headers { - aggregator_test - .insert_l1_batch( - header.clone(), - l1_batch_metadata_to_commitment_artifacts(&default_l1_batch_metadata()), - ) - .await; - - let sent_at = Utc::now().naive_utc(); - - let _ = aggregator_test - .storage - .via_data_availability_dal() - .insert_l1_batch_da(header.number, "blob_id", sent_at) - .await; - - let _ = aggregator_test - .storage - .via_data_availability_dal() - .insert_proof_da(header.number, "blob_id", sent_at) - .await; - } - - run_aggregator(pool.clone(), config.clone()).await; - run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; - - let inflight_inscriptions_before = aggregator_test - .storage - .btc_sender_dal() - .get_inflight_inscriptions() - .await - .unwrap(); - - assert!(!inflight_inscriptions_before.is_empty()); - - let last_inscription_history_before = aggregator_test - .storage - .btc_sender_dal() - .get_last_inscription_request_history(inflight_inscriptions_before[0].id) - .await - .unwrap(); - - assert!(last_inscription_history_before.is_some()); - - // Simulate the transaction is stuck for 10 blocks - mock_btc_ops_config.set_block_height(10); - - // THis hould create a new inscription_history - run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; - - let last_inscription_history_after = aggregator_test - .storage - .btc_sender_dal() - .get_last_inscription_request_history(inflight_inscriptions_before[0].id) - .await - .unwrap(); - - assert!(last_inscription_history_after.is_some()); - - assert_ne!( - last_inscription_history_after.unwrap().id, - last_inscription_history_before.unwrap().id - ); - - // Simulate the transaction was processed in next block - mock_btc_ops_config.set_block_height(11); - mock_btc_ops_config.set_tx_confirmation(true); - - run_manager(pool.clone(), config.clone(), mock_btc_ops_config.clone()).await; - - let inflight_inscriptions_after = aggregator_test - .storage - .btc_sender_dal() - .get_inflight_inscriptions() - .await - .unwrap(); - - assert!(inflight_inscriptions_after.is_empty()); - - let last_inscription_history_after = aggregator_test - .storage - .btc_sender_dal() - .get_last_inscription_request_history(inflight_inscriptions_before[0].id) - .await - .unwrap(); - - assert!(last_inscription_history_after - .unwrap() - .confirmed_at - .is_some()); - } - #[tokio::test] async fn test_btc_inscription_manager_run_one_inscription_request() { let pool = ConnectionPool::::test_pool().await; From dad418c2a2405f8527e2da91c887b014cbc3699f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 6 Feb 2025 07:27:34 +0100 Subject: [PATCH 202/212] clean: remove un used verification service crate --- via_verifier/node/verification_service/Cargo.toml | 11 ----------- via_verifier/node/verification_service/src/lib.rs | 0 2 files changed, 11 deletions(-) delete mode 100644 via_verifier/node/verification_service/Cargo.toml delete mode 100644 via_verifier/node/verification_service/src/lib.rs diff --git a/via_verifier/node/verification_service/Cargo.toml b/via_verifier/node/verification_service/Cargo.toml deleted file mode 100644 index 63cf7a09b..000000000 --- a/via_verifier/node/verification_service/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "via_verification_service" -description = "Via Verification Service" -version.workspace = true -edition.workspace = true -authors = ["Via Network"] - - -[dependencies] - -[dev-dependencies] diff --git a/via_verifier/node/verification_service/src/lib.rs b/via_verifier/node/verification_service/src/lib.rs deleted file mode 100644 index e69de29bb..000000000 From cb639f5a338557f7442cf8448791d7a18f9d578e Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Thu, 6 Feb 2025 10:11:41 +0100 Subject: [PATCH 203/212] refactor: fetch the base system contracts from db --- .../src/btc_inscription_aggregator.rs | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs index e40ff92dd..af3199fa4 100644 --- a/core/node/via_btc_sender/src/btc_inscription_aggregator.rs +++ b/core/node/via_btc_sender/src/btc_inscription_aggregator.rs @@ -1,12 +1,10 @@ -use std::str::FromStr; - use anyhow::{Context, Result}; use tokio::sync::watch; use via_btc_client::{inscriber::Inscriber, traits::Serializable, types::InscriptionMessage}; use zksync_config::ViaBtcSenderConfig; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{Connection, ConnectionPool, Core, CoreDal}; -use zksync_types::{ProtocolVersionId, H256}; +use zksync_types::ProtocolVersionId; use crate::aggregator::ViaAggregator; @@ -66,12 +64,12 @@ impl ViaBtcInscriptionAggregator { &mut self, storage: &mut Connection<'_, Core>, ) -> Result<(), anyhow::Error> { - let base_system_contracts_hashes = BaseSystemContractsHashes { - bootloader: self.get_bootloader_code_hash().await?, - default_aa: self.get_aa_code_hash().await?, - }; let protocol_version_id = self.get_protocol_version_id().await?; + let base_system_contracts_hashes = self + .load_base_system_contracts(storage, protocol_version_id) + .await?; + if let Some(operation) = self .aggregator .get_next_ready_operation(storage, base_system_contracts_hashes, protocol_version_id) @@ -122,19 +120,28 @@ impl ViaBtcInscriptionAggregator { Ok(()) } - // Todo: call indexer to fetch the data - async fn get_bootloader_code_hash(&self) -> anyhow::Result { - let hex_str = "010008e74e40a94b1c6e6eb5a1dfbbdbd9eb9e0ec90fd358d29e8c07c30d8491"; - Ok(H256::from_str(hex_str).unwrap()) - } - - // Todo: call indexer to fetch the data - async fn get_aa_code_hash(&self) -> anyhow::Result { - let hex_str = "01000563426437b886b132bf5bcf9b0d98c3648f02a6e362893db4345078d09f"; - Ok(H256::from_str(hex_str).unwrap()) + async fn load_base_system_contracts( + &self, + storage: &mut Connection<'_, Core>, + protocol_version: ProtocolVersionId, + ) -> anyhow::Result { + let base_system_contracts = storage + .protocol_versions_dal() + .load_base_system_contracts_by_version_id(protocol_version as u16) + .await + .context("failed loading base system contracts")?; + if let Some(contracts) = base_system_contracts { + return Ok(BaseSystemContractsHashes { + bootloader: contracts.bootloader.hash, + default_aa: contracts.default_aa.hash, + }); + } + anyhow::bail!( + "Failed to load the base system contracts for version {}", + protocol_version + ) } - // Todo: call indexer to fetch the data async fn get_protocol_version_id(&self) -> anyhow::Result { Ok(ProtocolVersionId::latest()) } From 5a971cdbf87659ad42b524b17c2482b7a2bc4180 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 6 Feb 2025 13:52:24 +0330 Subject: [PATCH 204/212] fix clippy warning --- via_verifier/lib/verifier_dal/src/via_votes_dal.rs | 2 +- .../node/withdrawal_service/src/coordinator/api_impl.rs | 2 +- via_verifier/node/withdrawal_service/src/verifier/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs index 83d132d94..489ba362e 100644 --- a/via_verifier/lib/verifier_dal/src/via_votes_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_votes_dal.rs @@ -311,7 +311,7 @@ impl ViaVotesDal<'_, '_> { l1_batch_number ) .instrument("get_finalized_block_and_non_processed_withdrawal") - .fetch_optional(&mut self.storage) // Use fetch_optional to handle None results + .fetch_optional(self.storage) // Use fetch_optional to handle None results .await?; // Map the result into the desired output format diff --git a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs index a15684f90..64e241fab 100644 --- a/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs +++ b/via_verifier/node/withdrawal_service/src/coordinator/api_impl.rs @@ -87,7 +87,7 @@ impl RestApi { .context("Error to get withdrawals from DA")?; if !withdrawals.is_empty() { - proof_txid = h256_to_txid(&proof_tx_id).context("Invalid proof tx id")?; + proof_txid = h256_to_txid(proof_tx_id).context("Invalid proof tx id")?; l1_block_number = *block_number; withdrawals_to_process = withdrawals; tracing::info!( diff --git a/via_verifier/node/withdrawal_service/src/verifier/mod.rs b/via_verifier/node/withdrawal_service/src/verifier/mod.rs index 5ba261a02..51e978fcb 100644 --- a/via_verifier/node/withdrawal_service/src/verifier/mod.rs +++ b/via_verifier/node/withdrawal_service/src/verifier/mod.rs @@ -224,13 +224,13 @@ impl ViaWithdrawalVerifier { .await? { if !self - ._verify_withdrawals(&session, &blob_id, proof_tx_id) + ._verify_withdrawals(session, &blob_id, proof_tx_id) .await? { return Ok(false); } - return self._verify_sighash(&session).await; + return self._verify_sighash(session).await; } Ok(false) } From 9418ce9d604c17572bb6bf1552fe2f162c5249b9 Mon Sep 17 00:00:00 2001 From: Hamid Bateni Date: Thu, 6 Feb 2025 17:07:25 +0330 Subject: [PATCH 205/212] exlude withdrawal change utxo from bridge transaction --- core/lib/via_btc_client/src/indexer/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index dedb4a700..f05cf418f 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -208,9 +208,22 @@ impl BitcoinInscriptionIndexer { let bridge_txs: Vec = transactions .iter() .filter(|tx| { + // Check if bridge address is in outputs (deposit destination) tx.output.iter().any(|output| { let script_pubkey = &output.script_pubkey; script_pubkey == &self.bridge_address.script_pubkey() + }) && !tx.output.iter().any(|output| { + if output.script_pubkey.is_op_return() { + // Extract OP_RETURN data + if let Some(op_return_data) = output.script_pubkey.as_bytes().get(2..) { + // Return true if it starts with withdrawal prefix (which will be negated) + op_return_data.starts_with(b"VIA_PROTOCOL:WITHDRAWAL") + } else { + false + } + } else { + false // Not an OP_RETURN output + } }) }) .cloned() From d67826a4c1130a54483940eb3e7afbf2440d3c6a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:22:06 +0100 Subject: [PATCH 206/212] feat: create a new crate via_da_client and move the logic related to da from the via_withdrawal_client --- Cargo.lock | 16 ++++++++++++-- Cargo.toml | 2 ++ via_verifier/lib/via_da_client/Cargo.toml | 22 +++++++++++++++++++ via_verifier/lib/via_da_client/src/lib.rs | 2 ++ .../src/pubdata.rs | 0 .../src/types.rs | 5 ++++- .../lib/via_withdrawal_client/Cargo.toml | 3 +-- .../lib/via_withdrawal_client/src/client.rs | 10 ++++----- .../lib/via_withdrawal_client/src/lib.rs | 2 -- .../lib/via_withdrawal_client/src/withdraw.rs | 3 +-- 10 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 via_verifier/lib/via_da_client/Cargo.toml create mode 100644 via_verifier/lib/via_da_client/src/lib.rs rename via_verifier/lib/{via_withdrawal_client => via_da_client}/src/pubdata.rs (100%) rename via_verifier/lib/{via_withdrawal_client => via_da_client}/src/types.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index b63481a5c..cb1164f74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9526,6 +9526,18 @@ dependencies = [ "zksync_types", ] +[[package]] +name = "via_da_client" +version = "0.1.0" +dependencies = [ + "anyhow", + "byteorder", + "hex", + "rand 0.8.5", + "zksync_types", + "zksync_utils", +] + [[package]] name = "via_da_clients" version = "0.1.0" @@ -9780,14 +9792,13 @@ version = "0.1.0" dependencies = [ "anyhow", "bitcoin", - "byteorder", "dotenv", "hex", - "rand 0.8.5", "tokio", "tracing", "tracing-subscriber", "via_btc_client", + "via_da_client", "via_da_clients", "zksync_basic_types", "zksync_config", @@ -9841,6 +9852,7 @@ dependencies = [ "tokio", "tracing", "via_btc_client", + "via_da_client", "via_verification", "via_verifier_dal", "vise", diff --git a/Cargo.toml b/Cargo.toml index 16911706c..b2ff737b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "via_verifier/node/via_zk_verifier", "via_verifier/node/via_btc_watch", "via_verifier/node/via_btc_sender", + "via_verifier/lib/via_da_client", ] resolver = "2" @@ -339,6 +340,7 @@ via_withdrawal_client = { version = "0.1.0", path = "via_verifier/lib/via_withdr via_verification = { version = "0.1.0", path = "via_verifier/lib/via_verification" } via_musig2 = { version = "0.1.0", path = "via_verifier/lib/via_musig2" } via_verifier_dal = { version = "0.1.0", path = "via_verifier/lib/verifier_dal" } +via_da_client = { version = "0.1.0", path = "via_verifier/lib/via_da_client" } via_withdrawal_service = { version = "0.1.0", path = "via_verifier/node/withdrawal_service" } via_zk_verifier = { version = "0.1.0", path = "via_verifier/node/via_zk_verifier" } via_verifier_btc_watch = { version = "0.1.0", path = "via_verifier/node/via_btc_watch" } diff --git a/via_verifier/lib/via_da_client/Cargo.toml b/via_verifier/lib/via_da_client/Cargo.toml new file mode 100644 index 000000000..002b9dce6 --- /dev/null +++ b/via_verifier/lib/via_da_client/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "via_da_client" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +anyhow.workspace = true +zksync_types.workspace = true +zksync_utils.workspace = true + +byteorder = "1.4" + +[dev-dependencies] +hex.workspace = true +rand = "0.8" + diff --git a/via_verifier/lib/via_da_client/src/lib.rs b/via_verifier/lib/via_da_client/src/lib.rs new file mode 100644 index 000000000..a3715fa02 --- /dev/null +++ b/via_verifier/lib/via_da_client/src/lib.rs @@ -0,0 +1,2 @@ +pub mod pubdata; +pub mod types; diff --git a/via_verifier/lib/via_withdrawal_client/src/pubdata.rs b/via_verifier/lib/via_da_client/src/pubdata.rs similarity index 100% rename from via_verifier/lib/via_withdrawal_client/src/pubdata.rs rename to via_verifier/lib/via_da_client/src/pubdata.rs diff --git a/via_verifier/lib/via_withdrawal_client/src/types.rs b/via_verifier/lib/via_da_client/src/types.rs similarity index 96% rename from via_verifier/lib/via_withdrawal_client/src/types.rs rename to via_verifier/lib/via_da_client/src/types.rs index 056572d2b..310d6cfec 100644 --- a/via_verifier/lib/via_withdrawal_client/src/types.rs +++ b/via_verifier/lib/via_da_client/src/types.rs @@ -8,9 +8,12 @@ use zksync_utils::{u256_to_bytes_be, u256_to_h256}; /// The function selector used in L2 to compute the message. pub const WITHDRAW_FUNC_SIG: &str = "finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[])"; -/// The L2 system bridge address. +/// The L2 BaseToken address. pub const L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR: &str = "000000000000000000000000000000000000800a"; +/// The L2 Bootloader address. +pub const L2_BOOTLOADER_CONTRACT_ADDR: &str = "0x0000000000000000000000000000000000008001"; + #[derive(Clone, Debug, Default)] #[allow(unused)] pub struct L2BridgeLogMetadata { diff --git a/via_verifier/lib/via_withdrawal_client/Cargo.toml b/via_verifier/lib/via_withdrawal_client/Cargo.toml index 63c0d161e..8325e43d7 100644 --- a/via_verifier/lib/via_withdrawal_client/Cargo.toml +++ b/via_verifier/lib/via_withdrawal_client/Cargo.toml @@ -21,12 +21,11 @@ tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true via_btc_client.workspace = true +via_da_client.workspace = true bitcoin = { version = "0.32.2", features = ["serde"] } -byteorder = "1.4" [dev-dependencies] -rand = "0.8" zksync_dal.workspace = true dotenv = "0.15" via_da_clients.workspace = true diff --git a/via_verifier/lib/via_withdrawal_client/src/client.rs b/via_verifier/lib/via_withdrawal_client/src/client.rs index cdb8bc465..cd052f083 100644 --- a/via_verifier/lib/via_withdrawal_client/src/client.rs +++ b/via_verifier/lib/via_withdrawal_client/src/client.rs @@ -2,14 +2,14 @@ use std::{collections::HashMap, str::FromStr}; use bitcoin::Network; use via_btc_client::withdrawal_builder::WithdrawalRequest; -use zksync_da_client::DataAvailabilityClient; -use zksync_types::{web3::keccak256, H160, H256}; - -use crate::{ +use via_da_client::{ pubdata::Pubdata, types::{L2BridgeLogMetadata, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR}, - withdraw::parse_l2_withdrawal_message, }; +use zksync_da_client::DataAvailabilityClient; +use zksync_types::{web3::keccak256, H160, H256}; + +use crate::withdraw::parse_l2_withdrawal_message; #[derive(Debug)] pub struct WithdrawalClient { diff --git a/via_verifier/lib/via_withdrawal_client/src/lib.rs b/via_verifier/lib/via_withdrawal_client/src/lib.rs index 32c497ef9..6b131403c 100644 --- a/via_verifier/lib/via_withdrawal_client/src/lib.rs +++ b/via_verifier/lib/via_withdrawal_client/src/lib.rs @@ -1,4 +1,2 @@ pub mod client; -mod pubdata; -mod types; mod withdraw; diff --git a/via_verifier/lib/via_withdrawal_client/src/withdraw.rs b/via_verifier/lib/via_withdrawal_client/src/withdraw.rs index 1a1efc876..92cf2f5fc 100644 --- a/via_verifier/lib/via_withdrawal_client/src/withdraw.rs +++ b/via_verifier/lib/via_withdrawal_client/src/withdraw.rs @@ -3,10 +3,9 @@ use std::str::FromStr; use anyhow::Context; use bitcoin::{Address as BitcoinAddress, Amount, Network}; use via_btc_client::withdrawal_builder::WithdrawalRequest; +use via_da_client::types::WITHDRAW_FUNC_SIG; use zksync_basic_types::{web3::keccak256, U256}; -use crate::types::WITHDRAW_FUNC_SIG; - pub fn parse_l2_withdrawal_message( l2_to_l1_message: Vec, network: Network, From e0a3dc333d9561db1eee0c9e9c805fa4a1f7c28a Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:23:03 +0100 Subject: [PATCH 207/212] feat: create a new transactions dal to track the users deposits from l1 to l2 --- ...9af0ee65e54b44c06733619afbaec6f1ec71e.json | 15 +++ ...d3b6e872a4de3cf8b70dafff15fee74207480.json | 22 +++ ...037973bb9a631bdf5503f0e4dc8201b0bfdf2.json | 19 +++ ...34c78fcf487984d098ef103bb228a787e6e2e.json | 20 +++ ...f5f2c1e476cdcbcca9a61c1af5f0234fc22a5.json | 22 +++ ...07164238_via_add_transactions_dal.down.sql | 1 + ...0207164238_via_add_transactions_dal.up.sql | 14 ++ via_verifier/lib/verifier_dal/src/lib.rs | 6 + .../verifier_dal/src/via_transactions_dal.rs | 126 ++++++++++++++++++ 9 files changed, 245 insertions(+) create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-ea3062d8c4eb8f234ba6fbc145734c78fcf487984d098ef103bb228a787e6e2e.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-ed6c76995db0b440fcce87a2acdf5f2c1e476cdcbcca9a61c1af5f0234fc22a5.json create mode 100644 via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.down.sql create mode 100644 via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.up.sql create mode 100644 via_verifier/lib/verifier_dal/src/via_transactions_dal.rs diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json b/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json new file mode 100644 index 000000000..5a0c60da0 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_transactions SET \n status = $2\n WHERE\n canonical_tx_hash = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json b/via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json new file mode 100644 index 000000000..d7235694d --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n canonical_tx_hash\n FROM\n via_transactions\n WHERE\n status IS NULL\n ORDER BY priority_id ASC\n LIMIT $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "canonical_tx_hash", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json b/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json new file mode 100644 index 000000000..3cba103f7 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_transactions (\n priority_id,\n tx_id,\n receiver,\n value,\n calldata,\n canonical_tx_hash\n )\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Varchar", + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-ea3062d8c4eb8f234ba6fbc145734c78fcf487984d098ef103bb228a787e6e2e.json b/via_verifier/lib/verifier_dal/.sqlx/query-ea3062d8c4eb8f234ba6fbc145734c78fcf487984d098ef103bb228a787e6e2e.json new file mode 100644 index 000000000..9f36c543c --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-ea3062d8c4eb8f234ba6fbc145734c78fcf487984d098ef103bb228a787e6e2e.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT COUNT(priority_id) as priority_id FROM via_transactions;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "priority_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "ea3062d8c4eb8f234ba6fbc145734c78fcf487984d098ef103bb228a787e6e2e" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-ed6c76995db0b440fcce87a2acdf5f2c1e476cdcbcca9a61c1af5f0234fc22a5.json b/via_verifier/lib/verifier_dal/.sqlx/query-ed6c76995db0b440fcce87a2acdf5f2c1e476cdcbcca9a61c1af5f0234fc22a5.json new file mode 100644 index 000000000..24761a046 --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-ed6c76995db0b440fcce87a2acdf5f2c1e476cdcbcca9a61c1af5f0234fc22a5.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n 1 AS cnt\n FROM\n via_transactions\n WHERE\n tx_id = $1\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "cnt", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + null + ] + }, + "hash": "ed6c76995db0b440fcce87a2acdf5f2c1e476cdcbcca9a61c1af5f0234fc22a5" +} diff --git a/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.down.sql b/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.down.sql new file mode 100644 index 000000000..40028abab --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS via_transactions; \ No newline at end of file diff --git a/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.up.sql b/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.up.sql new file mode 100644 index 000000000..7d3c82c0c --- /dev/null +++ b/via_verifier/lib/verifier_dal/migrations/20250207164238_via_add_transactions_dal.up.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS via_transactions ( + "priority_id" BIGINT NOT NULL, + "tx_id" BYTEA NOT NULL, + "receiver" VARCHAR NOT NULL, + "value" BIGINT NOT NULL, + "calldata" BYTEA, + "canonical_tx_hash" BYTEA NOT NULL, + "status" BOOLEAN, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW(), + PRIMARY KEY (tx_id) +); + +CREATE INDEX idx_via_transactions_priority ON via_transactions(priority_id); diff --git a/via_verifier/lib/verifier_dal/src/lib.rs b/via_verifier/lib/verifier_dal/src/lib.rs index c5ee81787..e7806acd7 100644 --- a/via_verifier/lib/verifier_dal/src/lib.rs +++ b/via_verifier/lib/verifier_dal/src/lib.rs @@ -4,6 +4,7 @@ #![warn(clippy::cast_lossless)] pub use sqlx::{types::BigDecimal, Error as SqlxError}; +use via_transactions_dal::ViaTransactionsDal; use zksync_db_connection::connection::DbMarker; pub use zksync_db_connection::{ connection::{Connection, IsolationLevel}, @@ -18,6 +19,7 @@ use crate::{ pub mod models; pub mod via_blocks_dal; pub mod via_btc_sender_dal; +pub mod via_transactions_dal; pub mod via_votes_dal; #[cfg(test)] @@ -37,6 +39,7 @@ where fn via_votes_dal(&mut self) -> ViaVotesDal<'_, 'a>; fn via_btc_sender_dal(&mut self) -> ViaBtcSenderDal<'_, 'a>; fn via_block_dal(&mut self) -> ViaBlocksDal<'_, 'a>; + fn via_transactions_dal(&mut self) -> ViaTransactionsDal<'_, 'a>; } #[derive(Clone, Debug)] @@ -58,4 +61,7 @@ impl<'a> VerifierDal<'a> for Connection<'a, Verifier> { fn via_block_dal(&mut self) -> ViaBlocksDal<'_, 'a> { ViaBlocksDal { storage: self } } + fn via_transactions_dal(&mut self) -> ViaTransactionsDal<'_, 'a> { + ViaTransactionsDal { storage: self } + } } diff --git a/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs new file mode 100644 index 000000000..cdd942a97 --- /dev/null +++ b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs @@ -0,0 +1,126 @@ +use zksync_db_connection::{connection::Connection, error::DalResult, instrument::InstrumentExt}; +use zksync_types::H256; + +use crate::Verifier; + +#[derive(Debug)] +pub struct ViaTransactionsDal<'a, 'c> { + pub(crate) storage: &'a mut Connection<'c, Verifier>, +} + +impl ViaTransactionsDal<'_, '_> { + pub async fn insert_transaction( + &mut self, + priority_id: i64, + tx_id: H256, + receiver: String, + value: i64, + calldata: Vec, + canonical_tx_hash: H256, + ) -> DalResult<()> { + sqlx::query!( + r#" + INSERT INTO + via_transactions (priority_id, tx_id, receiver, value, calldata, canonical_tx_hash) + VALUES + ($1, $2, $3, $4, $5, $6) + ON CONFLICT (tx_id) DO NOTHING + "#, + priority_id, + tx_id.as_bytes(), + receiver, + value, + calldata, + canonical_tx_hash.as_bytes(), + ) + .instrument("insert_transaction") + .fetch_optional(self.storage) + .await?; + + Ok(()) + } + + pub async fn get_last_priority_id(&mut self) -> DalResult { + let priority_id = sqlx::query_scalar!( + r#" + SELECT COUNT(priority_id) as priority_id FROM via_transactions; + "# + ) + .instrument("get_last_priority_id") + .fetch_one(self.storage) + .await?; + + Ok(priority_id.unwrap_or(0)) + } + + pub async fn list_transactions_not_processed(&mut self, limit: i64) -> DalResult>> { + let rows = sqlx::query!( + r#" + SELECT + canonical_tx_hash + FROM + via_transactions + WHERE + status IS NULL + ORDER BY + priority_id ASC + LIMIT + $1 + "#, + limit + ) + .instrument("list_transactions") + .fetch_all(self.storage) + .await?; + + let mut canonical_tx_hashs: Vec> = Vec::with_capacity(rows.len()); + for row in rows { + canonical_tx_hashs.push(row.canonical_tx_hash); + } + Ok(canonical_tx_hashs) + } + + pub async fn update_transaction( + &mut self, + canonical_tx_hash: &H256, + status: bool, + ) -> DalResult<()> { + sqlx::query!( + r#" + UPDATE via_transactions + SET + status = $2 + WHERE + canonical_tx_hash = $1 + "#, + canonical_tx_hash.as_bytes(), + status + ) + .instrument("update_transaction") + .fetch_optional(self.storage) + .await?; + + Ok(()) + } + + pub async fn transaction_exists_with_txid(&mut self, tx_id: &H256) -> DalResult { + let exists = sqlx::query!( + r#" + SELECT + 1 AS cnt + FROM + via_transactions + WHERE + tx_id = $1 + LIMIT + 1 + "#, + tx_id.as_bytes(), + ) + .instrument("transaction_exists_with_txid") + .fetch_optional(self.storage) + .await?; + + Ok(exists.is_some()) + } +} From e59c38d7b03aa5f0e868e4bf3560abd69c247d3f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:23:59 +0100 Subject: [PATCH 208/212] feat: index the l1 to l2 deposits by the verifier --- via_verifier/node/via_btc_watch/src/lib.rs | 12 +- .../src/message_processors/l1_to_l2.rs | 205 ++++++++++++++++++ .../src/message_processors/mod.rs | 2 + .../node/via_btc_watch/src/metrics.rs | 10 + 4 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 via_verifier/node/via_btc_watch/src/message_processors/l1_to_l2.rs diff --git a/via_verifier/node/via_btc_watch/src/lib.rs b/via_verifier/node/via_btc_watch/src/lib.rs index 42f05a838..014d55873 100644 --- a/via_verifier/node/via_btc_watch/src/lib.rs +++ b/via_verifier/node/via_btc_watch/src/lib.rs @@ -18,7 +18,10 @@ use self::{ message_processors::{MessageProcessor, MessageProcessorError}, metrics::METRICS, }; -use crate::{message_processors::VerifierMessageProcessor, metrics::ErrorType}; +use crate::{ + message_processors::{L1ToL2MessageProcessor, VerifierMessageProcessor}, + metrics::ErrorType, +}; const DEFAULT_VOTING_THRESHOLD: f64 = 0.5; @@ -60,9 +63,10 @@ impl VerifierBtcWatch { assert_eq!(actor_role, &ActorRole::Verifier); - let message_processors: Vec> = vec![Box::new( - VerifierMessageProcessor::new(DEFAULT_VOTING_THRESHOLD), - )]; + let message_processors: Vec> = vec![ + Box::new(L1ToL2MessageProcessor::new(indexer.get_state().0)), + Box::new(VerifierMessageProcessor::new(DEFAULT_VOTING_THRESHOLD)), + ]; let confirmations_for_btc_msg = confirmations_for_btc_msg.unwrap_or(0); diff --git a/via_verifier/node/via_btc_watch/src/message_processors/l1_to_l2.rs b/via_verifier/node/via_btc_watch/src/message_processors/l1_to_l2.rs new file mode 100644 index 000000000..9c784867e --- /dev/null +++ b/via_verifier/node/via_btc_watch/src/message_processors/l1_to_l2.rs @@ -0,0 +1,205 @@ +use via_btc_client::{ + indexer::BitcoinInscriptionIndexer, + types::{BitcoinAddress, FullInscriptionMessage, L1ToL2Message}, +}; +use via_verifier_dal::{Connection, Verifier, VerifierDal}; +use zksync_types::{ + abi::L2CanonicalTransaction, + ethabi::Address, + helpers::unix_timestamp_ms, + l1::{L1Tx, OpProcessingType, PriorityQueueType}, + Execute, L1TxCommonData, PriorityOpId, H256, PRIORITY_OPERATION_L2_TX_TYPE, U256, +}; + +use crate::{ + message_processors::{MessageProcessor, MessageProcessorError}, + metrics::{ErrorType, InscriptionStage, METRICS}, +}; + +#[derive(Debug)] +pub struct L1ToL2Transaction { + priority_id: i64, + tx_id: H256, + receiver: Address, + value: i64, + calldata: Vec, + canonical_tx_hash: H256, +} + +#[derive(Debug)] +pub struct L1ToL2MessageProcessor { + bridge_address: BitcoinAddress, +} + +impl L1ToL2MessageProcessor { + pub fn new(bridge_address: BitcoinAddress) -> Self { + Self { bridge_address } + } +} + +#[async_trait::async_trait] +impl MessageProcessor for L1ToL2MessageProcessor { + async fn process_messages( + &mut self, + storage: &mut Connection<'_, Verifier>, + msgs: Vec, + _: &mut BitcoinInscriptionIndexer, + ) -> Result<(), MessageProcessorError> { + let mut priority_ops = Vec::new(); + let last_priority_id = storage + .via_transactions_dal() + .get_last_priority_id() + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))?; + let mut next_expected_priority_id = PriorityOpId::from(last_priority_id as u64); + + for msg in msgs { + if let FullInscriptionMessage::L1ToL2Message(l1_to_l2_msg) = msg { + if l1_to_l2_msg + .tx_outputs + .iter() + .any(|output| output.script_pubkey == self.bridge_address.script_pubkey()) + { + let mut tx_id_bytes = l1_to_l2_msg.common.tx_id.as_raw_hash()[..].to_vec(); + tx_id_bytes.reverse(); + let tx_id = H256::from_slice(&tx_id_bytes); + + if storage + .via_transactions_dal() + .transaction_exists_with_txid(&tx_id) + .await + .map_err(|e| MessageProcessorError::DatabaseError(e.to_string()))? + { + tracing::debug!( + "Transaction with tx_id {} already processed, skipping", + tx_id + ); + continue; + } + let serial_id = next_expected_priority_id; + let l1_tx = self.create_l1_tx_from_message(tx_id, serial_id, &l1_to_l2_msg)?; + priority_ops.push(l1_tx); + next_expected_priority_id = next_expected_priority_id.next(); + } + } + } + + if priority_ops.is_empty() { + return Ok(()); + } + + for new_op in priority_ops { + METRICS.inscriptions_processed[&InscriptionStage::Deposit].inc(); + storage + .via_transactions_dal() + .insert_transaction( + new_op.priority_id, + new_op.tx_id, + new_op.receiver.to_string(), + new_op.value, + new_op.calldata, + new_op.canonical_tx_hash, + ) + .await + .map_err(|e| { + METRICS.errors[&ErrorType::DatabaseError].inc(); + MessageProcessorError::DatabaseError(e.to_string()) + })?; + } + + Ok(()) + } +} + +impl L1ToL2MessageProcessor { + fn create_l1_tx_from_message( + &self, + tx_id: H256, + serial_id: PriorityOpId, + msg: &L1ToL2Message, + ) -> Result { + let amount = msg.amount.to_sat() as i64; + let eth_address_l2 = msg.input.receiver_l2_address; + let calldata = msg.input.call_data.clone(); + + let mantissa = U256::from(10_000_000_000u64); // Eth 18 decimals - BTC 8 decimals + let value = U256::from(amount) * mantissa; + let max_fee_per_gas = U256::from(100_000_000u64); + let gas_limit = U256::from(1_000_000u64); + let gas_per_pubdata_limit = U256::from(800u64); + + let mut l1_tx = L1Tx { + execute: Execute { + contract_address: eth_address_l2, + calldata: calldata.clone(), + value: U256::zero(), + factory_deps: vec![], + }, + common_data: L1TxCommonData { + sender: eth_address_l2, + serial_id, + layer_2_tip_fee: U256::zero(), + full_fee: U256::zero(), + max_fee_per_gas, + gas_limit, + gas_per_pubdata_limit, + op_processing_type: OpProcessingType::Common, + priority_queue_type: PriorityQueueType::Deque, + canonical_tx_hash: H256::zero(), + to_mint: value, + refund_recipient: eth_address_l2, + eth_block: msg.common.block_height as u64, + }, + received_timestamp_ms: unix_timestamp_ms(), + }; + + let l2_transaction = L2CanonicalTransaction { + tx_type: PRIORITY_OPERATION_L2_TX_TYPE.into(), + from: address_to_u256(&l1_tx.common_data.sender), + to: address_to_u256(&l1_tx.execute.contract_address), + gas_limit: l1_tx.common_data.gas_limit, + gas_per_pubdata_byte_limit: l1_tx.common_data.gas_per_pubdata_limit, + max_fee_per_gas: l1_tx.common_data.max_fee_per_gas, + max_priority_fee_per_gas: U256::zero(), + paymaster: U256::zero(), + nonce: l1_tx.common_data.serial_id.0.into(), + value: l1_tx.execute.value, + reserved: [ + l1_tx.common_data.to_mint, + address_to_u256(&l1_tx.common_data.refund_recipient), + U256::zero(), + U256::zero(), + ], + data: l1_tx.execute.calldata.clone(), + signature: vec![], + factory_deps: vec![], + paymaster_input: vec![], + reserved_dynamic: vec![], + }; + + let canonical_tx_hash = l2_transaction.hash(); + + l1_tx.common_data.canonical_tx_hash = canonical_tx_hash; + + tracing::info!( + "Created L1 transaction with serial id {:?} (block {}) with deposit amount {} and tx hash {}", + l1_tx.common_data.serial_id, + l1_tx.common_data.eth_block, + amount, + l1_tx.common_data.canonical_tx_hash, + ); + + Ok(L1ToL2Transaction { + priority_id: serial_id.0 as i64, + tx_id, + receiver: eth_address_l2, + value: amount, + calldata, + canonical_tx_hash: l1_tx.common_data.canonical_tx_hash, + }) + } +} + +fn address_to_u256(address: &Address) -> U256 { + U256::from_big_endian(&address.0) +} diff --git a/via_verifier/node/via_btc_watch/src/message_processors/mod.rs b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs index 7e3e297ba..2e38a9801 100644 --- a/via_verifier/node/via_btc_watch/src/message_processors/mod.rs +++ b/via_verifier/node/via_btc_watch/src/message_processors/mod.rs @@ -1,3 +1,4 @@ +pub(crate) use l1_to_l2::L1ToL2MessageProcessor; pub(crate) use verifier::VerifierMessageProcessor; use via_btc_client::{ indexer::BitcoinInscriptionIndexer, @@ -6,6 +7,7 @@ use via_btc_client::{ use via_verifier_dal::{Connection, Verifier}; use zksync_types::H256; +mod l1_to_l2; mod verifier; #[derive(Debug, thiserror::Error)] diff --git a/via_verifier/node/via_btc_watch/src/metrics.rs b/via_verifier/node/via_btc_watch/src/metrics.rs index 1d37c8e82..e7174fb2f 100644 --- a/via_verifier/node/via_btc_watch/src/metrics.rs +++ b/via_verifier/node/via_btc_watch/src/metrics.rs @@ -1,9 +1,16 @@ use vise::{Counter, EncodeLabelSet, EncodeLabelValue, Family, Metrics}; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] +#[metrics(label = "stage", rename_all = "snake_case")] +pub enum InscriptionStage { + Deposit, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] #[metrics(label = "error_type", rename_all = "snake_case")] pub enum ErrorType { InternalError, + DatabaseError, } #[derive(Debug, Metrics)] @@ -12,6 +19,9 @@ pub struct ViaVerifierBtcWatcherMetrics { /// Number of times Bitcoin was polled. pub btc_poll: Counter, + /// Number of inscriptions processed, labeled by type. + pub inscriptions_processed: Family, + /// Number of errors encountered, labeled by error type. pub errors: Family, } From 6fedb9d04265c84e55aaddd5af790a3cdb07dc1f Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:24:25 +0100 Subject: [PATCH 209/212] feat: add verify op priority id --- via_verifier/node/via_zk_verifier/Cargo.toml | 1 + via_verifier/node/via_zk_verifier/src/lib.rs | 82 +++++++++++++++++--- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/via_verifier/node/via_zk_verifier/Cargo.toml b/via_verifier/node/via_zk_verifier/Cargo.toml index 9a9e8ba44..cead363a8 100644 --- a/via_verifier/node/via_zk_verifier/Cargo.toml +++ b/via_verifier/node/via_zk_verifier/Cargo.toml @@ -19,6 +19,7 @@ zksync_types.workspace = true zksync_config.workspace = true zksync_da_client.workspace = true zksync_prover_interface.workspace = true +via_da_client.workspace = true tokio.workspace = true anyhow.workspace = true diff --git a/via_verifier/node/via_zk_verifier/src/lib.rs b/via_verifier/node/via_zk_verifier/src/lib.rs index 189cc2302..750c61330 100644 --- a/via_verifier/node/via_zk_verifier/src/lib.rs +++ b/via_verifier/node/via_zk_verifier/src/lib.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use anyhow::Context; use serde::{Deserialize, Serialize}; use tokio::sync::watch; @@ -9,6 +11,7 @@ use via_btc_client::{ }, utils::bytes_to_txid, }; +use via_da_client::{pubdata::Pubdata, types::L2_BOOTLOADER_CONTRACT_ADDR}; use via_verification::proof::{ Bn256, ProofTrait, ViaZKProof, ZkSyncProof, ZkSyncSnarkWrapperCircuit, }; @@ -16,7 +19,7 @@ use via_verifier_dal::{Connection, ConnectionPool, Verifier, VerifierDal}; use zksync_config::ViaVerifierConfig; use zksync_da_client::{types::InclusionData, DataAvailabilityClient}; use zksync_types::{ - commitment::L1BatchWithMetadata, protocol_version::ProtocolSemanticVersion, H256, + commitment::L1BatchWithMetadata, protocol_version::ProtocolSemanticVersion, H160, H256, }; /// Copy of `zksync_l1_contract_interface::i_executor::methods::ProveBatches` @@ -123,12 +126,21 @@ impl ViaVerifier { } }; + tracing::info!( + "Fetch l1 batch pubdata for blob id {}", + batch_da.input.blob_id + ); + let (batch_blob, batch_hash) = self.process_batch_da_reference(batch_da).await?; - let is_verified = self - .verify_proof(batch_hash, &proof_blob.data, &batch_blob.data) + let mut is_verified = self + .verify_op_priority_id(storage, l1_batch_number, &batch_blob.data) .await?; + if is_verified { + is_verified = self.verify_proof(batch_hash, &proof_blob.data).await?; + } + storage .via_votes_dal() .verify_votable_transaction(l1_batch_number as u32, db_raw_tx_id, is_verified) @@ -138,6 +150,62 @@ impl ViaVerifier { Ok(()) } + pub async fn verify_op_priority_id( + &mut self, + storage: &mut Connection<'_, Verifier>, + l1_batch_number: i64, + pubdata: &[u8], + ) -> anyhow::Result { + let pubdata = Pubdata::decode_pubdata(pubdata.to_vec())?; + let mut deposit_logs = Vec::new(); + + for log in &pubdata.user_logs { + if log.sender == H160::from_str(L2_BOOTLOADER_CONTRACT_ADDR)? { + deposit_logs.push(log); + } + } + + let txs = storage + .via_transactions_dal() + .list_transactions_not_processed(deposit_logs.len() as i64) + .await?; + + if txs.len() != deposit_logs.len() { + tracing::error!( + "Verifier did not index all the deposits, expected {} found {}", + deposit_logs.len(), + txs.len() + ); + return Ok(false); + } + + if txs.is_empty() { + tracing::error!("There is no transactions to validate the op priority id",); + return Ok(true); + } + + for (i, raw_tx_id) in txs.iter().enumerate() { + let db_raw_tx_id = H256::from_slice(&raw_tx_id); + let log_raw_tx_id = deposit_logs[i].key; + if &db_raw_tx_id == &log_raw_tx_id { + let status = deposit_logs[i].value.is_zero(); + storage + .via_transactions_dal() + .update_transaction(&log_raw_tx_id, !status) + .await?; + continue; + } + tracing::error!("Sequencer did not process the deposit transactions in series for l1 batch {}, invalid priority id for transaction hash {}", l1_batch_number, db_raw_tx_id); + return Ok(false); + } + tracing::info!( + "Priority_id verified successfuly for l1 batch {}", + l1_batch_number + ); + + Ok(true) + } + /// Helper to ensure there's exactly one message in the array, or log an error. fn expect_single_msg<'a>( &self, @@ -185,16 +253,10 @@ impl ViaVerifier { Ok((blob, hash)) } - async fn verify_proof( - &self, - batch_hash: H256, - proof_bytes: &[u8], - batch_bytes: &[u8], - ) -> anyhow::Result { + async fn verify_proof(&self, batch_hash: H256, proof_bytes: &[u8]) -> anyhow::Result { tracing::info!( ?batch_hash, proof_len = proof_bytes.len(), - batch_len = batch_bytes.len(), "Verifying proof" ); let proof_data: ProveBatches = bincode::deserialize(proof_bytes)?; From c14467bdb44b15feed17c3fe6a500720d75769ea Mon Sep 17 00:00:00 2001 From: 0xatomFusion Date: Fri, 14 Feb 2025 09:07:09 +0100 Subject: [PATCH 210/212] Update via_verifier/lib/verifier_dal/src/via_transactions_dal.rs Co-authored-by: mpavlovic-txfusion <117362780+mpavlovic-txfusion@users.noreply.github.com> --- via_verifier/lib/verifier_dal/src/via_transactions_dal.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs index cdd942a97..b4e0f5492 100644 --- a/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs @@ -73,10 +73,10 @@ impl ViaTransactionsDal<'_, '_> { .fetch_all(self.storage) .await?; - let mut canonical_tx_hashs: Vec> = Vec::with_capacity(rows.len()); - for row in rows { - canonical_tx_hashs.push(row.canonical_tx_hash); - } + let canonical_tx_hashs: Vec> = rows + .into_iter() + .map(|row| row.canonical_tx_hash) + .collect(); Ok(canonical_tx_hashs) } From b05821512345329558002450f12bbc55cb9df8a6 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:02:53 +0100 Subject: [PATCH 211/212] chore: update the sqlx migration files --- ...dc773bf8e85190606d1b6f2203ce8b5aba2e.json} | 4 ++-- ...beeda15ca4daf5620896833c3cdd4c909a156.json | 19 +++++++++++++++++++ ...9af0ee65e54b44c06733619afbaec6f1ec71e.json | 15 --------------- ...037973bb9a631bdf5503f0e4dc8201b0bfdf2.json | 19 ------------------- ...024ec90890f94199b039933296c3f99ba63bf.json | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 36 deletions(-) rename via_verifier/lib/verifier_dal/.sqlx/{query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json => query-175807bfd3b6618ab60ede8cb56ddc773bf8e85190606d1b6f2203ce8b5aba2e.json} (74%) create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-1c5df79bec4f47dc94562f5d27fbeeda15ca4daf5620896833c3cdd4c909a156.json delete mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json delete mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json create mode 100644 via_verifier/lib/verifier_dal/.sqlx/query-c2f1e15f46b72570d02c7b8be08024ec90890f94199b039933296c3f99ba63bf.json diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json b/via_verifier/lib/verifier_dal/.sqlx/query-175807bfd3b6618ab60ede8cb56ddc773bf8e85190606d1b6f2203ce8b5aba2e.json similarity index 74% rename from via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json rename to via_verifier/lib/verifier_dal/.sqlx/query-175807bfd3b6618ab60ede8cb56ddc773bf8e85190606d1b6f2203ce8b5aba2e.json index d7235694d..df41de9be 100644 --- a/via_verifier/lib/verifier_dal/.sqlx/query-70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480.json +++ b/via_verifier/lib/verifier_dal/.sqlx/query-175807bfd3b6618ab60ede8cb56ddc773bf8e85190606d1b6f2203ce8b5aba2e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n canonical_tx_hash\n FROM\n via_transactions\n WHERE\n status IS NULL\n ORDER BY priority_id ASC\n LIMIT $1\n ", + "query": "\n SELECT\n canonical_tx_hash\n FROM\n via_transactions\n WHERE\n status IS NULL\n ORDER BY\n priority_id ASC\n LIMIT\n $1\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ false ] }, - "hash": "70cb5def2e99ba86b01fe5be7b2d3b6e872a4de3cf8b70dafff15fee74207480" + "hash": "175807bfd3b6618ab60ede8cb56ddc773bf8e85190606d1b6f2203ce8b5aba2e" } diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-1c5df79bec4f47dc94562f5d27fbeeda15ca4daf5620896833c3cdd4c909a156.json b/via_verifier/lib/verifier_dal/.sqlx/query-1c5df79bec4f47dc94562f5d27fbeeda15ca4daf5620896833c3cdd4c909a156.json new file mode 100644 index 000000000..1faa23e5d --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-1c5df79bec4f47dc94562f5d27fbeeda15ca4daf5620896833c3cdd4c909a156.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n via_transactions (priority_id, tx_id, receiver, value, calldata, canonical_tx_hash)\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (tx_id) DO NOTHING\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Bytea", + "Varchar", + "Int8", + "Bytea", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "1c5df79bec4f47dc94562f5d27fbeeda15ca4daf5620896833c3cdd4c909a156" +} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json b/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json deleted file mode 100644 index 5a0c60da0..000000000 --- a/via_verifier/lib/verifier_dal/.sqlx/query-5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE via_transactions SET \n status = $2\n WHERE\n canonical_tx_hash = $1\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "5a576095f5705891256b1ee1db09af0ee65e54b44c06733619afbaec6f1ec71e" -} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json b/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json deleted file mode 100644 index 3cba103f7..000000000 --- a/via_verifier/lib/verifier_dal/.sqlx/query-8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n via_transactions (\n priority_id,\n tx_id,\n receiver,\n value,\n calldata,\n canonical_tx_hash\n )\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (tx_id) DO NOTHING\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Bytea", - "Varchar", - "Int8", - "Bytea", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "8bf2ce186709b01538c6ba14380037973bb9a631bdf5503f0e4dc8201b0bfdf2" -} diff --git a/via_verifier/lib/verifier_dal/.sqlx/query-c2f1e15f46b72570d02c7b8be08024ec90890f94199b039933296c3f99ba63bf.json b/via_verifier/lib/verifier_dal/.sqlx/query-c2f1e15f46b72570d02c7b8be08024ec90890f94199b039933296c3f99ba63bf.json new file mode 100644 index 000000000..b7391ab5c --- /dev/null +++ b/via_verifier/lib/verifier_dal/.sqlx/query-c2f1e15f46b72570d02c7b8be08024ec90890f94199b039933296c3f99ba63bf.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE via_transactions\n SET\n status = $2\n WHERE\n canonical_tx_hash = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "c2f1e15f46b72570d02c7b8be08024ec90890f94199b039933296c3f99ba63bf" +} From 5b523c54326cab964c74c392fb21cae6910cabe4 Mon Sep 17 00:00:00 2001 From: 0xatomFusion <179967211+0xatomFusion@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:03:24 +0100 Subject: [PATCH 212/212] refactor: priority_id verification and lint the transaction dal --- .../verifier_dal/src/via_transactions_dal.rs | 6 ++-- via_verifier/node/via_zk_verifier/src/lib.rs | 29 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs index b4e0f5492..016fd1ace 100644 --- a/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs +++ b/via_verifier/lib/verifier_dal/src/via_transactions_dal.rs @@ -73,10 +73,8 @@ impl ViaTransactionsDal<'_, '_> { .fetch_all(self.storage) .await?; - let canonical_tx_hashs: Vec> = rows - .into_iter() - .map(|row| row.canonical_tx_hash) - .collect(); + let canonical_tx_hashs: Vec> = + rows.into_iter().map(|row| row.canonical_tx_hash).collect(); Ok(canonical_tx_hashs) } diff --git a/via_verifier/node/via_zk_verifier/src/lib.rs b/via_verifier/node/via_zk_verifier/src/lib.rs index 750c61330..2b81621d3 100644 --- a/via_verifier/node/via_zk_verifier/src/lib.rs +++ b/via_verifier/node/via_zk_verifier/src/lib.rs @@ -184,20 +184,25 @@ impl ViaVerifier { return Ok(true); } - for (i, raw_tx_id) in txs.iter().enumerate() { - let db_raw_tx_id = H256::from_slice(&raw_tx_id); - let log_raw_tx_id = deposit_logs[i].key; - if &db_raw_tx_id == &log_raw_tx_id { - let status = deposit_logs[i].value.is_zero(); - storage - .via_transactions_dal() - .update_transaction(&log_raw_tx_id, !status) - .await?; - continue; + for (raw_tx_id, deposit_log) in txs.iter().zip(deposit_logs.iter()) { + let db_raw_tx_id = H256::from_slice(raw_tx_id); + if db_raw_tx_id != deposit_log.key { + tracing::error!( + "Sequencer did not process the deposit transactions in series for l1 batch {}, \ + invalid priority id for transaction hash {}", + l1_batch_number, + db_raw_tx_id + ); + return Ok(false); } - tracing::error!("Sequencer did not process the deposit transactions in series for l1 batch {}, invalid priority id for transaction hash {}", l1_batch_number, db_raw_tx_id); - return Ok(false); + + let status = !deposit_log.value.is_zero(); + storage + .via_transactions_dal() + .update_transaction(&deposit_log.key, status) + .await?; } + tracing::info!( "Priority_id verified successfuly for l1 batch {}", l1_batch_number