diff --git a/adapters/solana/GEYSER.md b/adapters/solana/GEYSER.md new file mode 100644 index 000000000..c3aa4a602 --- /dev/null +++ b/adapters/solana/GEYSER.md @@ -0,0 +1,121 @@ +## Background +In order to prove data availability, we have an on-chain program that accepts chunks, calculates the merkle root once all the chunks are received on-chain and then updates a Program Derived Address (PDA) with the merkle root. +Solana does not have full state commitments every block, instead it has a commitment to the accounts that were modified within that block as part of the BankHash. +Since the PDA is modified everytime a full rollup blob is seen by solana (i.e. all the chunks), the root of the chunks will be committed to in the BankHash. +Details about how the PDA is modified are available in [README](README.md) + +### BankHash +* The BankHash is the commitment chosen by the staked validators to vote on +* The BankHash is created by hashing the following components +``` +let mut hash = hashv(&[ + self.parent_hash.as_ref(), + accounts_delta_hash.0.as_ref(), + &signature_count_buf, + self.last_blockhash().as_ref(), +]); +``` + * `parent_hash` refers to the parent bankhash + * `accounts_delta_hash` refers to the merkle root of the modified accounts in that block (these are sorted by account address) + * `signature_count_buf` is the number of signatures in the block + * `last_blockhash` is the "blockhash" - it's different from the bankhash and refers to the last PoH tick after interleaving all the transactions together. + +### Clarification about terminology +* Solana uses multiple terms `slothash`, `bankhash`, `blockhash` +* `slothash` is the same as `bankhash`. +* `blockhash` refers to a PoH tick +* However, the json rpc is mis-leading. `getBlock` for instance returns data of this example format +```json +{ + "jsonrpc": "2.0", + "result": { + "blockHeight": 428, + "blockTime": null, + "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA", + "parentSlot": 429, + "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B", + "transactions": [ + ] + }, + "id": 1 +} +``` +* In the above response `previousBlockhash` actually refers to the BankHash after the previous block was applied. It corresponds to `parent_hash` used in the previous section +* `blockhash` however corresponds to the PoH tick. + +## Geyser Plugin +* We need to prove that the blob has been published to solana. This is accomplished by running a geyser plugin inside the solana validator. +* The geyser plugin tracks account updates as blocks are executed and merkle proofs are generated against the `accounts_delta_hash` +* The proofs generated for a Pubkey being monitored are of the form +```rust +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub enum AccountDeltaProof { + /// Simplest proof for inclusion in the account delta hash + InclusionProof(Pubkey, (Data, Proof)), + /// Adjacency proof for non inclusion A C D E, non-inclusion for B means providing A and C + NonInclusionProofInner(Pubkey, ((Data, Proof), (Data, Proof))), + /// Left most leaf and proof + NonInclusionProofLeft(Pubkey, (Data, Proof)), + /// Right most leaf and proof. Also need to include hashes of all leaves to verify tree size + NonInclusionProofRight(Pubkey, (Data, Proof, Vec)), +} +``` +* The code exists for `InclusionProof`, as well as the `NonInclusionProof`s, but only the inclusion is verified currently. + +### Running the Geyser Plugin +* Build the geyser plugin - this is a `.dylib` (or `.so`) that implements the plugin interface and runs inside the solana validator +```bash +cd adapters/solana/account_proof_geyser +cargo build --release +``` +* The plugin needs to be built with the same rust version used to build the solana validator. We have a `rust-toolchain.toml` pinning the rust version +* The dynamic lib should be found in `target/release` +``` +ls -lahtr target/release/libaccount* +-rw-r--r-- 1 username staff 422B Oct 22 05:58 target/release/libaccount_proof_geyser.d +-rwxr-xr-x 1 username staff 3.6M Oct 24 05:19 target/release/libaccount_proof_geyser.dylib +-rw-r--r-- 1 username staff 12M Oct 24 05:19 target/release/libaccount_proof_geyser.rlib +``` +* The file we care about is `target/release/libaccount_proof_geyser.dylib` +* Build the solana test validator +```bash +git clone git@github.com:solana-labs/solana.git +git checkout tags/v1.16.15 +./cargo build --release --bin solana-test-validator +``` +* Update `adapater/solana/config.json` +```json +{ + "libpath": "~/sovereign/adapters/solana/account_proof_geyser/target/release/libaccount_proof_geyser.dylib", + "bind_address": "127.0.0.1:10000", + "account_list": ["SysvarS1otHashes111111111111111111111111111"] +} +``` + * Change libpath to point to the full path for `libaccount_proof_geyser.dylib` + * We can leave `account_list` as `SysvarS1otHashes111111111111111111111111111` for now because this is just an example and WIP +* Run the validator with the geyser config +```bash +~/solana/target/release/solana-test-validator --geyser-plugin-config config.json +``` +* Once the validator starts up, you can run the tcp client to fetch the Inclusion proofs for `SysvarS1otHashes111111111111111111111111111` each block +```bash +cd adapters/solana/da_client/ +cargo run --release --bin simple_tcp_client + Finished dev [unoptimized + debuginfo] target(s) in 2.36s + Running `target/debug/simple_tcp_client` +Proof verification succeeded for slot 36172 +Proof verification succeeded for slot 36173 +Proof verification succeeded for slot 36174 +Proof verification succeeded for slot 36175 +``` + +## Work Remaining +* Rigorous testing for merkle proof generation +* Testing for account update processing + * Currently, the plugin monitors updates as they arrive, moves them to different hashmaps based on SLot updates for "processed" and "confirmed" + * This works locally, but production validators fork a lot before confirmation, so we need to test this under load to ensure that we're generating proofs correctly +* Test cases for non inclusion proofs (Inclusion has some tests but Non inclusion doesn't) +* `verify_leaves_against_bankhash` needs to updated for Non inclusion proofs using the adjacency checks `are_adjacent` and `is_first` + * `is_last` is particularly interesting since proving that a leaf is the first leaf is trivial, but proving last leaf is more complicated since we don't have a commitment to the number of leaves in the tree (i.e. the number of accounts updated) +* The `da_client` PDA needs to be plugged into the `simple_tcp_client` as well as the geyser plugin. This would require non inclusion proofs to work +* Currently, the geyser plugin has a simple tcp server that does only one thing - stream account deltas and their inclusion or non-inclusion proofs. We need to replace this with a more comprehensive GRPC server \ No newline at end of file diff --git a/adapters/solana/account_proof_geyser/Cargo.lock b/adapters/solana/account_proof_geyser/Cargo.lock new file mode 100644 index 000000000..1113f17e3 --- /dev/null +++ b/adapters/solana/account_proof_geyser/Cargo.lock @@ -0,0 +1,4061 @@ +# This file is automatically @generated by Cargo. +# 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 = "account_proof_geyser" +version = "0.1.0" +dependencies = [ + "anyhow", + "blake3", + "borsh 0.10.3", + "crossbeam", + "crossbeam-channel", + "log", + "lru 0.12.0", + "rand 0.8.5", + "rayon", + "serde", + "serde_json", + "solana-geyser-plugin-interface", + "solana-logger", + "solana-runtime", + "solana-sdk", + "solana-transaction-status", + "tokio", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.4", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "array-bytes" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-compression" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[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", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2 1.0.69", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", + "proc-macro-crate 0.1.5", + "proc-macro2 1.0.69", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.69", + "quote 1.0.33", + "strsim", + "syn 2.0.38", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", + "rayon", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dir-diff" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +dependencies = [ + "walkdir", +] + +[[package]] +name = "dlopen" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +dependencies = [ + "dlopen_derive", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "dlopen_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +dependencies = [ + "libc", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "goblin" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "h2" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "index_list" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown 0.12.3", +] + +[[package]] +name = "lru" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +dependencies = [ + "hashbrown 0.14.2", +] + +[[package]] +name = "lz4" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +dependencies = [ + "libc", + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.3", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "ouroboros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +dependencies = [ + "aliasable", + "ouroboros_macro", +] + +[[package]] +name = "ouroboros_macro" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2 1.0.69", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "async-compression", + "base64 0.21.4", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64 0.21.4", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "solana-account-decoder" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850d5d9dc8fa6ea42f4e61c78e296bbbce5a3531ff4cb3c58ef36ee31781049c" +dependencies = [ + "Inflector", + "base64 0.21.4", + "bincode", + "bs58", + "bv", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-address-lookup-table-program", + "solana-config-program", + "solana-sdk", + "spl-token", + "spl-token-2022", + "thiserror", + "zstd", +] + +[[package]] +name = "solana-address-lookup-table-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7f867cde478a078d4c4ceb113f4f9ac7e29c2efea98f80a2b30cdcd7be83c5" +dependencies = [ + "bincode", + "bytemuck", + "log", + "num-derive", + "num-traits", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaf42dbfe8a42b80e24f2c087a3935d6e7bb49886313b006d88fb04fdc2a02f" +dependencies = [ + "bincode", + "byteorder", + "libsecp256k1", + "log", + "rand 0.7.3", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-bucket-map" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e050e58ea0c422f9db10d987b2a10992f103209454f70d54f6208b14ec5546a0" +dependencies = [ + "bv", + "log", + "memmap2", + "modular-bitfield", + "num_enum 0.6.1", + "rand 0.7.3", + "solana-measure", + "solana-sdk", + "tempfile", +] + +[[package]] +name = "solana-compute-budget-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c90fdaafdc41a4ba0a760af5491bd79f02d1d1eae6926b7796561681c843e4" +dependencies = [ + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-config-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f9f2201c7e526581511fa6525e281518be5cabaee82bd5b29fe4b78744148d" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-frozen-abi" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361cc834e5fbbe1a73f1d904fcb8ab052a665e5be6061bd1ba7ab478d7d17c9c" +dependencies = [ + "ahash 0.8.3", + "blake3", + "block-buffer 0.10.4", + "bs58", + "bv", + "byteorder", + "cc", + "either", + "generic-array", + "getrandom 0.1.16", + "im", + "lazy_static", + "log", + "memmap2", + "once_cell", + "rand_core 0.6.4", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575d875dc050689f9f88c542e292e295e2f081d4e96e0df297981e45cbad8824" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "rustc_version", + "syn 2.0.38", +] + +[[package]] +name = "solana-geyser-plugin-interface" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268db758cb4193ccf70c85459bfd0e8e5eb7a13b3ee876106d07fada04290a17" +dependencies = [ + "log", + "solana-sdk", + "solana-transaction-status", + "thiserror", +] + +[[package]] +name = "solana-loader-v4-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f1e56ce753307a1b169ad2ef3b9af024c93d4db6f6cd6659794c57635f32ff" +dependencies = [ + "log", + "rand 0.7.3", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana_rbpf", +] + +[[package]] +name = "solana-logger" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00faf7aa6a3f47c542bd45d2d7f13af9a382d993e647976a676fe1b0eec4eb2" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-measure" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e19c6e1b35df3c212619a7995ae3576fa92ab15ecfc065899f21385cbe45c95" +dependencies = [ + "log", + "solana-sdk", +] + +[[package]] +name = "solana-metrics" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10e62760a5f87d836169eb3bb446bae174181db07d2c8016be36de49c04fd432" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-sdk", +] + +[[package]] +name = "solana-perf" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d44a4998ba6d9b37e89399d9ce2812e84489dd4665df619fb23366e1c2ec1b" +dependencies = [ + "ahash 0.8.3", + "bincode", + "bv", + "caps", + "curve25519-dalek", + "dlopen", + "dlopen_derive", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.7.3", + "rayon", + "serde", + "solana-metrics", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-vote-program", +] + +[[package]] +name = "solana-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9863ff5c6e828015bec331c26fb53e48352a264a9be682e7e078d2c3b3e93b46" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "array-bytes", + "base64 0.21.4", + "bincode", + "bitflags 1.3.2", + "blake3", + "borsh 0.10.3", + "borsh 0.9.3", + "bs58", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.10", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "log", + "memoffset 0.9.0", + "num-bigint 0.4.4", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.7.3", + "rand_chacha 0.2.2", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-program-runtime" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05813d4d2e141ab4449cf684cc5b05512dfaabb7251561c5bb1ccf1e4221b210" +dependencies = [ + "base64 0.21.4", + "bincode", + "eager", + "enum-iterator", + "itertools", + "libc", + "log", + "num-derive", + "num-traits", + "percentage", + "rand 0.7.3", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ab62fc62458271d746678a3f5625e1654e3cb42a8f318ef4f1ea25991bb085" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-runtime" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf6db318fd94457b1e69a481dcf43c6fd4f44e264b35f2489f0a1c6f7736e50" +dependencies = [ + "arrayref", + "bincode", + "blake3", + "bv", + "bytemuck", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "dir-diff", + "flate2", + "fnv", + "im", + "index_list", + "itertools", + "lazy_static", + "log", + "lru 0.7.8", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive", + "num-traits", + "num_cpus", + "num_enum 0.6.1", + "once_cell", + "ouroboros", + "percentage", + "rand 0.7.3", + "rayon", + "regex", + "rustc_version", + "serde", + "serde_derive", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-bucket-map", + "solana-compute-budget-program", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-loader-v4-program", + "solana-measure", + "solana-metrics", + "solana-perf", + "solana-program-runtime", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", + "solana-zk-token-proof-program", + "solana-zk-token-sdk", + "static_assertions", + "strum", + "strum_macros", + "symlink", + "tar", + "tempfile", + "thiserror", + "zstd", +] + +[[package]] +name = "solana-sdk" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621e6973766420162541b26e7974783d32d5471571610da30c5bb0b6263046c9" +dependencies = [ + "assert_matches", + "base64 0.21.4", + "bincode", + "bitflags 1.3.2", + "borsh 0.10.3", + "bs58", + "bytemuck", + "byteorder", + "chrono", + "derivation-path", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "generic-array", + "hmac 0.12.1", + "itertools", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive", + "num-traits", + "num_enum 0.6.1", + "pbkdf2 0.11.0", + "qstring", + "rand 0.7.3", + "rand_chacha 0.2.2", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-logger", + "solana-program", + "solana-sdk-macro", + "thiserror", + "uriparse", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd177a74fb3a0a362f1292c027d668eff609ac189f08b78158324587a0a4f8d1" +dependencies = [ + "bs58", + "proc-macro2 1.0.69", + "quote 1.0.33", + "rustversion", + "syn 2.0.38", +] + +[[package]] +name = "solana-stake-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5421decf09671329c4786ed209acfe986bb51272f91e13e4744b13a69c800680" +dependencies = [ + "bincode", + "log", + "rustc_version", + "solana-config-program", + "solana-program-runtime", + "solana-sdk", + "solana-vote-program", +] + +[[package]] +name = "solana-system-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6101d189dc10a96388c695ca1d9f23f74f0fd96330f6adefafd7d6999a20ff6e" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-transaction-status" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aed485ddb4268b4e4ec64012016cd54ba3a4142377a99706fc3ab7768eb2bea" +dependencies = [ + "Inflector", + "base64 0.21.4", + "bincode", + "borsh 0.9.3", + "bs58", + "lazy_static", + "log", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-address-lookup-table-program", + "solana-sdk", + "spl-associated-token-account", + "spl-memo", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-vote-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8b719e077cc9e42b8965dd06ff6b5f09fa2a436f2297efdcf471c05d187a6c" +dependencies = [ + "bincode", + "log", + "num-derive", + "num-traits", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-zk-token-proof-program" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5404829f9236ac760a943a4e2f16be6f180ce4a07e1bbb9d538dcfa62b98888c" +dependencies = [ + "bytemuck", + "getrandom 0.1.16", + "num-derive", + "num-traits", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61aabdec9fe1b311dce5d21fa5bd58fbaa985e8003e0d0aedf3795113aacc1ea" +dependencies = [ + "aes-gcm-siv", + "base64 0.21.4", + "bincode", + "bytemuck", + "byteorder", + "curve25519-dalek", + "getrandom 0.1.16", + "itertools", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.7.3", + "serde", + "serde_json", + "sha3 0.9.1", + "solana-program", + "solana-sdk", + "subtle", + "thiserror", + "zeroize", +] + +[[package]] +name = "solana_rbpf" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d4ba1e58947346e360fabde0697029d36ba83c42f669199b16a8931313cf29" +dependencies = [ + "byteorder", + "combine", + "goblin", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spl-associated-token-account" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" +dependencies = [ + "assert_matches", + "borsh 0.9.3", + "num-derive", + "num-traits", + "solana-program", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "spl-memo" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-token" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "solana-zk-token-sdk", + "spl-memo", + "spl-token", + "thiserror", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2 1.0.69", + "quote 1.0.33", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.0.2", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote 1.0.33", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "xattr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +dependencies = [ + "libc", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/adapters/solana/account_proof_geyser/Cargo.toml b/adapters/solana/account_proof_geyser/Cargo.toml new file mode 100644 index 000000000..b0bf883c9 --- /dev/null +++ b/adapters/solana/account_proof_geyser/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "account_proof_geyser" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib","rlib"] + +[dependencies] +borsh = "0.10.3" +serde = { version = "1.0.145", features = ["derive"] } +serde_json = "1.0.86" +solana-geyser-plugin-interface = "=1.16.15" +solana-logger = "=1.16.15" +solana-sdk = "=1.16.15" +solana-transaction-status = "=1.16.15" +solana-runtime = "=1.16.15" +log = "0.4.17" +crossbeam-channel = "0.5.8" +crossbeam = "0.8.2" +blake3 = "1.3.3" +rayon = "1.7.0" +lru = "0.12.0" +anyhow = "1.0.75" +tokio = { version = "1", features = ["full"] } + +[dev-dependencies] +rand = "0.8.5" + +[workspace] + +[profile.release] +debug = true +lto = true +codegen-units = 1 diff --git a/adapters/solana/account_proof_geyser/rust-toolchain.toml b/adapters/solana/account_proof_geyser/rust-toolchain.toml new file mode 100644 index 000000000..4de7796f9 --- /dev/null +++ b/adapters/solana/account_proof_geyser/rust-toolchain.toml @@ -0,0 +1,5 @@ +[toolchain] +channel = "1.69.0" +components = ["clippy", "rustfmt"] +targets = [] +profile = "minimal" \ No newline at end of file diff --git a/adapters/solana/account_proof_geyser/src/config.rs b/adapters/solana/account_proof_geyser/src/config.rs new file mode 100644 index 000000000..e51b0783f --- /dev/null +++ b/adapters/solana/account_proof_geyser/src/config.rs @@ -0,0 +1,51 @@ +use std::net::SocketAddr; +use std::path::Path; +use std::{fs, io}; + +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub libpath: String, + pub account_list: Vec, + pub bind_address: SocketAddr, +} + +#[derive(Debug)] +pub enum ConfigError { + IoError(io::Error), + ParseError(serde_json::Error), +} + +impl std::fmt::Display for ConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + ConfigError::IoError(e) => write!(f, "I/O error: {}", e), + ConfigError::ParseError(e) => write!(f, "Parse error: {}", e), + } + } +} + +impl From for ConfigError { + fn from(err: io::Error) -> Self { + ConfigError::IoError(err) + } +} + +impl From for ConfigError { + fn from(err: serde_json::Error) -> Self { + ConfigError::ParseError(err) + } +} + +impl Config { + fn load_from_str(config: &str) -> Result { + serde_json::from_str(config).map_err(ConfigError::from) + } + + pub fn load_from_file>(file: P) -> Result { + let config = fs::read_to_string(file)?; + Self::load_from_str(&config) + } +} diff --git a/adapters/solana/account_proof_geyser/src/lib.rs b/adapters/solana/account_proof_geyser/src/lib.rs new file mode 100644 index 000000000..a8316efac --- /dev/null +++ b/adapters/solana/account_proof_geyser/src/lib.rs @@ -0,0 +1,581 @@ +pub mod config; +pub mod types; +pub mod utils; + +use std::collections::HashMap; +use std::fmt::Debug; +use std::str::FromStr; +use std::sync::atomic::{AtomicU8, Ordering}; +use std::thread; + +use borsh::BorshSerialize; +use crossbeam_channel::{unbounded, Sender}; +use log::error; +use solana_geyser_plugin_interface::geyser_plugin_interface::{ + GeyserPlugin, GeyserPluginError, ReplicaAccountInfoVersions, ReplicaBlockInfoVersions, + ReplicaEntryInfoVersions, ReplicaTransactionInfoVersions, Result as PluginResult, SlotStatus, +}; +use solana_sdk::clock::Slot; +use solana_sdk::hash::{hashv, Hash}; +use solana_sdk::pubkey::Pubkey; +use tokio::io::AsyncWriteExt; +use tokio::net::TcpListener; +use tokio::sync::broadcast; + +use crate::config::Config; +use crate::types::{ + AccountHashAccumulator, AccountInfo, BankHashProof, BlockInfo, GeyserMessage, SlotInfo, + TransactionInfo, TransactionSigAccumulator, Update, +}; +use crate::utils::{ + assemble_account_delta_proof, calculate_root_and_proofs, get_keys_for_non_inclusion_inner, + get_proof_pubkeys_required, hash_solana_account, +}; + +/// The primary goal of this function is to calculate the necessary proofs for accounts that we're interested in monitoring +/// against the BankHash. This includes both inclusion and non-inclusion proofs, so every confirmed slot results in an Update +/// being generated, either with inclusion proofs if the accounts we're interested in are modified, +/// or non-inclusion proofs if the accounts we're interested in are not modified. +/// +/// This function also recalculates the BankHash to ensure that the proof generation is consistent. +/// +/// The calculation is done based on accounts, transactions and blocks that are already in the "processed" commitment status. +/// Data that is in the "processed" commitment status is subject to change due to towerBFT and optimistic execution by solana. +/// The function "handle_processed_slot" takes care of updating data that is in the "processed" status if it changes. +/// This function looks at the latest data for a slot in the "processed" status when a slot is marked as "confirmed" +/// and uses it to generate the proofs required, organize them into an "Update" and return it to the caller +/// +/// # Arguments +/// * `slot` - The slot number that has been confirmed. +/// * `block_accumulator` - A mutable reference to the hashmap maintaining block information. +/// * `processed_slot_account_accumulator` - A mutable reference to the hashmap tracking accounts in the processed state +/// * `processed_transaction_accumulator` - A mutable reference to the hashmap tracking transactions in the processed state +/// * `pubkeys_for_proofs` - A slice of public keys that we need to generate proofs for +/// +/// # Steps +/// 1. If the slot we're trying to "confirm" has any data missing in the processed hashmaps, we "bail", because something has gone wrong. +/// 2. We extract the information from the processed hashmaps necessary for generating the BankHash +/// * Number of signatures in the block - we get this from the `processed_transaction_accumulator` +/// * Previous BankHash - This is part of the `block_accumulator`. +/// * Blockhash - This is the value of the last entry (PoH tick) +/// * Account Hashes for modified Accounts - This is part of the `processed_slot_account_accumulator` +/// 3. We extract the pubkeys for which we need to generate the proofs +/// * If the pubkey's account is modified in the current block, then we need an inclusion proof, so the pubkey is passed as is +/// * If the pubkey's account is not modified, we need a non-inclusion proof. The kind of non-inclusion proof we need depends on +/// * Non-inclusion Left (Our pubkey is smaller than the smallest pubkey at index 0) +/// * Non-inclusion Right (Our pubkey is larger than the largest pubkey at the last index) +/// * Non-inclusion inner (Our pubkey is in between. This means we need two adjacent pubkeys from the modified set) +/// 4. The pubkeys for which proofs are needed and the account hashes are passed into the `calculate_root_and_proofs` function. This returns the account_delta_hash (merkle root) +/// and merkle proofs for each of the pubkeys that we need +/// 5. Calculate BankHash based on hashing the information from step 4 and step 2. +/// 6. Assemble the merkle proofs using `assemble_account_delta_proof` to tag them as inclusion, non-inclusion and to provide additional data necessary for verification. +/// 7. Once a slot is confirmed and the necessary proofs are generated, the data from the `processed` hashmaps can be cleaned up +/// 8. Construct the "Update" struct which contains an update for a single confirmed block. +/// +/// # Errors +/// This function returns an error if any of the required data for the given slot is not present in the accumulators. +/// +/// # Returns +/// Returns an `anyhow::Result` which is Ok if the function succeeds or an error otherwise. +/// +/// ``` +fn handle_confirmed_slot( + slot: u64, + block_accumulator: &mut HashMap, + processed_slot_account_accumulator: &mut AccountHashAccumulator, + processed_transaction_accumulator: &mut TransactionSigAccumulator, + pubkeys_for_proofs: &[Pubkey], +) -> anyhow::Result { + // Step 1: Bail if required information is not present + let Some(block) = block_accumulator.get(&slot) else { + anyhow::bail!("block not available"); + }; + let Some(num_sigs) = processed_transaction_accumulator.get(&slot) else { + anyhow::bail!("list of txns not available"); + }; + let Some(account_hashes_data) = processed_slot_account_accumulator.get(&slot) else { + anyhow::bail!("account hashes not available"); + }; + + // Step 2: Extract necessary information for calculating Bankhash + let num_sigs = num_sigs.clone(); + let parent_bankhash = Hash::from_str(&block.parent_bankhash).unwrap(); + let blockhash = Hash::from_str(&block.blockhash).unwrap(); + let mut account_hashes: Vec<(Pubkey, Hash)> = account_hashes_data + .iter() + .map(|(k, (_, v, _))| (k.clone(), v.clone())) + .collect(); + + // Step 3: Determine which Pubkeys we need the merkle proofs for + let (inclusion, non_inclusion_left, non_inclusion_right, non_inclusion_inner) = + get_proof_pubkeys_required(&mut account_hashes, pubkeys_for_proofs); + + let (non_inclusion_inner_adjacent_keys, non_inclusion_inner_mapping) = + get_keys_for_non_inclusion_inner(&non_inclusion_inner, &mut account_hashes); + + // Based on the above calls, construct a list of pubkeys to pass to `calculate_root_and_proofs` + let mut amended_leaves = inclusion.clone(); + + if non_inclusion_left.len() > 0 { + amended_leaves.push(account_hashes[0].0.clone()); + } + if non_inclusion_right.len() > 0 { + amended_leaves.push(account_hashes[account_hashes.len() - 1].0.clone()); + } + if non_inclusion_inner.len() > 0 { + amended_leaves.extend(non_inclusion_inner_adjacent_keys.iter().cloned()); + } + + // Step 4: Calculate Account Delta Hash (Merkle Root) and Merkle proofs for pubkeys + let (accounts_delta_hash, account_proofs) = + calculate_root_and_proofs(&mut account_hashes, &amended_leaves); + + // Step 5: Calculate BankHash based on accounts_delta_hash and information extracted in Step 2 + let bank_hash = hashv(&[ + parent_bankhash.as_ref(), + accounts_delta_hash.as_ref(), + &num_sigs.to_le_bytes(), + blockhash.as_ref(), + ]); + + // Step 6: Assembled raw merkle proofs into tagged variants for specific inclusion and non inclusion proofs + // Include additional data that is needed to verify against the BankHash as well + let proofs = assemble_account_delta_proof( + &account_hashes, + &account_hashes_data, + &account_proofs, + &inclusion, + &non_inclusion_left, + &non_inclusion_right, + &non_inclusion_inner, + &non_inclusion_inner_mapping, + ) + .unwrap(); + + // Step 7: Clean up data after proofs are generated + block_accumulator.remove(&slot); + processed_slot_account_accumulator.remove(&slot); + processed_transaction_accumulator.remove(&slot); + + // Step 8: Return the `Update` structure which can be borsh serialized and passed to a client + Ok(Update { + slot, + root: bank_hash, + proof: BankHashProof { + proofs, + num_sigs, + account_delta_root: accounts_delta_hash, + parent_bankhash, + blockhash, + }, + }) +} + +fn handle_processed_slot( + slot: u64, + raw_slot_account_accumulator: &mut AccountHashAccumulator, + processed_slot_account_accumulator: &mut AccountHashAccumulator, + raw_transaction_accumulator: &mut TransactionSigAccumulator, + processed_transaction_accumulator: &mut TransactionSigAccumulator, +) -> anyhow::Result<()> { + transfer_slot( + slot, + raw_slot_account_accumulator, + processed_slot_account_accumulator, + ); + transfer_slot( + slot, + raw_transaction_accumulator, + processed_transaction_accumulator, + ); + Ok(()) +} + +fn transfer_slot(slot: u64, raw: &mut HashMap, processed: &mut HashMap) { + if let Some(entry) = raw.remove(&slot) { + processed.insert(slot, entry); + } +} + +/// The goal of this function is to process messages passed through the geyser interface by a solana full node. +/// The message types are variants of the `GeyserMessage` enum. +/// ``` +/// pub enum GeyserMessage { +/// AccountMessage(AccountInfo), +/// BlockMessage(BlockInfo), +/// TransactionMessage(TransactionInfo), +/// SlotMessage(SlotInfo), +/// } +/// ``` +/// * AccountMessage: indicates a specific account is updated for a slot number (can be called multiple times for the same slot) +/// * BlockMessage: indicates a block is updated +/// * TransactionMessage: indicates a transaction is "executed" for a specific slot number. +/// * SlotMessage: indicates a change in the status of a slot. we're interested in "processed" and "confirmed" +/// +/// Logic for handling each message +/// * AccountMessage +/// -> we update `raw_slot_account_accumulator` when an account update is received for a specific slot. +/// -> The hash of the account is also calculated in a way consistent with how solana calculates it +/// -> Versioning is also handled since the same account can be modified multiple times in the same slot (by multiple transactions) +/// * TransactionMessage +/// -> We only need the number of signatures in the block and since this is not directly provided, we accumulate the number of signatures +/// for each transaction for each slot into `raw_transaction_accumulator` +/// * BlockMessage +/// -> We update the `block_accumulator` hashmap with the latest info for each block. +/// * SlotMessage +/// -> When a slot is "processed", we move the information from `raw_slot_account_accumulator` and `raw_transaction_accumulator` to +/// `processed_slot_account_accumulator` and `processed_transaction_accumulator` +/// -> This is done by calling `handle_processed_slot` which moves the information to the corresponding hashmaps +/// -> Key thing to note here is that if a slot is re-processed, then the hashmap is updated so it always has the latest information +/// -> When a slot is "confirmed", we call `handle_confirmed_slot` with the latest information from `processed` +/// +/// NOTE: This processing is single threaded because we rely on ordering of events. If a slot is re-processed, then +/// we expect messages in the following order +/// 1. the transactions in the new block for that slot are sent as `TransactionMessage` +/// 2. The new account values are sent as `AccountMessage` +/// 3. `SlotMessage` is sent with processed status again. +/// +/// The above 3 steps would ensure that the `processed_slot_account_accumulator` and `processed_transaction_accumulator` would contain +/// the latest values needed in preparation for when the `confirmed` message is received for a slot +/// +fn process_messages( + geyser_receiver: crossbeam::channel::Receiver, + tx: broadcast::Sender, + pubkeys_for_proofs: Vec, +) { + let mut raw_slot_account_accumulator: AccountHashAccumulator = HashMap::new(); + let mut processed_slot_account_accumulator: AccountHashAccumulator = HashMap::new(); + + let mut raw_transaction_accumulator: TransactionSigAccumulator = HashMap::new(); + let mut processed_transaction_accumulator: TransactionSigAccumulator = HashMap::new(); + + let mut block_accumulator: HashMap = HashMap::new(); + + loop { + match geyser_receiver.recv() { + // Handle account update + Ok(GeyserMessage::AccountMessage(acc)) => { + let account_hash = hash_solana_account( + acc.lamports, + acc.owner.as_ref(), + acc.executable, + acc.rent_epoch, + &acc.data, + acc.pubkey.as_ref(), + ); + + // Overwrite an account if it already exists + // Overwrite an older version with a newer version of the account data (if account is modified multiple times in the same slot) + let write_version = acc.write_version; + let slot = acc.slot; + + let slot_entry = raw_slot_account_accumulator + .entry(slot) + .or_insert_with(HashMap::new); + + let account_entry = slot_entry + .entry(acc.pubkey) + .or_insert_with(|| (0, Hash::default(), AccountInfo::default())); + + if write_version > account_entry.0 { + *account_entry = (write_version, Hash::from(account_hash), acc); + } + } + // Handle transaction message. We only require the number of signatures for the purpose of calculating the BankHash + Ok(GeyserMessage::TransactionMessage(txn)) => { + let slot_num = txn.slot; + *raw_transaction_accumulator.entry(slot_num).or_insert(0) += txn.num_sigs; + } + // Handle Block updates + Ok(GeyserMessage::BlockMessage(block)) => { + let slot = block.slot; + block_accumulator.insert( + slot, + BlockInfo { + slot, + parent_bankhash: block.parent_bankhash, + blockhash: block.blockhash, + executed_transaction_count: block.executed_transaction_count, + }, + ); + } + // Handle `processed` and `confirmed` slot messages. + // `handle_processed_slot` moves from "working" hashmaps to "processed" hashmaps + // `handle_confirmed_slot` gets the necessary proofs when a slot is "confirmed" + Ok(GeyserMessage::SlotMessage(slot_info)) => match slot_info.status { + SlotStatus::Processed => { + // handle a slot being processed. + // move data from raw -> processed + if let Err(e) = handle_processed_slot( + slot_info.slot, + &mut raw_slot_account_accumulator, + &mut processed_slot_account_accumulator, + &mut raw_transaction_accumulator, + &mut processed_transaction_accumulator, + ) { + error!( + "Error when handling processed slot {}: {:?}", + slot_info.slot, e + ); + } + } + SlotStatus::Confirmed => { + // handle a slot being confirmed + // use latest information in "processed" hashmaps and generate required proofs + // cleanup the processed hashmaps + match handle_confirmed_slot( + slot_info.slot, + &mut block_accumulator, + &mut processed_slot_account_accumulator, + &mut processed_transaction_accumulator, + &pubkeys_for_proofs, + ) { + Ok(update) => { + if let Err(e) = tx.send(update) { + error!( + "No subscribers to receive the update {}: {:?}", + slot_info.slot, e + ); + } + } + Err(err) => { + error!("{:?}", err); + } + } + } + _ => {} + }, + _ => {} + } + } +} + +const STARTUP_END_OF_RECEIVED: u8 = 1 << 0; +const STARTUP_PROCESSED_RECEIVED: u8 = 1 << 1; + +#[derive(Debug)] +pub struct PluginInner { + startup_status: AtomicU8, + geyser_sender: Sender, +} + +impl PluginInner { + fn send_message(&self, message: GeyserMessage) { + if let Err(e) = self.geyser_sender.send(message) { + error!("error when sending message to geyser {:?}", e); + } + } +} + +#[derive(Debug, Default)] +pub struct Plugin { + inner: Option, +} + +impl Plugin { + fn with_inner(&self, f: F) -> PluginResult<()> + where + F: FnOnce(&PluginInner) -> PluginResult<()>, + { + // Before processed slot after end of startup message we will fail to construct full block + let inner = self.inner.as_ref().expect("initialized"); + if inner.startup_status.load(Ordering::SeqCst) + == STARTUP_END_OF_RECEIVED | STARTUP_PROCESSED_RECEIVED + { + f(inner) + } else { + Ok(()) + } + } +} + +impl GeyserPlugin for Plugin { + fn name(&self) -> &'static str { + "AccountProofGeyserPlugin" + } + + fn on_load(&mut self, config_file: &str) -> PluginResult<()> { + let config = Config::load_from_file(config_file) + .map_err(|e| GeyserPluginError::ConfigFileReadError { msg: e.to_string() })?; + solana_logger::setup_with_default("error"); + let (geyser_sender, geyser_receiver) = unbounded(); + let pubkeys_for_proofs: Vec = config + .account_list + .iter() + .map(|x| Pubkey::from_str(x).unwrap()) + .collect(); + + let (tx, _rx) = broadcast::channel(32); + let tx_process_messages = tx.clone(); + + thread::spawn(move || { + process_messages(geyser_receiver, tx_process_messages, pubkeys_for_proofs); + }); + + thread::spawn(move || { + let runtime = tokio::runtime::Runtime::new().unwrap(); + runtime.block_on(async { + let listener = TcpListener::bind(&config.bind_address).await.unwrap(); + loop { + let (mut socket, _) = match listener.accept().await { + Ok(connection) => connection, + Err(e) => { + error!("Failed to accept connection: {:?}", e); + continue; + } + }; + let mut rx = tx.subscribe(); + tokio::spawn(async move { + loop { + match rx.recv().await { + Ok(update) => { + let data = update.try_to_vec().unwrap(); + let _ = socket.write_all(&data).await; + } + Err(_) => {} + } + } + }); + } + }); + }); + + self.inner = Some(PluginInner { + startup_status: AtomicU8::new(0), + geyser_sender, + }); + + Ok(()) + } + + fn on_unload(&mut self) { + if let Some(inner) = self.inner.take() { + drop(inner.geyser_sender); + } + } + + fn update_account( + &self, + account: ReplicaAccountInfoVersions, + slot: Slot, + _is_startup: bool, + ) -> PluginResult<()> { + self.with_inner(|inner| { + let account = match account { + ReplicaAccountInfoVersions::V0_0_3(a) => a, + _ => { + unreachable!("Only ReplicaAccountInfoVersions::V0_0_3 is supported") + } + }; + let pubkey = Pubkey::try_from(account.pubkey).unwrap(); + let owner = Pubkey::try_from(account.owner).unwrap(); + + let message = GeyserMessage::AccountMessage(AccountInfo { + pubkey, + lamports: account.lamports, + owner, + executable: account.executable, + rent_epoch: account.rent_epoch, + data: account.data.to_vec(), + write_version: account.write_version, + slot, + }); + inner.send_message(message); + Ok(()) + }) + } + + fn notify_end_of_startup(&self) -> PluginResult<()> { + let inner = self.inner.as_ref().expect("initialized"); + inner + .startup_status + .fetch_or(STARTUP_END_OF_RECEIVED, Ordering::SeqCst); + Ok(()) + } + + fn update_slot_status( + &self, + slot: Slot, + _parent: Option, + status: SlotStatus, + ) -> PluginResult<()> { + let inner = self.inner.as_ref().expect("initialized"); + if inner.startup_status.load(Ordering::SeqCst) == STARTUP_END_OF_RECEIVED + && status == SlotStatus::Processed + { + inner + .startup_status + .fetch_or(STARTUP_PROCESSED_RECEIVED, Ordering::SeqCst); + } + + self.with_inner(|inner| { + let message = GeyserMessage::SlotMessage(SlotInfo { slot, status }); + inner.send_message(message); + Ok(()) + }) + } + + fn notify_transaction( + &self, + transaction: ReplicaTransactionInfoVersions<'_>, + slot: Slot, + ) -> PluginResult<()> { + self.with_inner(|inner| { + let transaction = match transaction { + ReplicaTransactionInfoVersions::V0_0_2(t) => t, + _ => { + unreachable!("Only ReplicaTransactionInfoVersions::V0_0_2 is supported") + } + }; + + let message = GeyserMessage::TransactionMessage(TransactionInfo { + slot, + num_sigs: transaction.transaction.signatures().len() as u64, + }); + inner.send_message(message); + Ok(()) + }) + } + + fn notify_entry(&self, _entry: ReplicaEntryInfoVersions) -> PluginResult<()> { + Ok(()) + } + + fn notify_block_metadata(&self, blockinfo: ReplicaBlockInfoVersions<'_>) -> PluginResult<()> { + self.with_inner(|inner| { + let blockinfo = match blockinfo { + ReplicaBlockInfoVersions::V0_0_2(info) => info, + _ => { + unreachable!("Only ReplicaBlockInfoVersions::V0_0_1 is supported") + } + }; + + let message = GeyserMessage::BlockMessage((blockinfo).into()); + inner.send_message(message); + + Ok(()) + }) + } + + fn account_data_notifications_enabled(&self) -> bool { + true + } + + fn transaction_notifications_enabled(&self) -> bool { + true + } + + fn entry_notifications_enabled(&self) -> bool { + false + } +} + +#[no_mangle] +#[allow(improper_ctypes_definitions)] +/// # Safety +/// This function returns the Plugin pointer as trait GeyserPlugin. +pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin { + let plugin = Plugin::default(); + let plugin: Box = Box::new(plugin); + Box::into_raw(plugin) +} diff --git a/adapters/solana/account_proof_geyser/src/types.rs b/adapters/solana/account_proof_geyser/src/types.rs new file mode 100644 index 000000000..a1f44761e --- /dev/null +++ b/adapters/solana/account_proof_geyser/src/types.rs @@ -0,0 +1,136 @@ +use std::collections::HashMap; + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_geyser_plugin_interface::geyser_plugin_interface::{ReplicaBlockInfoV2, SlotStatus}; +use solana_sdk::hash::Hash; +use solana_sdk::pubkey::Pubkey; + +pub type AccountHashAccumulator = HashMap; +pub type TransactionSigAccumulator = HashMap; +pub type AccountHashMap = HashMap; + +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub struct Proof { + pub path: Vec, // Position in the chunk (between 0 and 15) for each level. + pub siblings: Vec>, // Sibling hashes at each level. +} + +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub struct Data { + pub pubkey: Pubkey, + pub hash: Hash, + pub account: AccountInfo, +} + +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub enum AccountDeltaProof { + /// Simplest proof for inclusion in the account delta hash + InclusionProof(Pubkey, (Data, Proof)), + /// Adjacency proof for non inclusion A C D E, non-inclusion for B means providing A and C + NonInclusionProofInner(Pubkey, ((Data, Proof), (Data, Proof))), + /// Left most leaf and proof + NonInclusionProofLeft(Pubkey, (Data, Proof)), + /// Right most leaf and proof. Also need to include hashes of all leaves to verify tree size + NonInclusionProofRight(Pubkey, (Data, Proof, Vec)), +} + +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub struct BankHashProof { + pub proofs: Vec, + pub num_sigs: u64, + pub account_delta_root: Hash, + pub parent_bankhash: Hash, + pub blockhash: Hash, +} + +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +pub struct Update { + pub slot: u64, + pub root: Hash, + pub proof: BankHashProof, +} + +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +pub struct AccountInfo { + /// The Pubkey for the account + pub pubkey: Pubkey, + + /// The lamports for the account + pub lamports: u64, + + /// The Pubkey of the owner program account + pub owner: Pubkey, + + /// This account's data contains a loaded program (and is now read-only) + pub executable: bool, + + /// The epoch at which this account will next owe rent + pub rent_epoch: u64, + + /// The data held in this account. + pub data: Vec, + + /// A global monotonically increasing atomic number, which can be used + /// to tell the order of the account update. For example, when an + /// account is updated in the same slot multiple times, the update + /// with higher write_version should supersede the one with lower + /// write_version. + pub write_version: u64, + + /// Slot number for this update + pub slot: u64, +} + +impl Default for AccountInfo { + fn default() -> Self { + AccountInfo { + pubkey: Pubkey::default(), + lamports: 0, + owner: Pubkey::default(), + executable: false, + rent_epoch: 0, + data: Vec::new(), + write_version: 0, + slot: 0, + } + } +} + +#[derive(Debug, Clone)] +pub struct TransactionInfo { + pub slot: u64, + pub num_sigs: u64, +} + +#[derive(Debug, Clone)] +pub struct BlockInfo { + pub slot: u64, + pub parent_bankhash: String, + pub blockhash: String, + pub executed_transaction_count: u64, +} + +impl<'a> From<&'a ReplicaBlockInfoV2<'a>> for BlockInfo { + fn from(block: &'a ReplicaBlockInfoV2<'a>) -> Self { + Self { + slot: block.slot, + parent_bankhash: block.parent_blockhash.to_string(), + blockhash: block.blockhash.to_string(), + executed_transaction_count: block.executed_transaction_count, + } + } +} + +#[derive(Debug, Clone)] +pub struct SlotInfo { + pub slot: u64, + pub status: SlotStatus, +} + +#[derive(Debug, Clone)] +pub enum GeyserMessage { + AccountMessage(AccountInfo), + BlockMessage(BlockInfo), + TransactionMessage(TransactionInfo), + SlotMessage(SlotInfo), +} diff --git a/adapters/solana/account_proof_geyser/src/utils.rs b/adapters/solana/account_proof_geyser/src/utils.rs new file mode 100644 index 000000000..c4dfca300 --- /dev/null +++ b/adapters/solana/account_proof_geyser/src/utils.rs @@ -0,0 +1,598 @@ +use std::collections::HashMap; + +use blake3::traits::digest::Digest; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use rayon::prelude::*; +use solana_runtime::accounts_hash::{AccountsHasher, MERKLE_FANOUT}; +use solana_sdk::hash::{Hash, Hasher, hashv}; +use solana_sdk::pubkey::Pubkey; + +use crate::types::{AccountDeltaProof, AccountHashMap, Data, Proof}; + +/// Util helper function to calculate the hash of a solana account +/// https://github.com/solana-labs/solana/blob/v1.16.15/runtime/src/accounts_db.rs#L6076-L6118 +/// We can see as we make the code more resilient to see if we can also make +/// the structures match and use the function from solana-sdk, but currently it seems a bit more +/// complicated and lower priority, since getting a stable version working is top priority +pub fn hash_solana_account( + lamports: u64, + owner: &[u8], + executable: bool, + rent_epoch: u64, + data: &[u8], + pubkey: &[u8], +) -> [u8; 32] { + if lamports == 0 { + return [08; 32]; + } + let mut hasher = blake3::Hasher::new(); + + hasher.update(&lamports.to_le_bytes()); + hasher.update(&rent_epoch.to_le_bytes()); + hasher.update(data); + + if executable { + hasher.update(&[1u8; 1]); + } else { + hasher.update(&[0u8; 1]); + } + hasher.update(owner.as_ref()); + hasher.update(pubkey.as_ref()); + + hasher.finalize().into() +} + +// Simple wrapper around the solana function +pub fn calculate_root(pubkey_hash_vec: Vec<(Pubkey, Hash)>) -> Hash { + AccountsHasher::accumulate_account_hashes(pubkey_hash_vec) +} + +// Originally attempted to calculate the proof while generating the root +// but logically felt more complex, so the root calculation is separated from proof gen +// TODO: see if these can be combined +pub fn calculate_root_and_proofs( + pubkey_hash_vec: &mut [(Pubkey, Hash)], + leaves_for_proof: &[Pubkey], +) -> (Hash, Vec<(Pubkey, Proof)>) { + pubkey_hash_vec.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); + + let root = compute_merkle_root_loop(pubkey_hash_vec, MERKLE_FANOUT, |i: &(Pubkey, Hash)| &i.1); + let proofs = generate_merkle_proofs(pubkey_hash_vec, leaves_for_proof); + + (root, proofs) +} + +pub fn generate_merkle_proofs( + pubkey_hash_vec: &[(Pubkey, Hash)], + leaves_for_proof: &[Pubkey], +) -> Vec<(Pubkey, Proof)> { + let mut proofs = Vec::new(); + + for &key in leaves_for_proof { + let mut path = Vec::new(); + let mut siblings = Vec::new(); + + // Find the position of the key in the sorted pubkey_hash_vec + let mut pos = pubkey_hash_vec + .binary_search_by(|&(ref k, _)| k.cmp(&key)) + .unwrap(); + + let mut current_hashes: Vec<_> = pubkey_hash_vec + .iter() + .map(|&(_, ref h)| h.clone()) + .collect(); + while current_hashes.len() > 1 { + let chunk_index = pos / MERKLE_FANOUT; + let index_in_chunk = pos % MERKLE_FANOUT; + + path.push(index_in_chunk); + + // Collect the hashes of the siblings for the current hash in this level. + let mut sibling_hashes = Vec::with_capacity(MERKLE_FANOUT - 1); + for i in 0..MERKLE_FANOUT { + if i == index_in_chunk { + continue; + } + let sibling_pos = chunk_index * MERKLE_FANOUT + i; + if sibling_pos < current_hashes.len() { + sibling_hashes.push(current_hashes[sibling_pos].clone()); + } + } + siblings.push(sibling_hashes); + + // Move up one level in the tree. + current_hashes = compute_hashes_at_next_level(¤t_hashes); + pos = chunk_index; + } + + proofs.push((key, Proof { path, siblings })); + } + + proofs +} + +fn compute_hashes_at_next_level(hashes: &[Hash]) -> Vec { + let chunks = div_ceil(hashes.len(), MERKLE_FANOUT); + (0..chunks) + .map(|i| { + let start_index = i * MERKLE_FANOUT; + let end_index = std::cmp::min(start_index + MERKLE_FANOUT, hashes.len()); + + let mut hasher = Hasher::default(); + for hash in &hashes[start_index..end_index] { + hasher.hash(hash.as_ref()); + } + + hasher.result() + }) + .collect() +} + +pub fn compute_merkle_root_loop(hashes: &[T], fanout: usize, extractor: F) -> Hash +where + F: Fn(&T) -> &Hash + std::marker::Sync, + T: std::marker::Sync, +{ + if hashes.is_empty() { + return Hasher::default().result(); + } + + let total_hashes = hashes.len(); + let chunks = div_ceil(total_hashes, fanout); + + let result: Vec<_> = (0..chunks) + .into_par_iter() + .map(|i| { + let start_index = i * fanout; + let end_index = std::cmp::min(start_index + fanout, total_hashes); + + let mut hasher = Hasher::default(); + for item in hashes.iter().take(end_index).skip(start_index) { + let h = extractor(item); + hasher.hash(h.as_ref()); + } + + hasher.result() + }) + .collect(); + + if result.len() == 1 { + result[0] + } else { + compute_merkle_root_recurse(&result, fanout) + } +} + +// this function avoids an infinite recursion compiler error +pub fn compute_merkle_root_recurse(hashes: &[Hash], fanout: usize) -> Hash { + compute_merkle_root_loop(hashes, fanout, |t| t) +} + +pub fn div_ceil(x: usize, y: usize) -> usize { + let mut result = x / y; + if x % y != 0 { + result += 1; + } + result +} + +pub fn verify_proof(leaf_hash: &Hash, proof: &Proof, root: &Hash) -> bool { + // Validate path length and siblings length + if proof.path.len() != proof.siblings.len() { + return false; + } + + let mut current_hash = leaf_hash.clone(); + + for (index_in_chunk, sibling_hashes) in proof.path.iter().zip(&proof.siblings) { + let mut hasher = Hasher::default(); + + // We need to hash the elements in the correct order. + // Before the current hash, add the siblings. + for i in 0..*index_in_chunk { + hasher.hash(sibling_hashes[i].as_ref()); + } + + // Hash the current hash + hasher.hash(current_hash.as_ref()); + + // After the current hash, add the remaining siblings. + for i in *index_in_chunk..sibling_hashes.len() { + hasher.hash(sibling_hashes[i].as_ref()); + } + + current_hash = hasher.result(); + } + + ¤t_hash == root +} + +pub fn are_adjacent(proof1: &Proof, proof2: &Proof) -> bool { + if proof1.path.len() != proof2.path.len() { + println!( + "Proofs have different path lengths: {} vs {}", + proof1.path.len(), + proof2.path.len() + ); + return false; + } + + for i in 0..proof1.path.len() { + if proof1.path[i] != proof2.path[i] { + let divergence = (proof1.path[i] as i32 - proof2.path[i] as i32).abs(); + + if divergence != 1 && divergence != ((MERKLE_FANOUT - 1) as i32) { + println!( + "Proofs diverge at position {}: proof1[{}]={}, proof2[{}]={}", + i, i, proof1.path[i], i, proof2.path[i] + ); + return false; + } + } + } + true +} + +pub fn is_first(proof: &Proof) -> bool { + proof.path.iter().all(|&position| position == 0) +} + +pub fn get_proof_pubkeys_required( + pubkey_hash_vec: &mut [(Pubkey, Hash)], + leaves_for_proof: &[Pubkey], +) -> (Vec, Vec, Vec, Vec) { + pubkey_hash_vec.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); + + let smallest_key_in_hash_vec = pubkey_hash_vec.first().map(|(pubkey, _)| pubkey).unwrap(); + let largest_key_in_hash_vec = pubkey_hash_vec.last().map(|(pubkey, _)| pubkey).unwrap(); + + let mut inclusion = vec![]; + let mut non_inclusion_left = vec![]; + let mut non_inclusion_right = vec![]; + let mut non_inclusion_inner = vec![]; + + for &leaf in leaves_for_proof { + if pubkey_hash_vec.iter().any(|(pubkey, _)| &leaf == pubkey) { + inclusion.push(leaf); + } else if leaf < *smallest_key_in_hash_vec { + non_inclusion_left.push(leaf); + } else if leaf > *largest_key_in_hash_vec { + non_inclusion_right.push(leaf); + } else { + non_inclusion_inner.push(leaf); + } + } + + ( + inclusion, + non_inclusion_left, + non_inclusion_right, + non_inclusion_inner, + ) +} + +pub fn get_keys_for_non_inclusion_inner( + non_inclusion_inner: &[Pubkey], + pubkey_hash_vec: &mut [(Pubkey, Hash)], +) -> (Vec, HashMap) { + pubkey_hash_vec.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + let sorted_keys: Vec<&Pubkey> = pubkey_hash_vec.iter().map(|(pubkey, _)| pubkey).collect(); + + let mut adjacent_pairs = Vec::new(); + let mut missing_key_to_adjacent = HashMap::new(); + + for &missing_key in non_inclusion_inner { + let position = match sorted_keys.binary_search(&&missing_key) { + Ok(pos) => pos, // This shouldn't really happen, but in case it does + Err(pos) => pos, + }; + + if position > 0 && position < sorted_keys.len() { + let previous_key = sorted_keys[position - 1]; + let next_key = sorted_keys[position]; + + // Add adjacent keys to the result vector + if !adjacent_pairs.contains(previous_key) { + adjacent_pairs.push(*previous_key); + } + if !adjacent_pairs.contains(next_key) { + adjacent_pairs.push(*next_key); + } + + // Associate the missing key with its adjacent keys in the HashMap + missing_key_to_adjacent.insert(missing_key, (*previous_key, *next_key)); + } + } + + (adjacent_pairs, missing_key_to_adjacent) +} + +pub fn assemble_account_delta_proof( + account_hashes: &[(Pubkey, Hash)], + account_data_hashes: &AccountHashMap, + account_proofs: &[(Pubkey, Proof)], + inclusion: &[Pubkey], + non_inclusion_left: &[Pubkey], + non_inclusion_right: &[Pubkey], + non_inclusion_inner: &[Pubkey], + non_inclusion_inner_mapping: &HashMap, +) -> anyhow::Result> { + let account_proofs_map: HashMap = account_proofs.iter().cloned().collect(); + + let mut proofs = vec![]; + for incl in inclusion { + let data = Data { + pubkey: incl.clone(), + hash: account_data_hashes.get(&incl).unwrap().1, + account: account_data_hashes.get(&incl).unwrap().2.clone(), + }; + let account_proof = AccountDeltaProof::InclusionProof( + incl.clone(), + (data, account_proofs_map.get(&incl).unwrap().clone()), + ); + proofs.push(account_proof) + } + + for nil in non_inclusion_left { + let data = Data { + pubkey: nil.clone(), + hash: account_data_hashes.get(&nil).unwrap().1, + account: account_data_hashes.get(&nil).unwrap().2.clone(), + }; + let account_proof = AccountDeltaProof::NonInclusionProofLeft( + nil.clone(), + ( + data, + account_proofs_map + .get(&account_hashes[0].0) + .unwrap() + .clone(), + ), + ); + proofs.push(account_proof) + } + + for nii in non_inclusion_inner { + let (nii_l, nii_r) = non_inclusion_inner_mapping.get(nii).unwrap(); + let data_l = Data { + pubkey: nii_l.clone(), + hash: account_data_hashes.get(&nii_l).unwrap().1, + account: account_data_hashes.get(&nii_l).unwrap().2.clone(), + }; + let data_r = Data { + pubkey: nii_r.clone(), + hash: account_data_hashes.get(&nii_r).unwrap().1, + account: account_data_hashes.get(&nii_r).unwrap().2.clone(), + }; + let account_proof = AccountDeltaProof::NonInclusionProofInner( + nii.clone(), + ( + (data_l, account_proofs_map.get(nii_l).unwrap().clone()), + (data_r, account_proofs_map.get(nii_r).unwrap().clone()), + ), + ); + proofs.push(account_proof) + } + + for nir in non_inclusion_right { + let last_pubkey = account_hashes[account_hashes.len() - 1].0; + let all_hashes: Vec = account_hashes.iter().map(|x| x.1).collect(); + let data = Data { + pubkey: last_pubkey.clone(), + hash: account_data_hashes.get(&last_pubkey).unwrap().1, + account: account_data_hashes.get(&last_pubkey).unwrap().2.clone(), + }; + let account_proof = AccountDeltaProof::NonInclusionProofRight( + nir.clone(), + ( + data, + account_proofs_map.get(&last_pubkey).unwrap().clone(), + all_hashes.clone(), + ), + ); + proofs.push(account_proof) + } + + Ok(proofs) +} + +pub fn verify_leaves_against_bankhash(account_proof: AccountDeltaProof, + bankhash: Hash, + num_sigs: u64, + account_delta_root: Hash, + parent_bankhash: Hash, + blockhash: Hash) -> anyhow::Result<()> { + + match account_proof { + AccountDeltaProof::InclusionProof(pubkey, (data, proof)) => { + if data.account.pubkey != pubkey { + anyhow::bail!("account info pubkey doesn't match pubkey in provided update"); + } + if data.hash.as_ref() != hash_solana_account( + data.account.lamports, + data.account.owner.as_ref(), + data.account.executable, + data.account.rent_epoch, + &data.account.data, + data.account.pubkey.as_ref()) { + anyhow::bail!("account data does not match account hash"); + } + if bankhash != hashv(&[ + parent_bankhash.as_ref(), + account_delta_root.as_ref(), + &num_sigs.to_le_bytes(), + blockhash.as_ref(), + ]) { + anyhow::bail!("bank hash does not match data"); + } + if !verify_proof(&data.hash, &proof, &account_delta_root) { + anyhow::bail!("account merkle proof verification failure"); + } + Ok(()) + } + _ => { + anyhow::bail!("Only Inclusion proof"); + } + } +} + +#[cfg(test)] +mod tests { + use std::convert::TryFrom; + + use rand::Rng; + use solana_sdk::hash::hashv; + + use super::*; + + fn generate_random_pubkey() -> Pubkey { + let random_bytes: [u8; 32] = rand::thread_rng().gen(); + Pubkey::try_from(random_bytes).unwrap() + } + + fn generate_random_hash() -> Hash { + let random_bytes: Vec = (0..32).map(|_| rand::random::()).collect(); + hashv(&[&random_bytes]) + } + + #[test] + fn test_proof_verification() { + let mut pubkey_hash_vec: Vec<(Pubkey, Hash)> = (0..1000) + .map(|_| (generate_random_pubkey(), generate_random_hash())) + .collect(); + + let mut rng = rand::thread_rng(); + + pubkey_hash_vec.par_sort_unstable_by(|a, b| a.0.cmp(&b.0)); + + let random_index = rng.gen_range(2..pubkey_hash_vec.len() - 3); // "- 2" to avoid picking the last element. + println!("{}", random_index); + let mut proof_leaves: Vec<_> = (random_index..random_index + 3) + .map(|i| pubkey_hash_vec[i].0.clone()) + .collect(); + let first_leaf = pubkey_hash_vec[0].0.clone(); + let last_leaf = pubkey_hash_vec[pubkey_hash_vec.len() - 1].0.clone(); + let inner_leaves = proof_leaves.clone(); + proof_leaves.push(first_leaf); + proof_leaves.push(last_leaf); + let (root, proofs) = calculate_root_and_proofs(&mut pubkey_hash_vec, &proof_leaves); + + for (pubkey, proof) in &proofs { + let leaf_hash = pubkey_hash_vec + .iter() + .find(|(k, _)| k == pubkey) + .unwrap() + .1 + .clone(); + assert!(verify_proof(&leaf_hash, proof, &root)); + } + + let solana_root = calculate_root(pubkey_hash_vec); + + assert_eq!(solana_root, root); + let first_leaf_proof = proofs + .iter() + .find(|(k, _)| *k == first_leaf) + .unwrap() + .1 + .clone(); + let last_leaf_proof = proofs + .iter() + .find(|(k, _)| *k == last_leaf) + .unwrap() + .1 + .clone(); + + let inner_1 = proofs + .iter() + .find(|(k, _)| *k == inner_leaves[0]) + .unwrap() + .1 + .clone(); + let inner_2 = proofs + .iter() + .find(|(k, _)| *k == inner_leaves[1]) + .unwrap() + .1 + .clone(); + let inner_3 = proofs + .iter() + .find(|(k, _)| *k == inner_leaves[2]) + .unwrap() + .1 + .clone(); + + println!("{:?}", inner_leaves); + + assert!(are_adjacent(&inner_1, &inner_2)); + assert!(are_adjacent(&inner_2, &inner_1)); + assert!(!are_adjacent(&inner_1, &inner_3)); + assert!(!are_adjacent(&inner_3, &inner_1)); + + assert!(is_first(&first_leaf_proof)); + } + + #[test] + fn test_invalid_proof_verification() { + let mut pubkey_hash_vec: Vec<(Pubkey, Hash)> = (0..1000) + .map(|_| (generate_random_pubkey(), generate_random_hash())) + .collect(); + + let mut rng = rand::thread_rng(); + let random_indices: Vec<_> = (0..3) + .map(|_| rng.gen_range(0..pubkey_hash_vec.len())) + .collect(); + let proof_leaves: Vec<_> = random_indices + .iter() + .map(|&i| pubkey_hash_vec[i].0.clone()) + .collect(); + + let (root, mut proofs) = calculate_root_and_proofs(&mut pubkey_hash_vec, &proof_leaves); + + // Keep a copy of the original proof for comparison + let original_proof = proofs[0].1.clone(); + + // Modify one of the proofs to make it invalid + if let Some((_pubkey, proof)) = proofs.iter_mut().next() { + if !proof.path.is_empty() { + proof.path[0] = (proof.path[0] + 1) % MERKLE_FANOUT; // Change the path slightly to invalidate it + } + } + + // Print the modified and original proofs for comparison + println!("Original Proof: {:?}", original_proof); + println!("Modified Proof: {:?}", proofs[0].1); + + // Verify the proofs + for (idx, (pubkey, proof)) in proofs.iter().enumerate() { + let leaf_hash = pubkey_hash_vec + .iter() + .find(|(k, _)| k == pubkey) + .unwrap() + .1 + .clone(); + + // Diagnostic + println!( + "\nVerifying proof for pubkey at index {}: {:?}", + random_indices[idx], pubkey + ); + + let verification_result = verify_proof(&leaf_hash, proof, &root); + + // Diagnostic + println!("Leaf Hash: {:?}", leaf_hash); + println!("Root: {:?}", root); + println!("Verification Result: {}", verification_result); + + // Check that we're testing the modified proof and assert accordingly + if proof.path == proofs[0].1.path { + println!("Testing modified proof..."); + assert!(!verification_result); + } else { + println!("Testing non-modified proof..."); + assert!(verification_result); + } + } + } +} diff --git a/adapters/solana/config.json b/adapters/solana/config.json index 346887cc5..e125317a6 100644 --- a/adapters/solana/config.json +++ b/adapters/solana/config.json @@ -1,9 +1,5 @@ { - "libpath": "./libyellowstone_grpc_geyser.dylib", - "grpc": { - "address": "0.0.0.0:10000", - "channel_capacity": "100_000", - "unary_concurrency_limit": 100, - "unary_disabled": false - } + "libpath": "~/sovereign/adapters/solana/account_proof_geyser/target/release/libaccount_proof_geyser.dylib", + "bind_address": "127.0.0.1:10000", + "account_list": ["SysvarS1otHashes111111111111111111111111111"] } diff --git a/adapters/solana/da_client/Cargo.lock b/adapters/solana/da_client/Cargo.lock index f643ca318..e8b107f2d 100644 --- a/adapters/solana/da_client/Cargo.lock +++ b/adapters/solana/da_client/Cargo.lock @@ -12,6 +12,28 @@ dependencies = [ "regex", ] +[[package]] +name = "account_proof_geyser" +version = "0.1.0" +dependencies = [ + "anyhow", + "blake3", + "borsh 0.10.3", + "crossbeam", + "crossbeam-channel", + "log", + "lru 0.12.0", + "rayon", + "serde", + "serde_json", + "solana-geyser-plugin-interface", + "solana-logger", + "solana-runtime", + "solana-sdk", + "solana-transaction-status", + "tokio", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -116,6 +138,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "anchor-attribute-access-control" version = "0.28.0" @@ -805,7 +833,7 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blockroot" -version = "0.1.0" +version = "0.3.0" dependencies = [ "anchor-lang", ] @@ -1208,6 +1236,13 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "copy" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1242,6 +1277,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -1276,6 +1325,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -1338,18 +1397,25 @@ dependencies = [ name = "da_client" version = "0.3.0" dependencies = [ + "account_proof_geyser", "anchor-client", "anchor-lang", "anyhow", "backoff", + "bincode", "blake3", "blockroot", + "borsh 0.10.3", "bs58 0.5.0", "clap 4.4.6", + "copy", + "crossbeam", + "crossbeam-channel", "env_logger 0.10.0", "futures", "hex", "log", + "lru 0.12.0", "rand 0.8.5", "solana-rpc-client", "solana-runtime", @@ -1941,6 +2007,10 @@ name = "hashbrown" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", +] [[package]] name = "heck" @@ -2381,6 +2451,15 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "lru" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +dependencies = [ + "hashbrown 0.14.1", +] + [[package]] name = "lz4" version = "1.24.0" @@ -3967,6 +4046,18 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "solana-geyser-plugin-interface" +version = "1.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268db758cb4193ccf70c85459bfd0e8e5eb7a13b3ee876106d07fada04290a17" +dependencies = [ + "log", + "solana-sdk", + "solana-transaction-status", + "thiserror", +] + [[package]] name = "solana-loader-v4-program" version = "1.16.15" @@ -4314,7 +4405,7 @@ dependencies = [ "itertools", "lazy_static", "log", - "lru", + "lru 0.7.8", "lz4", "memmap2", "modular-bitfield", diff --git a/adapters/solana/da_client/Cargo.toml b/adapters/solana/da_client/Cargo.toml index 9e9c570fc..ca81173e7 100644 --- a/adapters/solana/da_client/Cargo.toml +++ b/adapters/solana/da_client/Cargo.toml @@ -8,21 +8,28 @@ edition = "2021" [dependencies] anchor-lang = "0.28.0" anchor-client = "0.28.0" -solana-sdk = "1.16" +solana-sdk = "=1.16.15" +borsh = "0.10.3" bs58 = "0.5.0" clap = { workspace = true } blockroot = {path = "../solana_da_programs/programs/blockroot", features = ["no-entrypoint"]} -solana-runtime = "1.16" -solana-rpc-client = "1.16" +copy = {path = "../solana_da_programs/programs/copy", features = ["no-entrypoint"]} +solana-runtime = "=1.16.15" +solana-rpc-client = "=1.16.15" anyhow = "1.0.75" rand = "0.8.5" +lru = "0.12.0" hex = "0.4.3" blake3 = "1.3.3" futures = "0.3.24" env_logger = "0.10.0" +crossbeam = "0.8.2" +bincode = "1.3.3" +crossbeam-channel = "0.5.8" backoff = { version = "0.4.0", features = ["tokio"] } tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "time"] } log = { version = "0.4.14", features = ["std"] } +account_proof_geyser = { path = "../account_proof_geyser"} yellowstone-grpc-proto = { git = "https://github.com/rpcpool/yellowstone-grpc.git", package = "yellowstone-grpc-proto", rev = "v1.9.0+solana.1.16.15" } yellowstone-grpc-client = { git = "https://github.com/rpcpool/yellowstone-grpc.git", package = "yellowstone-grpc-client", rev = "v1.9.0+solana.1.16.15" } diff --git a/adapters/solana/da_client/src/bin/account_delta_processor.rs b/adapters/solana/da_client/src/bin/account_delta_processor.rs index b65aa595c..70f82883a 100644 --- a/adapters/solana/da_client/src/bin/account_delta_processor.rs +++ b/adapters/solana/da_client/src/bin/account_delta_processor.rs @@ -6,22 +6,26 @@ // ---------------------------------------------------------------------------- use std::collections::HashMap; +use std::str::FromStr; +use std::thread; use std::time::Duration; use backoff::future::retry; use backoff::ExponentialBackoff; use clap::Parser; -use da_client::hash_solana_account; -use futures::future::TryFutureExt; +use crossbeam_channel::{select, unbounded}; +use da_client::{calculate_root, hash_solana_account}; use futures::sink::SinkExt; use futures::stream::StreamExt; use log::{error, info}; +use solana_sdk::hash::{hashv, Hash}; +use solana_sdk::pubkey::Pubkey; use yellowstone_grpc_client::{GeyserGrpcClient, GeyserGrpcClientError}; use yellowstone_grpc_proto::prelude::subscribe_update::UpdateOneof; use yellowstone_grpc_proto::prelude::{ SubscribeRequest, SubscribeRequestFilterAccounts, SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, - SubscribeRequestFilterTransactions, SubscribeUpdateAccount, + SubscribeRequestFilterTransactions, SubscribeUpdateAccount, SubscribeUpdateBlock, }; type SlotsFilterMap = HashMap; @@ -43,10 +47,10 @@ struct Cli { fn get_subscribe_request() -> SubscribeRequest { let mut accounts: AccountFilterMap = HashMap::new(); - let slots: SlotsFilterMap = HashMap::new(); + let mut slots: SlotsFilterMap = HashMap::new(); let transactions: TransactionsFilterMap = HashMap::new(); let entry: EntryFilterMap = HashMap::new(); - let blocks: BlocksFilterMap = HashMap::new(); + let mut blocks: BlocksFilterMap = HashMap::new(); let blocks_meta: BlocksMetaFilterMap = HashMap::new(); let accounts_data_slice = Vec::new(); @@ -58,6 +62,17 @@ fn get_subscribe_request() -> SubscribeRequest { filters: vec![], }, ); + blocks.insert( + "client".to_owned(), + SubscribeRequestFilterBlocks { + account_include: vec![], + include_transactions: Some(true), + include_accounts: Some(false), + include_entries: Some(false), + }, + ); + slots.insert("client".to_owned(), SubscribeRequestFilterSlots {}); + SubscribeRequest { slots, accounts, @@ -70,24 +85,100 @@ fn get_subscribe_request() -> SubscribeRequest { } } -fn print_account(sub_account: SubscribeUpdateAccount) { - let slot_num = sub_account.slot; - let account = sub_account.account.unwrap(); - let pub_key = account.pubkey.clone(); - let account_hash = hash_solana_account( - account.lamports, - &account.owner, - account.executable, - account.rent_epoch, - &account.data, - &pub_key, - ); - println!( - "slot:{:?}, pubkey:{:?}, hash:{:?}", - slot_num, - bs58::encode(pub_key).into_string(), - bs58::encode(account_hash).into_string() - ); +struct BlockInfoForBankHash { + pub blockhash: Hash, + pub parent_bankhash: Hash, + pub num_sigs: u64, + pub updated_account_count: u64, +} + +fn process_block( + slot_accumulator: &mut HashMap>, + block_info: &mut HashMap, +) -> anyhow::Result<()> { + let mut to_remove: Vec = Vec::new(); + + for (pending_slotnum, pending_block) in block_info.iter() { + let acc_hashes = match slot_accumulator.get(pending_slotnum) { + Some(hashes) => hashes, + None => continue, + }; + if (acc_hashes.len() as u64) != pending_block.updated_account_count { + continue; + } + let accounts_delta_hash = calculate_root( + acc_hashes + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + ); + let bank_hash = hashv(&[ + pending_block.parent_bankhash.as_ref(), + accounts_delta_hash.as_ref(), + &pending_block.num_sigs.to_le_bytes(), + pending_block.blockhash.as_ref(), + ]); + info!("CALCULATED: {:?}: {:?} ", pending_slotnum, bank_hash); + info!( + "FROM GEYSER: {:?}: {:?} ", + pending_slotnum - 1, + pending_block.parent_bankhash + ); + to_remove.push(*pending_slotnum); + } + for slotnum in to_remove { + block_info.remove(&slotnum); + slot_accumulator.remove(&slotnum); + } + + Ok(()) +} + +fn generate_proofs( + r_account: crossbeam::channel::Receiver, + r_block: crossbeam::channel::Receiver, +) { + let mut slot_accumulator: HashMap> = HashMap::new(); + let mut block_info: HashMap = HashMap::new(); + + loop { + select! { + recv(r_account) -> sub_account_msg => { + let sub_account = sub_account_msg.unwrap(); + let slot_num = sub_account.slot; + let account = sub_account.account.unwrap(); + let pub_key = account.pubkey.clone(); + let account_hash = hash_solana_account( + account.lamports, + &account.owner, + account.executable, + account.rent_epoch, + &account.data, + &pub_key, + ); + let account_map = slot_accumulator.entry(slot_num).or_default(); + account_map.insert(Pubkey::try_from(pub_key.clone()).unwrap(), Hash::from(account_hash)); + } + recv(r_block) -> sub_account_block => { + let sub_block = sub_account_block.unwrap(); + let slot_num = sub_block.slot; + let blockhash = sub_block.blockhash; + let updated_account_count = sub_block.updated_account_count; + let parent_bankhash = sub_block.parent_blockhash; + let num_sigs: usize = sub_block.transactions.iter() + .filter_map(|t| t.transaction.as_ref()) + .map(|transaction| transaction.signatures.len()) + .sum(); + block_info.insert(slot_num, BlockInfoForBankHash { + blockhash: Hash::from_str(&blockhash).unwrap(), + parent_bankhash: Hash::from_str(&parent_bankhash).unwrap(), + num_sigs: num_sigs as u64, + updated_account_count + }); + process_block(&mut slot_accumulator, &mut block_info); + } + } + } } #[tokio::main] @@ -100,7 +191,17 @@ async fn main() -> anyhow::Result<()> { let grpc_url = &cli.grpc_url; let mut maybe_first_attempt = Some(()); + let (s_account, r_account) = unbounded::(); + let (s_block, r_block) = unbounded::(); + + thread::spawn(move || { + generate_proofs(r_account, r_block); + }); + retry(ExponentialBackoff::default(), move || { + let sender_account = s_account.clone(); + let sender_block = s_block.clone(); + async move { if maybe_first_attempt.take().is_none() { info!("Retry to connect to the server"); @@ -137,7 +238,11 @@ async fn main() -> anyhow::Result<()> { #[allow(clippy::single_match)] match msg.update_oneof { Some(UpdateOneof::Account(account)) => { - print_account(account); + sender_account.send(account).unwrap(); + continue; + } + Some(UpdateOneof::Block(block)) => { + sender_block.send(block).unwrap(); continue; } _ => {} @@ -151,7 +256,6 @@ async fn main() -> anyhow::Result<()> { } Ok::<(), backoff::Error>(()) } - .inspect_err(|error| error!("failed to connect: {error}")) }) .await .map_err(Into::into) diff --git a/adapters/solana/da_client/src/bin/initiate_copy.rs b/adapters/solana/da_client/src/bin/initiate_copy.rs new file mode 100644 index 000000000..ce7c8d8b8 --- /dev/null +++ b/adapters/solana/da_client/src/bin/initiate_copy.rs @@ -0,0 +1,115 @@ +use alloc::rc::Rc; +use std::str::FromStr; + +use anchor_client::{Client, Cluster}; +use anchor_lang::solana_program::sysvar::clock::Clock; +use clap::Parser; +use copy::{accounts as copy_accounts, instruction as copy_instruction, PREFIX}; +use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::{Keypair, Signature, Signer}; +use solana_sdk::signer::keypair::read_keypair_file; +use solana_sdk::sysvar::SysvarId; +use solana_sdk::system_program; +extern crate alloc; + +const DEFAULT_RPC_URL: &str = "http://localhost:8899"; +const DEFAULT_WS_URL: &str = "ws://localhost:8900"; + +pub struct CopyClient { + pub rpc_url: String, + pub ws_url: String, + pub signer: Keypair, + pub copy_program: Pubkey, + pub copy_pda: (Pubkey, u8), + pub clock_account: Pubkey, + pub system_program: Pubkey, +} + +impl CopyClient { + pub fn new(rpc_url: String, ws_url: String, signer: Keypair, copy_program: &str) -> Self { + let copy_program_pubkey = Pubkey::from_str(copy_program).unwrap(); + let (copy_pda, bump) = + Pubkey::find_program_address(&[PREFIX.as_bytes()], ©_program_pubkey); + + CopyClient { + rpc_url, + ws_url, + signer, + copy_program: Pubkey::from_str(copy_program).unwrap(), + copy_pda: (copy_pda, bump), + clock_account: Clock::id(), + system_program: system_program::id(), + } + } + + pub fn send_transaction(&self, source_account: &Pubkey) -> anyhow::Result { + let creator_pubkey = self.signer.pubkey(); + let c = Client::new( + Cluster::Custom(self.rpc_url.clone(), self.ws_url.clone()), + Rc::new(self.signer.insecure_clone()), + ); + let prog = c.program(self.copy_program).unwrap(); + + let signature = prog + .request() + .accounts(copy_accounts::CopyHash { + creator: creator_pubkey, + source_account: *source_account, + copy_account: self.copy_pda.0, + clock: self.clock_account, + system_program: self.system_program, + }) + .args(copy_instruction::CopyHash { + bump: self.copy_pda.1, + }) + .options(CommitmentConfig { + commitment: CommitmentLevel::Processed, + }) + .send()?; + Ok(signature) + } +} + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + #[arg(long, required = true)] + /// Path to the signer key + signer: String, + + #[arg(long, required = true)] + /// b58 encoded address for the on chain sovereign blockroot program + copy_program: String, + + #[arg(long, required = true)] + account_for_proof: String, + + #[arg(short, long, default_value_t=DEFAULT_RPC_URL.to_string())] + /// URL for solana RPC + rpc_url: String, + + #[arg(short, long, default_value_t=DEFAULT_WS_URL.to_string())] + /// URL for solana Websocket + ws_url: String, +} + +fn main() { + let cli = Cli::parse(); + + // required parameters + let signer = cli.signer; + let copy_program = &cli.copy_program; + let account_for_proof = Pubkey::from_str(&cli.account_for_proof).unwrap(); + + // optional overrides + let rpc_url = cli.rpc_url; + let ws_url = cli.ws_url; + + let signer_keypair = read_keypair_file(signer).unwrap(); + + let copy_client = CopyClient::new(rpc_url, ws_url, signer_keypair, copy_program); + let sig = copy_client.send_transaction(&account_for_proof); + println!("{:?}", sig); + // println!("account_list"); +} diff --git a/adapters/solana/da_client/src/bin/simple_tcp_client.rs b/adapters/solana/da_client/src/bin/simple_tcp_client.rs new file mode 100644 index 000000000..0de267914 --- /dev/null +++ b/adapters/solana/da_client/src/bin/simple_tcp_client.rs @@ -0,0 +1,43 @@ +use account_proof_geyser::types::Update; +use account_proof_geyser::utils::{verify_leaves_against_bankhash}; +use borsh::{BorshDeserialize}; +use tokio::io::AsyncReadExt; +use tokio::net::TcpStream; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut stream = TcpStream::connect("127.0.0.1:10000").await?; + + // Using a large buffer for simplicity. + // Replace this with framing or an other alternative + let mut buffer = vec![0u8; 65536]; + + loop { + let n = stream.read(&mut buffer).await?; + + if n == 0 { + break; // Connection closed. + } + + let received_update: Update = Update::try_from_slice(&buffer[..n])?; + + let bankhash = received_update.root; + let bankhash_proof = received_update.proof; + let slot_num = received_update.slot; + + for p in bankhash_proof.proofs { + if let Err(e) = verify_leaves_against_bankhash(p, + bankhash, + bankhash_proof.num_sigs, + bankhash_proof.account_delta_root, + bankhash_proof.parent_bankhash, + bankhash_proof.blockhash) { + println!("Error in slot {}: {:?}",slot_num,e); + } else { + println!("Proof verification succeeded for slot {}",slot_num); + } + } + } + + Ok(()) +} diff --git a/adapters/solana/solana_da_programs/Anchor.toml b/adapters/solana/solana_da_programs/Anchor.toml index 14d69ba61..db48a6a1a 100644 --- a/adapters/solana/solana_da_programs/Anchor.toml +++ b/adapters/solana/solana_da_programs/Anchor.toml @@ -4,6 +4,7 @@ skip-lint = false [programs.localnet] blob_chunks = "5dEVwohfk3ciDudFS7mXi35ET2e5nrQMnuWbis1J5PJ7" blockroot = "6YQGvP866CHpLTdHwmLqj2Vh5q7T1GF4Kk9gS9MCta8E" +copy = "Fx9d54Cy4RAwYmwgiZf8gDaaUGkFS65diagDX2vvMRqc" solana_da_programs = "FYTJ57g8BhUwVK5Y3d2KbBeHHe1hLrA5NckBbENssK3U" [registry] diff --git a/adapters/solana/solana_da_programs/Cargo.lock b/adapters/solana/solana_da_programs/Cargo.lock index c5cfb701f..ecc14b3bb 100644 --- a/adapters/solana/solana_da_programs/Cargo.lock +++ b/adapters/solana/solana_da_programs/Cargo.lock @@ -595,6 +595,13 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "copy" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + [[package]] name = "cpufeatures" version = "0.2.9" diff --git a/adapters/solana/solana_da_programs/programs/copy/Cargo.toml b/adapters/solana/solana_da_programs/programs/copy/Cargo.toml new file mode 100644 index 000000000..e643b35ff --- /dev/null +++ b/adapters/solana/solana_da_programs/programs/copy/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "copy" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "copy" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = {version = "0.28.0", features = ["init-if-needed"]} diff --git a/adapters/solana/solana_da_programs/programs/copy/Xargo.toml b/adapters/solana/solana_da_programs/programs/copy/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/adapters/solana/solana_da_programs/programs/copy/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/adapters/solana/solana_da_programs/programs/copy/src/lib.rs b/adapters/solana/solana_da_programs/programs/copy/src/lib.rs new file mode 100644 index 000000000..a4469c907 --- /dev/null +++ b/adapters/solana/solana_da_programs/programs/copy/src/lib.rs @@ -0,0 +1,82 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::keccak::hashv; + +declare_id!("Fx9d54Cy4RAwYmwgiZf8gDaaUGkFS65diagDX2vvMRqc"); + +pub const PREFIX: &str = "copy_hash"; + +#[program] +pub mod copy { + use super::*; + + #[allow(unused_variables)] + pub fn copy_hash<'info>(ctx: Context, bump: u8) -> Result<()> { + let acc = &ctx.accounts.source_account; + let lamport_ref = acc.lamports.borrow(); + let data_ref = acc.data.borrow(); + let current_slot_num = ctx.accounts.clock.slot; + let account_hash = hashv(&[ + acc.key.as_ref(), + &lamport_ref.to_le_bytes(), + *data_ref, + acc.owner.as_ref(), + &acc.rent_epoch.to_le_bytes(), + ]); + + let ca = &mut ctx.accounts.copy_account; + ca.accumulate_hash(&account_hash.to_bytes(), current_slot_num); + msg!( + "slot: {:?}, triggering account hash: {:?}, accumulated hash: {:?}", + current_slot_num, + account_hash, + ca.digest + ); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct CopyHash<'info> { + /// The signer who initiates the chunk processing. + #[account(mut)] + pub creator: Signer<'info>, + /// CHECK: no writes, no deser + pub source_account: AccountInfo<'info>, + /// Account (PDA) for storing the Merkle root of the accumulated chunks. Initializes if not already present. + #[account(init_if_needed, payer=creator, space=8+32+8, seeds= [PREFIX.as_bytes()], bump)] + pub copy_account: Account<'info, CopyAccount>, + + /// The built-in Solana system program. + pub system_program: Program<'info, System>, + + /// The Solana sysvar to fetch the current slot number. + pub clock: Sysvar<'info, Clock>, +} + +/// Represents the root account for blocks, typically storing a Merkle root. +#[account] +#[derive(Default, Debug)] +pub struct CopyAccount { + /// The accumulated digest for all the merkle roots for each blob that is successfully "accumulated" during that slot + pub digest: [u8; 32], + /// The current slot number in Solana when this root is recorded. + pub slot: u64, +} + +impl CopyAccount { + pub fn accumulate_hash(&mut self, account_hash: &[u8; 32], slot_num: u64) { + // slot number switched + if slot_num > self.slot { + self.digest = *account_hash; + self.slot = self.slot; + } else { + // we're in the same solana slot + self.digest = digest_accumulator(&self.digest, account_hash); + } + } +} + +fn digest_accumulator(current_hash: &[u8; 32], digest: &[u8; 32]) -> [u8; 32] { + let combined = [current_hash.as_ref(), digest.as_ref()]; + hashv(&combined).0 +}