diff --git a/eth-bytecode-db/Cargo.lock b/eth-bytecode-db/Cargo.lock index 4d2588e38..b79da39ff 100644 --- a/eth-bytecode-db/Cargo.lock +++ b/eth-bytecode-db/Cargo.lock @@ -339,6 +339,55 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "alloy-json-abi" +version = "0.5.2" +source = "git+https://github.com/alloy-rs/core?rev=398d7e2#398d7e27b235f85f776c1b6b8fe2c9b081f2907a" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-primitives" +version = "0.5.2" +source = "git+https://github.com/alloy-rs/core?rev=398d7e2#398d7e27b235f85f776c1b6b8fe2c9b081f2907a" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +dependencies = [ + "arrayvec", + "bytes", + "smol_str", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.5.2" +source = "git+https://github.com/alloy-rs/core?rev=398d7e2#398d7e27b235f85f776c1b6b8fe2c9b081f2907a" +dependencies = [ + "winnow", +] + [[package]] name = "amplify" version = "3.14.2" @@ -379,6 +428,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -442,6 +497,130 @@ version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +[[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", + "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 = [ + "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.6", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "arrayvec" version = "0.7.2" @@ -611,7 +790,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -1066,7 +1245,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.17", "serde", "serde_json", "thiserror", @@ -1089,15 +1268,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "serde", - "winapi", + "windows-targets 0.48.0", ] [[package]] @@ -1250,6 +1429,19 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-oid" version = "0.9.2" @@ -1551,7 +1743,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn 1.0.109", ] @@ -1759,6 +1951,7 @@ dependencies = [ name = "eth-bytecode-db" version = "0.1.0" dependencies = [ + "alloy-json-abi", "anyhow", "async-trait", "blockscout-display-bytes", @@ -1779,7 +1972,7 @@ dependencies = [ "reqwest", "rstest", "sea-orm", - "semver", + "semver 1.0.17", "serde", "serde_json", "smart-contract-verifier-proto", @@ -2047,7 +2240,7 @@ dependencies = [ "ethers-core", "ethers-solc", "reqwest", - "semver", + "semver 1.0.17", "serde", "serde_json", "thiserror", @@ -2155,7 +2348,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver", + "semver 1.0.17", "serde", "serde_json", "solang-parser", @@ -2193,6 +2386,17 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" @@ -2597,6 +2801,15 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" @@ -3378,9 +3591,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -3855,7 +4068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -4139,6 +4352,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.3.3", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "prost" version = "0.11.9" @@ -4219,6 +4452,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.31" @@ -4270,6 +4509,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.7.0" @@ -4365,6 +4613,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "relative-path" version = "1.9.0" @@ -4595,7 +4849,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version", + "rustc_version 0.4.0", ] [[package]] @@ -4610,11 +4864,41 @@ dependencies = [ "quote", "regex", "relative-path", - "rustc_version", + "rustc_version 0.4.0", "syn 2.0.26", "unicode-ident", ] +[[package]] +name = "ruint" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" + [[package]] name = "rust-ini" version = "0.18.0" @@ -4655,13 +4939,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.17", ] [[package]] @@ -4752,6 +5045,18 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +[[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.13" @@ -4858,9 +5163,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "0.12.2" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f6c7daef05dde3476d97001e11fca7a52b655aa3bf4fd610ab2da1176a2ed5" +checksum = "c5181eedee8ad0d002d2a288600140fe9937581c4668426a4ff1295c14c736cf" dependencies = [ "async-stream", "async-trait", @@ -4886,9 +5191,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "0.12.2" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3f0ff2fa5672e2e7314d107c6498a18e469beeb340a0ed84e3075fce73c2cd" +checksum = "507c2b99f83129f4d5d511012ab47c9f40d1c7923fd4698c19fae23f0bf62913" dependencies = [ "chrono", "clap", @@ -4903,9 +5208,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "0.12.2" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd90e73d5f5b184bad525767da29fbfec132b4e62ebd6f60d2f2737ec6468f62" +checksum = "816183a751bf9c22087679b20b6142da0b5c6d8981835ebb7b99bf1bf924640a" dependencies = [ "heck", "proc-macro2", @@ -4917,9 +5222,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "0.12.2" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f673fcefb3a7e7b89a12b6c0e854ec0be14367635ac3435369c8ad7f11e09e" +checksum = "9d45937e5d4869a0dcf0222bb264df564c077cbe9b312265f3717401d023a633" dependencies = [ "async-trait", "clap", @@ -4934,9 +5239,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.30.1" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c05a5bf6403834be253489bbe95fa9b1e5486bc843b61f60d26b5c9c1e244b" +checksum = "41558fa9bb5f4d73952dac0b9d9c2ce23966493fc9ee0008037b01d709838a68" dependencies = [ "bigdecimal", "chrono", @@ -4968,22 +5273,22 @@ dependencies = [ [[package]] name = "sea-query-derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd78f2e0ee8e537e9195d1049b752e0433e2cac125426bccb7b5c3e508096117" +checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.26", "thiserror", ] [[package]] name = "sea-schema" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e09eb40c78cee8fef8dfbb648036a26b7ad1f618499203ad0e8b6f97593f7f" +checksum = "0cd9561232bd1b82ea748b581f15909d11de0db6563ddcf28c5d908aee8282f1" dependencies = [ "futures", "sea-query", @@ -5045,6 +5350,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.17" @@ -5054,6 +5368,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 = "send_wrapper" version = "0.4.0" @@ -5277,6 +5600,15 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + [[package]] name = "socket2" version = "0.4.9" @@ -5309,7 +5641,7 @@ checksum = "18f0ee752c2f80c87498dba10c2120492c42073f73b37ffb49e79fcd1e91bff3" dependencies = [ "blockscout-display-bytes", "minicbor", - "semver", + "semver 1.0.17", "thiserror", ] @@ -5658,7 +5990,7 @@ dependencies = [ "home", "once_cell", "reqwest", - "semver", + "semver 1.0.17", "serde", "serde_json", "sha2 0.10.6", @@ -5926,9 +6258,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -6251,6 +6583,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.6.0" @@ -6409,6 +6747,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.1.0" @@ -6766,9 +7113,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.3" +version = "0.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" dependencies = [ "memchr", ] @@ -6793,7 +7140,7 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version", + "rustc_version 0.4.0", "send_wrapper 0.6.0", "thiserror", "wasm-bindgen", @@ -6830,6 +7177,20 @@ name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +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.26", +] [[package]] name = "zip" diff --git a/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/api_config_http.yaml b/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/api_config_http.yaml index 994c8cd23..aedf09902 100644 --- a/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/api_config_http.yaml +++ b/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/api_config_http.yaml @@ -3,7 +3,7 @@ config_version: 3 http: rules: - #################### SolidityVerifier #################### + #################### Database #################### - selector: blockscout.ethBytecodeDb.v2.Database.SearchSources post: /api/v2/bytecodes/sources:search @@ -17,6 +17,14 @@ http: post: /api/v2/bytecodes/sources:search-all body: "*" + - selector: blockscout.ethBytecodeDb.v2.Database.SearchEventDescriptions + post: /api/v2/event-descriptions:search + body: "*" + + - selector: blockscout.ethBytecodeDb.v2.Database.BatchSearchEventDescriptions + post: /api/v2/event-descriptions:batch-search + body: "*" + #################### SolidityVerifier #################### - selector: blockscout.ethBytecodeDb.v2.SolidityVerifier.VerifyMultiPart diff --git a/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/eth-bytecode-db.proto b/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/eth-bytecode-db.proto index a0af98485..501f16ce9 100644 --- a/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/eth-bytecode-db.proto +++ b/eth-bytecode-db/eth-bytecode-db-proto/proto/v2/eth-bytecode-db.proto @@ -10,6 +10,10 @@ service Database { rpc SearchSourcifySources(SearchSourcifySourcesRequest) returns (SearchSourcesResponse) {} rpc SearchAllSources(SearchAllSourcesRequest) returns (SearchAllSourcesResponse) {} + + rpc SearchEventDescriptions(SearchEventDescriptionsRequest) returns (SearchEventDescriptionsResponse) {} + + rpc BatchSearchEventDescriptions(BatchSearchEventDescriptionsRequest) returns (BatchSearchEventDescriptionsResponse) {} } service SolidityVerifier { @@ -231,6 +235,27 @@ message SearchAllSourcesResponse { repeated Source sourcify_sources = 2; } +message SearchEventDescriptionsRequest { + /// For non-anonymous events, this is a bytes32 value + /// containing the keccak256 hash of the event signature, + /// as used in the default topic. + string selector = 1; +} + +message SearchEventDescriptionsResponse { + repeated EventDescription event_descriptions = 1; +} + +message BatchSearchEventDescriptionsRequest { + // The selectors of the events to look for. + // A maximum of 100 selectors can be retrieved in a batch. + repeated string selectors = 1; +} + +message BatchSearchEventDescriptionsResponse { + repeated SearchEventDescriptionsResponse responses = 1; +} + message VerifySourcifyRequest { /// Address of the contract to be verified string address = 1; @@ -260,3 +285,12 @@ message ListCompilerVersionsResponse { /// Compiler versions available repeated string compiler_versions = 1; } + +message EventDescription { + /// Will always be "event" + string type = 1; + /// The name of the event + string name = 2; + /// Json encoded array of objects each describing one of the event arguments + string inputs = 3; +} diff --git a/eth-bytecode-db/eth-bytecode-db-proto/swagger/v2/eth-bytecode-db.swagger.yaml b/eth-bytecode-db/eth-bytecode-db-proto/swagger/v2/eth-bytecode-db.swagger.yaml index deca2c60d..69d262354 100644 --- a/eth-bytecode-db/eth-bytecode-db-proto/swagger/v2/eth-bytecode-db.swagger.yaml +++ b/eth-bytecode-db/eth-bytecode-db-proto/swagger/v2/eth-bytecode-db.swagger.yaml @@ -73,6 +73,46 @@ paths: $ref: '#/definitions/v2SearchSourcifySourcesRequest' tags: - Database + /api/v2/event-descriptions:batch-search: + post: + operationId: Database_BatchSearchEventDescriptions + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v2BatchSearchEventDescriptionsResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: body + in: body + required: true + schema: + $ref: '#/definitions/v2BatchSearchEventDescriptionsRequest' + tags: + - Database + /api/v2/event-descriptions:search: + post: + operationId: Database_SearchEventDescriptions + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v2SearchEventDescriptionsResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: body + in: body + required: true + schema: + $ref: '#/definitions/v2SearchEventDescriptionsRequest' + tags: + - Database /api/v2/verifier/solidity/sources:verify-multi-part: post: operationId: SolidityVerifier_VerifyMultiPart @@ -289,6 +329,24 @@ definitions: '@type': type: string additionalProperties: {} + v2BatchSearchEventDescriptionsRequest: + type: object + properties: + selectors: + type: array + items: + type: string + description: |- + The selectors of the events to look for. + A maximum of 100 selectors can be retrieved in a batch. + v2BatchSearchEventDescriptionsResponse: + type: object + properties: + responses: + type: array + items: + type: object + $ref: '#/definitions/v2SearchEventDescriptionsResponse' v2BytecodeType: type: string enum: @@ -296,6 +354,18 @@ definitions: - CREATION_INPUT - DEPLOYED_BYTECODE default: BYTECODE_TYPE_UNSPECIFIED + v2EventDescription: + type: object + properties: + type: + type: string + title: / Will always be "event" + name: + type: string + title: / The name of the event + inputs: + type: string + title: / Json encoded array of objects each describing one of the event arguments v2HealthCheckResponse: type: object properties: @@ -337,6 +407,23 @@ definitions: items: type: object $ref: '#/definitions/v2Source' + v2SearchEventDescriptionsRequest: + type: object + properties: + selector: + type: string + description: |- + / For non-anonymous events, this is a bytes32 value + / containing the keccak256 hash of the event signature, + / as used in the default topic. + v2SearchEventDescriptionsResponse: + type: object + properties: + eventDescriptions: + type: array + items: + type: object + $ref: '#/definitions/v2EventDescription' v2SearchSourcesRequest: type: object properties: diff --git a/eth-bytecode-db/eth-bytecode-db-server/src/proto.rs b/eth-bytecode-db/eth-bytecode-db-server/src/proto.rs index d3844cc72..00a48cb40 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/src/proto.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/src/proto.rs @@ -2,10 +2,12 @@ pub use eth_bytecode_db_proto::blockscout::eth_bytecode_db::v2::{ database_actix, database_server, health_actix, health_check_response, health_server, solidity_verifier_actix, solidity_verifier_server, source, sourcify_verifier_actix, sourcify_verifier_server, verify_response, vyper_verifier_actix, vyper_verifier_server, - BytecodeType, HealthCheckRequest, HealthCheckResponse, ListCompilerVersionsRequest, + BatchSearchEventDescriptionsRequest, BatchSearchEventDescriptionsResponse, BytecodeType, + EventDescription, HealthCheckRequest, HealthCheckResponse, ListCompilerVersionsRequest, ListCompilerVersionsResponse, SearchAllSourcesRequest, SearchAllSourcesResponse, - SearchSourcesRequest, SearchSourcesResponse, SearchSourcifySourcesRequest, Source, - VerificationMetadata, VerifyFromEtherscanSourcifyRequest, VerifyResponse, - VerifySolidityMultiPartRequest, VerifySolidityStandardJsonRequest, VerifySourcifyRequest, - VerifyVyperMultiPartRequest, VerifyVyperStandardJsonRequest, + SearchEventDescriptionsRequest, SearchEventDescriptionsResponse, SearchSourcesRequest, + SearchSourcesResponse, SearchSourcifySourcesRequest, Source, VerificationMetadata, + VerifyFromEtherscanSourcifyRequest, VerifyResponse, VerifySolidityMultiPartRequest, + VerifySolidityStandardJsonRequest, VerifySourcifyRequest, VerifyVyperMultiPartRequest, + VerifyVyperStandardJsonRequest, }; diff --git a/eth-bytecode-db/eth-bytecode-db-server/src/services/database.rs b/eth-bytecode-db/eth-bytecode-db-server/src/services/database.rs index ea89638b5..9c4080055 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/src/services/database.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/src/services/database.rs @@ -1,10 +1,12 @@ use crate::{ proto::{ - database_server::Database, BytecodeType, SearchAllSourcesRequest, SearchAllSourcesResponse, + database_server::Database, BatchSearchEventDescriptionsRequest, + BatchSearchEventDescriptionsResponse, BytecodeType, SearchAllSourcesRequest, + SearchAllSourcesResponse, SearchEventDescriptionsRequest, SearchEventDescriptionsResponse, SearchSourcesRequest, SearchSourcesResponse, SearchSourcifySourcesRequest, Source, VerifyResponse, }, - types::{BytecodeTypeWrapper, SourceWrapper, VerifyResponseWrapper}, + types::{BytecodeTypeWrapper, EventDescriptionWrapper, SourceWrapper, VerifyResponseWrapper}, }; use amplify::Wrapper; use async_trait::async_trait; @@ -14,6 +16,7 @@ use eth_bytecode_db::{ verification, verification::sourcify_from_etherscan, }; +use ethers::types::H256; use std::str::FromStr; use tracing::instrument; @@ -133,6 +136,57 @@ impl Database for DatabaseService { Ok(tonic::Response::new(response)) } + + async fn search_event_descriptions( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let selector = H256::from_str(&request.selector).map_err(|err| { + tonic::Status::invalid_argument(format!("selector is not valid: {err}")) + })?; + + let event_descriptions = + search::find_event_descriptions(self.client.db_client.as_ref(), vec![selector]) + .await + .remove(0) + .map_err(|err| tonic::Status::internal(err.to_string()))?; + + Ok(tonic::Response::new(event_descriptions_to_search_response( + event_descriptions, + ))) + } + + async fn batch_search_event_descriptions( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + const BATCH_LIMIT: usize = 100; + + let request = request.into_inner(); + let selectors = request + .selectors + .into_iter() + .take(BATCH_LIMIT) + .map(|selector| { + H256::from_str(&selector).map_err(|err| { + tonic::Status::invalid_argument(format!("selector is not valid: {err}")) + }) + }) + .collect::, _>>()?; + + let responses: Vec<_> = + search::find_event_descriptions(self.client.db_client.as_ref(), selectors) + .await + .into_iter() + .map(|event_descriptions| event_descriptions.unwrap_or_default()) + .map(event_descriptions_to_search_response) + .collect(); + + Ok(tonic::Response::new(BatchSearchEventDescriptionsResponse { + responses, + })) + } } impl DatabaseService { @@ -232,3 +286,14 @@ fn process_sourcify_error( } } } + +fn event_descriptions_to_search_response( + event_descriptions: Vec, +) -> SearchEventDescriptionsResponse { + SearchEventDescriptionsResponse { + event_descriptions: event_descriptions + .into_iter() + .map(|event| EventDescriptionWrapper::from(event).into()) + .collect(), + } +} diff --git a/eth-bytecode-db/eth-bytecode-db-server/src/types/event_description.rs b/eth-bytecode-db/eth-bytecode-db-server/src/types/event_description.rs new file mode 100644 index 000000000..b4b12c0a5 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db-server/src/types/event_description.rs @@ -0,0 +1,16 @@ +use crate::proto; +use amplify::{From, Wrapper}; +use eth_bytecode_db::search; + +#[derive(Wrapper, From, Clone, Debug, PartialEq)] +pub struct EventDescriptionWrapper(proto::EventDescription); + +impl From for EventDescriptionWrapper { + fn from(value: search::EventDescription) -> Self { + EventDescriptionWrapper(proto::EventDescription { + r#type: "event".to_string(), + name: value.name, + inputs: value.inputs.to_string(), + }) + } +} diff --git a/eth-bytecode-db/eth-bytecode-db-server/src/types/mod.rs b/eth-bytecode-db/eth-bytecode-db-server/src/types/mod.rs index 37819e376..dfd2a6c15 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/src/types/mod.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/src/types/mod.rs @@ -1,9 +1,11 @@ mod enums; +mod event_description; mod source; mod verification_metadata; mod verify_response; pub use enums::{BytecodeTypeWrapper, MatchTypeWrapper, SourceTypeWrapper}; +pub use event_description::EventDescriptionWrapper; pub use source::SourceWrapper; pub use verification_metadata::VerificationMetadataWrapper; pub use verify_response::VerifyResponseWrapper; diff --git a/eth-bytecode-db/eth-bytecode-db-server/tests/database_search.rs b/eth-bytecode-db/eth-bytecode-db-server/tests/database_search.rs index ace12c184..8aee3f666 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/tests/database_search.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/tests/database_search.rs @@ -9,7 +9,9 @@ use eth_bytecode_db::{verification, verification::MatchType}; use eth_bytecode_db_proto::blockscout::eth_bytecode_db::{ v2 as eth_bytecode_db_v2, v2::{ - SearchAllSourcesRequest, SearchAllSourcesResponse, SearchSourcesResponse, + BatchSearchEventDescriptionsRequest, BatchSearchEventDescriptionsResponse, + EventDescription, SearchAllSourcesRequest, SearchAllSourcesResponse, + SearchEventDescriptionsRequest, SearchEventDescriptionsResponse, SearchSourcesResponse, SearchSourcifySourcesRequest, Source, }, }; @@ -306,3 +308,135 @@ async fn search_sources_returns_latest_contract() { "Invalid response returned" ); } + +#[rstest] +#[tokio::test] +#[timeout(std::time::Duration::from_secs(60))] +#[ignore = "Needs database to run"] +async fn search_event_descriptions() { + const ROUTE: &str = "/api/v2/event-descriptions:search"; + + let db = init_db(TEST_SUITE_NAME, "search_event_descriptions").await; + + let abi = r#"[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}],"name":"A","type":"event"},{"anonymous":true,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"middle","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Anonymous","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}],"name":"B","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"f","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]"#; + + let test_data = { + let mut test_data = + test_input_data::basic(verification::SourceType::Solidity, MatchType::Partial); + test_data.set_abi(abi.to_string()); + test_data + }; + + let db_url = db.db_url(); + let verifier_addr = init_verifier_server(service(), test_data.verifier_response).await; + + let eth_bytecode_db_base = init_eth_bytecode_db_server(db_url, verifier_addr).await; + + // Fill the database with existing value + { + let dummy_request = default_verify_request(); + let _verification_response: eth_bytecode_db_v2::VerifyResponse = + test_server::send_post_request(ð_bytecode_db_base, VERIFY_ROUTE, &dummy_request) + .await; + } + + let selector = "0xa17a9e66f0c355e3aa3b9ea969991204d6b1d2e62a47877f612cb2371d79e06a"; + + let request = SearchEventDescriptionsRequest { + selector: selector.into(), + }; + + let event_descriptions: SearchEventDescriptionsResponse = + test_server::send_post_request(ð_bytecode_db_base, ROUTE, &request).await; + + let expected_response = SearchEventDescriptionsResponse { + event_descriptions: vec![EventDescription { + r#type: "event".into(), + name: "A".into(), + inputs: r#"[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}]"# + .into(), + }], + }; + + assert_eq!( + expected_response, event_descriptions, + "Invalid response returned" + ); +} + +#[rstest] +#[tokio::test] +#[timeout(std::time::Duration::from_secs(60))] +#[ignore = "Needs database to run"] +async fn batch_search_event_descriptions() { + const ROUTE: &str = "/api/v2/event-descriptions:batch-search"; + + let db = init_db(TEST_SUITE_NAME, "batch_search_event_descriptions").await; + + let abi = r#"[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}],"name":"A","type":"event"},{"anonymous":true,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"middle","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Anonymous","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}],"name":"B","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"f","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]"#; + + let test_data = { + let mut test_data = + test_input_data::basic(verification::SourceType::Solidity, MatchType::Partial); + test_data.set_abi(abi.to_string()); + test_data + }; + + let db_url = db.db_url(); + let verifier_addr = init_verifier_server(service(), test_data.verifier_response).await; + + let eth_bytecode_db_base = init_eth_bytecode_db_server(db_url, verifier_addr).await; + + // Fill the database with existing value + { + let dummy_request = default_verify_request(); + let _verification_response: eth_bytecode_db_v2::VerifyResponse = + test_server::send_post_request(ð_bytecode_db_base, VERIFY_ROUTE, &dummy_request) + .await; + } + + let selectors = [ + "0xbcf5c814cb65249e306ec7aeaef6fc1ca35e1b8e18c08b054c9f9c76160bc923".to_string(), + "0xa17a9e66f0c355e3aa3b9ea969991204d6b1d2e62a47877f612cb2371d79e06a".to_string(), + "0x6bda65e31c7e349462fbf26f88a201b5f967d8582bcfe8d12b9be6ba824324a1".to_string(), + ]; + + let request = BatchSearchEventDescriptionsRequest { + selectors: selectors.into(), + }; + + let batch_event_descriptions: BatchSearchEventDescriptionsResponse = + test_server::send_post_request(ð_bytecode_db_base, ROUTE, &request).await; + + let expected_response = BatchSearchEventDescriptionsResponse { + responses: vec![ + SearchEventDescriptionsResponse { + event_descriptions: vec![ + EventDescription { + r#type: "event".into(), + name: "B".into(), + inputs: r#"[{"indexed":false,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}]"#.into(), + }, + ] + }, + SearchEventDescriptionsResponse { + event_descriptions: vec![ + EventDescription { + r#type: "event".into(), + name: "A".into(), + inputs: r#"[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}]"# + .into(), + }, + ] + }, + SearchEventDescriptionsResponse { + event_descriptions: vec![] + }, + ], + }; + + assert_eq!( + expected_response, batch_event_descriptions, + "Invalid response returned" + ); +} diff --git a/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/test_input_data.rs b/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/test_input_data.rs index bf2b9a8e5..45794a184 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/test_input_data.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/test_input_data.rs @@ -106,6 +106,15 @@ impl TestInputData { }); } + pub fn set_abi(&mut self, abi: String) { + if let Some(source) = self.verifier_response.source.as_mut() { + source.abi = Some(abi.clone()) + } + if let Some(source) = self.eth_bytecode_db_response.source.as_mut() { + source.abi = Some(abi) + } + } + pub fn add_source_file(&mut self, file_name: String, content: String) { self.verifier_response .source diff --git a/eth-bytecode-db/eth-bytecode-db/Cargo.toml b/eth-bytecode-db/eth-bytecode-db/Cargo.toml index 9aa4038b3..47a970057 100644 --- a/eth-bytecode-db/eth-bytecode-db/Cargo.toml +++ b/eth-bytecode-db/eth-bytecode-db/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" entity = { path = "./entity" } verifier-alliance-entity = { path = "./verifier-alliance-entity" } +alloy-json-abi = { git = "https://github.com/alloy-rs/core", rev = "398d7e2", features = ["serde_json"] } anyhow = "1.0" blockscout-display-bytes = "1.0" bytes = "1.2" @@ -34,6 +35,7 @@ smart-contract-verifier-proto = { git = "https://github.com/blockscout/blockscou solidity-metadata = "1.0" thiserror = "1.0" tokio = "1.22" +tokio-stream = { version = "0.1" } tonic = { version = "0.8", features = ["tls-roots"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"]} diff --git a/eth-bytecode-db/eth-bytecode-db/entity/src/events.rs b/eth-bytecode-db/eth-bytecode-db/entity/src/events.rs new file mode 100644 index 000000000..118319ad8 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/entity/src/events.rs @@ -0,0 +1,22 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "events")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i64, + pub created_at: DateTime, + pub updated_at: DateTime, + #[sea_orm(column_type = "Binary(BlobSize::Blob(None))")] + pub selector: Vec, + pub name: String, + #[sea_orm(column_type = "JsonBinary")] + pub inputs: Json, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/eth-bytecode-db/eth-bytecode-db/entity/src/lib.rs b/eth-bytecode-db/eth-bytecode-db/entity/src/lib.rs index 25940d1f3..c21c667dc 100644 --- a/eth-bytecode-db/eth-bytecode-db/entity/src/lib.rs +++ b/eth-bytecode-db/eth-bytecode-db/entity/src/lib.rs @@ -4,6 +4,7 @@ pub mod prelude; pub mod bytecode_parts; pub mod bytecodes; +pub mod events; pub mod files; pub mod parts; pub mod sea_orm_active_enums; diff --git a/eth-bytecode-db/eth-bytecode-db/entity/src/prelude.rs b/eth-bytecode-db/eth-bytecode-db/entity/src/prelude.rs index da122b261..6fe296553 100644 --- a/eth-bytecode-db/eth-bytecode-db/entity/src/prelude.rs +++ b/eth-bytecode-db/eth-bytecode-db/entity/src/prelude.rs @@ -2,6 +2,7 @@ pub use super::{ bytecode_parts::Entity as BytecodeParts, bytecodes::Entity as Bytecodes, - files::Entity as Files, parts::Entity as Parts, source_files::Entity as SourceFiles, - sources::Entity as Sources, verified_contracts::Entity as VerifiedContracts, + events::Entity as Events, files::Entity as Files, parts::Entity as Parts, + source_files::Entity as SourceFiles, sources::Entity as Sources, + verified_contracts::Entity as VerifiedContracts, }; diff --git a/eth-bytecode-db/eth-bytecode-db/migration/src/lib.rs b/eth-bytecode-db/eth-bytecode-db/migration/src/lib.rs index 4e273ddb9..401cbf7f2 100644 --- a/eth-bytecode-db/eth-bytecode-db/migration/src/lib.rs +++ b/eth-bytecode-db/eth-bytecode-db/migration/src/lib.rs @@ -15,6 +15,7 @@ mod m20230509_132647_add_not_null_constraint_parts_data_text_column; mod m20230510_151046_add_search_speedup_indexes_on_parts; mod m20230531_191321_update_parts_data_text_prefix_index_to_150_chars; mod m20230911_103441_update_sources_add_verification_artifact_columns; +mod m20231210_129532_create_event_descriptions_table; pub struct Migrator; @@ -36,6 +37,7 @@ impl MigratorTrait for Migrator { Box::new(m20230510_151046_add_search_speedup_indexes_on_parts::Migration), Box::new(m20230531_191321_update_parts_data_text_prefix_index_to_150_chars::Migration), Box::new(m20230911_103441_update_sources_add_verification_artifact_columns::Migration), + Box::new(m20231210_129532_create_event_descriptions_table::Migration), ] } } diff --git a/eth-bytecode-db/eth-bytecode-db/migration/src/m20231210_129532_create_event_descriptions_table.rs b/eth-bytecode-db/eth-bytecode-db/migration/src/m20231210_129532_create_event_descriptions_table.rs new file mode 100644 index 000000000..2fb67f3c4 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/migration/src/m20231210_129532_create_event_descriptions_table.rs @@ -0,0 +1,32 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let sql = r#" + CREATE TABLE "events" ( + "id" BIGSERIAL PRIMARY KEY, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + "selector" bytea NOT NULL, + "name" varchar NOT NULL, + "inputs" jsonb NOT NULL + ); + + CREATE UNIQUE INDEX "unique_events_name_and_inputs_index" ON "events" ("name", md5("inputs"::text)); + + CREATE INDEX "events_selector_index" ON "events" ("selector"); + "#; + crate::from_sql(manager, sql).await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let sql = r#" + DROP TABLE "events"; + "#; + crate::from_sql(manager, sql).await + } +} diff --git a/eth-bytecode-db/eth-bytecode-db/src/search/events.rs b/eth-bytecode-db/eth-bytecode-db/src/search/events.rs new file mode 100644 index 000000000..17d64c633 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/src/search/events.rs @@ -0,0 +1,28 @@ +use anyhow::Context; +use entity::events; +use ethers_core::types::H256; +use futures::StreamExt; +use sea_orm::{ColumnTrait, ConnectionTrait, EntityTrait, QueryFilter, TransactionTrait}; + +pub type EventDescription = events::Model; + +pub async fn find_event_descriptions( + db: &C, + selectors: Vec, +) -> Vec, anyhow::Error>> +where + C: ConnectionTrait + TransactionTrait, +{ + tokio_stream::iter(selectors.into_iter().map(|selector| async move { + events::Entity::find() + .filter(events::Column::Selector.eq(selector.as_bytes().to_vec())) + .all(db) + .await + .context(format!( + "extracting events from the database for {selector:x}" + )) + })) + .buffered(20) + .collect() + .await +} diff --git a/eth-bytecode-db/eth-bytecode-db/src/search/mod.rs b/eth-bytecode-db/eth-bytecode-db/src/search/mod.rs index e0e09a558..6b4378398 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/search/mod.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/search/mod.rs @@ -1,11 +1,13 @@ mod any_match; mod bytecodes_comparison; mod candidates; +mod events; mod match_contract; mod matches; mod types; pub use any_match::find_contract; pub use entity::sea_orm_active_enums::BytecodeType; +pub use events::{find_event_descriptions, EventDescription}; pub use match_contract::MatchContract; pub use types::BytecodeRemote; diff --git a/eth-bytecode-db/eth-bytecode-db/src/verification/db/eth_bytecode_db.rs b/eth-bytecode-db/eth-bytecode-db/src/verification/db/eth_bytecode_db.rs index 4f0b69d9f..10a6bb546 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/verification/db/eth_bytecode_db.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/verification/db/eth_bytecode_db.rs @@ -5,7 +5,7 @@ use super::{ use crate::verification::VerificationMetadata; use anyhow::Context; use entity::{ - bytecode_parts, bytecodes, files, parts, sea_orm_active_enums, source_files, sources, + bytecode_parts, bytecodes, events, files, parts, sea_orm_active_enums, source_files, sources, verified_contracts, }; use sea_orm::{ @@ -99,6 +99,42 @@ pub(crate) async fn insert_verified_contract_data( Ok(()) } +pub(crate) async fn insert_event_descriptions( + db_client: &DatabaseConnection, + events: Vec, +) -> Result<(), anyhow::Error> { + let active_models: Vec<_> = events + .into_iter() + .filter_map(|event| { + let selector = event.selector(); + serde_json::to_value(event.inputs) + .map_err(|err| { + tracing::error!("{:x} event input serialization failed: {err}", selector) + }) + .ok() + .map(|inputs| events::ActiveModel { + selector: Set(selector.to_vec()), + name: Set(event.name), + inputs: Set(inputs), + ..Default::default() + }) + }) + .collect(); + + let result = events::Entity::insert_many(active_models) + .on_conflict(OnConflict::new().do_nothing().to_owned()) + .exec(db_client) + .await; + match result { + Ok(_) | Err(DbErr::RecordNotInserted) => {} + Err(err) => { + return Err(err).context("insert into \"events\""); + } + } + + Ok(()) +} + async fn insert_files( txn: &DatabaseTransaction, files: BTreeMap, diff --git a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs index 73c0de1d9..6291fea7b 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs @@ -18,7 +18,10 @@ use anyhow::Context; use sea_orm::DatabaseConnection; enum EthBytecodeDbAction<'a> { - IgnoreDb, + SaveOnlyAbiData { + db_client: &'a DatabaseConnection, + verification_metadata: Option, + }, SaveData { db_client: &'a DatabaseConnection, bytecode_type: BytecodeType, @@ -30,37 +33,56 @@ enum EthBytecodeDbAction<'a> { } impl<'a> EthBytecodeDbAction<'a> { - fn contract_address(&self) -> Option { - if let EthBytecodeDbAction::SaveData { - verification_metadata: - Some(VerificationMetadata { - contract_address: Some(contract_address), - .. - }), - .. - } = self - { - Some(blockscout_display_bytes::Bytes::from( - contract_address.to_vec(), - )) - } else { - None + fn db_client(&self) -> &'a DatabaseConnection { + match self { + EthBytecodeDbAction::SaveOnlyAbiData { db_client, .. } => db_client, + EthBytecodeDbAction::SaveData { db_client, .. } => db_client, } } + fn contract_address(&self) -> Option { + let contract_address = match self { + EthBytecodeDbAction::SaveOnlyAbiData { + verification_metadata: + Some(VerificationMetadata { + contract_address: Some(contract_address), + .. + }), + .. + } => Some(contract_address), + EthBytecodeDbAction::SaveData { + verification_metadata: + Some(VerificationMetadata { + contract_address: Some(contract_address), + .. + }), + .. + } => Some(contract_address), + _ => None, + }; + contract_address.map(|contract_address| { + blockscout_display_bytes::Bytes::from(contract_address.to_vec()) + }) + } fn chain_id(&self) -> Option { - if let EthBytecodeDbAction::SaveData { - verification_metadata: - Some(VerificationMetadata { - chain_id: Some(chain_id), - .. - }), - .. - } = self - { - Some(*chain_id) - } else { - None + match self { + EthBytecodeDbAction::SaveOnlyAbiData { + verification_metadata: + Some(VerificationMetadata { + chain_id: Some(chain_id), + .. + }), + .. + } => Some(*chain_id), + EthBytecodeDbAction::SaveData { + verification_metadata: + Some(VerificationMetadata { + chain_id: Some(chain_id), + .. + }), + .. + } => Some(*chain_id), + _ => None, } } } @@ -168,6 +190,9 @@ async fn process_verify_response( let alliance_db_action_contract_address = alliance_db_action.contract_address(); let alliance_db_action_chain_id = alliance_db_action.chain_id(); + let process_abi_data_future = + process_abi_data(source.abi.clone(), eth_bytecode_db_action.db_client()); + let process_eth_bytecode_db_future = process_eth_bytecode_db_action(source.clone(), eth_bytecode_db_action); @@ -175,8 +200,20 @@ async fn process_verify_response( process_verifier_alliance_db_action(source.clone(), alliance_db_action); // We may process insertion into both databases concurrently, as they are independent from one another. - let (process_eth_bytecode_db_result, process_alliance_db_result) = - futures::future::join(process_eth_bytecode_db_future, process_alliance_db_future).await; + let (process_abi_data_result, process_eth_bytecode_db_result, process_alliance_db_result) = + futures::future::join3( + process_abi_data_future, + process_eth_bytecode_db_future, + process_alliance_db_future, + ) + .await; + let _ = process_abi_data_result.map_err(|err: anyhow::Error| { + tracing::error!( + ?eth_bytecode_db_action_contract_address, + ?eth_bytecode_db_action_chain_id, + "Error while inserting abi data into database: {err:#}" + ) + }); let _ = process_eth_bytecode_db_result.map_err(|err: anyhow::Error| { tracing::error!( ?eth_bytecode_db_action_contract_address, @@ -223,7 +260,7 @@ async fn process_eth_bytecode_db_action( action: EthBytecodeDbAction<'_>, ) -> Result<(), anyhow::Error> { match action { - EthBytecodeDbAction::IgnoreDb => {} + EthBytecodeDbAction::SaveOnlyAbiData { .. } => {} EthBytecodeDbAction::SaveData { db_client, bytecode_type, @@ -327,3 +364,28 @@ async fn process_verifier_alliance_db_action( Ok(()) } + +async fn process_abi_data( + abi: Option, + db_client: &DatabaseConnection, +) -> Result<(), anyhow::Error> { + if abi.is_none() { + return Ok(()); + } + + // We use `alloy_json_abi::JsonAbi` and not `ethabi::Contract` because + // `ethabi::Contract` lose the notion of internal type during deserialization + let abi = alloy_json_abi::JsonAbi::from_json_str(&abi.unwrap()).context("Parse abi")?; + + let events = abi + .events + .into_values() + .flatten() + .filter(|event| !event.anonymous) + .collect(); + db::eth_bytecode_db::insert_event_descriptions(db_client, events) + .await + .context("Insert event descriptions into database")?; + + Ok(()) +} diff --git a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify.rs b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify.rs index eba37293a..a56fcb552 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify.rs @@ -1,12 +1,12 @@ use super::{ super::{ client::Client, errors::Error, smart_contract_verifier::VerifySourcifyRequest, - types::Source, + types::Source, VerificationMetadata, }, process_verify_response, EthBytecodeDbAction, VerifierAllianceDbAction, }; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, str::FromStr}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct VerificationRequest { @@ -27,7 +27,20 @@ impl From for VerifySourcifyRequest { } } +impl<'a> From<&'a VerificationRequest> for VerificationMetadata { + fn from(value: &'a VerificationRequest) -> Self { + Self { + chain_id: i64::from_str(&value.chain).ok(), + contract_address: blockscout_display_bytes::Bytes::from_str(&value.address) + .ok() + .map(|v| v.0), + ..Default::default() + } + } +} + pub async fn verify(mut client: Client, request: VerificationRequest) -> Result { + let verification_metadata = VerificationMetadata::from(&request); let request: VerifySourcifyRequest = request.into(); let response = client .sourcify_client @@ -38,7 +51,10 @@ pub async fn verify(mut client: Client, request: VerificationRequest) -> Result< process_verify_response( response, - EthBytecodeDbAction::IgnoreDb, + EthBytecodeDbAction::SaveOnlyAbiData { + db_client: client.db_client.as_ref(), + verification_metadata: Some(verification_metadata), + }, VerifierAllianceDbAction::IgnoreDb, ) .await diff --git a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify_from_etherscan.rs b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify_from_etherscan.rs index 575a52378..4cfdd4be7 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify_from_etherscan.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/sourcify_from_etherscan.rs @@ -1,11 +1,12 @@ use super::{ super::{ client::Client, errors::Error, smart_contract_verifier::VerifyFromEtherscanSourcifyRequest, - types::Source, + types::Source, VerificationMetadata, }, process_verify_response, EthBytecodeDbAction, VerifierAllianceDbAction, }; use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct VerificationRequest { @@ -22,7 +23,20 @@ impl From for VerifyFromEtherscanSourcifyRequest { } } +impl<'a> From<&'a VerificationRequest> for VerificationMetadata { + fn from(value: &'a VerificationRequest) -> Self { + Self { + chain_id: i64::from_str(&value.chain).ok(), + contract_address: blockscout_display_bytes::Bytes::from_str(&value.address) + .ok() + .map(|v| v.0), + ..Default::default() + } + } +} + pub async fn verify(mut client: Client, request: VerificationRequest) -> Result { + let verification_metadata = VerificationMetadata::from(&request); let request: VerifyFromEtherscanSourcifyRequest = request.into(); let response = client .sourcify_client @@ -33,7 +47,10 @@ pub async fn verify(mut client: Client, request: VerificationRequest) -> Result< process_verify_response( response, - EthBytecodeDbAction::IgnoreDb, + EthBytecodeDbAction::SaveOnlyAbiData { + db_client: client.db_client.as_ref(), + verification_metadata: Some(verification_metadata), + }, VerifierAllianceDbAction::IgnoreDb, ) .await diff --git a/eth-bytecode-db/eth-bytecode-db/tests/solidity_multi_part.rs b/eth-bytecode-db/eth-bytecode-db/tests/solidity_multi_part.rs index c09f020e6..45618f98c 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/solidity_multi_part.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/solidity_multi_part.rs @@ -141,3 +141,11 @@ async fn test_verification_of_updated_source_replace_the_old_result() { ) .await; } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/solidity_standard_json.rs b/eth-bytecode-db/eth-bytecode-db/tests/solidity_standard_json.rs index 0df1ecac0..5dbe011d4 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/solidity_standard_json.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/solidity_standard_json.rs @@ -135,3 +135,11 @@ async fn test_verification_of_updated_source_replace_the_old_result() { ) .await; } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/sourcify.rs b/eth-bytecode-db/eth-bytecode-db/tests/sourcify.rs index c2ea488fc..4238f51be 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/sourcify.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/sourcify.rs @@ -64,3 +64,11 @@ fn service() -> MockSourcifyVerifierService { async fn returns_valid_source(service: MockSourcifyVerifierService) { verification_test_helpers::test_returns_valid_source(DB_PREFIX, service).await } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/sourcify_from_etherscan.rs b/eth-bytecode-db/eth-bytecode-db/tests/sourcify_from_etherscan.rs index 35ff34782..5acd56180 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/sourcify_from_etherscan.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/sourcify_from_etherscan.rs @@ -62,3 +62,11 @@ fn service() -> MockSourcifyVerifierService { async fn returns_valid_source(service: MockSourcifyVerifierService) { verification_test_helpers::test_returns_valid_source(DB_PREFIX, service).await } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/mod.rs b/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/mod.rs index 782404eac..0f95959f8 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/mod.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/mod.rs @@ -9,7 +9,7 @@ use async_trait::async_trait; use blockscout_display_bytes::Bytes as DisplayBytes; use blockscout_service_launcher::test_database::TestDbGuard; use entity::{ - bytecode_parts, bytecodes, files, parts, sea_orm_active_enums, source_files, sources, + bytecode_parts, bytecodes, events, files, parts, sea_orm_active_enums, source_files, sources, verified_contracts, }; use eth_bytecode_db::verification::{ @@ -743,3 +743,127 @@ pub async fn test_verification_of_updated_source_replace_the_old_result( + db_prefix: &str, + service_generator: impl Fn() -> Service, +) where + Request: Clone, + Service: VerifierService, +{ + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + struct Event { + pub selector: Vec, + pub name: String, + pub inputs: String, + } + + impl From for Event { + fn from(value: events::Model) -> Self { + Self { + selector: value.selector, + name: value.name, + inputs: value.inputs.to_string(), + } + } + } + + let db = init_db(db_prefix, "test_verification_inserts_event_descriptions").await; + + let service = service_generator(); + let source_type = service.source_type(); + let input_data = test_input_data::input_data_1(service.generate_request(1, None), source_type); + + let mut expected_events = HashSet::new(); + { + let abi = r#"[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}],"name":"A","type":"event"},{"anonymous":true,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"middle","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Anonymous","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}],"name":"B","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"f","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]"#; + expected_events.insert(Event { + selector: blockscout_display_bytes::Bytes::from_str( + "0xa17a9e66f0c355e3aa3b9ea969991204d6b1d2e62a47877f612cb2371d79e06a", + ) + .unwrap() + .to_vec(), + name: "A".to_string(), + inputs: serde_json::Value::from_str( + r#"[{"indexed":true,"internalType":"uint256","name":"a","type":"uint256"}]"#, + ) + .unwrap() + .to_string(), + }); + expected_events.insert(Event { + selector: blockscout_display_bytes::Bytes::from_str("0xbcf5c814cb65249e306ec7aeaef6fc1ca35e1b8e18c08b054c9f9c76160bc923").unwrap().to_vec(), + name: "B".to_string(), + inputs: serde_json::Value::from_str(r#"[{"indexed":false,"internalType":"string","name":"a","type":"string"},{"indexed":true,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}]"#).unwrap().to_string(), + }); + + let input_data = input_data.clone().with_abi(abi.to_string()); + let client = start_server_and_init_client( + db.client().clone(), + service_generator(), + vec![input_data.clone()], + ) + .await; + let _source = Service::verify(client.clone(), input_data.eth_bytecode_db_request) + .await + .expect("Verification failed"); + + let db_events: HashSet<_> = events::Entity::find() + .all(db.client().as_ref()) + .await + .expect("Error while reading events") + .into_iter() + .map(Event::from) + .collect(); + + assert_eq!( + expected_events, db_events, + "Events after first submission do not match" + ); + } + + { + let abi = r#"[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":true,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"middle","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Anonymous","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"a","type":"string"},{"indexed":false,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}],"name":"B","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"c","type":"string"}],"name":"C","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"},{"inputs":[],"name":"f","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]"#; + expected_events.insert(Event { + selector: blockscout_display_bytes::Bytes::from_str("0xbcf5c814cb65249e306ec7aeaef6fc1ca35e1b8e18c08b054c9f9c76160bc923").unwrap().to_vec(), + name: "B".to_string(), + inputs: serde_json::Value::from_str(r#"[{"indexed":true,"internalType":"string","name":"a","type":"string"},{"indexed":false,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"c","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"d","type":"bytes"}]"#).unwrap().to_string(), + }); + expected_events.insert(Event { + selector: blockscout_display_bytes::Bytes::from_str( + "0x7076fab50c7b30ea53db9880b1c8ea59a80cdaf0341135a4c2ec691b8cdd4a9a", + ) + .unwrap() + .to_vec(), + name: "C".to_string(), + inputs: serde_json::Value::from_str( + r#"[{"indexed":false,"internalType":"string","name":"c","type":"string"}]"#, + ) + .unwrap() + .to_string(), + }); + + let input_data = input_data.clone().with_abi(abi.to_string()); + let client = start_server_and_init_client( + db.client().clone(), + service_generator(), + vec![input_data.clone()], + ) + .await; + let _source = Service::verify(client.clone(), input_data.eth_bytecode_db_request) + .await + .expect("Verification failed"); + + let db_events: HashSet<_> = events::Entity::find() + .all(db.client().as_ref()) + .await + .expect("Error while reading events") + .into_iter() + .map(Event::from) + .collect(); + + assert_eq!( + expected_events, db_events, + "Events after second submission do not match" + ); + } +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/test_input_data.rs b/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/test_input_data.rs index 82ffffd3f..5b5aa8a8c 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/test_input_data.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/verification_test_helpers/test_input_data.rs @@ -110,6 +110,16 @@ impl TestInputData { } } +impl TestInputData { + pub fn with_abi(mut self, abi: String) -> Self { + self.eth_bytecode_db_source.abi = Some(abi.clone()); + if let Some(source) = self.verifier_response.source.as_mut() { + source.abi = Some(abi) + } + self + } +} + pub fn input_data_1(request: T, source_type: SourceType) -> TestInputData { let verifier_source = smart_contract_verifier_v2::Source { file_name: "source_file1.sol".to_string(), diff --git a/eth-bytecode-db/eth-bytecode-db/tests/vyper_multi_part.rs b/eth-bytecode-db/eth-bytecode-db/tests/vyper_multi_part.rs index 28782d701..256e0bece 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/vyper_multi_part.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/vyper_multi_part.rs @@ -133,3 +133,11 @@ async fn test_verification_of_updated_source_replace_the_old_result() { ) .await; } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +} diff --git a/eth-bytecode-db/eth-bytecode-db/tests/vyper_standard_json.rs b/eth-bytecode-db/eth-bytecode-db/tests/vyper_standard_json.rs index de153e7c3..4aea6a24c 100644 --- a/eth-bytecode-db/eth-bytecode-db/tests/vyper_standard_json.rs +++ b/eth-bytecode-db/eth-bytecode-db/tests/vyper_standard_json.rs @@ -133,3 +133,11 @@ async fn test_verification_of_updated_source_replace_the_old_result() { ) .await; } + +#[rstest] +#[tokio::test] +#[ignore = "Needs database to run"] +async fn test_verification_inserts_event_descriptions() { + verification_test_helpers::test_verification_inserts_event_descriptions(DB_PREFIX, service) + .await; +}