diff --git a/Cargo.lock b/Cargo.lock index 00762bcea58..1ef70023508 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,6 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if 1.0.0", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -57,6 +58,459 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8ebf106e84a1c37f86244df7da0c7587e697b71a0d565cce079449b85ac6f8" +dependencies = [ + "alloy-consensus", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-provider", + "alloy-rpc-client", + "alloy-serde", + "alloy-transport-http", +] + +[[package]] +name = "alloy-chains" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c660915971620592abe2c292c859957eb60e73a60c0eba34a6793eea60512cff" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed961a48297c732a5d97ee321aa8bb5009ecadbcb077d8bec90cb54e651629" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "c-kzg", + "derive_more 1.0.0", + "serde", +] + +[[package]] +name = "alloy-core" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72bf30967a232bec83809bea1623031f6285a013096229330c68c406192a4ca" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5228b189b18b85761340dc9eaac0141148a8503657b36f9bc3a869413d987ca" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.13", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ffc577390ce50234e02d841214b3dc0bea6aaaae8e04bbf3cb82e9a45da9eb" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more 1.0.0", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69e06cf9c37be824b9d26d6d101114fdde6af0c87de2828b414c05c4b3daa71" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more 1.0.0", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde15e14944a88bd6a57d325e9a49b75558746fe16aaccc79713ae50a6a9574c" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31a0f0d51db8a1a30a4d98a9f90e090a94c8f44cb4d9eafc7e03aa6d00aae984" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af5979e0d5a7bf9c7eb79749121e8256e59021af611322aee56e77e20776b4b3" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "204237129086ce5dc17a58025e93739b01b45313841f98fa339eb1d780511e57" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514f70ee2a953db21631cd817b13a1571474ec77ddc03d47616d5e8203489fde" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8edae627382349b56cd6a7a2106f4fd69b243a9233e560c55c2e03cabb7e1d3c" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if 1.0.0", + "const-hex", + "derive_more 1.0.0", + "foldhash", + "hashbrown 0.15.0", + "hex-literal 0.4.1", + "indexmap 2.6.0", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand", + "ruint", + "rustc-hash 2.0.0", + "serde", + "sha3", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "alloy-provider" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4814d141ede360bb6cd1b4b064f1aab9de391e7c4d0d4d50ac89ea4bc1e25fbd" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures 0.3.30", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "reqwest", + "schnellru", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +dependencies = [ + "alloy-rlp-derive", + "arrayvec 0.7.4", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc2bd1e7403463a5f2c61e955bcc9d3072b63aa177442b0f9aa6a6d22a941e3" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "alloy-transport-http", + "futures 0.3.30", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.5.0", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b034779a4850b4b03f5be5ea674a1cf7d746b2da762b34d1860ab45e48ca27" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "derive_more 1.0.0", + "itertools 0.13.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028e72eaa9703e4882344983cfe7636ce06d8cce104a78ea62fd19b46659efc4" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592c185d7100258c041afac51877660c7bf6213447999787197db4842f0e938e" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841eabaa4710f719fddbc24c95d386eae313f07e6da4babc25830ee37945be0c" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6672337f19d837b9f7073c45853aeb528ed9f7dd6a4154ce683e9e5cb7794014" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck 0.5.0", + "indexmap 2.6.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.69", + "syn-solidity", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dff37dd20bfb118b777c96eda83b2067f4226d2644c5cfa00187b3bc01770ba" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.69", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b853d42292dbb159671a3edae3b2750277ff130f32b726fe07dc2b17aa6f2b5" +dependencies = [ + "serde", + "winnow 0.6.13", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa828bb1b9a6dc52208fbb18084fb9ce2c30facc2bfda6a5d922349b4990354f" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be77579633ebbc1266ae6fd7694f75c408beb1aeb6865d0b18f22893c265a061" +dependencies = [ + "alloy-json-rpc", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower 0.5.0", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-transport-http" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fd1a5d0827939847983b46f2f79510361f901dc82f8e3c38ac7397af142c6e" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower 0.5.0", + "tracing", + "url", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -67,77 +521,201 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "libc", + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", ] [[package]] -name = "anstream" -version = "0.6.14" +name = "ark-ff-asm" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", + "quote", + "syn 1.0.109", ] [[package]] -name = "anstyle" -version = "1.0.7" +name = "ark-ff-asm" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] [[package]] -name = "anstyle-parse" -version = "0.2.4" +name = "ark-ff-macros" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "utf8parse", + "num-bigint 0.4.6", + "num-traits", + "quote", + "syn 1.0.109", ] [[package]] -name = "anstyle-query" -version = "1.1.0" +name = "ark-ff-macros" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "windows-sys 0.52.0", + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "anstyle-wincon" -version = "3.0.3" +name = "ark-serialize" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" dependencies = [ - "anstyle", - "windows-sys 0.52.0", + "ark-std 0.3.0", + "digest 0.9.0", ] [[package]] -name = "anyhow" -version = "1.0.86" +name = "ark-serialize" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] [[package]] -name = "arbitrary" -version = "1.3.2" +name = "ark-std" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] [[package]] -name = "arc-swap" -version = "1.7.1" +name = "ark-std" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] [[package]] name = "arrayref" @@ -199,7 +777,7 @@ dependencies = [ "futures-util", "handlebars", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "mime", "multer", "num-traits", @@ -269,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5ec94176a12a8cbe985cd73f2e54dc9c702c88c766bdef12f1f3a67cedbee1" dependencies = [ "bytes", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_json", ] @@ -330,6 +908,17 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -460,6 +1049,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -487,6 +1082,12 @@ dependencies = [ "base64 0.22.1", ] +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "beef" version = "0.5.2" @@ -528,6 +1129,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -598,6 +1214,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "bs58" version = "0.4.0" @@ -641,6 +1269,21 @@ dependencies = [ "serde", ] +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + [[package]] name = "cc" version = "1.0.105" @@ -766,6 +1409,25 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "const-hex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1007,6 +1669,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1083,6 +1757,20 @@ dependencies = [ "syn 2.0.69", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -1142,6 +1830,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "930c7171c8df9fb1782bdf9b918ed9ed2d33d1d22300abb754f9085bc48bf8e8" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1172,8 +1870,29 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", + "syn 2.0.69", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", "syn 2.0.69", + "unicode-xid", ] [[package]] @@ -1279,6 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -1349,12 +2069,51 @@ dependencies = [ "syn 2.0.69", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1453,7 +2212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", "tiny-keccak 2.0.2", @@ -1466,10 +2225,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", - "primitive-types", + "primitive-types 0.11.1", "uint 0.9.5", ] @@ -1500,6 +2259,27 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "firestorm" version = "0.4.6" @@ -1524,6 +2304,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1546,6 +2338,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1678,6 +2476,12 @@ dependencies = [ "slab", ] +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + [[package]] name = "fxhash" version = "0.2.1" @@ -1708,6 +2512,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1728,7 +2533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator 0.3.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "stable_deref_trait", ] @@ -1760,6 +2565,12 @@ dependencies = [ "time", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.14" @@ -1778,6 +2589,7 @@ name = "graph" version = "0.35.0" dependencies = [ "Inflector", + "alloy", "anyhow", "async-stream", "async-trait", @@ -1794,7 +2606,6 @@ dependencies = [ "diesel", "diesel_derives", "envconfig", - "ethabi", "futures 0.1.31", "futures 0.3.30", "graph_derive", @@ -1825,7 +2636,7 @@ dependencies = [ "rand", "regex", "reqwest", - "semver", + "semver 1.0.23", "serde", "serde_derive", "serde_json", @@ -1891,7 +2702,7 @@ dependencies = [ "graph-runtime-wasm", "prost 0.12.6", "prost-types 0.12.6", - "semver", + "semver 1.0.23", "serde", "tonic-build", ] @@ -1911,7 +2722,7 @@ dependencies = [ "jsonrpc-core", "prost 0.12.6", "prost-types 0.12.6", - "semver", + "semver 1.0.23", "serde", "tiny-keccak 1.5.0", "tonic-build", @@ -1961,7 +2772,7 @@ dependencies = [ "lazy_static", "prost 0.12.6", "prost-types 0.12.6", - "semver", + "semver 1.0.23", "serde", "tokio", "tonic-build", @@ -2060,7 +2871,7 @@ dependencies = [ "graph-runtime-derive", "graph-runtime-wasm", "rand", - "semver", + "semver 1.0.23", "test-store", "wasmtime", ] @@ -2072,13 +2883,12 @@ dependencies = [ "anyhow", "async-trait", "bs58", - "ethabi", "graph", "graph-runtime-derive", "hex", "never", "parity-wasm", - "semver", + "semver 1.0.23", "uuid", "wasm-instrument", "wasmtime", @@ -2147,7 +2957,7 @@ dependencies = [ "blake3 1.5.1", "chrono", "clap", - "derive_more", + "derive_more 0.99.18", "diesel", "diesel-derive-enum", "diesel-dynamic-schema", @@ -2281,6 +3091,17 @@ dependencies = [ "serde_with", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -2293,7 +3114,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util 0.7.11", @@ -2312,7 +3133,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util 0.7.11", @@ -2357,6 +3178,18 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -2752,12 +3585,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -2956,6 +3789,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2965,6 +3811,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2983,6 +3839,12 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libm" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00419de735aac21d53b0de5ce2c03bd3627277cf471300f27ebc89f7d828047" + [[package]] name = "libredox" version = "0.1.3" @@ -3015,6 +3877,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.0", +] + [[package]] name = "lru_time_cache" version = "0.11.11" @@ -3262,6 +4133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3274,6 +4146,26 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + [[package]] name = "object" version = "0.32.2" @@ -3282,7 +4174,7 @@ checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "memchr", ] @@ -3515,7 +4407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.6.0", ] [[package]] @@ -3568,6 +4460,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -3687,13 +4589,24 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", "impl-codec", "impl-rlp", "impl-serde", "uint 0.9.5", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "uint 0.9.5", +] + [[package]] name = "priority-queue" version = "2.0.3" @@ -3702,7 +4615,7 @@ checksum = "70c501afe3a2e25c9bd219aa56ec1e04cdb3fcdd763055be268778c13fa82c1f" dependencies = [ "autocfg", "equivalent", - "indexmap 2.2.6", + "indexmap 2.6.0", ] [[package]] @@ -3714,6 +4627,28 @@ dependencies = [ "toml_edit 0.21.1", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.69", +] + [[package]] name = "proc-macro-utils" version = "0.10.0" @@ -3751,6 +4686,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "prost" version = "0.11.9" @@ -3882,7 +4837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a16027030d4ec33e423385f73bb559821827e9ec18c50e7874e4d6de5a4e96f" dependencies = [ "anyhow", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "protobuf 3.5.0", "protobuf-support", @@ -3909,6 +4864,12 @@ dependencies = [ "cc", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-xml" version = "0.36.2" @@ -4001,6 +4962,7 @@ dependencies = [ "libc", "rand_chacha", "rand_core", + "serde", ] [[package]] @@ -4022,6 +4984,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "rayon" version = "1.10.0" @@ -4171,6 +5142,16 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.8" @@ -4196,6 +5177,36 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint 0.4.6", + "num-traits", + "parity-scale-codec", + "primitive-types 0.12.2", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4220,13 +5231,22 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.23", ] [[package]] @@ -4316,6 +5336,18 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.18" @@ -4349,12 +5381,37 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "schnellru" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +dependencies = [ + "ahash", + "cfg-if 1.0.0", + "hashbrown 0.13.2", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.21.3" @@ -4396,6 +5453,15 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.23" @@ -4405,6 +5471,15 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.204" @@ -4520,7 +5595,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -4572,6 +5647,16 @@ dependencies = [ "keccak", ] +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if 1.0.0", +] + [[package]] name = "shellexpand" version = "3.1.0" @@ -4590,6 +5675,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -4737,6 +5832,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "sptr" version = "0.3.2" @@ -4941,6 +6046,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16320d4a2021ba1a32470b3759676114a918885e9800e68ad60f2c67969fba62" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.69", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5049,6 +6166,7 @@ dependencies = [ "lazy_static", "pretty_assertions", "prost-types 0.12.6", + "serde_json", ] [[package]] @@ -5081,6 +6199,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.36" @@ -5380,7 +6507,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "toml_datetime", "winnow 0.5.40", ] @@ -5391,7 +6518,7 @@ version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -5482,6 +6609,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tower-service 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tower-http" version = "0.5.2" @@ -5661,6 +6802,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicase" version = "2.7.0" @@ -5775,6 +6922,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -5793,6 +6946,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -5936,8 +7098,8 @@ version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" dependencies = [ - "indexmap 2.2.6", - "semver", + "indexmap 2.6.0", + "semver 1.0.23", ] [[package]] @@ -5946,8 +7108,8 @@ version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" dependencies = [ - "indexmap 2.2.6", - "semver", + "indexmap 2.6.0", + "semver 1.0.23", ] [[package]] @@ -5962,7 +7124,7 @@ dependencies = [ "bumpalo", "cfg-if 1.0.0", "fxprof-processed-profile", - "indexmap 2.2.6", + "indexmap 2.6.0", "libc", "log", "object 0.32.2", @@ -6087,7 +7249,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.28.1", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "object 0.32.2", "serde", @@ -6172,7 +7334,7 @@ dependencies = [ "anyhow", "cc", "cfg-if 1.0.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "libc", "log", "mach", @@ -6224,7 +7386,7 @@ checksum = "4b804dfd3d0c0d6d37aa21026fe7772ba1a769c89ee4f5c4f13b82d91d75216f" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.2.6", + "indexmap 2.6.0", "wit-parser", ] @@ -6234,6 +7396,20 @@ version = "15.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6060bc082cc32d9a45587c7640e29e3c7b89ada82677ac25d87850aaccb368" +[[package]] +name = "wasmtimer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +dependencies = [ + "futures 0.3.30", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "wast" version = "212.0.0" @@ -6274,7 +7450,7 @@ dependencies = [ "arrayvec 0.7.4", "base64 0.13.1", "bytes", - "derive_more", + "derive_more 0.99.18", "ethabi", "ethereum-types", "futures 0.3.30", @@ -6575,9 +7751,9 @@ checksum = "316b36a9f0005f5aa4b03c39bc3728d045df136f8c13a73b7db4510dec725e08" dependencies = [ "anyhow", "id-arena", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", - "semver", + "semver 1.0.23", "serde", "serde_derive", "serde_json", @@ -6630,6 +7806,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +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", + "quote", + "syn 2.0.69", +] [[package]] name = "zstd" diff --git a/Cargo.toml b/Cargo.toml index 0421a32e274..ad7acde8fa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ repository = "https://github.com/graphprotocol/graph-node" license = "MIT OR Apache-2.0" [workspace.dependencies] +alloy = { version = "0.5.4", features = ["dyn-abi", "json-abi"] } anyhow = "1.0" async-graphql = { version = "7.0.11", features = ["chrono", "uuid"] } async-graphql-axum = "7.0.11" diff --git a/chain/ethereum/src/adapter.rs b/chain/ethereum/src/adapter.rs index f78ff1b0bec..a21511ee7eb 100644 --- a/chain/ethereum/src/adapter.rs +++ b/chain/ethereum/src/adapter.rs @@ -1,5 +1,4 @@ use anyhow::Error; -use ethabi::{Error as ABIError, Function, ParamType, Token}; use graph::blockchain::ChainIdentifier; use graph::components::subgraph::MappingError; use graph::data::store::ethereum::call; @@ -98,8 +97,8 @@ pub struct ContractCall { pub contract_name: String, pub address: Address, pub block_ptr: BlockPtr, - pub function: Function, - pub args: Vec, + pub function: graph::abi::Function, + pub args: Vec, pub gas: Option, } @@ -113,13 +112,12 @@ pub enum EthereumRpcError { #[derive(Error, Debug)] pub enum ContractCallError { - #[error("ABI error: {0}")] - ABIError(#[from] ABIError), - /// `Token` is not of expected `ParamType` - #[error("type mismatch, token {0:?} is not of kind {1:?}")] - TypeError(Token, ParamType), - #[error("error encoding input call data: {0}")] - EncodingError(ethabi::Error), + #[error("ABI error: {0:#}")] + ABIError(anyhow::Error), + #[error("type mismatch, decoded value {0:?} is not of kind {1:?}")] + TypeError(graph::abi::DynSolValue, graph::abi::DynSolType), + #[error("error encoding input call data: {0:#}")] + EncodingError(anyhow::Error), #[error("call error: {0}")] Web3Error(web3::Error), #[error("ethereum node took too long to perform call")] @@ -1174,7 +1172,7 @@ pub trait EthereumAdapter: Send + Sync + 'static { logger: &Logger, call: &ContractCall, cache: Arc, - ) -> Result<(Option>, call::Source), ContractCallError>; + ) -> Result<(Option>, call::Source), ContractCallError>; /// Make multiple contract calls in a single batch. The returned `Vec` /// has results in the same order as the calls in `calls` on input. The @@ -1184,7 +1182,7 @@ pub trait EthereumAdapter: Send + Sync + 'static { logger: &Logger, calls: &[&ContractCall], cache: Arc, - ) -> Result>, call::Source)>, ContractCallError>; + ) -> Result>, call::Source)>, ContractCallError>; fn get_balance( &self, @@ -1213,9 +1211,9 @@ mod tests { use graph::blockchain::TriggerFilter as _; use graph::firehose::{CallToFilter, CombinedFilter, LogFilter, MultiLogFilter}; use graph::petgraph::graphmap::GraphMap; - use graph::prelude::ethabi::ethereum_types::H256; use graph::prelude::web3::types::Address; use graph::prelude::web3::types::Bytes; + use graph::prelude::web3::types::H256; use graph::prelude::EthereumCall; use hex::ToHex; use itertools::Itertools; diff --git a/chain/ethereum/src/data_source.rs b/chain/ethereum/src/data_source.rs index c0253d2e60e..360d2b000e1 100644 --- a/chain/ethereum/src/data_source.rs +++ b/chain/ethereum/src/data_source.rs @@ -1,5 +1,7 @@ use anyhow::{anyhow, Error}; use anyhow::{ensure, Context}; +use graph::abi::EventExt; +use graph::abi::FunctionExt; use graph::blockchain::{BlockPtr, TriggerWithHandler}; use graph::components::metrics::subgraph::SubgraphInstanceMetrics; use graph::components::store::{EthereumCallCache, StoredDynamicDataSource}; @@ -11,10 +13,10 @@ use graph::env::ENV_VARS; use graph::futures03::future::try_join; use graph::futures03::stream::FuturesOrdered; use graph::futures03::TryStreamExt; -use graph::prelude::ethabi::ethereum_types::H160; -use graph::prelude::ethabi::{StateMutability, Token}; use graph::prelude::lazy_static; use graph::prelude::regex::Regex; +use graph::prelude::web3::types::Address; +use graph::prelude::web3::types::H160; use graph::prelude::{Link, SubgraphManifestValidationError}; use graph::slog::{debug, error, o, trace}; use itertools::Itertools; @@ -32,9 +34,7 @@ use graph::{ blockchain::{self, Blockchain}, derive::CheapClone, prelude::{ - async_trait, - ethabi::{Address, Contract, Event, Function, LogParam, ParamType, RawLog}, - serde_json, warn, + async_trait, serde_json, warn, web3::types::{Log, Transaction, H256}, BlockNumber, CheapClone, EthereumCall, LightEthereumBlock, LightEthereumBlockExt, LinkResolver, Logger, @@ -527,28 +527,28 @@ impl DataSource { } } - /// Returns the contract event with the given signature, if it exists. A an event from the ABI + /// Returns the contract event with the given signature, if it exists. An event from the ABI /// will be matched if: /// 1. An event signature is equal to `signature`. /// 2. There are no equal matches, but there is exactly one event that equals `signature` if all /// `indexed` modifiers are removed from the parameters. - fn contract_event_with_signature(&self, signature: &str) -> Option<&Event> { + fn contract_event_with_signature(&self, signature: &str) -> Option<&graph::abi::Event> { // Returns an `Event(uint256,address)` signature for an event, without `indexed` hints. - fn ambiguous_event_signature(event: &Event) -> String { + fn ambiguous_event_signature(event: &graph::abi::Event) -> String { format!( "{}({})", event.name, event .inputs .iter() - .map(|input| event_param_type_signature(&input.kind)) + .map(|input| input.selector_type().into_owned()) .collect::>() .join(",") ) } // Returns an `Event(indexed uint256,address)` type signature for an event. - fn event_signature(event: &Event) -> String { + fn event_signature(event: &graph::abi::Event) -> String { format!( "{}({})", event.name, @@ -558,40 +558,13 @@ impl DataSource { .map(|input| format!( "{}{}", if input.indexed { "indexed " } else { "" }, - event_param_type_signature(&input.kind) + input.selector_type() )) .collect::>() .join(",") ) } - // Returns the signature of an event parameter type (e.g. `uint256`). - fn event_param_type_signature(kind: &ParamType) -> String { - use ParamType::*; - - match kind { - Address => "address".into(), - Bytes => "bytes".into(), - Int(size) => format!("int{}", size), - Uint(size) => format!("uint{}", size), - Bool => "bool".into(), - String => "string".into(), - Array(inner) => format!("{}[]", event_param_type_signature(inner)), - FixedBytes(size) => format!("bytes{}", size), - FixedArray(inner, size) => { - format!("{}[{}]", event_param_type_signature(inner), size) - } - Tuple(components) => format!( - "({})", - components - .iter() - .map(event_param_type_signature) - .collect::>() - .join(",") - ), - } - } - self.contract_abi .contract .events() @@ -630,7 +603,12 @@ impl DataSource { }) } - fn contract_function_with_signature(&self, target_signature: &str) -> Option<&Function> { + fn contract_function_with_signature( + &self, + target_signature: &str, + ) -> Option<&graph::abi::Function> { + use graph::abi::StateMutability; + self.contract_abi .contract .functions() @@ -644,7 +622,7 @@ impl DataSource { let mut arguments = function .inputs .iter() - .map(|input| format!("{}", input.kind)) + .map(|input| format!("{}", input.selector_type())) .collect::>() .join(","); // `address,uint256,bool) @@ -734,11 +712,7 @@ impl DataSource { .into_iter() .filter_map(|(event_handler, event_abi)| { event_abi - .parse_log(RawLog { - topics: log.topics.clone(), - data: log.data.clone().0, - }) - .map(|log| log.params) + .decode_log(&log) .map_err(|e| { trace!( logger, @@ -838,20 +812,15 @@ impl DataSource { ) })?; - // Parse the inputs - // - // Take the input for the call, chop off the first 4 bytes, then call - // `function.decode_input` to get a vector of `Token`s. Match the `Token`s - // with the `Param`s in `function.inputs` to create a `Vec`. - let tokens = match function_abi.decode_input(&call.input.0[4..]).with_context( - || { + let values = match function_abi + .abi_decode_input(&call.input.0[4..]) + .with_context(|| { format!( "Generating function inputs for the call {:?} failed, raw input: {}", &function_abi, hex::encode(&call.input.0) ) - }, - ) { + }) { Ok(val) => val, // See also 280b0108-a96e-4738-bb37-60ce11eeb5bf Err(err) => { @@ -861,27 +830,22 @@ impl DataSource { }; ensure!( - tokens.len() == function_abi.inputs.len(), + values.len() == function_abi.inputs.len(), "Number of arguments in call does not match \ number of inputs in function signature." ); - let inputs = tokens + let inputs = values .into_iter() .enumerate() - .map(|(i, token)| LogParam { + .map(|(i, value)| graph::abi::DynSolParam { name: function_abi.inputs[i].name.clone(), - value: token, + value, }) .collect::>(); - // Parse the outputs - // - // Take the output for the call, then call `function.decode_output` to - // get a vector of `Token`s. Match the `Token`s with the `Param`s in - // `function.outputs` to create a `Vec`. - let tokens = function_abi - .decode_output(&call.output.0) + let values = function_abi + .abi_decode_output(&call.output.0) .with_context(|| { format!( "Decoding function outputs for the call {:?} failed, raw output: {}", @@ -891,17 +855,17 @@ impl DataSource { })?; ensure!( - tokens.len() == function_abi.outputs.len(), + values.len() == function_abi.outputs.len(), "Number of parameters in the call output does not match \ number of outputs in the function signature." ); - let outputs = tokens + let outputs = values .into_iter() .enumerate() - .map(|(i, token)| LogParam { + .map(|(i, value)| graph::abi::DynSolParam { name: function_abi.outputs[i].name.clone(), - value: token, + value, }) .collect::>(); @@ -939,8 +903,8 @@ pub struct DeclaredCall { label: String, contract_name: String, address: Address, - function: Function, - args: Vec, + function: graph::abi::Function, + args: Vec, } impl DeclaredCall { @@ -948,7 +912,7 @@ impl DeclaredCall { mapping: &Mapping, handler: &MappingEventHandler, log: &Log, - params: &[LogParam], + params: &[graph::abi::DynSolParam], ) -> Result, anyhow::Error> { let mut calls = Vec::new(); for decl in handler.calls.decls.iter() { @@ -961,12 +925,15 @@ impl DeclaredCall { // Behavior for apiVersion < 0.0.4: look up function by name; for overloaded // functions this always picks the same overloaded variant, which is incorrect // and may lead to encoding/decoding errors - abi.contract.function(function_name).with_context(|| { - format!( - "Unknown function \"{}::{}\" called from WASM runtime", - contract_name, function_name - ) - })? + abi.contract + .function(function_name) + .and_then(|matches| matches.first()) + .with_context(|| { + format!( + "Unknown function \"{}::{}\" called from WASM runtime", + contract_name, function_name + ) + })? }; let address = decl.address(log, params)?; @@ -1454,7 +1421,7 @@ impl UnresolvedMappingABI { self.name, self.file.link ) })?; - let contract = Contract::load(&*contract_bytes)?; + let contract = serde_json::from_slice(&contract_bytes)?; Ok(MappingABI { name: self.name, contract, @@ -1465,7 +1432,7 @@ impl UnresolvedMappingABI { #[derive(Clone, Debug, PartialEq)] pub struct MappingABI { pub name: String, - pub contract: Contract, + pub contract: graph::abi::JsonAbi, } impl MappingABI { @@ -1474,24 +1441,27 @@ impl MappingABI { contract_name: &str, name: &str, signature: Option<&str>, - ) -> Result<&Function, Error> { + ) -> Result<&graph::abi::Function, Error> { let contract = &self.contract; let function = match signature { // Behavior for apiVersion < 0.0.4: look up function by name; for overloaded // functions this always picks the same overloaded variant, which is incorrect // and may lead to encoding/decoding errors - None => contract.function(name).with_context(|| { - format!( - "Unknown function \"{}::{}\" called from WASM runtime", - contract_name, name - ) - })?, + None => contract + .function(name) + .and_then(|matches| matches.first()) + .with_context(|| { + format!( + "Unknown function \"{}::{}\" called from WASM runtime", + contract_name, name + ) + })?, // Behavior for apiVersion >= 0.0.04: look up function by signature of // the form `functionName(uint256,string) returns (bytes32,string)`; this // correctly picks the correct variant of an overloaded function Some(ref signature) => contract - .functions_by_name(name) + .function(name) .with_context(|| { format!( "Unknown function \"{}::{}\" called from WASM runtime", @@ -1499,7 +1469,7 @@ impl MappingABI { ) })? .iter() - .find(|f| signature == &f.signature()) + .find(|f| signature == &f.signature_compat()) .with_context(|| { format!( "Unknown function \"{}::{}\" with signature `{}` \ @@ -1673,32 +1643,42 @@ pub struct CallDecl { readonly: (), } impl CallDecl { - fn address(&self, log: &Log, params: &[LogParam]) -> Result { + fn address(&self, log: &Log, params: &[graph::abi::DynSolParam]) -> Result { let address = match &self.expr.address { CallArg::Address => log.address, CallArg::HexAddress(address) => *address, CallArg::Param(name) => { - let value = params + let value = ¶ms .iter() .find(|param| ¶m.name == name.as_str()) .ok_or_else(|| anyhow!("unknown param {name}"))? - .value - .clone(); - value - .into_address() - .ok_or_else(|| anyhow!("param {name} is not an address"))? + .value; + + let address = value + .as_address() + .ok_or_else(|| anyhow!("param '{name}' is not an address"))?; + + Address::from(address.into_array()) } }; Ok(address) } - fn args(&self, log: &Log, params: &[LogParam]) -> Result, Error> { + fn args( + &self, + log: &Log, + params: &[graph::abi::DynSolParam], + ) -> Result, Error> { + use graph::abi::DynSolValue; + self.expr .args .iter() .map(|arg| match arg { - CallArg::Address => Ok(Token::Address(log.address)), - CallArg::HexAddress(address) => Ok(Token::Address(*address)), + CallArg::Address => Ok(DynSolValue::Address(log.address.to_fixed_bytes().into())), + CallArg::HexAddress(address) => { + Ok(DynSolValue::Address(address.to_fixed_bytes().into())) + } CallArg::Param(name) => { let value = params .iter() diff --git a/chain/ethereum/src/ethereum_adapter.rs b/chain/ethereum/src/ethereum_adapter.rs index c4ea6323c7d..d7dcee4b76f 100644 --- a/chain/ethereum/src/ethereum_adapter.rs +++ b/chain/ethereum/src/ethereum_adapter.rs @@ -1,4 +1,6 @@ use futures03::{future::BoxFuture, stream::FuturesUnordered}; +use graph::abi::DynSolValueExt; +use graph::abi::FunctionExt; use graph::blockchain::client::ChainClient; use graph::blockchain::BlockHash; use graph::blockchain::ChainIdentifier; @@ -14,8 +16,6 @@ use graph::futures03::future::try_join_all; use graph::futures03::{ self, compat::Future01CompatExt, FutureExt, StreamExt, TryFutureExt, TryStreamExt, }; -use graph::prelude::ethabi::ParamType; -use graph::prelude::ethabi::Token; use graph::prelude::tokio::try_join; use graph::prelude::web3::types::U256; use graph::slog::o; @@ -25,8 +25,7 @@ use graph::{ blockchain::{block_stream::BlockWithTriggers, BlockPtr, IngestorError}, prelude::{ anyhow::{self, anyhow, bail, ensure, Context}, - async_trait, debug, error, ethabi, hex, info, retry, serde_json as json, tiny_keccak, - trace, warn, + async_trait, debug, error, hex, info, retry, serde_json as json, tiny_keccak, trace, warn, web3::{ self, types::{ @@ -656,9 +655,10 @@ impl EthereumAdapter { match bytes.len() >= 4 && &bytes[..4] == solidity_revert_function_selector { false => None, - true => ethabi::decode(&[ParamType::String], &bytes[4..]) + true => graph::abi::DynSolType::String + .abi_decode(&bytes[4..]) .ok() - .and_then(|tokens| tokens[0].clone().into_string()), + .and_then(|val| val.clone().as_str().map(ToOwned::to_owned)), } }; @@ -1501,7 +1501,7 @@ impl EthereumAdapterTrait for EthereumAdapter { logger: &Logger, inp_call: &ContractCall, cache: Arc, - ) -> Result<(Option>, call::Source), ContractCallError> { + ) -> Result<(Option>, call::Source), ContractCallError> { let mut result = self.contract_calls(logger, &[inp_call], cache).await?; // unwrap: self.contract_calls returns as many results as there were calls Ok(result.pop().unwrap()) @@ -1512,20 +1512,26 @@ impl EthereumAdapterTrait for EthereumAdapter { logger: &Logger, calls: &[&ContractCall], cache: Arc, - ) -> Result>, call::Source)>, ContractCallError> { + ) -> Result>, call::Source)>, ContractCallError> { fn as_req( logger: &Logger, call: &ContractCall, index: u32, ) -> Result { // Emit custom error for type mismatches. - for (token, kind) in call + for (val, kind) in call .args .iter() - .zip(call.function.inputs.iter().map(|p| &p.kind)) + .zip(call.function.inputs.iter().map(|p| p.selector_type())) { - if !token.type_check(kind) { - return Err(ContractCallError::TypeError(token.clone(), kind.clone())); + let kind: graph::abi::DynSolType = kind.parse().map_err(|err| { + ContractCallError::ABIError(anyhow!( + "failed to parse function input type '{kind}': {err}" + )) + })?; + + if !val.type_check(&kind) { + return Err(ContractCallError::TypeError(val.clone(), kind.clone())); } } @@ -1533,8 +1539,8 @@ impl EthereumAdapterTrait for EthereumAdapter { let req = { let encoded_call = call .function - .encode_input(&call.args) - .map_err(ContractCallError::EncodingError)?; + .abi_encode_input(&call.args) + .map_err(|err| ContractCallError::EncodingError(err.into()))?; call::Request::new(call.address, encoded_call, index) }; @@ -1552,7 +1558,7 @@ impl EthereumAdapterTrait for EthereumAdapter { logger: &Logger, resp: call::Response, call: &ContractCall, - ) -> (Option>, call::Source) { + ) -> (Option>, call::Source) { let call::Response { retval, source, @@ -1560,7 +1566,7 @@ impl EthereumAdapterTrait for EthereumAdapter { } = resp; use call::Retval::*; match retval { - Value(output) => match call.function.decode_output(&output) { + Value(output) => match call.function.abi_decode_output(&output) { Ok(tokens) => (Some(tokens), source), Err(e) => { // Decode failures are reverts. The reasoning is that if Solidity fails to @@ -2607,9 +2613,9 @@ mod tests { EthereumBlockWithCalls, }; use graph::blockchain::BlockPtr; - use graph::prelude::ethabi::ethereum_types::U64; use graph::prelude::tokio::{self}; use graph::prelude::web3::transports::test::TestTransport; + use graph::prelude::web3::types::U64; use graph::prelude::web3::types::{Address, Block, Bytes, H256}; use graph::prelude::web3::Web3; use graph::prelude::EthereumCall; diff --git a/chain/ethereum/src/ingestor.rs b/chain/ethereum/src/ingestor.rs index d22e08c4294..5b281d9ba80 100644 --- a/chain/ethereum/src/ingestor.rs +++ b/chain/ethereum/src/ingestor.rs @@ -10,8 +10,8 @@ use graph::{ blockchain::{BlockHash, BlockIngestor, BlockPtr, IngestorError}, cheap_clone::CheapClone, prelude::{ - async_trait, error, ethabi::ethereum_types::H256, info, tokio, trace, warn, ChainStore, - Error, EthereumBlockWithCalls, LogCode, Logger, + async_trait, error, info, tokio, trace, warn, web3::types::H256, ChainStore, Error, + EthereumBlockWithCalls, LogCode, Logger, }, }; use std::{sync::Arc, time::Duration}; diff --git a/chain/ethereum/src/runtime/abi.rs b/chain/ethereum/src/runtime/abi.rs index d88bf2b22d7..7d4a8f18745 100644 --- a/chain/ethereum/src/runtime/abi.rs +++ b/chain/ethereum/src/runtime/abi.rs @@ -4,7 +4,6 @@ use crate::trigger::{ }; use graph::{ prelude::{ - ethabi, web3::types::{Log, TransactionReceipt, H256}, BigInt, }, @@ -37,7 +36,7 @@ impl AscType for AscLogParamArray { } } -impl ToAscObj for Vec { +impl ToAscObj for Vec { fn to_asc_obj( &self, heap: &mut H, @@ -519,7 +518,7 @@ impl ToAscObj for EthereumTransactionData { value: asc_new(heap, &BigInt::from_unsigned_u256(&self.value), gas)?, gas_limit: asc_new(heap, &BigInt::from_unsigned_u256(&self.gas_limit), gas)?, gas_price: asc_new(heap, &BigInt::from_unsigned_u256(&self.gas_price), gas)?, - input: asc_new(heap, &*self.input, gas)?, + input: asc_new(heap, &self.input, gas)?, }) } } @@ -541,7 +540,7 @@ impl ToAscObj for EthereumTransactionData { value: asc_new(heap, &BigInt::from_unsigned_u256(&self.value), gas)?, gas_limit: asc_new(heap, &BigInt::from_unsigned_u256(&self.gas_limit), gas)?, gas_price: asc_new(heap, &BigInt::from_unsigned_u256(&self.gas_price), gas)?, - input: asc_new(heap, &*self.input, gas)?, + input: asc_new(heap, &self.input, gas)?, nonce: asc_new(heap, &BigInt::from_unsigned_u256(&self.nonce), gas)?, }) } @@ -771,7 +770,7 @@ impl ToAscObj for ethabi::LogParam { +impl ToAscObj for graph::abi::DynSolParam { fn to_asc_obj( &self, heap: &mut H, diff --git a/chain/ethereum/src/runtime/runtime_adapter.rs b/chain/ethereum/src/runtime/runtime_adapter.rs index 4147d61f5b0..8e1845d88c8 100644 --- a/chain/ethereum/src/runtime/runtime_adapter.rs +++ b/chain/ethereum/src/runtime/runtime_adapter.rs @@ -8,12 +8,14 @@ use crate::{ }; use anyhow::{anyhow, Context, Error}; use blockchain::HostFn; +use graph::abi::DynSolValueExt; use graph::blockchain::ChainIdentifier; use graph::components::subgraph::HostMetrics; use graph::data::store::ethereum::call; use graph::data::store::scalar::BigInt; use graph::data::subgraph::API_VERSION_0_0_9; use graph::futures03::compat::Future01CompatExt; +use graph::prelude::web3::types::Address; use graph::prelude::web3::types::H160; use graph::runtime::gas::Gas; use graph::runtime::{AscIndexId, IndexForAscTypeId}; @@ -21,10 +23,7 @@ use graph::slog::debug; use graph::{ blockchain::{self, BlockPtr, HostFnCtx}, cheap_clone::CheapClone, - prelude::{ - ethabi::{self, Address, Token}, - EthereumCallCache, - }, + prelude::EthereumCallCache, runtime::{asc_get, asc_new, AscPtr, HostExportError}, semver::Version, slog::Logger, @@ -256,20 +255,7 @@ fn eth_call( abis: &[Arc], eth_call_gas: Option, metrics: Arc, -) -> Result>, HostExportError> { - // Helpers to log the result of the call at the end - fn tokens_as_string(tokens: &[Token]) -> String { - tokens.iter().map(|arg| arg.to_string()).join(", ") - } - - fn result_as_string(result: &Result>, HostExportError>) -> String { - match result { - Ok(Some(tokens)) => format!("({})", tokens_as_string(&tokens)), - Ok(None) => "none".to_string(), - Err(_) => "error".to_string(), - } - } - +) -> Result>, HostExportError> { let start_time = Instant::now(); // Obtain the path to the contract ABI @@ -348,16 +334,26 @@ fn eth_call( ); } - debug!(logger, "Contract call finished"; - "address" => format!("0x{:x}", &unresolved_call.contract_address), - "contract" => &unresolved_call.contract_name, - "signature" => &unresolved_call.function_signature, - "args" => format!("[{}]", tokens_as_string(&unresolved_call.function_args)), - "time_ms" => format!("{}ms", elapsed.as_millis()), - "result" => result_as_string(&result), - "block_hash" => block_ptr.hash_hex(), - "block_number" => block_ptr.block_number(), - "source" => source.to_string()); + let args_as_string = format!("[{}]", values_to_string(&unresolved_call.function_args)); + + let result_as_string = match &result { + Ok(Some(values)) => format!("({})", values_to_string(values)), + Ok(None) => "none".to_owned(), + Err(_err) => "error".to_owned(), + }; + + debug!( + logger, "Contract call finished"; + "address" => format!("0x{:x}", &unresolved_call.contract_address), + "contract" => &unresolved_call.contract_name, + "signature" => &unresolved_call.function_signature, + "args" => args_as_string, + "time_ms" => format!("{}ms", elapsed.as_millis()), + "result" => result_as_string, + "block_hash" => block_ptr.hash_hex(), + "block_number" => block_ptr.block_number(), + "source" => source.to_string(), + ); result } @@ -368,9 +364,18 @@ pub struct UnresolvedContractCall { pub contract_address: Address, pub function_name: String, pub function_signature: Option, - pub function_args: Vec, + pub function_args: Vec, } impl AscIndexId for AscUnresolvedContractCall { const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::SmartContractCall; } + +#[inline] +fn values_to_string(values: &[graph::abi::DynSolValue]) -> String { + values + .iter() + .map(|x| x.to_string()) + .collect_vec() + .join(", ") +} diff --git a/chain/ethereum/src/trigger.rs b/chain/ethereum/src/trigger.rs index 128ed8d3e98..5454695cec5 100644 --- a/chain/ethereum/src/trigger.rs +++ b/chain/ethereum/src/trigger.rs @@ -3,18 +3,17 @@ use graph::blockchain::TriggerData; use graph::data::subgraph::API_VERSION_0_0_2; use graph::data::subgraph::API_VERSION_0_0_6; use graph::data::subgraph::API_VERSION_0_0_7; -use graph::prelude::ethabi::ethereum_types::H160; -use graph::prelude::ethabi::ethereum_types::H256; -use graph::prelude::ethabi::ethereum_types::U128; -use graph::prelude::ethabi::ethereum_types::U256; -use graph::prelude::ethabi::ethereum_types::U64; -use graph::prelude::ethabi::Address; -use graph::prelude::ethabi::Bytes; -use graph::prelude::ethabi::LogParam; +use graph::prelude::web3::types::Address; use graph::prelude::web3::types::Block; +use graph::prelude::web3::types::Bytes; use graph::prelude::web3::types::Log; use graph::prelude::web3::types::Transaction; use graph::prelude::web3::types::TransactionReceipt; +use graph::prelude::web3::types::H160; +use graph::prelude::web3::types::H256; +use graph::prelude::web3::types::U128; +use graph::prelude::web3::types::U256; +use graph::prelude::web3::types::U64; use graph::prelude::BlockNumber; use graph::prelude::BlockPtr; use graph::prelude::{CheapClone, EthereumCall}; @@ -47,7 +46,7 @@ pub enum MappingTrigger { block: Arc, transaction: Arc, log: Arc, - params: Vec, + params: Vec, receipt: Option>, calls: Vec, }, @@ -55,8 +54,8 @@ pub enum MappingTrigger { block: Arc, transaction: Arc, call: Arc, - inputs: Vec, - outputs: Vec, + inputs: Vec, + outputs: Vec, }, Block { block: Arc, @@ -86,13 +85,13 @@ impl std::fmt::Debug for MappingTrigger { Log { _transaction: Arc, _log: Arc, - _params: Vec, + _params: Vec, }, Call { _transaction: Arc, _call: Arc, - _inputs: Vec, - _outputs: Vec, + _inputs: Vec, + _outputs: Vec, }, Block, } @@ -488,7 +487,7 @@ impl From<&'_ Transaction> for EthereumTransactionData { value: tx.value, gas_limit: tx.gas, gas_price: tx.gas_price.unwrap_or(U256::zero()), // EIP-1559 made this optional. - input: tx.input.0.clone(), + input: tx.input.clone(), nonce: tx.nonce, } } @@ -503,7 +502,7 @@ pub struct EthereumEventData { pub log_type: Option, pub block: EthereumBlockData, pub transaction: EthereumTransactionData, - pub params: Vec, + pub params: Vec, } /// An Ethereum call executed within a transaction within a block to a contract address. @@ -513,6 +512,6 @@ pub struct EthereumCallData { pub to: Address, pub block: EthereumBlockData, pub transaction: EthereumTransactionData, - pub inputs: Vec, - pub outputs: Vec, + pub inputs: Vec, + pub outputs: Vec, } diff --git a/graph/Cargo.toml b/graph/Cargo.toml index 089d46bd9ec..bf3cd4882df 100644 --- a/graph/Cargo.toml +++ b/graph/Cargo.toml @@ -4,6 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] +alloy = { workspace = true } base64 = "=0.21.7" anyhow = "1.0" async-trait = "0.1.74" @@ -24,7 +25,6 @@ envconfig = "0.10.0" Inflector = "0.11.3" isatty = "0.1.9" reqwest = { version = "0.12.5", features = ["json", "stream", "multipart"] } -ethabi = "17.2" hex = "0.4.3" http0 = { version = "0", package = "http" } http = "1" diff --git a/graph/src/abi/event_ext.rs b/graph/src/abi/event_ext.rs new file mode 100644 index 00000000000..f8f8eff044e --- /dev/null +++ b/graph/src/abi/event_ext.rs @@ -0,0 +1,142 @@ +use alloy::json_abi::Event; +use alloy::primitives::LogData; +use anyhow::anyhow; +use anyhow::Context; +use anyhow::Result; +use itertools::Itertools; +use web3::types::Log; + +use crate::abi::DynSolParam; + +pub trait EventExt { + fn decode_log(&self, log: &Log) -> Result>; +} + +impl EventExt for Event { + fn decode_log(&self, log: &Log) -> Result> { + let log_data = log_to_log_data(log)?; + let decoded_event = alloy::dyn_abi::EventExt::decode_log(self, &log_data, true)?; + + if self.inputs.len() != decoded_event.indexed.len() + decoded_event.body.len() { + return Err(anyhow!( + "unexpected number of decoded event inputs; expected {}, got {}", + self.inputs.len(), + decoded_event.indexed.len() + decoded_event.body.len(), + )); + } + + let decoded_params = decoded_event + .indexed + .into_iter() + .chain(decoded_event.body.into_iter()) + .enumerate() + .map(|(i, value)| DynSolParam { + name: self.inputs[i].name.clone(), + value, + }) + .collect(); + + Ok(decoded_params) + } +} + +fn log_to_log_data(log: &Log) -> Result { + let topics = log + .topics + .iter() + .map(|x| x.to_fixed_bytes().into()) + .collect_vec(); + + let data = log.data.0.clone().into(); + + LogData::new(topics, data).context("log has an invalid number of topics") +} + +#[cfg(test)] +mod tests { + use alloy::dyn_abi::DynSolValue; + use alloy::primitives::U256; + + use super::*; + + fn make_log(topics: &[[u8; 32]], data: Vec) -> Log { + Log { + address: [1; 20].into(), + topics: topics.iter().map(Into::into).collect(), + data: data.into(), + block_hash: None, + block_number: None, + transaction_hash: None, + transaction_index: None, + log_index: None, + transaction_log_index: None, + log_type: None, + removed: None, + } + } + + #[test] + fn decode_log_no_topic_0() { + let event = Event::parse("event X(uint256 indexed a, bytes32 b)").unwrap(); + let a = U256::from(10).to_be_bytes::<32>(); + let b = DynSolValue::FixedBytes([10; 32].into(), 32).abi_encode(); + + let log = make_log(&[a], b); + let err = event.decode_log(&log).unwrap_err(); + + assert_eq!( + err.to_string(), + "invalid log topic list length: expected 2 topics, got 1", + ); + } + + #[test] + fn decode_log_invalid_topic_0() { + let event = Event::parse("event X(uint256 indexed a, bytes32 b)").unwrap(); + let a = U256::from(10).to_be_bytes::<32>(); + let b = DynSolValue::FixedBytes([10; 32].into(), 32).abi_encode(); + + let log = make_log(&[[0; 32], a], b); + let err = event.decode_log(&log).unwrap_err(); + + assert!(err.to_string().starts_with("invalid event signature:")); + } + + #[test] + fn decode_log_success() { + let event = Event::parse("event X(uint256 indexed a, bytes32 b)").unwrap(); + let topic_0 = event.selector().0; + let a = U256::from(10).to_be_bytes::<32>(); + let b = DynSolValue::FixedBytes([10; 32].into(), 32).abi_encode(); + + let log = make_log(&[topic_0, a], b); + let resp = event.decode_log(&log).unwrap(); + + assert_eq!( + resp, + vec![ + DynSolParam { + name: "a".to_owned(), + value: DynSolValue::Uint(U256::from(10), 256), + }, + DynSolParam { + name: "b".to_owned(), + value: DynSolValue::FixedBytes([10; 32].into(), 32), + } + ], + ); + } + + #[test] + fn decode_log_too_many_topics() { + let event = Event::parse("event X(uint256 indexed a, bytes32 b)").unwrap(); + let topic_0 = event.selector().0; + let a = U256::from(10).to_be_bytes::<32>(); + let b = DynSolValue::FixedBytes([10; 32].into(), 32).abi_encode(); + + let log = make_log(&[topic_0, a, a, a, a], b); + let err = event.decode_log(&log).unwrap_err(); + + assert_eq!(err.to_string(), "log has an invalid number of topics"); + } +} diff --git a/graph/src/abi/function_ext.rs b/graph/src/abi/function_ext.rs new file mode 100644 index 00000000000..634ca9a08d6 --- /dev/null +++ b/graph/src/abi/function_ext.rs @@ -0,0 +1,303 @@ +use std::borrow::Cow; + +use alloy::dyn_abi::DynSolType; +use alloy::dyn_abi::DynSolValue; +use alloy::dyn_abi::Specifier; +use alloy::json_abi::Function; +use alloy::json_abi::Param; +use anyhow::anyhow; +use anyhow::Result; +use itertools::Itertools; + +use crate::abi::DynSolValueExt; + +pub trait FunctionExt { + /// Returns the signature of this function in the following formats: + /// - if the function has no outputs: `$name($($inputs),*)` + /// - if the function has outputs: `$name($($inputs),*):($(outputs),*)` + /// + /// Examples: + /// - `functionName()` + /// - `functionName():(uint256)` + /// - `functionName(bool):(uint256,string)` + /// - `functionName(uint256,bytes32):(string,uint256)` + fn signature_compat(&self) -> String; + + /// ABI-decodes the given data according to the function's input types. + fn abi_decode_input(&self, data: &[u8]) -> Result>; + + /// ABI-decodes the given data according to the function's output types. + fn abi_decode_output(&self, data: &[u8]) -> Result>; + + /// ABI-encodes the given values, prefixed by the function's selector, if any. + /// + /// This behaviour is to ensure consistency with `ethabi`. + fn abi_encode_input(&self, values: &[DynSolValue]) -> Result>; +} + +impl FunctionExt for Function { + fn signature_compat(&self) -> String { + let name = &self.name; + let inputs = &self.inputs; + let outputs = &self.outputs; + + // This is what `alloy` uses internally when creating signatures. + const MAX_SOL_TYPE_LEN: usize = 32; + + let mut sig_cap = name.len() + 1 + inputs.len() * MAX_SOL_TYPE_LEN + 1; + + if !outputs.is_empty() { + sig_cap = sig_cap + 2 + outputs.len() * MAX_SOL_TYPE_LEN + 1; + } + + let mut sig = String::with_capacity(sig_cap); + + sig.push_str(&name); + signature_part(&inputs, &mut sig); + + if !outputs.is_empty() { + sig.push(':'); + signature_part(&outputs, &mut sig); + } + + sig + } + + fn abi_decode_input(&self, data: &[u8]) -> Result> { + (self as &dyn alloy::dyn_abi::FunctionExt) + .abi_decode_input(data, true) + .map_err(Into::into) + } + + fn abi_decode_output(&self, data: &[u8]) -> Result> { + (self as &dyn alloy::dyn_abi::FunctionExt) + .abi_decode_output(data, true) + .map_err(Into::into) + } + + fn abi_encode_input(&self, values: &[DynSolValue]) -> Result> { + let inputs = &self.inputs; + + if inputs.len() != values.len() { + return Err(anyhow!( + "unexpected number of values; expected {}, got {}", + inputs.len(), + values.len(), + )); + } + + let mut fixed_values = Vec::with_capacity(values.len()); + + for (i, input) in inputs.iter().enumerate() { + let ty = input.resolve()?; + let val = &values[i]; + + fixed_values.push(fix_type_size(&ty, val)?); + } + + if fixed_values.iter().all(|x| matches!(x, Cow::Borrowed(_))) { + return (self as &dyn alloy::dyn_abi::JsonAbiExt) + .abi_encode_input(values) + .map_err(Into::into); + } + + // Required because of `alloy::dyn_abi::JsonAbiExt::abi_encode_input` API; + let owned_fixed_values = fixed_values + .into_iter() + .map(|x| x.into_owned()) + .collect_vec(); + + (self as &dyn alloy::dyn_abi::JsonAbiExt) + .abi_encode_input(&owned_fixed_values) + .map_err(Into::into) + } +} + +// An efficient way to compute a part of the signature without new allocations. +fn signature_part(params: &[Param], out: &mut String) { + out.push('('); + + match params.len() { + 0 => {} + 1 => { + params[0].selector_type_raw(out); + } + n => { + params[0].selector_type_raw(out); + + for i in 1..n { + out.push(','); + params[i].selector_type_raw(out); + } + } + } + + out.push(')'); +} + +// Alloy is stricter in type checking than `ehtabi` and requires that the decoded values have +// exactly the same number of bits / bytes as the type used for checking. +// +// This is a problem because in some ASC conversions we lose the original number of bits / bytes +// if the actual data takes less memory. +// +// This method fixes that in a simple but not very cheap way, by encoding the value and trying +// to decode it again using the given type. The result fixes the number of bits / bytes in the +// decoded values, so we can use `alloy` methods that have strict type checking internally. +fn fix_type_size<'a>(ty: &DynSolType, val: &'a DynSolValue) -> Result> { + if val.matches(ty) { + return Ok(Cow::Borrowed(val)); + } + + if !val.type_check(ty) { + return Err(anyhow!( + "invalid value type; expected '{}', got '{:?}'", + ty.sol_type_name(), + val.sol_type_name(), + )); + } + + let bytes = val.abi_encode(); + let new_val = ty.abi_decode(&bytes)?; + + Ok(Cow::Owned(new_val)) +} + +#[cfg(test)] +mod tests { + use alloy::primitives::I256; + use alloy::primitives::U256; + + use super::*; + + fn s(f: &str) -> String { + Function::parse(f).unwrap().signature_compat() + } + + fn u256(u: u64) -> U256 { + U256::from(u) + } + + fn i256(i: i32) -> I256 { + I256::try_from(i).unwrap() + } + + #[test] + fn signature_compat_no_inputs_no_outputs() { + assert_eq!(s("x()"), "x()"); + } + + #[test] + fn signature_compat_one_input_no_outputs() { + assert_eq!(s("x(uint256 a)"), "x(uint256)"); + } + + #[test] + fn signature_compat_multiple_inputs_no_outputs() { + assert_eq!(s("x(uint256 a, bytes32 b)"), "x(uint256,bytes32)"); + } + + #[test] + fn signature_compat_no_inputs_one_output() { + assert_eq!(s("x() returns (uint256)"), "x():(uint256)"); + } + + #[test] + fn signature_compat_no_inputs_multiple_outputs() { + assert_eq!(s("x() returns (uint256, bytes32)"), "x():(uint256,bytes32)"); + } + + #[test] + fn signature_compat_multiple_inputs_multiple_outputs() { + assert_eq!( + s("x(bytes32 a, uint256 b) returns (uint256, bytes32)"), + "x(bytes32,uint256):(uint256,bytes32)", + ); + } + + #[test] + fn abi_decode_input() { + use DynSolValue::{Int, Tuple, Uint}; + + let f = Function::parse("x(uint256 a, int256 b)").unwrap(); + let data = Tuple(vec![Uint(u256(10), 256), Int(i256(-10), 256)]).abi_encode_params(); + let inputs = f.abi_decode_input(&data).unwrap(); + + assert_eq!(inputs, vec![Uint(u256(10), 256), Int(i256(-10), 256)]); + } + + #[test] + fn abi_decode_output() { + use DynSolValue::{Int, Tuple, Uint}; + + let f = Function::parse("x() returns (uint256 a, int256 b)").unwrap(); + let data = Tuple(vec![Uint(u256(10), 256), Int(i256(-10), 256)]).abi_encode_params(); + let outputs = f.abi_decode_output(&data).unwrap(); + + assert_eq!(outputs, vec![Uint(u256(10), 256), Int(i256(-10), 256)]); + } + + #[test] + fn abi_encode_input_no_values() { + let f = Function::parse("x(uint256 a, int256 b)").unwrap(); + let err = f.abi_encode_input(&[]).unwrap_err(); + + assert_eq!( + err.to_string(), + "unexpected number of values; expected 2, got 0", + ); + } + + #[test] + fn abi_encode_input_too_many_values() { + use DynSolValue::Bool; + + let f = Function::parse("x(uint256 a, int256 b)").unwrap(); + + let err = f + .abi_encode_input(&[Bool(true), Bool(false), Bool(true)]) + .unwrap_err(); + + assert_eq!( + err.to_string(), + "unexpected number of values; expected 2, got 3", + ); + } + + #[test] + fn abi_encode_input_invalid_types() { + use DynSolValue::Bool; + + let f = Function::parse("x(uint256 a, int256 b)").unwrap(); + let err = f.abi_encode_input(&[Bool(true), Bool(false)]).unwrap_err(); + assert!(err.to_string().starts_with("invalid value type;")); + } + + #[test] + fn abi_encode_success() { + use DynSolValue::{Bool, Uint}; + + let f = Function::parse("x(uint256 a, bool b)").unwrap(); + let a = Uint(u256(10), 256); + let b = Bool(true); + + let data = f.abi_encode_input(&[a.clone(), b.clone()]).unwrap(); + let inputs = f.abi_decode_input(&data[4..]).unwrap(); + + assert_eq!(inputs, vec![a, b]); + } + + #[test] + fn abi_encode_success_with_size_fix() { + use DynSolValue::{Int, Uint}; + + let f = Function::parse("x(uint256 a, int256 b)").unwrap(); + let a = Uint(u256(10), 32); + let b = Int(i256(-10), 32); + + let data = f.abi_encode_input(&[a, b]).unwrap(); + let inputs = f.abi_decode_input(&data[4..]).unwrap(); + + assert_eq!(inputs, vec![Uint(u256(10), 256), Int(i256(-10), 256)]); + } +} diff --git a/graph/src/abi/mod.rs b/graph/src/abi/mod.rs new file mode 100644 index 00000000000..88fe14b1806 --- /dev/null +++ b/graph/src/abi/mod.rs @@ -0,0 +1,20 @@ +mod event_ext; +mod function_ext; +mod param; +mod value_ext; + +pub use alloy::dyn_abi::DynSolType; +pub use alloy::dyn_abi::DynSolValue; + +pub use alloy::json_abi::Event; +pub use alloy::json_abi::Function; +pub use alloy::json_abi::JsonAbi; +pub use alloy::json_abi::StateMutability; + +pub use alloy::primitives::I256; +pub use alloy::primitives::U256; + +pub use self::event_ext::EventExt; +pub use self::function_ext::FunctionExt; +pub use self::param::DynSolParam; +pub use self::value_ext::DynSolValueExt; diff --git a/graph/src/abi/param.rs b/graph/src/abi/param.rs new file mode 100644 index 00000000000..49e0f0878ea --- /dev/null +++ b/graph/src/abi/param.rs @@ -0,0 +1,7 @@ +use alloy::dyn_abi::DynSolValue; + +#[derive(Clone, Debug, PartialEq)] +pub struct DynSolParam { + pub name: String, + pub value: DynSolValue, +} diff --git a/graph/src/abi/value_ext.rs b/graph/src/abi/value_ext.rs new file mode 100644 index 00000000000..cb0f220e036 --- /dev/null +++ b/graph/src/abi/value_ext.rs @@ -0,0 +1,277 @@ +use alloy::dyn_abi::DynSolType; +use alloy::dyn_abi::DynSolValue; +use anyhow::anyhow; +use anyhow::Result; +use itertools::Itertools; + +pub trait DynSolValueExt { + /// Creates a fixed-byte decoded value from a slice. + /// + /// Fails if the source slice exceeds 32 bytes. + fn fixed_bytes_from_slice(s: &[u8]) -> Result; + + /// Returns the decoded value as a string. + /// + /// The resulting string contains no type information. + fn to_string(&self) -> String; + + /// Checks whether the value is of the specified type. + /// + /// For types with additional size information, returns true if the size of the value is less + /// than or equal to the size of the specified type. + #[must_use] + fn type_check(&self, ty: &DynSolType) -> bool; +} + +impl DynSolValueExt for DynSolValue { + fn fixed_bytes_from_slice(s: &[u8]) -> Result { + let num_bytes = s.len(); + + if num_bytes > 32 { + return Err(anyhow!( + "input slice must contain a maximum of 32 bytes, got {num_bytes}" + )); + } + + let mut bytes = [0u8; 32]; + + // Access: If `x` is of type `bytesI`, then `x[k]` for `0 <= k < I` returns the `k`th byte. + // Ref: + bytes[..num_bytes].copy_from_slice(s); + + Ok(Self::FixedBytes(bytes.into(), num_bytes)) + } + + fn to_string(&self) -> String { + let s = |v: &[Self]| v.iter().map(|x| x.to_string()).collect_vec().join(","); + + // Output format is taken from `ethabi`; + // See: + match self { + Self::Bool(v) => v.to_string(), + Self::Int(v, _) => format!("{v:x}"), + Self::Uint(v, _) => format!("{v:x}"), + Self::FixedBytes(v, _) => hex::encode(v), + Self::Address(v) => format!("{v:x}"), + Self::Function(v) => format!("{v:x}"), + Self::Bytes(v) => hex::encode(v), + Self::String(v) => v.to_owned(), + Self::Array(v) => format!("[{}]", s(v)), + Self::FixedArray(v) => format!("[{}]", s(v)), + Self::Tuple(v) => format!("({})", s(v)), + } + } + + fn type_check(&self, ty: &DynSolType) -> bool { + match self { + Self::Bool(_) => *ty == DynSolType::Bool, + Self::Int(_, a) => { + if let DynSolType::Int(b) = ty { + b >= a + } else { + false + } + } + Self::Uint(_, a) => { + if let DynSolType::Uint(b) = ty { + b >= a + } else { + false + } + } + Self::FixedBytes(_, a) => { + if let DynSolType::FixedBytes(b) = ty { + b >= a + } else { + false + } + } + Self::Address(_) => *ty == DynSolType::Address, + Self::Function(_) => *ty == DynSolType::Function, + Self::Bytes(_) => *ty == DynSolType::Bytes, + Self::String(_) => *ty == DynSolType::String, + Self::Array(values) => { + if let DynSolType::Array(ty) = ty { + values.iter().all(|x| x.type_check(ty)) + } else { + false + } + } + Self::FixedArray(values) => { + if let DynSolType::FixedArray(ty, size) = ty { + *size == values.len() && values.iter().all(|x| x.type_check(ty)) + } else { + false + } + } + Self::Tuple(values) => { + if let DynSolType::Tuple(types) = ty { + types.len() == values.len() + && values + .iter() + .enumerate() + .all(|(i, x)| x.type_check(&types[i])) + } else { + false + } + } + } + } +} + +#[cfg(test)] +mod tests { + use alloy::primitives::I256; + use alloy::primitives::U256; + + use super::*; + + #[test] + fn fixed_bytes_from_slice_empty_slice() { + let val = DynSolValue::fixed_bytes_from_slice(&[]).unwrap(); + let bytes = [0; 32]; + + assert_eq!(val, DynSolValue::FixedBytes(bytes.into(), 0)); + } + + #[test] + fn fixed_bytes_from_slice_one_byte() { + let val = DynSolValue::fixed_bytes_from_slice(&[10]).unwrap(); + let mut bytes = [0; 32]; + bytes[0] = 10; + + assert_eq!(val, DynSolValue::FixedBytes(bytes.into(), 1)); + } + + #[test] + fn fixed_bytes_from_slice_multiple_bytes() { + let val = DynSolValue::fixed_bytes_from_slice(&[10, 20, 30]).unwrap(); + let mut bytes = [0; 32]; + bytes[0] = 10; + bytes[1] = 20; + bytes[2] = 30; + + assert_eq!(val, DynSolValue::FixedBytes(bytes.into(), 3)); + } + + #[test] + fn fixed_bytes_from_slice_max_bytes() { + let val = DynSolValue::fixed_bytes_from_slice(&[10; 32]).unwrap(); + let bytes = [10; 32]; + + assert_eq!(val, DynSolValue::FixedBytes(bytes.into(), 32)); + } + + #[test] + fn fixed_bytes_from_slice_too_many_bytes() { + DynSolValue::fixed_bytes_from_slice(&[10; 33]).unwrap_err(); + } + + #[test] + fn to_string() { + use DynSolValue::*; + + assert_eq!(Bool(false).to_string(), "false"); + assert_eq!(Bool(true).to_string(), "true"); + + assert_eq!( + Int(I256::try_from(-10).unwrap(), 256).to_string(), + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6", + ); + + assert_eq!(Uint(U256::from(10), 256).to_string(), "a"); + + assert_eq!( + FixedBytes([10; 32].into(), 32).to_string(), + "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", + ); + + assert_eq!( + Address([10; 20].into()).to_string(), + "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", + ); + + assert_eq!( + Function([10; 24].into()).to_string(), + "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a", + ); + + assert_eq!(Bytes(vec![10, 20, 30]).to_string(), "0a141e"); + + assert_eq!( + String("one two three".to_owned()).to_string(), + "one two three" + ); + + assert_eq!( + Array(vec![String("one".to_owned()), String("two".to_owned())]).to_string(), + "[one,two]", + ); + + assert_eq!( + FixedArray(vec![String("one".to_owned()), String("two".to_owned())]).to_string(), + "[one,two]" + ); + + assert_eq!( + Tuple(vec![String("one".to_owned()), String("two".to_owned())]).to_string(), + "(one,two)" + ); + } + + #[test] + fn type_check() { + use DynSolType as T; + use DynSolValue::*; + + assert!(Bool(true).type_check(&T::Bool)); + assert!(!Bool(true).type_check(&T::Int(256))); + + assert!(!Int(I256::try_from(-10).unwrap(), 32).type_check(&T::Int(24))); + assert!(Int(I256::try_from(-10).unwrap(), 32).type_check(&T::Int(32))); + assert!(Int(I256::try_from(-10).unwrap(), 32).type_check(&T::Int(256))); + assert!(!Int(I256::try_from(-10).unwrap(), 32).type_check(&T::Uint(256))); + + assert!(!Uint(U256::from(10), 32).type_check(&T::Uint(24))); + assert!(Uint(U256::from(10), 32).type_check(&T::Uint(32))); + assert!(Uint(U256::from(10), 32).type_check(&T::Uint(256))); + assert!(!Uint(U256::from(10), 32).type_check(&T::FixedBytes(32))); + + assert!(!FixedBytes([0; 32].into(), 16).type_check(&T::FixedBytes(8))); + assert!(FixedBytes([0; 32].into(), 16).type_check(&T::FixedBytes(16))); + assert!(FixedBytes([0; 32].into(), 16).type_check(&T::FixedBytes(32))); + assert!(!FixedBytes([0; 32].into(), 32).type_check(&T::Address)); + + assert!(Address([0; 20].into()).type_check(&T::Address)); + assert!(!Address([0; 20].into()).type_check(&T::Function)); + + assert!(Function([0; 24].into()).type_check(&T::Function)); + assert!(!Function([0; 24].into()).type_check(&T::Bytes)); + + assert!(Bytes(vec![0, 0, 0]).type_check(&T::Bytes)); + assert!(!Bytes(vec![0, 0, 0]).type_check(&T::String)); + + assert!(String("".to_owned()).type_check(&T::String)); + assert!(!String("".to_owned()).type_check(&T::Array(Box::new(T::Bool)))); + + assert!(Array(vec![Bool(true)]).type_check(&T::Array(Box::new(T::Bool)))); + assert!(!Array(vec![Bool(true)]).type_check(&T::Array(Box::new(T::String)))); + assert!(!Array(vec![Bool(true)]).type_check(&T::FixedArray(Box::new(T::Bool), 1))); + + assert!(!FixedArray(vec![String("".to_owned())]) + .type_check(&T::FixedArray(Box::new(T::Bool), 1))); + assert!(!FixedArray(vec![Bool(true), Bool(false)]) + .type_check(&T::FixedArray(Box::new(T::Bool), 1))); + assert!(FixedArray(vec![Bool(true), Bool(false)]) + .type_check(&T::FixedArray(Box::new(T::Bool), 2))); + assert!(!FixedArray(vec![Bool(true), Bool(false)]) + .type_check(&T::FixedArray(Box::new(T::Bool), 3))); + assert!(!FixedArray(vec![Bool(true), Bool(false)]) + .type_check(&T::Tuple(vec![T::Bool, T::Bool]))); + + assert!(!Tuple(vec![Bool(true), Bool(false)]).type_check(&T::Tuple(vec![T::Bool]))); + assert!(Tuple(vec![Bool(true), Bool(false)]).type_check(&T::Tuple(vec![T::Bool, T::Bool]))); + assert!(!Tuple(vec![Bool(true)]).type_check(&T::Tuple(vec![T::Bool, T::Bool]))); + assert!(!Tuple(vec![Bool(true)]).type_check(&T::Bool)); + } +} diff --git a/graph/src/cheap_clone.rs b/graph/src/cheap_clone.rs index b8863d3918e..0d894d84434 100644 --- a/graph/src/cheap_clone.rs +++ b/graph/src/cheap_clone.rs @@ -118,4 +118,4 @@ cheap_clone_is_copy!( &'static str, std::time::Duration ); -cheap_clone_is_copy!(ethabi::Address); +cheap_clone_is_copy!(web3::types::Address); diff --git a/graph/src/components/adapter.rs b/graph/src/components/adapter.rs index aaae5a89518..f56f36dc25b 100644 --- a/graph/src/components/adapter.rs +++ b/graph/src/components/adapter.rs @@ -595,8 +595,8 @@ mod test { }; use async_trait::async_trait; use chrono::{Duration, Utc}; - use ethabi::ethereum_types::H256; use slog::{o, Discard, Logger}; + use web3::types::H256; use crate::{blockchain::ChainIdentifier, components::adapter::ProviderManagerError}; diff --git a/graph/src/components/store/mod.rs b/graph/src/components/store/mod.rs index 31b0e62cfae..c79b5b3a9e0 100644 --- a/graph/src/components/store/mod.rs +++ b/graph/src/components/store/mod.rs @@ -1262,7 +1262,7 @@ pub struct CachedEthereumCall { pub block_ptr: BlockPtr, /// The address to the called contract. - pub contract_address: ethabi::Address, + pub contract_address: web3::types::Address, /// The encoded return value of this call. pub return_value: Vec, diff --git a/graph/src/data/store/ethereum.rs b/graph/src/data/store/ethereum.rs index 12d48f992df..ae39f1ffcbc 100644 --- a/graph/src/data/store/ethereum.rs +++ b/graph/src/data/store/ethereum.rs @@ -104,7 +104,7 @@ pub mod call { /// on the call's return value #[derive(Debug, Clone, CheapClone)] pub struct Request { - pub address: ethabi::Address, + pub address: web3::types::Address, pub encoded_call: Arc, /// The index is set by the caller and is used to identify the /// request in related data structures that the caller might have @@ -112,7 +112,7 @@ pub mod call { } impl Request { - pub fn new(address: ethabi::Address, encoded_call: Vec, index: u32) -> Self { + pub fn new(address: web3::types::Address, encoded_call: Vec, index: u32) -> Self { Request { address, encoded_call: Arc::new(Bytes::from(encoded_call)), diff --git a/graph/src/lib.rs b/graph/src/lib.rs index fe1b6949642..e48755f848f 100644 --- a/graph/src/lib.rs +++ b/graph/src/lib.rs @@ -37,8 +37,11 @@ pub mod env; pub mod ipfs; +pub mod abi; + /// Wrapper for spawning tasks that abort on panic, which is our default. mod task_spawn; + pub use task_spawn::{ block_on, spawn, spawn_allow_panic, spawn_blocking, spawn_blocking_allow_panic, spawn_thread, }; @@ -81,7 +84,6 @@ pub mod prelude { pub use chrono; pub use diesel; pub use envconfig; - pub use ethabi; pub use hex; pub use isatty; pub use lazy_static::lazy_static; diff --git a/runtime/test/src/common.rs b/runtime/test/src/common.rs index 2416a96a198..776bd3fa91a 100644 --- a/runtime/test/src/common.rs +++ b/runtime/test/src/common.rs @@ -1,4 +1,3 @@ -use ethabi::Contract; use graph::blockchain::BlockTime; use graph::components::store::DeploymentLocator; use graph::data::subgraph::*; @@ -84,7 +83,7 @@ fn mock_host_exports( fn mock_abi() -> MappingABI { MappingABI { name: "mock_abi".to_string(), - contract: Contract::load( + contract: serde_json::from_str( r#"[ { "inputs": [ @@ -95,8 +94,7 @@ fn mock_abi() -> MappingABI { ], "type": "constructor" } - ]"# - .as_bytes(), + ]"#, ) .unwrap(), } diff --git a/runtime/test/src/test/abi.rs b/runtime/test/src/test/abi.rs index b681287c50c..c9d2ce4246d 100644 --- a/runtime/test/src/test/abi.rs +++ b/runtime/test/src/test/abi.rs @@ -1,4 +1,4 @@ -use graph::prelude::{ethabi::Token, web3::types::U256}; +use graph::prelude::web3::types::U256; use graph_runtime_wasm::asc_abi::class::{ ArrayBuffer, AscAddress, AscEnum, AscEnumArray, EthereumValueKind, StoreValueKind, TypedArray, }; @@ -178,9 +178,9 @@ async fn abi_bytes_and_fixed_bytes_v0_0_5() { test_abi_bytes_and_fixed_bytes(API_VERSION_0_0_5).await; } -async fn test_abi_ethabi_token_identity(api_version: Version) { +async fn test_abi_alloy_token_identity(api_version: Version) { let mut instance = test_module( - "abiEthabiTokenIdentity", + "abiAlloyTokenIdentity", mock_data_source( &wasm_file_path("abi_token.wasm", api_version.clone()), api_version.clone(), @@ -190,8 +190,8 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { .await; // Token::Address - let address = H160([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); - let token_address = Token::Address(address); + let address = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + let token_address = graph::abi::DynSolValue::Address(address.into()); let new_address_obj: AscPtr = instance.invoke_export1("token_to_address", &token_address); @@ -202,7 +202,7 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_eq!(token_address, new_token); // Token::Bytes - let token_bytes = Token::Bytes(vec![42, 45, 7, 245, 45]); + let token_bytes = graph::abi::DynSolValue::Bytes(vec![42, 45, 7, 245, 45]); let new_bytes_obj: AscPtr = instance.invoke_export1("token_to_bytes", &token_bytes); let new_token_ptr = instance.takes_ptr_returns_ptr("token_from_bytes", new_bytes_obj); @@ -211,7 +211,8 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_eq!(token_bytes, new_token); // Token::Int - let int_token = Token::Int(U256([256, 453452345, 0, 42])); + let int = graph::abi::I256::from_limbs([256, 453452345, 0, 42]); + let int_token = graph::abi::DynSolValue::Int(int, int.bits() as usize); let new_int_obj: AscPtr = instance.invoke_export1("token_to_int", &int_token); let new_token_ptr = instance.takes_ptr_returns_ptr("token_from_int", new_int_obj); @@ -220,7 +221,8 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_eq!(int_token, new_token); // Token::Uint - let uint_token = Token::Uint(U256([256, 453452345, 0, 42])); + let uint = graph::abi::U256::from_limbs([256, 453452345, 0, 42]); + let uint_token = graph::abi::DynSolValue::Uint(uint, uint.bit_len()); let new_uint_obj: AscPtr = instance.invoke_export1("token_to_uint", &uint_token); let new_token_ptr = instance.takes_ptr_returns_ptr("token_from_uint", new_uint_obj); @@ -230,7 +232,7 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_ne!(uint_token, int_token); // Token::Bool - let token_bool = Token::Bool(true); + let token_bool = graph::abi::DynSolValue::Bool(true); let token_bool_ptr = instance.asc_new(&token_bool).unwrap(); let func = instance @@ -251,7 +253,7 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_eq!(token_bool, new_token); // Token::String - let token_string = Token::String("漢字Go🇧🇷".into()); + let token_string = graph::abi::DynSolValue::String("漢字Go🇧🇷".into()); let new_string_obj: AscPtr = instance.invoke_export1("token_to_string", &token_string); let new_token_ptr = instance.takes_ptr_returns_ptr("token_from_string", new_string_obj); @@ -260,13 +262,13 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { assert_eq!(token_string, new_token); // Token::Array - let token_array = Token::Array(vec![token_address, token_bytes, token_bool]); - let token_array_nested = Token::Array(vec![token_string, token_array]); + let token_array = graph::abi::DynSolValue::Array(vec![token_address, token_bytes, token_bool]); + let token_array_nested = graph::abi::DynSolValue::Array(vec![token_string, token_array]); let new_array_obj: AscEnumArray = instance.invoke_export1("token_to_array", &token_array_nested); let new_token_ptr = instance.takes_ptr_returns_ptr("token_from_array", new_array_obj); - let new_token: Token = instance.asc_get(new_token_ptr).unwrap(); + let new_token: graph::abi::DynSolValue = instance.asc_get(new_token_ptr).unwrap(); assert_eq!(new_token, token_array_nested); } @@ -274,15 +276,15 @@ async fn test_abi_ethabi_token_identity(api_version: Version) { /// Test a roundtrip Token -> Payload -> Token identity conversion through asc, /// and assert the final token is the same as the starting one. #[tokio::test] -async fn abi_ethabi_token_identity_v0_0_4() { - test_abi_ethabi_token_identity(API_VERSION_0_0_4).await; +async fn abi_alloy_token_identity_v0_0_4() { + test_abi_alloy_token_identity(API_VERSION_0_0_4).await; } /// Test a roundtrip Token -> Payload -> Token identity conversion through asc, /// and assert the final token is the same as the starting one. #[tokio::test] -async fn abi_ethabi_token_identity_v0_0_5() { - test_abi_ethabi_token_identity(API_VERSION_0_0_5).await; +async fn abi_alloy_token_identity_v0_0_5() { + test_abi_alloy_token_identity(API_VERSION_0_0_5).await; } async fn test_abi_store_value(api_version: Version) { diff --git a/runtime/wasm/Cargo.toml b/runtime/wasm/Cargo.toml index 0e6e5d64100..28af409d8ed 100644 --- a/runtime/wasm/Cargo.toml +++ b/runtime/wasm/Cargo.toml @@ -5,7 +5,6 @@ edition.workspace = true [dependencies] async-trait = "0.1.50" -ethabi = "17.2" hex = "0.4.3" graph = { path = "../../graph" } bs58 = "0.4.0" diff --git a/runtime/wasm/src/asc_abi/class.rs b/runtime/wasm/src/asc_abi/class.rs index 366ff844b08..2e15f42cb52 100644 --- a/runtime/wasm/src/asc_abi/class.rs +++ b/runtime/wasm/src/asc_abi/class.rs @@ -1,5 +1,3 @@ -use ethabi; - use graph::{ data::store::{self, scalar::Timestamp}, runtime::{ @@ -520,21 +518,25 @@ pub enum EthereumValueKind { FixedArray, Array, Tuple, + Function, } impl EthereumValueKind { - pub(crate) fn get_kind(token: ðabi::Token) -> Self { - match token { - ethabi::Token::Address(_) => EthereumValueKind::Address, - ethabi::Token::FixedBytes(_) => EthereumValueKind::FixedBytes, - ethabi::Token::Bytes(_) => EthereumValueKind::Bytes, - ethabi::Token::Int(_) => EthereumValueKind::Int, - ethabi::Token::Uint(_) => EthereumValueKind::Uint, - ethabi::Token::Bool(_) => EthereumValueKind::Bool, - ethabi::Token::String(_) => EthereumValueKind::String, - ethabi::Token::FixedArray(_) => EthereumValueKind::FixedArray, - ethabi::Token::Array(_) => EthereumValueKind::Array, - ethabi::Token::Tuple(_) => EthereumValueKind::Tuple, + pub(crate) fn get_kind(value: &graph::abi::DynSolValue) -> Self { + use graph::abi::DynSolValue; + + match value { + DynSolValue::Bool(_) => Self::Bool, + DynSolValue::Int(_, _) => Self::Int, + DynSolValue::Uint(_, _) => Self::Uint, + DynSolValue::FixedBytes(_, _) => Self::FixedBytes, + DynSolValue::Address(_) => Self::Address, + DynSolValue::Function(_) => Self::Function, + DynSolValue::Bytes(_) => Self::Bytes, + DynSolValue::String(_) => Self::String, + DynSolValue::Array(_) => Self::Array, + DynSolValue::FixedArray(_) => Self::FixedArray, + DynSolValue::Tuple(_) => Self::Tuple, } } } diff --git a/runtime/wasm/src/host_exports.rs b/runtime/wasm/src/host_exports.rs index 4d050db23de..481191f2c50 100644 --- a/runtime/wasm/src/host_exports.rs +++ b/runtime/wasm/src/host_exports.rs @@ -21,8 +21,6 @@ use graph::components::subgraph::{ use graph::data::store::{self}; use graph::data_source::{CausalityRegion, DataSource, EntityTypeAccess}; use graph::ensure; -use graph::prelude::ethabi::param_type::Reader; -use graph::prelude::ethabi::{decode, encode, Token}; use graph::prelude::serde_json; use graph::prelude::{slog::b, slog::record_static, *}; use graph::runtime::gas::{self, complexity, Gas, GasCounter}; @@ -1190,11 +1188,11 @@ impl HostExports { pub(crate) fn ethereum_encode( &self, - token: Token, + value: graph::abi::DynSolValue, gas: &GasCounter, state: &mut BlockState, ) -> Result, DeterministicHostError> { - let encoded = encode(&[token]); + let encoded = value.abi_encode(); Self::track_gas_and_ops( gas, @@ -1212,7 +1210,7 @@ impl HostExports { data: Vec, gas: &GasCounter, state: &mut BlockState, - ) -> Result { + ) -> Result { Self::track_gas_and_ops( gas, state, @@ -1220,15 +1218,9 @@ impl HostExports { "ethereum_decode", )?; - let param_types = - Reader::read(&types).map_err(|e| anyhow::anyhow!("Failed to read types: {}", e))?; + let ty: graph::abi::DynSolType = types.parse().context("Failed to read types")?; - decode(&[param_types], &data) - // The `.pop().unwrap()` here is ok because we're always only passing one - // `param_types` to `decode`, so the returned `Vec` has always size of one. - // We can't do `tokens[0]` because the value can't be moved out of the `Vec`. - .map(|mut tokens| tokens.pop().unwrap()) - .context("Failed to decode") + ty.abi_decode(&data).context("Failed to decode") } } diff --git a/runtime/wasm/src/to_from/external.rs b/runtime/wasm/src/to_from/external.rs index f08eacee94f..216284f6ae6 100644 --- a/runtime/wasm/src/to_from/external.rs +++ b/runtime/wasm/src/to_from/external.rs @@ -1,5 +1,4 @@ -use ethabi; - +use graph::abi::DynSolValueExt; use graph::data::store::scalar::Timestamp; use graph::data::value::Word; use graph::prelude::{BigDecimal, BigInt}; @@ -162,32 +161,42 @@ impl ToAscObj>> for Vec { } } -impl ToAscObj> for ethabi::Token { +impl ToAscObj> for graph::abi::DynSolValue { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, ) -> Result, HostExportError> { - use ethabi::Token::*; - let kind = EthereumValueKind::get_kind(self); + let payload = match self { - Address(address) => asc_new::(heap, address, gas)?.to_payload(), - FixedBytes(bytes) | Bytes(bytes) => { - asc_new::(heap, &**bytes, gas)?.to_payload() - } - Int(uint) => { - let n = BigInt::from_signed_u256(uint); + Self::Bool(val) => *val as u64, + Self::Int(val, _) => { + let bytes = val.to_le_bytes::<32>(); + let n = BigInt::from_signed_bytes_le(&bytes)?; + asc_new(heap, &n, gas)?.to_payload() } - Uint(uint) => { - let n = BigInt::from_unsigned_u256(uint); + Self::Uint(val, _) => { + let bytes = val.to_le_bytes::<32>(); + let n = BigInt::from_unsigned_bytes_le(&bytes)?; + asc_new(heap, &n, gas)?.to_payload() } - Bool(b) => *b as u64, - String(string) => asc_new(heap, &**string, gas)?.to_payload(), - FixedArray(tokens) | Array(tokens) => asc_new(heap, &**tokens, gas)?.to_payload(), - Tuple(tokens) => asc_new(heap, &**tokens, gas)?.to_payload(), + Self::FixedBytes(val, _) => { + asc_new::(heap, val.as_slice(), gas)?.to_payload() + } + Self::Address(val) => { + asc_new::(heap, val.as_slice(), gas)?.to_payload() + } + Self::Function(val) => { + asc_new::(heap, val.as_slice(), gas)?.to_payload() + } + Self::Bytes(val) => asc_new::(heap, &**val, gas)?.to_payload(), + Self::String(val) => asc_new(heap, &**val, gas)?.to_payload(), + Self::Array(values) => asc_new(heap, &**values, gas)?.to_payload(), + Self::FixedArray(values) => asc_new(heap, &**values, gas)?.to_payload(), + Self::Tuple(values) => asc_new(heap, &**values, gas)?.to_payload(), }; Ok(AscEnum { @@ -198,57 +207,78 @@ impl ToAscObj> for ethabi::Token { } } -impl FromAscObj> for ethabi::Token { +impl FromAscObj> for graph::abi::DynSolValue { fn from_asc_obj( asc_enum: AscEnum, heap: &H, gas: &GasCounter, depth: usize, ) -> Result { - use ethabi::Token; - let payload = asc_enum.payload; - Ok(match asc_enum.kind { - EthereumValueKind::Bool => Token::Bool(bool::from(payload)), + + let value = match asc_enum.kind { EthereumValueKind::Address => { let ptr: AscPtr = AscPtr::from(payload); - Token::Address(asc_get(heap, ptr, gas, depth)?) + let bytes: [u8; 20] = asc_get(heap, ptr, gas, depth)?; + + Self::Address(bytes.into()) } EthereumValueKind::FixedBytes => { let ptr: AscPtr = AscPtr::from(payload); - Token::FixedBytes(asc_get(heap, ptr, gas, depth)?) + let bytes: Vec = asc_get(heap, ptr, gas, depth)?; + + Self::fixed_bytes_from_slice(&bytes)? } EthereumValueKind::Bytes => { let ptr: AscPtr = AscPtr::from(payload); - Token::Bytes(asc_get(heap, ptr, gas, depth)?) + let bytes: Vec = asc_get(heap, ptr, gas, depth)?; + + Self::Bytes(bytes) } EthereumValueKind::Int => { let ptr: AscPtr = AscPtr::from(payload); let n: BigInt = asc_get(heap, ptr, gas, depth)?; - Token::Int(n.to_signed_u256()) + let x = graph::abi::I256::from_limbs(n.to_signed_u256().0); + + Self::Int(x, x.bits() as usize) } EthereumValueKind::Uint => { let ptr: AscPtr = AscPtr::from(payload); let n: BigInt = asc_get(heap, ptr, gas, depth)?; - Token::Uint(n.to_unsigned_u256()) + let x = graph::abi::U256::from_limbs(n.to_unsigned_u256().0); + + Self::Uint(x, x.bit_len()) } + EthereumValueKind::Bool => Self::Bool(bool::from(payload)), EthereumValueKind::String => { let ptr: AscPtr = AscPtr::from(payload); - Token::String(asc_get(heap, ptr, gas, depth)?) + + Self::String(asc_get(heap, ptr, gas, depth)?) } EthereumValueKind::FixedArray => { let ptr: AscEnumArray = AscPtr::from(payload); - Token::FixedArray(asc_get(heap, ptr, gas, depth)?) + + Self::FixedArray(asc_get(heap, ptr, gas, depth)?) } EthereumValueKind::Array => { let ptr: AscEnumArray = AscPtr::from(payload); - Token::Array(asc_get(heap, ptr, gas, depth)?) + + Self::Array(asc_get(heap, ptr, gas, depth)?) } EthereumValueKind::Tuple => { let ptr: AscEnumArray = AscPtr::from(payload); - Token::Tuple(asc_get(heap, ptr, gas, depth)?) + + Self::Tuple(asc_get(heap, ptr, gas, depth)?) } - }) + EthereumValueKind::Function => { + let ptr: AscPtr = AscPtr::from(payload); + let bytes: [u8; 24] = asc_get(heap, ptr, gas, depth)?; + + Self::Function(bytes.into()) + } + }; + + Ok(value) } } diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index b399b15b788..448d0c6065f 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -90,8 +90,8 @@ mod data { use graph::blockchain::{Block, BlockHash}; use graph::constraint_violation; use graph::data::store::scalar::Bytes; - use graph::prelude::ethabi::ethereum_types::H160; use graph::prelude::transaction_receipt::LightTransactionReceipt; + use graph::prelude::web3::types::H160; use graph::prelude::web3::types::H256; use graph::prelude::{ serde_json as json, BlockNumber, BlockPtr, CachedEthereumCall, Error, StoreError, diff --git a/store/test-store/Cargo.toml b/store/test-store/Cargo.toml index fe05f12233e..c6e0ad5f59f 100644 --- a/store/test-store/Cargo.toml +++ b/store/test-store/Cargo.toml @@ -19,3 +19,4 @@ prost-types = { workspace = true } [dev-dependencies] hex = "0.4.3" pretty_assertions = "1.4.0" +serde_json = { workspace = true } diff --git a/store/test-store/tests/postgres/store.rs b/store/test-store/tests/postgres/store.rs index aba953975a3..c50d407fe2f 100644 --- a/store/test-store/tests/postgres/store.rs +++ b/store/test-store/tests/postgres/store.rs @@ -22,7 +22,6 @@ use graph::{ BlockStore as _, EntityFilter, EntityOrder, EntityQuery, StatusStore, SubscriptionManager as _, }, - prelude::ethabi::Contract, }; use graph::{data::store::scalar, semver::Version}; use graph::{entity, prelude::*}; @@ -1145,19 +1144,18 @@ fn mock_data_source() -> graph_chain_ethereum::DataSource { fn mock_abi() -> MappingABI { MappingABI { name: "mock_abi".to_string(), - contract: Contract::load( + contract: serde_json::from_str( r#"[ - { - "inputs": [ - { - "name": "a", - "type": "address" - } - ], - "type": "constructor" - } - ]"# - .as_bytes(), + { + "inputs": [ + { + "name": "a", + "type": "address" + } + ], + "type": "constructor" + } + ]"#, ) .unwrap(), } diff --git a/tests/src/fixture/ethereum.rs b/tests/src/fixture/ethereum.rs index b20672ce563..17026f61f02 100644 --- a/tests/src/fixture/ethereum.rs +++ b/tests/src/fixture/ethereum.rs @@ -6,13 +6,14 @@ use super::{ test_ptr, CommonChainConfig, MutexBlockStreamBuilder, NoopAdapterSelector, NoopRuntimeAdapterBuilder, StaticBlockRefetcher, StaticStreamBuilder, Stores, TestChain, }; +use graph::blockchain::block_stream::BlockWithTriggers; use graph::blockchain::client::ChainClient; use graph::blockchain::{BlockPtr, TriggersAdapterSelector}; use graph::cheap_clone::CheapClone; -use graph::prelude::ethabi::ethereum_types::H256; +use graph::prelude::web3::types::H256; +use graph::prelude::web3::types::U64; use graph::prelude::web3::types::{Address, Log, Transaction, H160}; -use graph::prelude::{ethabi, tiny_keccak, LightEthereumBlock, ENV_VARS}; -use graph::{blockchain::block_stream::BlockWithTriggers, prelude::ethabi::ethereum_types::U64}; +use graph::prelude::{tiny_keccak, LightEthereumBlock, ENV_VARS}; use graph_chain_ethereum::network::EthereumNetworkAdapters; use graph_chain_ethereum::trigger::LogRef; use graph_chain_ethereum::Chain; @@ -136,7 +137,9 @@ pub fn push_test_log(block: &mut BlockWithTriggers, payload: impl Into