From b3426485bc7d48175327adda1d9c2e5d38ca00b5 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 16 May 2025 13:41:30 +0100 Subject: [PATCH 1/6] chore: update dependencies and clean up unused packages --- Cargo.lock | 517 ++---------------- Cargo.toml | 14 +- .../method/get_validity_proof/prover/gnark.rs | 16 +- .../method/get_validity_proof/prover/prove.rs | 6 +- src/ingester/persist/mod.rs | 3 +- src/monitor/mod.rs | 1 + 6 files changed, 77 insertions(+), 480 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee17d50c..375331cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,7 +105,7 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "aligned-sized" version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "proc-macro2", "quote", @@ -259,7 +259,7 @@ dependencies = [ "borsh 0.10.4", "bytemuck", "getrandom 0.2.15", - "solana-program 1.18.22", + "solana-program", "thiserror 1.0.69", ] @@ -3525,8 +3525,8 @@ dependencies = [ [[package]] name = "light-account-checks" -version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "0.2.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "solana-account-info", "solana-program-error", @@ -3538,7 +3538,7 @@ dependencies = [ [[package]] name = "light-batched-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3550,7 +3550,11 @@ dependencies = [ "light-merkle-tree-metadata", "light-verifier", "light-zero-copy", - "solana-program 2.2.1", + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "solana-sysvar", "thiserror 2.0.12", "zerocopy 0.8.24", ] @@ -3558,19 +3562,19 @@ dependencies = [ [[package]] name = "light-bloom-filter" version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "bitvec", "fastmurmur3", "num-bigint 0.4.6", - "solana-program 2.2.1", + "solana-program-error", "thiserror 2.0.12", ] [[package]] name = "light-bounded-vec" version = "1.2.0" -source = "git+https://github.com/lightprotocol/program-libs?rev=cf87f3e002d8a7dd40dd19d9387e73398cdcfef8#cf87f3e002d8a7dd40dd19d9387e73398cdcfef8" +source = "git+https://github.com/lightprotocol/program-libs?rev=f5aa99e4617672bab00073377a2db92e42610a73#f5aa99e4617672bab00073377a2db92e42610a73" dependencies = [ "bytemuck", "memoffset 0.9.1", @@ -3579,16 +3583,16 @@ dependencies = [ [[package]] name = "light-compressed-account" -version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "0.2.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "borsh 0.10.4", "bytemuck", "light-hasher", "light-macros", "light-zero-copy", - "rand 0.8.5", - "solana-program 2.2.1", + "solana-program-error", + "solana-pubkey", "thiserror 2.0.12", "zerocopy 0.8.24", ] @@ -3596,7 +3600,7 @@ dependencies = [ [[package]] name = "light-concurrent-merkle-tree" version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "borsh 0.10.4", "light-bounded-vec", @@ -3607,8 +3611,8 @@ dependencies = [ [[package]] name = "light-hasher" -version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "3.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", @@ -3618,14 +3622,15 @@ dependencies = [ "num-bigint 0.4.6", "sha2 0.10.8", "sha3 0.10.8", - "solana-program 2.2.1", + "solana-program-error", + "solana-pubkey", "thiserror 2.0.12", ] [[package]] name = "light-indexed-array" version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "light-hasher", "num-bigint 0.4.6", @@ -3635,8 +3640,8 @@ dependencies = [ [[package]] name = "light-macros" -version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "bs58 0.5.1", "proc-macro2", @@ -3647,12 +3652,14 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "borsh 0.10.4", "bytemuck", "light-compressed-account", - "solana-program 2.2.1", + "solana-msg", + "solana-program-error", + "solana-sysvar", "thiserror 2.0.12", "zerocopy 0.8.24", ] @@ -3660,7 +3667,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-reference" version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "light-hasher", "light-indexed-array", @@ -3693,53 +3700,24 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "light-sdk" -version = "0.11.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" -dependencies = [ - "borsh 0.10.4", - "light-account-checks", - "light-compressed-account", - "light-hasher", - "light-macros", - "light-sdk-macros", - "light-verifier", - "num-bigint 0.4.6", - "solana-program 2.2.1", - "thiserror 2.0.12", -] - -[[package]] -name = "light-sdk-macros" -version = "0.4.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" -dependencies = [ - "ark-bn254 0.5.0", - "light-hasher", - "light-poseidon 0.3.0", - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "light-verifier" -version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ "groth16-solana", "light-compressed-account", - "solana-program 2.2.1", + "solana-msg", + "solana-program-error", "thiserror 2.0.12", ] [[package]] name = "light-zero-copy" -version = "0.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=368f9f08272db78c74b2ade1a1c2fead27dd0a96#368f9f08272db78c74b2ade1a1c2fead27dd0a96" +version = "0.2.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=a16015358aee65da5f67e4ae73197df5e75495d9#a16015358aee65da5f67e4ae73197df5e75495d9" dependencies = [ - "solana-program 2.2.1", + "solana-program-error", "thiserror 2.0.12", "zerocopy 0.8.24", ] @@ -4427,7 +4405,6 @@ dependencies = [ "light-merkle-tree-metadata", "light-merkle-tree-reference", "light-poseidon 0.3.0", - "light-sdk", "log", "num-bigint 0.4.6", "num-traits", @@ -4443,7 +4420,7 @@ dependencies = [ "serde_json", "serial_test", "solana-client", - "solana-program 1.18.22", + "solana-program", "solana-pubkey", "solana-sdk", "solana-transaction-status", @@ -5977,19 +5954,6 @@ dependencies = [ "sha-1", ] -[[package]] -name = "solana-account" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" -dependencies = [ - "solana-account-info", - "solana-clock", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", -] - [[package]] name = "solana-account-decoder" version = "1.18.22" @@ -6021,30 +5985,11 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" dependencies = [ - "bincode", - "serde", "solana-program-error", "solana-program-memory", "solana-pubkey", ] -[[package]] -name = "solana-address-lookup-table-interface" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" -dependencies = [ - "bincode", - "bytemuck", - "serde", - "serde_derive", - "solana-clock", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-slot-hashes", -] - [[package]] name = "solana-atomic-u64" version = "2.2.1" @@ -6054,40 +5999,6 @@ dependencies = [ "parking_lot 0.12.3", ] -[[package]] -name = "solana-big-mod-exp" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "solana-define-syscall", -] - -[[package]] -name = "solana-bincode" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" -dependencies = [ - "bincode", - "serde", - "solana-instruction", -] - -[[package]] -name = "solana-blake3-hasher" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" -dependencies = [ - "blake3", - "solana-define-syscall", - "solana-hash", - "solana-sanitize", -] - [[package]] name = "solana-bn254" version = "2.2.2" @@ -6103,16 +6014,6 @@ dependencies = [ "thiserror 2.0.12", ] -[[package]] -name = "solana-borsh" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" -dependencies = [ - "borsh 0.10.4", - "borsh 1.5.7", -] - [[package]] name = "solana-clap-utils" version = "1.18.22" @@ -6268,46 +6169,6 @@ dependencies = [ "solana-sysvar-id", ] -[[package]] -name = "solana-example-mocks" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" -dependencies = [ - "serde", - "serde_derive", - "solana-address-lookup-table-interface", - "solana-clock", - "solana-hash", - "solana-instruction", - "solana-keccak-hasher", - "solana-message", - "solana-nonce", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", - "thiserror 2.0.12", -] - -[[package]] -name = "solana-feature-gate-interface" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" -dependencies = [ - "bincode", - "serde", - "serde_derive", - "solana-account", - "solana-account-info", - "solana-instruction", - "solana-program-error", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-system-interface", -] - [[package]] name = "solana-fee-calculator" version = "2.2.1" @@ -6362,7 +6223,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" dependencies = [ - "borsh 1.5.7", "bs58 0.5.1", "bytemuck", "bytemuck_derive", @@ -6381,7 +6241,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" dependencies = [ "bincode", - "borsh 1.5.7", "getrandom 0.2.15", "js-sys", "num-traits", @@ -6394,9 +6253,9 @@ dependencies = [ [[package]] name = "solana-instructions-sysvar" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427f2d0d6dc0bb49f16cef5e7f975180d2e80aab9bdd3b2af68e2d029ec63f43" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" dependencies = [ "bitflags 2.9.0", "solana-account-info", @@ -6409,18 +6268,6 @@ dependencies = [ "solana-sysvar-id", ] -[[package]] -name = "solana-keccak-hasher" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" -dependencies = [ - "sha3 0.10.8", - "solana-define-syscall", - "solana-hash", - "solana-sanitize", -] - [[package]] name = "solana-last-restart-slot" version = "2.2.1" @@ -6434,50 +6281,6 @@ dependencies = [ "solana-sysvar-id", ] -[[package]] -name = "solana-loader-v2-interface" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", -] - -[[package]] -name = "solana-loader-v3-interface" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", -] - -[[package]] -name = "solana-loader-v4-interface" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" -dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "solana-instruction", - "solana-pubkey", - "solana-sdk-ids", - "solana-system-interface", -] - [[package]] name = "solana-logger" version = "1.18.22" @@ -6499,29 +6302,6 @@ dependencies = [ "solana-sdk", ] -[[package]] -name = "solana-message" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6bf99c4570173710107a1f233f3bee226feea5fc817308707d4f7cb100a72d" -dependencies = [ - "bincode", - "blake3", - "lazy_static", - "serde", - "serde_derive", - "solana-bincode", - "solana-hash", - "solana-instruction", - "solana-pubkey", - "solana-sanitize", - "solana-sdk-ids", - "solana-short-vec", - "solana-system-interface", - "solana-transaction-error", - "wasm-bindgen", -] - [[package]] name = "solana-metrics" version = "1.18.22" @@ -6546,12 +6326,6 @@ dependencies = [ "solana-define-syscall", ] -[[package]] -name = "solana-native-token" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307fb2f78060995979e9b4f68f833623565ed4e55d3725f100454ce78a99a1a3" - [[package]] name = "solana-net-utils" version = "1.18.22" @@ -6574,20 +6348,6 @@ dependencies = [ "url", ] -[[package]] -name = "solana-nonce" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" -dependencies = [ - "serde", - "serde_derive", - "solana-fee-calculator", - "solana-hash", - "solana-pubkey", - "solana-sha256-hasher", -] - [[package]] name = "solana-perf" version = "1.18.22" @@ -6672,86 +6432,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "solana-program" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" -dependencies = [ - "bincode", - "blake3", - "borsh 0.10.4", - "borsh 1.5.7", - "bs58 0.5.1", - "bytemuck", - "console_error_panic_hook", - "console_log", - "getrandom 0.2.15", - "lazy_static", - "log", - "memoffset 0.9.1", - "num-bigint 0.4.6", - "num-derive 0.4.2", - "num-traits", - "rand 0.8.5", - "serde", - "serde_bytes", - "serde_derive", - "solana-account-info", - "solana-address-lookup-table-interface", - "solana-atomic-u64", - "solana-big-mod-exp", - "solana-bincode", - "solana-blake3-hasher", - "solana-borsh", - "solana-clock", - "solana-cpi", - "solana-decode-error", - "solana-define-syscall", - "solana-epoch-rewards", - "solana-epoch-schedule", - "solana-example-mocks", - "solana-feature-gate-interface", - "solana-fee-calculator", - "solana-hash", - "solana-instruction", - "solana-instructions-sysvar", - "solana-keccak-hasher", - "solana-last-restart-slot", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-message", - "solana-msg", - "solana-native-token", - "solana-nonce", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", - "solana-program-option", - "solana-program-pack", - "solana-pubkey", - "solana-rent", - "solana-sanitize", - "solana-sdk-ids", - "solana-sdk-macro 2.2.1", - "solana-secp256k1-recover", - "solana-serde-varint", - "solana-serialize-utils", - "solana-sha256-hasher", - "solana-short-vec", - "solana-slot-hashes", - "solana-slot-history", - "solana-stable-layout", - "solana-stake-interface", - "solana-system-interface", - "solana-sysvar", - "solana-sysvar-id", - "solana-vote-interface", - "thiserror 2.0.12", - "wasm-bindgen", -] - [[package]] name = "solana-program-entrypoint" version = "2.2.1" @@ -6770,10 +6450,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8ae2c1a8d0d4ae865882d5770a7ebca92bab9c685e43f0461682c6c05a35bfa" dependencies = [ - "borsh 1.5.7", "num-traits", - "serde", - "serde_derive", "solana-decode-error", "solana-instruction", "solana-msg", @@ -6790,21 +6467,6 @@ dependencies = [ "solana-define-syscall", ] -[[package]] -name = "solana-program-option" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" - -[[package]] -name = "solana-program-pack" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" -dependencies = [ - "solana-program-error", -] - [[package]] name = "solana-program-runtime" version = "1.18.22" @@ -6842,8 +6504,6 @@ dependencies = [ "borsh 0.10.4", "borsh 1.5.7", "bs58 0.5.1", - "bytemuck", - "bytemuck_derive", "curve25519-dalek 4.1.3", "five8_const", "getrandom 0.2.15", @@ -7068,7 +6728,7 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", - "solana-program 1.18.22", + "solana-program", "solana-sdk-macro 1.18.22", "thiserror 1.0.69", "uriparse", @@ -7109,32 +6769,12 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "solana-secp256k1-recover" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" -dependencies = [ - "libsecp256k1", - "solana-define-syscall", - "thiserror 2.0.12", -] - [[package]] name = "solana-security-txt" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" -[[package]] -name = "solana-serde-varint" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" -dependencies = [ - "serde", -] - [[package]] name = "solana-serialize-utils" version = "2.2.1" @@ -7157,15 +6797,6 @@ dependencies = [ "solana-hash", ] -[[package]] -name = "solana-short-vec" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" -dependencies = [ - "serde", -] - [[package]] name = "solana-slot-hashes" version = "2.2.1" @@ -7208,8 +6839,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" dependencies = [ - "borsh 0.10.4", - "borsh 1.5.7", "num-traits", "serde", "serde_derive", @@ -7280,8 +6909,6 @@ checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" dependencies = [ "base64 0.22.1", "bincode", - "bytemuck", - "bytemuck_derive", "lazy_static", "serde", "serde_derive", @@ -7358,16 +6985,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "solana-transaction-error" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" -dependencies = [ - "solana-instruction", - "solana-sanitize", -] - [[package]] name = "solana-transaction-status" version = "1.18.22" @@ -7424,30 +7041,6 @@ dependencies = [ "solana-sdk", ] -[[package]] -name = "solana-vote-interface" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f039b0788337bedc6c5450d2f237718f938defb5ce0e0ad8ef507e78dcd370" -dependencies = [ - "bincode", - "num-derive 0.4.2", - "num-traits", - "serde", - "serde_derive", - "solana-clock", - "solana-decode-error", - "solana-hash", - "solana-instruction", - "solana-pubkey", - "solana-rent", - "solana-sdk-ids", - "solana-serde-varint", - "solana-serialize-utils", - "solana-short-vec", - "solana-system-interface", -] - [[package]] name = "solana-vote-program" version = "1.18.22" @@ -7464,7 +7057,7 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-metrics", - "solana-program 1.18.22", + "solana-program", "solana-program-runtime", "solana-sdk", "thiserror 1.0.69", @@ -7492,7 +7085,7 @@ dependencies = [ "serde", "serde_json", "sha3 0.9.1", - "solana-program 1.18.22", + "solana-program", "solana-sdk", "subtle", "thiserror 1.0.69", @@ -7553,7 +7146,7 @@ dependencies = [ "borsh 0.10.4", "num-derive 0.4.2", "num-traits", - "solana-program 1.18.22", + "solana-program", "spl-token", "spl-token-2022", "thiserror 1.0.69", @@ -7566,7 +7159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" dependencies = [ "bytemuck", - "solana-program 1.18.22", + "solana-program", "spl-discriminator-derive", ] @@ -7600,7 +7193,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" dependencies = [ - "solana-program 1.18.22", + "solana-program", ] [[package]] @@ -7611,7 +7204,7 @@ checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" dependencies = [ "borsh 0.10.4", "bytemuck", - "solana-program 1.18.22", + "solana-program", "solana-zk-token-sdk", "spl-program-error", ] @@ -7624,7 +7217,7 @@ checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" dependencies = [ "num-derive 0.4.2", "num-traits", - "solana-program 1.18.22", + "solana-program", "spl-program-error-derive", "thiserror 1.0.69", ] @@ -7648,7 +7241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" dependencies = [ "bytemuck", - "solana-program 1.18.22", + "solana-program", "spl-discriminator", "spl-pod", "spl-program-error", @@ -7666,7 +7259,7 @@ dependencies = [ "num-derive 0.3.3", "num-traits", "num_enum 0.6.1", - "solana-program 1.18.22", + "solana-program", "thiserror 1.0.69", ] @@ -7681,7 +7274,7 @@ dependencies = [ "num-derive 0.4.2", "num-traits", "num_enum 0.7.3", - "solana-program 1.18.22", + "solana-program", "solana-security-txt", "solana-zk-token-sdk", "spl-memo", @@ -7701,7 +7294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" dependencies = [ "bytemuck", - "solana-program 1.18.22", + "solana-program", "spl-discriminator", "spl-pod", "spl-program-error", @@ -7714,7 +7307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" dependencies = [ "borsh 0.10.4", - "solana-program 1.18.22", + "solana-program", "spl-discriminator", "spl-pod", "spl-program-error", @@ -7729,7 +7322,7 @@ checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" dependencies = [ "arrayref", "bytemuck", - "solana-program 1.18.22", + "solana-program", "spl-discriminator", "spl-pod", "spl-program-error", @@ -7744,7 +7337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" dependencies = [ "bytemuck", - "solana-program 1.18.22", + "solana-program", "spl-discriminator", "spl-pod", "spl-program-error", diff --git a/Cargo.toml b/Cargo.toml index a1a5eeca..255b5e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,13 +81,13 @@ solana-pubkey = "2.3.0" solana-transaction-status = "1.18.0" +light-concurrent-merkle-tree = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } +light-batched-merkle-tree = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } +light-merkle-tree-metadata = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } +light-compressed-account = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } +light-hasher = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } + light-poseidon = "0.3.0" -light-batched-merkle-tree = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } -light-compressed-account = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } -light-concurrent-merkle-tree = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } -light-hasher = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } -light-merkle-tree-metadata = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } -light-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } sqlx = { version = "0.6.2", features = [ "macros", @@ -131,7 +131,7 @@ rust-s3 = "0.34.0" [dev-dependencies] function_name = "0.3.0" serial_test = "2.0.0" -light-merkle-tree-reference = { git = "https://github.com/Lightprotocol/light-protocol", rev = "368f9f08272db78c74b2ade1a1c2fead27dd0a96" } +light-merkle-tree-reference = { git = "https://github.com/Lightprotocol/light-protocol", rev = "a16015358aee65da5f67e4ae73197df5e75495d9" } [profile.dev] # Do not produce debug info for ~40% faster incremental compilation. diff --git a/src/api/method/get_validity_proof/prover/gnark.rs b/src/api/method/get_validity_proof/prover/gnark.rs index 61e3ab7d..801115fd 100644 --- a/src/api/method/get_validity_proof/prover/gnark.rs +++ b/src/api/method/get_validity_proof/prover/gnark.rs @@ -1,7 +1,7 @@ +use crate::api::error::PhotonApiError; use crate::api::method::get_validity_proof::prover::structs::{CompressedProof, ProofABC}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; use std::ops::Neg; -use crate::api::error::PhotonApiError; type G1 = ark_bn254::g1::G1Affine; @@ -78,19 +78,26 @@ pub fn negate_proof(proof: ProofABC) -> Result &*[&change_endianness(&proof.a), &[0u8][..]].concat(), Compress::No, Validate::No, - ).map_err(|e| PhotonApiError::UnexpectedError(format!("Failed to deserialize G1 point: {}", e)))?; + ) + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to deserialize G1 point: {}", e)) + })?; proof_a .neg() .x .serialize_with_mode(&mut proof_a_neg[..32], Compress::No) - .map_err(|e| PhotonApiError::UnexpectedError(format!("Failed to serialize x coordinate: {}", e)))?; + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to serialize x coordinate: {}", e)) + })?; proof_a .neg() .y .serialize_with_mode(&mut proof_a_neg[32..], Compress::No) - .map_err(|e| PhotonApiError::UnexpectedError(format!("Failed to serialize y coordinate: {}", e)))?; + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to serialize y coordinate: {}", e)) + })?; let compressed_proof = CompressedProof { a: proof_a_neg[0..32].to_vec(), @@ -100,4 +107,3 @@ pub fn negate_proof(proof: ProofABC) -> Result Ok(compressed_proof) } - diff --git a/src/api/method/get_validity_proof/prover/prove.rs b/src/api/method/get_validity_proof/prover/prove.rs index 766d11fe..498a97a5 100644 --- a/src/api/method/get_validity_proof/prover/prove.rs +++ b/src/api/method/get_validity_proof/prover/prove.rs @@ -11,13 +11,11 @@ use crate::api::method::get_validity_proof::prover::structs::{ }; use crate::common::typedefs::hash::Hash; use crate::ingester::parser::tree_info::TreeInfo; -use crate::ingester::persist::MerkleProofWithContext; +use crate::ingester::persist::{MerkleProofWithContext, TREE_HEIGHT_V1}; use light_batched_merkle_tree::constants::{ DEFAULT_BATCH_ADDRESS_TREE_HEIGHT, DEFAULT_BATCH_STATE_TREE_HEIGHT, }; use light_batched_merkle_tree::merkle_tree_metadata::BatchedMerkleTreeMetadata; -use light_sdk::STATE_MERKLE_TREE_HEIGHT; - use reqwest::Client; const STATE_TREE_QUEUE_SIZE: u64 = 2400; @@ -87,7 +85,7 @@ pub(crate) async fn generate_proof( } else { address_tree_height }; - let queue_size = if queue_determining_height == STATE_MERKLE_TREE_HEIGHT { + let queue_size = if queue_determining_height == TREE_HEIGHT_V1 as usize { STATE_TREE_QUEUE_SIZE } else if queue_determining_height == 0 { // No proofs, default for batched (should ideally not hit if circuit_type is determined) diff --git a/src/ingester/persist/mod.rs b/src/ingester/persist/mod.rs index 91746b59..611b3fc4 100644 --- a/src/ingester/persist/mod.rs +++ b/src/ingester/persist/mod.rs @@ -37,13 +37,12 @@ pub mod persisted_indexed_merkle_tree; pub mod persisted_state_tree; use crate::dao::generated::address_queue; -use crate::ingester::persist::leaf_node::TREE_HEIGHT_V1; pub use merkle_proof_with_context::MerkleProofWithContext; mod leaf_node; mod leaf_node_proof; -pub use self::leaf_node::{persist_leaf_nodes, LeafNode}; +pub use self::leaf_node::{persist_leaf_nodes, LeafNode, TREE_HEIGHT_V1}; pub use self::leaf_node_proof::{ get_multiple_compressed_leaf_proofs, get_multiple_compressed_leaf_proofs_by_indices, get_multiple_compressed_leaf_proofs_from_full_leaf_info, diff --git a/src/monitor/mod.rs b/src/monitor/mod.rs index 5c85e637..90d71995 100644 --- a/src/monitor/mod.rs +++ b/src/monitor/mod.rs @@ -30,6 +30,7 @@ use solana_sdk::account::Account as SolanaAccount; use crate::common::typedefs::context::Context; use light_batched_merkle_tree::merkle_tree::BatchedMerkleTreeAccount; + use solana_sdk::pubkey::Pubkey; use std::mem; From 847241efc9c44a9393c8615ca24b4fb643e8a7cc Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 16 May 2025 14:28:44 +0100 Subject: [PATCH 2/6] refactor: consolidate PublicTransactionEvent structs and update references --- src/ingester/parser/indexer_events.rs | 68 +---------------------- src/ingester/parser/tx_event_parser.rs | 6 +- src/ingester/parser/tx_event_parser_v2.rs | 13 ++--- 3 files changed, 9 insertions(+), 78 deletions(-) diff --git a/src/ingester/parser/indexer_events.rs b/src/ingester/parser/indexer_events.rs index cbb4f99b..9f693b5c 100644 --- a/src/ingester/parser/indexer_events.rs +++ b/src/ingester/parser/indexer_events.rs @@ -46,7 +46,7 @@ impl MerkleTreeSequenceNumber { } #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, Default, PartialEq, Eq)] -pub struct PublicTransactionEventV1 { +pub struct PublicTransactionEvent { pub input_compressed_account_hashes: Vec<[u8; 32]>, pub output_compressed_account_hashes: Vec<[u8; 32]>, pub output_compressed_accounts: Vec, @@ -60,74 +60,10 @@ pub struct PublicTransactionEventV1 { pub message: Option>, } -#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, Default, PartialEq, Eq)] -pub struct PublicTransactionEventV2 { - pub input_compressed_account_hashes: Vec<[u8; 32]>, - pub output_compressed_account_hashes: Vec<[u8; 32]>, - pub output_compressed_accounts: Vec, - pub output_leaf_indices: Vec, - pub sequence_numbers: Vec, - pub relay_fee: Option, - pub is_compress: bool, - pub compression_lamports: Option, - pub pubkey_array: Vec, - // TODO: remove(data can just be written into a compressed account) - pub message: Option>, -} - -impl Into for PublicTransactionEventV2 { - fn into(self) -> PublicTransactionEventV1 { - PublicTransactionEventV1 { - input_compressed_account_hashes: self.input_compressed_account_hashes, - output_compressed_account_hashes: self.output_compressed_account_hashes, - output_compressed_accounts: self.output_compressed_accounts, - output_leaf_indices: self.output_leaf_indices, - sequence_numbers: self - .sequence_numbers - .iter() - .map(|x| MerkleTreeSequenceNumberV1 { - pubkey: x.tree_pubkey, - seq: x.seq, - }) - .collect(), - relay_fee: self.relay_fee, - is_compress: self.is_compress, - compression_lamports: self.compression_lamports, - pubkey_array: self.pubkey_array, - message: self.message, - } - } -} - -impl Into for PublicTransactionEventV1 { - fn into(self) -> PublicTransactionEventV2 { - PublicTransactionEventV2 { - input_compressed_account_hashes: self.input_compressed_account_hashes, - output_compressed_account_hashes: self.output_compressed_account_hashes, - output_compressed_accounts: self.output_compressed_accounts, - output_leaf_indices: self.output_leaf_indices, - sequence_numbers: self - .sequence_numbers - .iter() - .map(|x| MerkleTreeSequenceNumberV2 { - tree_pubkey: x.pubkey, - queue_pubkey: x.pubkey, // Default queue pubkey to tree pubkey - tree_type: 0, // Default tree type to 0 (StateV1) - seq: x.seq, - }) - .collect(), - relay_fee: self.relay_fee, - is_compress: self.is_compress, - compression_lamports: self.compression_lamports, - pubkey_array: self.pubkey_array, - message: self.message, - } - } -} #[derive(Debug, Clone)] pub struct BatchPublicTransactionEvent { - pub event: PublicTransactionEventV2, + pub event: PublicTransactionEvent, pub new_addresses: Vec, pub input_sequence_numbers: Vec, pub address_sequence_numbers: Vec, diff --git a/src/ingester/parser/tx_event_parser.rs b/src/ingester/parser/tx_event_parser.rs index d73e1963..a1336aec 100644 --- a/src/ingester/parser/tx_event_parser.rs +++ b/src/ingester/parser/tx_event_parser.rs @@ -1,6 +1,6 @@ use crate::common::typedefs::account::AccountWithContext; use crate::ingester::error::IngesterError; -use crate::ingester::parser::indexer_events::PublicTransactionEventV1; +use crate::ingester::parser::indexer_events::PublicTransactionEvent; use crate::ingester::parser::state_update::{AccountTransaction, StateUpdate}; use crate::ingester::parser::tree_info::TreeInfo; use crate::ingester::parser::{get_compression_program_id, NOOP_PROGRAM_ID, SYSTEM_PROGRAM}; @@ -29,7 +29,7 @@ pub fn parse_public_transaction_event_v1( ); let public_transaction_event = - PublicTransactionEventV1::deserialize(&mut next_next_instruction.data.as_slice()) + PublicTransactionEvent::deserialize(&mut next_next_instruction.data.as_slice()) .map_err(|e| { IngesterError::ParserError(format!( "Failed to deserialize PublicTransactionEvent: {}", @@ -45,7 +45,7 @@ pub fn parse_public_transaction_event_v1( pub fn create_state_update_v1( tx: Signature, slot: u64, - transaction_event: PublicTransactionEventV1, + transaction_event: PublicTransactionEvent, ) -> Result { let mut state_update = StateUpdate::new(); let mut tree_to_seq_number = transaction_event diff --git a/src/ingester/parser/tx_event_parser_v2.rs b/src/ingester/parser/tx_event_parser_v2.rs index e3835a29..0706f84a 100644 --- a/src/ingester/parser/tx_event_parser_v2.rs +++ b/src/ingester/parser/tx_event_parser_v2.rs @@ -1,9 +1,6 @@ use crate::common::typedefs::serializable_pubkey::SerializablePubkey; use crate::ingester::error::IngesterError; -use crate::ingester::parser::indexer_events::{ - BatchPublicTransactionEvent, CompressedAccount, CompressedAccountData, - MerkleTreeSequenceNumberV2, OutputCompressedAccountWithPackedContext, PublicTransactionEventV2, -}; +use crate::ingester::parser::indexer_events::{BatchPublicTransactionEvent, CompressedAccount, CompressedAccountData, MerkleTreeSequenceNumberV1, MerkleTreeSequenceNumberV2, OutputCompressedAccountWithPackedContext, PublicTransactionEvent}; use crate::ingester::parser::state_update::StateUpdate; use crate::ingester::parser::tx_event_parser::create_state_update_v1; @@ -23,7 +20,7 @@ pub fn parse_public_transaction_event_v2( events .into_iter() .map(|public_transaction_event| { - let event = PublicTransactionEventV2 { + let event = PublicTransactionEvent { input_compressed_account_hashes: public_transaction_event .event .input_compressed_account_hashes, @@ -55,10 +52,8 @@ pub fn parse_public_transaction_event_v2( .event .sequence_numbers .iter() - .map(|x| MerkleTreeSequenceNumberV2 { - tree_pubkey: x.tree_pubkey, - queue_pubkey: x.queue_pubkey, - tree_type: x.tree_type, + .map(|x| MerkleTreeSequenceNumberV1 { + pubkey: x.tree_pubkey, seq: x.seq, }) .collect(), From 5df2f70b307b5c07d848ab2c99e0fa67c50abd22 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 16 May 2025 19:33:40 +0100 Subject: [PATCH 3/6] refactor: adjust root_seq assignment and add Debug trait to struct definitions --- src/api/method/get_validity_proof/prover/structs.rs | 6 +++--- src/ingester/persist/persisted_indexed_merkle_tree.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/method/get_validity_proof/prover/structs.rs b/src/api/method/get_validity_proof/prover/structs.rs index 2f175c6a..3bf7895a 100644 --- a/src/api/method/get_validity_proof/prover/structs.rs +++ b/src/api/method/get_validity_proof/prover/structs.rs @@ -35,7 +35,7 @@ pub(crate) struct ProverResult { pub address_proof_details: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub(crate) struct InclusionHexInputsForProver { pub root: String, @@ -44,7 +44,7 @@ pub(crate) struct InclusionHexInputsForProver { pub leaf: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub(crate) struct NonInclusionHexInputsForProver { pub root: String, @@ -77,7 +77,7 @@ pub struct CompressedProof { pub c: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct HexBatchInputsForProver { #[serde(rename = "circuitType")] diff --git a/src/ingester/persist/persisted_indexed_merkle_tree.rs b/src/ingester/persist/persisted_indexed_merkle_tree.rs index 0c42f967..c0824680 100644 --- a/src/ingester/persist/persisted_indexed_merkle_tree.rs +++ b/src/ingester/persist/persisted_indexed_merkle_tree.rs @@ -163,7 +163,7 @@ pub async fn get_exclusion_range_with_proof_v2( merkle_tree: SerializablePubkey::try_from(tree.clone()).map_err(|e| { PhotonApiError::UnexpectedError(format!("Failed to serialize pubkey: {}", e)) })?, - root_seq: 3, + root_seq: if TREE_HEIGHT_V1 == tree_height { 3 } else { 0 }, }; merkle_proof.validate()?; return Ok((zeroeth_element, merkle_proof)); From 3d2dfe85020c4b3f2ac67cb8a419552fec5b0494 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 17 May 2025 12:46:37 +0100 Subject: [PATCH 4/6] refactor: proof compression and error handling in prover --- .../method/get_validity_proof/prover/gnark.rs | 127 +++++------------ .../get_validity_proof/prover/helpers.rs | 128 +++++++++++++----- .../method/get_validity_proof/prover/prove.rs | 12 +- .../get_validity_proof/prover/structs.rs | 14 +- src/ingester/parser/indexer_events.rs | 1 - src/ingester/parser/tx_event_parser_v2.rs | 6 +- 6 files changed, 139 insertions(+), 149 deletions(-) diff --git a/src/api/method/get_validity_proof/prover/gnark.rs b/src/api/method/get_validity_proof/prover/gnark.rs index 801115fd..ed35122d 100644 --- a/src/api/method/get_validity_proof/prover/gnark.rs +++ b/src/api/method/get_validity_proof/prover/gnark.rs @@ -1,109 +1,46 @@ use crate::api::error::PhotonApiError; use crate::api::method::get_validity_proof::prover::structs::{CompressedProof, ProofABC}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; +use solana_program::alt_bn128::compression::prelude::{ + alt_bn128_g1_compress, alt_bn128_g2_compress, convert_endianness, +}; use std::ops::Neg; type G1 = ark_bn254::g1::G1Affine; -/// Changes the endianness of the given slice of bytes by reversing the order of every 32-byte chunk. -/// -/// # Arguments -/// -/// * `bytes` - A reference to a slice of bytes whose endianness will be changed. -/// -/// # Returns -/// -/// A `Vec` containing the bytes with their order reversed in chunks of 32 bytes. If the number -/// of bytes in the slice is not a multiple of 32, the remaining bytes at the end will also be reversed. -/// -/// # Examples -/// -/// ``` -/// let input = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, -/// 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, -/// 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, -/// 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20]; -/// let output = change_endianness(&input); -/// assert_eq!(output, vec![0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, -/// 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, -/// 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, -/// 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]); -/// -/// let input = vec![0x01, 0x02, 0x03]; -/// let output = change_endianness(&input); -/// assert_eq!(output, vec![0x03, 0x02, 0x01]); -/// ``` -fn change_endianness(bytes: &[u8]) -> Vec { - let mut vec = Vec::new(); - for b in bytes.chunks(32) { - for byte in b.iter().rev() { - vec.push(*byte); - } - } - vec -} - -/// Negates the `a` component of the given proof and compresses the proof into a `CompressedProof`. -/// -/// # Arguments -/// -/// * `proof` - A `ProofABC` structure containing three components: `a`, `b`, and `c`. -/// -/// - `a` is negated and serialized in big-endian format. -/// - `b` and `c` are trimmed and included as-is in the compressed form. -/// -/// # Returns -/// -/// A `CompressedProof` containing: -/// -/// * The negated and serialized `a` component as a vector of bytes. -/// * The first 64 bytes of the `b` component. -/// * The first 32 bytes of the `c` component. -/// -/// # Panics -/// -/// This function will panic if: -/// -/// * The deserialization or serialization of the `G1` point fails. -/// * The `proof.a` slice length is insufficient to produce a valid G1 when adding padding for deserialization. -/// -/// # Note -/// -/// The function assumes that the `ProofABC` structure contains its `a`, `b`, and `c` components in valid formats -/// necessary for transformation and compression. -pub fn negate_proof(proof: ProofABC) -> Result { - let mut proof_a_neg = [0u8; 65]; - - let proof_a: G1 = G1::deserialize_with_mode( - &*[&change_endianness(&proof.a), &[0u8][..]].concat(), - Compress::No, - Validate::No, - ) - .map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to deserialize G1 point: {}", e)) - })?; +pub fn negate_g1(g1_be: &[u8; 64]) -> Result<[u8; 64], PhotonApiError> { + let g1_le = convert_endianness::<32, 64>(g1_be); + let g1: G1 = G1::deserialize_with_mode(g1_le.as_slice(), Compress::No, Validate::No).unwrap(); - proof_a - .neg() + let g1_neg = g1.neg(); + let mut g1_neg_be = [0u8; 64]; + g1_neg .x - .serialize_with_mode(&mut proof_a_neg[..32], Compress::No) - .map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to serialize x coordinate: {}", e)) + .serialize_with_mode(&mut g1_neg_be[..32], Compress::No) + .map_err(|_| { + PhotonApiError::UnexpectedError("Failed to serialize G1 x coordinate".to_string()) })?; - - proof_a - .neg() + g1_neg .y - .serialize_with_mode(&mut proof_a_neg[32..], Compress::No) - .map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to serialize y coordinate: {}", e)) + .serialize_with_mode(&mut g1_neg_be[32..], Compress::No) + .map_err(|_| { + PhotonApiError::UnexpectedError("Failed to serialize G1 y coordinate".to_string()) })?; + let g1_neg_be: [u8; 64] = convert_endianness::<32, 64>(&g1_neg_be); + Ok(g1_neg_be) +} - let compressed_proof = CompressedProof { - a: proof_a_neg[0..32].to_vec(), - b: proof.b[0..64].to_vec(), - c: proof.c[0..32].to_vec(), - }; - - Ok(compressed_proof) +pub fn compress_proof(proof: &ProofABC) -> Result { + let proof_a = alt_bn128_g1_compress(&proof.a) + .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G1 proof".to_string()))?; + let proof_b = alt_bn128_g2_compress(&proof.b) + .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G2 proof".to_string()))?; + let proof_c = alt_bn128_g1_compress(&proof.c) + .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G1 proof".to_string()))?; + + Ok(CompressedProof { + a: Vec::from(proof_a), + b: Vec::from(proof_b), + c: Vec::from(proof_c), + }) } diff --git a/src/api/method/get_validity_proof/prover/helpers.rs b/src/api/method/get_validity_proof/prover/helpers.rs index 91c9b2cb..234f831f 100644 --- a/src/api/method/get_validity_proof/prover/helpers.rs +++ b/src/api/method/get_validity_proof/prover/helpers.rs @@ -1,4 +1,6 @@ +use crate::api::error::PhotonApiError; use crate::api::method::get_multiple_new_address_proofs::MerkleContextWithNewAddressProof; +use crate::api::method::get_validity_proof::prover::gnark::negate_g1; use crate::api::method::get_validity_proof::prover::structs::{ GnarkProofJson, InclusionHexInputsForProver, NonInclusionHexInputsForProver, ProofABC, }; @@ -64,73 +66,125 @@ pub fn hash_to_hex(hash: &Hash) -> String { fn pubkey_to_hex(pubkey: &SerializablePubkey) -> String { let bytes = pubkey.to_bytes_vec(); let hex = hex::encode(bytes); + format!("0x{}", hex) } -fn deserialize_hex_string_to_bytes(hex_str: &str) -> Vec { +pub fn deserialize_hex_string_to_bytes(hex_str: &str) -> Result, PhotonApiError> { let hex_str = if hex_str.starts_with("0x") { &hex_str[2..] } else { hex_str }; - - // Left pad with 0s if the length is not 64 let hex_str = format!("{:0>64}", hex_str); - hex::decode(&hex_str).expect("Failed to decode hex string") + hex::decode(hex_str) + .map_err(|_| PhotonApiError::UnexpectedError("Failed to decode hex string".to_string())) } -pub fn proof_from_json_struct(json: GnarkProofJson) -> ProofABC { - let proof_ax = deserialize_hex_string_to_bytes(&json.ar[0]); - let proof_ay = deserialize_hex_string_to_bytes(&json.ar[1]); - let proof_a = [proof_ax, proof_ay].concat(); +pub fn proof_from_json_struct(json: GnarkProofJson) -> Result { + let proof_a_x = deserialize_hex_string_to_bytes(&json.ar[0])?; + let proof_a_y = deserialize_hex_string_to_bytes(&json.ar[1])?; + let proof_a: [u8; 64] = [proof_a_x, proof_a_y].concat().try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Failed to convert proof_a to [u8; 64]".to_string()) + })?; + let proof_a = negate_g1(&proof_a)?; - let proof_bx0 = deserialize_hex_string_to_bytes(&json.bs[0][0]); - let proof_bx1 = deserialize_hex_string_to_bytes(&json.bs[0][1]); - let proof_by0 = deserialize_hex_string_to_bytes(&json.bs[1][0]); - let proof_by1 = deserialize_hex_string_to_bytes(&json.bs[1][1]); - let proof_b = [proof_bx0, proof_bx1, proof_by0, proof_by1].concat(); + let proof_b_x_0 = deserialize_hex_string_to_bytes(&json.bs[0][0])?; + let proof_b_x_1 = deserialize_hex_string_to_bytes(&json.bs[0][1])?; + let proof_b_y_0 = deserialize_hex_string_to_bytes(&json.bs[1][0])?; + let proof_b_y_1 = deserialize_hex_string_to_bytes(&json.bs[1][1])?; + let proof_b: [u8; 128] = [proof_b_x_0, proof_b_x_1, proof_b_y_0, proof_b_y_1] + .concat() + .try_into() + .map_err(|_| { + PhotonApiError::UnexpectedError("Failed to convert proof_b to [u8; 128]".to_string()) + })?; - let proof_cx = deserialize_hex_string_to_bytes(&json.krs[0]); - let proof_cy = deserialize_hex_string_to_bytes(&json.krs[1]); - let proof_c = [proof_cx, proof_cy].concat(); + let proof_c_x = deserialize_hex_string_to_bytes(&json.krs[0])?; + let proof_c_y = deserialize_hex_string_to_bytes(&json.krs[1])?; + let proof_c: [u8; 64] = [proof_c_x, proof_c_y].concat().try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Failed to convert proof_c to [u8; 64]".to_string()) + })?; - ProofABC { + Ok(ProofABC { a: proof_a, b: proof_b, c: proof_c, - } + }) } pub fn get_public_input_hash( account_proofs: &[MerkleProofWithContext], new_address_proofs: &[MerkleContextWithNewAddressProof], -) -> [u8; 32] { - let account_hashes: Vec<[u8; 32]> = account_proofs +) -> Result<[u8; 32], PhotonApiError> { + let account_hashes: Result, PhotonApiError> = account_proofs .iter() - .map(|x| x.hash.to_vec().clone().try_into().unwrap()) - .collect::>(); - let account_roots: Vec<[u8; 32]> = account_proofs + .map(|x| { + x.hash.to_vec().try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Failed to convert hash to [u8; 32]".to_string()) + }) + }) + .collect(); + let account_hashes = account_hashes?; + + let account_roots: Result, PhotonApiError> = account_proofs .iter() - .map(|x| x.root.to_vec().clone().try_into().unwrap()) - .collect::>(); - let inclusion_hash_chain: [u8; 32] = - create_two_inputs_hash_chain(&account_roots, &account_hashes).unwrap(); - let new_address_hashes: Vec<[u8; 32]> = new_address_proofs + .map(|x| { + x.root.to_vec().try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Failed to convert root to [u8; 32]".to_string()) + }) + }) + .collect(); + let account_roots = account_roots?; + + let inclusion_hash_chain = create_two_inputs_hash_chain(&account_roots, &account_hashes) + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to create hash chain: {}", e)) + })?; + + let new_address_hashes: Result, PhotonApiError> = new_address_proofs .iter() - .map(|x| x.address.try_to_vec().unwrap().clone().try_into().unwrap()) - .collect::>(); - let new_address_roots: Vec<[u8; 32]> = new_address_proofs + .map(|x| { + x.address + .try_to_vec() + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to serialize address: {}", e)) + })? + .try_into() + .map_err(|_| { + PhotonApiError::UnexpectedError( + "Failed to convert address bytes to [u8; 32]".to_string(), + ) + }) + }) + .collect(); + let new_address_hashes = new_address_hashes?; + + let new_address_roots: Result, PhotonApiError> = new_address_proofs .iter() - .map(|x| x.root.to_vec().clone().try_into().unwrap()) - .collect::>(); + .map(|x| { + x.root.to_vec().try_into().map_err(|_| { + PhotonApiError::UnexpectedError( + "Failed to convert new address root to [u8; 32]".to_string(), + ) + }) + }) + .collect(); + let new_address_roots = new_address_roots?; + let non_inclusion_hash_chain = - create_two_inputs_hash_chain(&new_address_roots, &new_address_hashes).unwrap(); + create_two_inputs_hash_chain(&new_address_roots, &new_address_hashes).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to create hash chain: {}", e)) + })?; + if non_inclusion_hash_chain != [0u8; 32] { - non_inclusion_hash_chain + Ok(non_inclusion_hash_chain) } else if inclusion_hash_chain != [0u8; 32] { - inclusion_hash_chain + Ok(inclusion_hash_chain) } else { - create_two_inputs_hash_chain(&[inclusion_hash_chain], &[non_inclusion_hash_chain]).unwrap() + create_two_inputs_hash_chain(&[inclusion_hash_chain], &[non_inclusion_hash_chain]).map_err( + |e| PhotonApiError::UnexpectedError(format!("Failed to create hash chain: {}", e)), + ) } } diff --git a/src/api/method/get_validity_proof/prover/prove.rs b/src/api/method/get_validity_proof/prover/prove.rs index 498a97a5..3e9ea427 100644 --- a/src/api/method/get_validity_proof/prover/prove.rs +++ b/src/api/method/get_validity_proof/prover/prove.rs @@ -1,6 +1,6 @@ use crate::api::error::PhotonApiError; use crate::api::method::get_multiple_new_address_proofs::MerkleContextWithNewAddressProof; -use crate::api::method::get_validity_proof::prover::gnark::negate_proof; +use crate::api::method::get_validity_proof::prover::gnark::compress_proof; use crate::api::method::get_validity_proof::prover::helpers::{ convert_inclusion_proofs_to_hex, convert_non_inclusion_merkle_proof_to_hex, get_public_input_hash, hash_to_hex, proof_from_json_struct, @@ -71,7 +71,8 @@ pub(crate) async fn generate_proof( let is_v2_tree_height = (state_tree_height == DEFAULT_BATCH_STATE_TREE_HEIGHT as usize) || (address_tree_height == DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize); - let public_input_hash_bytes = get_public_input_hash(&db_account_proofs, &db_new_address_proofs); + let public_input_hash_bytes = + get_public_input_hash(&db_account_proofs, &db_new_address_proofs)?; let public_input_hash_str = if is_v2_tree_height || circuit_type == CircuitType::Combined { hash_to_hex(&Hash(public_input_hash_bytes)) } else { @@ -138,9 +139,8 @@ pub(crate) async fn generate_proof( )) })?; - let proof_abc = proof_from_json_struct(proof_json); - let compressed_gnark_proof = negate_proof(proof_abc); - + let proof = proof_from_json_struct(proof_json)?; + let compressed_proof = compress_proof(&proof)?; let mut account_details = Vec::with_capacity(db_account_proofs.len()); for acc_proof in db_account_proofs.iter() { let tree_info = TreeInfo::get(&acc_proof.merkle_tree.to_string().as_str()) @@ -178,7 +178,7 @@ pub(crate) async fn generate_proof( } Ok(ProverResult { - compressed_proof: compressed_gnark_proof?, + compressed_proof, account_proof_details: account_details, address_proof_details: address_details, }) diff --git a/src/api/method/get_validity_proof/prover/structs.rs b/src/api/method/get_validity_proof/prover/structs.rs index 3bf7895a..d7859f20 100644 --- a/src/api/method/get_validity_proof/prover/structs.rs +++ b/src/api/method/get_validity_proof/prover/structs.rs @@ -19,13 +19,9 @@ pub(crate) struct AddressProofDetail { pub address: String, pub root: String, pub root_index_mod_queue: u64, - pub path_index: u32, // from lowElementLeafIndex, needed for v1 + pub path_index: u32, pub merkle_tree_id: String, pub tree_info: TreeInfo, - // pub next_index: u32, - // pub lower_range_address_hex: String, // Store as hex string - // pub higher_range_address_hex: String, // Store as hex string - // pub original_proof_context: MerkleContextWithNewAddressProof, // Option } #[derive(Debug, Clone)] @@ -65,12 +61,12 @@ pub(crate) struct GnarkProofJson { #[derive(Debug)] pub(crate) struct ProofABC { - pub a: Vec, - pub b: Vec, - pub c: Vec, + pub a: [u8; 64], + pub b: [u8; 128], + pub c: [u8; 64], } -#[derive(Serialize, Deserialize, ToSchema, Default, Debug, Clone)] +#[derive(Serialize, Deserialize, Default, ToSchema, Debug, Clone)] pub struct CompressedProof { pub a: Vec, pub b: Vec, diff --git a/src/ingester/parser/indexer_events.rs b/src/ingester/parser/indexer_events.rs index 9f693b5c..fae6f9bc 100644 --- a/src/ingester/parser/indexer_events.rs +++ b/src/ingester/parser/indexer_events.rs @@ -60,7 +60,6 @@ pub struct PublicTransactionEvent { pub message: Option>, } - #[derive(Debug, Clone)] pub struct BatchPublicTransactionEvent { pub event: PublicTransactionEvent, diff --git a/src/ingester/parser/tx_event_parser_v2.rs b/src/ingester/parser/tx_event_parser_v2.rs index 0706f84a..4ddba16e 100644 --- a/src/ingester/parser/tx_event_parser_v2.rs +++ b/src/ingester/parser/tx_event_parser_v2.rs @@ -1,6 +1,10 @@ use crate::common::typedefs::serializable_pubkey::SerializablePubkey; use crate::ingester::error::IngesterError; -use crate::ingester::parser::indexer_events::{BatchPublicTransactionEvent, CompressedAccount, CompressedAccountData, MerkleTreeSequenceNumberV1, MerkleTreeSequenceNumberV2, OutputCompressedAccountWithPackedContext, PublicTransactionEvent}; +use crate::ingester::parser::indexer_events::{ + BatchPublicTransactionEvent, CompressedAccount, CompressedAccountData, + MerkleTreeSequenceNumberV1, MerkleTreeSequenceNumberV2, + OutputCompressedAccountWithPackedContext, PublicTransactionEvent, +}; use crate::ingester::parser::state_update::StateUpdate; use crate::ingester::parser::tx_event_parser::create_state_update_v1; From 41ac9d0e3607a820ef1dbf4312b288992f792864 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 17 May 2025 18:12:55 +0100 Subject: [PATCH 5/6] refactor: simplify AddressProofInputs, rootIndex: u16 --- src/api/method/get_validity_proof/v2.rs | 4 ++-- ...ultiple_new_address_proofs_interop-validity-proof-v2.snap | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/api/method/get_validity_proof/v2.rs b/src/api/method/get_validity_proof/v2.rs index d918ccd6..d173ef04 100644 --- a/src/api/method/get_validity_proof/v2.rs +++ b/src/api/method/get_validity_proof/v2.rs @@ -90,7 +90,7 @@ pub struct AccountProofInputs { pub struct AddressProofInputs { pub address: String, pub root: String, - pub root_index: RootIndex, + pub root_index: u16, pub merkle_context: MerkleContextV2, } @@ -265,7 +265,7 @@ pub async fn get_validity_proof_v2( v2_addresses_from_prover.push(AddressProofInputs { address: detail.address, root: detail.root, - root_index: Some(detail.root_index_mod_queue).into(), + root_index: detail.root_index_mod_queue as u16, merkle_context: MerkleContextV2 { tree_type: detail.tree_info.tree_type as u16, tree: SerializablePubkey::from(detail.tree_info.tree), diff --git a/tests/integration_tests/snapshots/integration_tests__mock_tests__get_multiple_new_address_proofs_interop-validity-proof-v2.snap b/tests/integration_tests/snapshots/integration_tests__mock_tests__get_multiple_new_address_proofs_interop-validity-proof-v2.snap index 222d2f23..ac95ed9e 100644 --- a/tests/integration_tests/snapshots/integration_tests__mock_tests__get_multiple_new_address_proofs_interop-validity-proof-v2.snap +++ b/tests/integration_tests/snapshots/integration_tests__mock_tests__get_multiple_new_address_proofs_interop-validity-proof-v2.snap @@ -15,10 +15,7 @@ expression: validity_proof_v2 { "address": "12nCKqGG85jHxbTeA8i2Z7D4vnNUUrQ4r5e8dv2o16X", "root": "3FrGzyXtjqjnukHDS2M5oyVj8tMVcHSahcHpWBGR5MHY", - "rootIndex": { - "rootIndex": 3, - "proveByIndex": false - }, + "rootIndex": 3, "merkleContext": { "treeType": 2, "tree": "amt1Ayt45jfbdw5YSo7iz6WZxUmnZsQTYXy82hVwyC2", From 1a788af386e4756c658e30cf9fe114e0647ebbee Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 18 May 2025 08:55:13 +0100 Subject: [PATCH 6/6] refactor: extract proof generation for empty tree into separate function --- .../persist/persisted_indexed_merkle_tree.rs | 97 ++++++++++++------- 1 file changed, 62 insertions(+), 35 deletions(-) diff --git a/src/ingester/persist/persisted_indexed_merkle_tree.rs b/src/ingester/persist/persisted_indexed_merkle_tree.rs index c0824680..26ac84e8 100644 --- a/src/ingester/persist/persisted_indexed_merkle_tree.rs +++ b/src/ingester/persist/persisted_indexed_merkle_tree.rs @@ -132,41 +132,7 @@ pub async fn get_exclusion_range_with_proof_v2( )) })?; if btree.is_empty() { - let zeroeth_element = get_zeroeth_exclusion_range(tree.clone()); - let zeroeth_element_hash = compute_range_node_hash(&zeroeth_element).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to compute hash: {}", e)) - })?; - - let mut proof: Vec = vec![]; - for i in 0..(tree_height - 1) { - let hash = Hash::try_from(ZERO_BYTES[i as usize]).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to convert hash: {}", e)) - })?; - proof.push(hash); - } - - let mut root = zeroeth_element_hash.clone().to_vec(); - - for elem in proof.iter() { - root = compute_parent_hash(root, elem.to_vec()).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to compute hash: {}", e)) - })?; - } - - let merkle_proof = MerkleProofWithContext { - proof, - root: Hash::try_from(root).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to convert hash: {}", e)) - })?, - leaf_index: 0, - hash: zeroeth_element_hash, - merkle_tree: SerializablePubkey::try_from(tree.clone()).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to serialize pubkey: {}", e)) - })?, - root_seq: if TREE_HEIGHT_V1 == tree_height { 3 } else { 0 }, - }; - merkle_proof.validate()?; - return Ok((zeroeth_element, merkle_proof)); + return proof_for_empty_tree(tree, tree_height); } let range_node = btree.values().next().ok_or(PhotonApiError::RecordNotFound( @@ -222,6 +188,46 @@ pub async fn get_exclusion_range_with_proof_v2( Ok((range_node.clone(), leaf_proof)) } +fn proof_for_empty_tree( + tree: Vec, + tree_height: u32, +) -> Result<(indexed_trees::Model, MerkleProofWithContext), PhotonApiError> { + let zeroeth_element = get_zeroeth_exclusion_range(tree.clone()); + let zeroeth_element_hash = compute_range_node_hash(&zeroeth_element) + .map_err(|e| PhotonApiError::UnexpectedError(format!("Failed to compute hash: {}", e)))?; + + let mut proof: Vec = vec![]; + for i in 0..(tree_height - 1) { + let hash = Hash::try_from(ZERO_BYTES[i as usize]).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to convert hash: {}", e)) + })?; + proof.push(hash); + } + + let mut root = zeroeth_element_hash.clone().to_vec(); + + for elem in proof.iter() { + root = compute_parent_hash(root, elem.to_vec()).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to compute hash: {}", e)) + })?; + } + + let merkle_proof = MerkleProofWithContext { + proof, + root: Hash::try_from(root).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to convert hash: {}", e)) + })?, + leaf_index: 0, + hash: zeroeth_element_hash, + merkle_tree: SerializablePubkey::try_from(tree.clone()).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to serialize pubkey: {}", e)) + })?, + root_seq: if TREE_HEIGHT_V1 == tree_height { 3 } else { 0 }, + }; + merkle_proof.validate()?; + Ok((zeroeth_element, merkle_proof)) +} + pub async fn get_exclusion_range_with_proof_v1( txn: &DatabaseTransaction, tree: Vec, @@ -687,3 +693,24 @@ pub async fn validate_tree(db_conn: &sea_orm::DatabaseConnection, tree: Serializ } info!("Finished validating tree"); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_zeroeth_element_hash_is_not_zero_bytes_0() { + let dummy_tree_id = vec![1u8; 32]; + let zeroeth_element = get_zeroeth_exclusion_range(dummy_tree_id.clone()); + let zeroeth_element_hash_result = compute_range_node_hash(&zeroeth_element); + assert!( + zeroeth_element_hash_result.is_ok(), + "Failed to compute zeroeth_element_hash: {:?}", + zeroeth_element_hash_result.err() + ); + let zeroeth_element_hash = zeroeth_element_hash_result.unwrap(); + + let zero_hash_at_level_0 = ZERO_BYTES[0]; + assert_ne!(zeroeth_element_hash.to_vec(), zero_hash_at_level_0.to_vec(),); + } +}