diff --git a/Cargo.lock b/Cargo.lock index 502a94bc253e..b351a18ece36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "const-random", "getrandom 0.2.15", "once_cell", "version_check", @@ -500,7 +501,7 @@ dependencies = [ "alloy-primitives", "alloy-pubsub", "alloy-rpc-client 0.4.2", - "alloy-rpc-types-admin", + "alloy-rpc-types-admin 0.4.2", "alloy-rpc-types-engine 0.4.2", "alloy-rpc-types-eth 0.4.2", "alloy-transport 0.4.2", @@ -634,6 +635,18 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-rpc-types-admin" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fefd12e99dd6b7de387ed13ad047ce2c90d8950ca62fc48b8a457ebb8f936c61" +dependencies = [ + "alloy-genesis 0.3.6", + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-rpc-types-admin" version = "0.4.2" @@ -646,6 +659,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-rpc-types-anvil" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25cb45ad7c0930dd62eecf164d2afe4c3d2dd2c82af85680ad1f118e1e5cb83" +dependencies = [ + "alloy-primitives", + "alloy-serde 0.3.6", + "serde", +] + [[package]] name = "alloy-rpc-types-anvil" version = "0.4.2" @@ -657,6 +681,20 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-rpc-types-beacon" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7081d2206dca51ce23a06338d78d9b536931cc3f15134fc1c6535eb2b77f18" +dependencies = [ + "alloy-eips 0.3.6", + "alloy-primitives", + "alloy-rpc-types-engine 0.3.6", + "serde", + "serde_with", + "thiserror", +] + [[package]] name = "alloy-rpc-types-beacon" version = "0.4.2" @@ -693,8 +731,7 @@ dependencies = [ "alloy-rlp", "alloy-serde 0.3.6", "derive_more 1.0.0", - "jsonwebtoken", - "rand 0.8.5", + "jsonrpsee-types", "serde", ] @@ -734,6 +771,7 @@ dependencies = [ "derive_more 1.0.0", "hashbrown 0.14.5", "itertools 0.13.0", + "jsonrpsee-types", "serde", "serde_json", ] @@ -758,6 +796,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-rpc-types-mev" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922d92389e5022650c4c60ffd2f9b2467c3f853764f0f74ff16a23106f9017d5" +dependencies = [ + "alloy-eips 0.3.6", + "alloy-primitives", + "alloy-serde 0.3.6", + "serde", + "serde_json", +] + [[package]] name = "alloy-rpc-types-mev" version = "0.4.2" @@ -771,6 +822,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-rpc-types-trace" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98db35cd42c90b484377e6bc44d95377a7a38a5ebee996e67754ac0446d542ab" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth 0.3.6", + "alloy-serde 0.3.6", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "alloy-rpc-types-trace" version = "0.4.2" @@ -785,6 +850,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-rpc-types-txpool" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bac37082c3b21283b3faf5cc0e08974272aee2f756ce1adeb26db56a5fce0d5" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth 0.3.6", + "alloy-serde 0.3.6", + "serde", +] + [[package]] name = "alloy-rpc-types-txpool" version = "0.4.2" @@ -1146,10 +1223,42 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "antelope-client" +version = "0.2.1" +source = "git+https://github.com/telosnetwork/antelope-rs?branch=development#ed53c75b6b9ce14aa72002ddd491a6697ae563d9" +dependencies = [ + "antelope-client-macros", + "async-trait", + "base64 0.21.7", + "bs58", + "chrono", + "digest 0.10.7", + "ecdsa", + "flate2", + "hex", + "hmac 0.12.1", + "k256", + "log", + "once_cell", + "p256", + "rand 0.8.5", + "rand_core 0.6.4", + "reqwest 0.11.27", + "ripemd", + "serde", + "serde-big-array", + "serde_json", + "sha2 0.10.8", + "signature", + "thiserror", + "tokio", +] + [[package]] name = "antelope-client" version = "0.3.0" -source = "git+https://github.com/telosnetwork/antelope-rs?rev=d701cd9ca2e87e8e0fd99746f9c672cb3536e5ec#d701cd9ca2e87e8e0fd99746f9c672cb3536e5ec" +source = "git+https://github.com/telosnetwork/antelope-rs?branch=master#fea2203b2edb5cfcedd5365031e5286b47dc5c66" dependencies = [ "antelope-client-macros", "async-trait", @@ -1354,6 +1463,248 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "arrow" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219d05930b81663fd3b32e3bde8ce5bff3c4d23052a99f11a8fa50a3b47b2658" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0272150200c07a86a390be651abdd320a2d12e84535f0837566ca87ecd8f95e0" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + +[[package]] +name = "arrow-array" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8010572cf8c745e242d1b632bd97bd6d4f40fefed5ed1290a8f433abaa686fea" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.14.5", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0a2432f0cba5692bf4cb757469c66791394bac9ec7ce63c1afe74744c37b27" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9abc10cd7995e83505cc290df9384d6e5412b207b79ce6bdff89a10505ed2cba" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cbcba196b862270bf2a5edb75927380a7f3a163622c61d40cbba416a6305f2" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2742ac1f6650696ab08c88f6dd3f0eb68ce10f8c253958a18c943a68cd04aec5" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a42ea853130f7e78b9b9d178cb4cd01dee0f78e64d96c2949dc0a915d6d9e19d" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", +] + +[[package]] +name = "arrow-json" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaafb5714d4e59feae964714d724f880511500e3569cc2a94d02456b403a2a49" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap 2.6.0", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e6b61e3dc468f503181dccc2fc705bdcc5f2f146755fa5b56d0a6c5943f412" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848ee52bb92eb459b811fb471175ea3afcf620157674c8794f539838920f9228" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", + "hashbrown 0.14.5", +] + +[[package]] +name = "arrow-schema" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d9483aaabe910c4781153ae1b6ae0393f72d9ef757d38d09d450070cf2e528" + +[[package]] +name = "arrow-select" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "849524fa70e0e3c5ab58394c770cb8f514d0122d20de08475f7b472ed8075830" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "51.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9373cb5a021aee58863498c37eb484998ef13377f69989c6c5ccfbd258236cdb" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax 0.8.5", +] + +[[package]] +name = "arrowbatch" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e304bae8e33446c64842dba444042ce65cb23e2b1e439fa2f4abb7591db562c5" +dependencies = [ + "arrow", + "base64 0.22.1", + "chrono", + "env_logger 0.10.2", + "futures", + "futures-util", + "hex", + "log", + "moka", + "num", + "num-bigint", + "rlp", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite 0.21.0", + "tungstenite 0.21.0", + "uuid", + "zstd", +] + [[package]] name = "asn1_der" version = "0.7.6" @@ -1451,6 +1802,15 @@ dependencies = [ "rustc_version 0.4.1", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -2318,6 +2678,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "tiny-keccak", +] + [[package]] name = "const_format" version = "0.2.33" @@ -3112,6 +3492,19 @@ dependencies = [ "regex", ] +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.11.5" @@ -3152,7 +3545,7 @@ name = "example-beacon-api-sidecar-fetcher" version = "0.1.0" dependencies = [ "alloy-primitives", - "alloy-rpc-types-beacon", + "alloy-rpc-types-beacon 0.4.2", "clap", "eyre", "futures-util", @@ -3168,7 +3561,7 @@ dependencies = [ name = "example-beacon-api-sse" version = "0.0.0" dependencies = [ - "alloy-rpc-types-beacon", + "alloy-rpc-types-beacon 0.4.2", "clap", "futures-util", "mev-share-sse", @@ -3444,7 +3837,7 @@ name = "example-txpool-tracing" version = "0.0.0" dependencies = [ "alloy-primitives", - "alloy-rpc-types-trace", + "alloy-rpc-types-trace 0.4.2", "clap", "futures-util", "reth", @@ -3555,6 +3948,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flatbuffers" +version = "23.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" +dependencies = [ + "bitflags 1.3.2", + "rustc_version 0.4.1", +] + [[package]] name = "flate2" version = "1.0.34" @@ -3915,6 +4318,7 @@ checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", + "num-traits", ] [[package]] @@ -5091,6 +5495,70 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.159" @@ -5104,7 +5572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -5897,6 +6365,20 @@ dependencies = [ "spin", ] +[[package]] +name = "op-alloy-genesis" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1b8a9b70da0e027242ec1762f0f3a386278b6291d00d12ff5a64929dc19f68" +dependencies = [ + "alloy-consensus 0.3.6", + "alloy-eips 0.3.6", + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_repr", +] + [[package]] name = "op-alloy-genesis" version = "0.3.3" @@ -5925,6 +6407,23 @@ dependencies = [ "op-alloy-rpc-types 0.3.3", ] +[[package]] +name = "op-alloy-protocol" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf300a82ae2d30e2255bfea87a2259da49f63a25a44db561ae64cc9e3084139f" +dependencies = [ + "alloy-consensus 0.3.6", + "alloy-eips 0.3.6", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.3.6", + "hashbrown 0.14.5", + "op-alloy-consensus 0.2.12", + "op-alloy-genesis 0.2.12", + "serde", +] + [[package]] name = "op-alloy-protocol" version = "0.3.3" @@ -5938,7 +6437,7 @@ dependencies = [ "alloy-serde 0.4.2", "derive_more 1.0.0", "op-alloy-consensus 0.3.3", - "op-alloy-genesis", + "op-alloy-genesis 0.3.3", "serde", ] @@ -5977,6 +6476,23 @@ dependencies = [ "serde_json", ] +[[package]] +name = "op-alloy-rpc-types-engine" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2947272a81ebf988f4804b6f0f6a7c0b2f6f89a908cb410e36f8f3828f81c778" +dependencies = [ + "alloy-eips 0.3.6", + "alloy-primitives", + "alloy-rpc-types-engine 0.3.6", + "alloy-serde 0.3.6", + "derive_more 1.0.0", + "op-alloy-consensus 0.2.12", + "op-alloy-genesis 0.2.12", + "op-alloy-protocol 0.2.12", + "serde", +] + [[package]] name = "op-alloy-rpc-types-engine" version = "0.3.3" @@ -5987,7 +6503,7 @@ dependencies = [ "alloy-rpc-types-engine 0.4.2", "alloy-serde 0.4.2", "derive_more 1.0.0", - "op-alloy-protocol", + "op-alloy-protocol 0.3.3", "serde", ] @@ -7838,7 +8354,7 @@ dependencies = [ "futures-util", "jsonrpsee", "jsonrpsee-types", - "op-alloy-rpc-types-engine", + "op-alloy-rpc-types-engine 0.3.3", "reth", "reth-chainspec", "reth-db", @@ -8272,6 +8788,7 @@ dependencies = [ "revm-primitives", "secp256k1", "serde_json", + "sha2 0.10.8", ] [[package]] @@ -8590,7 +9107,7 @@ name = "reth-network-api" version = "1.0.8" dependencies = [ "alloy-primitives", - "alloy-rpc-types-admin", + "alloy-rpc-types-admin 0.4.2", "auto_impl", "derive_more 1.0.0", "enr", @@ -8898,7 +9415,7 @@ dependencies = [ name = "reth-node-telos" version = "1.0.8" dependencies = [ - "alloy-consensus 0.3.6", + "alloy-consensus 0.4.2", "alloy-contract", "alloy-network 0.4.2", "alloy-primitives", @@ -8908,18 +9425,18 @@ dependencies = [ "alloy-signer-local", "alloy-sol-types", "alloy-transport-http 0.4.2", - "antelope-client", + "antelope-client 0.3.0", "clap", "derive_more 1.0.0", - "env_logger", + "env_logger 0.11.5", "eyre", - "num-bigint", "reqwest 0.12.8", "reth", "reth-auto-seal-consensus", "reth-basic-payload-builder", "reth-beacon-consensus", "reth-chainspec", + "reth-db", "reth-e2e-test-utils", "reth-ethereum-engine-primitives", "reth-ethereum-payload-builder", @@ -8935,6 +9452,7 @@ dependencies = [ "reth-rpc", "reth-stages", "reth-telos-rpc", + "reth-telos-rpc-engine-api 1.0.8", "reth-tracing", "reth-transaction-pool", "serde", @@ -9083,7 +9601,7 @@ dependencies = [ "jsonrpsee", "jsonrpsee-types", "op-alloy-consensus 0.3.3", - "op-alloy-rpc-types-engine", + "op-alloy-rpc-types-engine 0.3.3", "parking_lot 0.12.3", "reqwest 0.12.8", "reth", @@ -9130,7 +9648,7 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine 0.4.2", - "op-alloy-rpc-types-engine", + "op-alloy-rpc-types-engine 0.3.3", "reth-basic-payload-builder", "reth-chain-state", "reth-chainspec", @@ -9242,7 +9760,7 @@ dependencies = [ "alloy-primitives", "alloy-rpc-types 0.4.2", "async-trait", - "op-alloy-rpc-types-engine", + "op-alloy-rpc-types-engine 0.3.3", "pin-project", "reth-chain-state", "reth-chainspec", @@ -9524,12 +10042,12 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "alloy-rpc-types 0.4.2", - "alloy-rpc-types-admin", + "alloy-rpc-types-admin 0.4.2", "alloy-rpc-types-debug", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-mev", - "alloy-rpc-types-trace", - "alloy-rpc-types-txpool", + "alloy-rpc-types-mev 0.4.2", + "alloy-rpc-types-trace 0.4.2", + "alloy-rpc-types-txpool 0.4.2", "alloy-serde 0.4.2", "alloy-signer 0.4.2", "alloy-signer-local", @@ -9589,15 +10107,15 @@ dependencies = [ "alloy-json-rpc 0.4.2", "alloy-primitives", "alloy-rpc-types 0.4.2", - "alloy-rpc-types-admin", - "alloy-rpc-types-anvil", - "alloy-rpc-types-beacon", + "alloy-rpc-types-admin 0.4.2", + "alloy-rpc-types-anvil 0.4.2", + "alloy-rpc-types-beacon 0.4.2", "alloy-rpc-types-debug", "alloy-rpc-types-engine 0.4.2", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-mev", - "alloy-rpc-types-trace", - "alloy-rpc-types-txpool", + "alloy-rpc-types-mev 0.4.2", + "alloy-rpc-types-trace 0.4.2", + "alloy-rpc-types-txpool 0.4.2", "alloy-serde 0.4.2", "jsonrpsee", "reth-engine-primitives", @@ -9615,7 +10133,7 @@ dependencies = [ "alloy-primitives", "alloy-rpc-types 0.4.2", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-trace", + "alloy-rpc-types-trace 0.4.2", "futures", "jsonrpsee", "jsonrpsee-http-client", @@ -9636,7 +10154,7 @@ dependencies = [ "alloy-rpc-types 0.4.2", "alloy-rpc-types-engine 0.4.2", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-trace", + "alloy-rpc-types-trace 0.4.2", "alloy-serde 0.4.2", "clap", "http 1.1.0", @@ -9727,7 +10245,7 @@ dependencies = [ "alloy-primitives", "alloy-rpc-types 0.4.2", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-mev", + "alloy-rpc-types-mev 0.4.2", "async-trait", "auto_impl", "dyn-clone", @@ -9830,6 +10348,26 @@ dependencies = [ "strum", ] +[[package]] +name = "reth-rpc-types" +version = "1.0.6" +source = "git+https://github.com/telosnetwork/telos-reth?branch=telos-main#63d23e00982a0ab7704a6dff97b3f5d355e11d56" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types 0.3.6", + "alloy-rpc-types-admin 0.3.6", + "alloy-rpc-types-anvil 0.3.6", + "alloy-rpc-types-beacon 0.3.6", + "alloy-rpc-types-engine 0.3.6", + "alloy-rpc-types-mev 0.3.6", + "alloy-rpc-types-trace 0.3.6", + "alloy-rpc-types-txpool 0.3.6", + "alloy-serde 0.3.6", + "jsonrpsee-types", + "op-alloy-rpc-types 0.2.12", + "op-alloy-rpc-types-engine 0.2.12", +] + [[package]] name = "reth-rpc-types-compat" version = "1.0.8" @@ -10054,6 +10592,7 @@ dependencies = [ "alloy-eips 0.4.2", "alloy-primitives", "alloy-rlp", + "alloy-rpc-types 0.4.2", "alloy-serde 0.4.2", "arbitrary", "bytes", @@ -10071,13 +10610,12 @@ dependencies = [ "alloy-network 0.4.2", "alloy-primitives", "alloy-rpc-types 0.4.2", - "antelope-client", + "antelope-client 0.3.0", "async-trait", "derive_more 1.0.0", "jsonrpsee-types", "log", "parking_lot 0.12.3", - "regex", "reth-chainspec", "reth-evm", "reth-network-api", @@ -10118,6 +10656,7 @@ dependencies = [ "revm", "revm-primitives", "serde", + "sha2 0.10.8", "tracing", ] @@ -10342,7 +10881,7 @@ dependencies = [ [[package]] name = "revm" version = "14.0.3" -source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c" +source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256" dependencies = [ "auto_impl", "cfg-if", @@ -10360,7 +10899,7 @@ source = "git+https://github.com/telosnetwork/telos-evm-inspectors?branch=telos- dependencies = [ "alloy-primitives", "alloy-rpc-types-eth 0.4.2", - "alloy-rpc-types-trace", + "alloy-rpc-types-trace 0.4.2", "alloy-sol-types", "anstyle", "boa_engine", @@ -10374,7 +10913,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "10.0.3" -source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c" +source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256" dependencies = [ "revm-primitives", "serde", @@ -10383,7 +10922,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "11.0.3" -source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c" +source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256" dependencies = [ "aurora-engine-modexp", "blst", @@ -10402,7 +10941,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "10.0.0" -source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c" +source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -11539,14 +12078,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "telos-consensus-client" version = "0.1.0" -source = "git+https://github.com/telosnetwork/telos-consensus-client?rev=9fadee1fd565e3a7ad51c1142e2673df52bd9028#9fadee1fd565e3a7ad51c1142e2673df52bd9028" +source = "git+https://github.com/telosnetwork/telos-consensus-client?rev=f8ecbe1aeea57911c9fbefdddf49efa92d8472ce#f8ecbe1aeea57911c9fbefdddf49efa92d8472ce" dependencies = [ "alloy", "alloy-consensus 0.3.6", "alloy-rlp", - "alloy-rpc-types 0.3.6", - "alloy-rpc-types-engine 0.3.6", - "antelope-client", + "antelope-client 0.2.1", + "arrowbatch", "base64 0.22.1", "bytes", "chrono", @@ -11559,6 +12097,7 @@ dependencies = [ "rand 0.8.5", "reqwest 0.11.27", "reth-primitives 1.0.6", + "reth-rpc-types", "rocksdb", "serde", "serde_json", @@ -11576,10 +12115,12 @@ dependencies = [ name = "telos-reth" version = "1.0.8" dependencies = [ + "alloy-primitives", "clap", "reth", "reth-chainspec", "reth-cli-util", + "reth-db", "reth-node-builder", "reth-node-telos", "reth-provider", @@ -11590,14 +12131,13 @@ dependencies = [ [[package]] name = "telos-translator-rs" version = "0.1.0" -source = "git+https://github.com/telosnetwork/telos-consensus-client?rev=9fadee1fd565e3a7ad51c1142e2673df52bd9028#9fadee1fd565e3a7ad51c1142e2673df52bd9028" +source = "git+https://github.com/telosnetwork/telos-consensus-client?rev=f8ecbe1aeea57911c9fbefdddf49efa92d8472ce#f8ecbe1aeea57911c9fbefdddf49efa92d8472ce" dependencies = [ "alloy", "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-rlp", - "alloy-rpc-types-engine 0.3.6", - "antelope-client", + "antelope-client 0.2.1", "bytes", "clap", "dashmap 5.5.3", @@ -11609,6 +12149,7 @@ dependencies = [ "moka", "num-bigint", "reth-primitives 1.0.6", + "reth-rpc-types", "reth-telos-rpc-engine-api 1.0.6", "reth-trie-common 1.0.6", "rlp", @@ -11635,6 +12176,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "termtree" version = "0.4.1" @@ -11968,6 +12518,18 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.21.0", +] + [[package]] name = "tokio-tungstenite" version = "0.23.1" @@ -12332,6 +12894,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.23.0" @@ -12737,7 +13318,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 413a3e75411c..7a7989f8e05d 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -20,6 +20,7 @@ reth-revm.workspace = true reth-ethereum-consensus.workspace = true reth-prune-types.workspace = true reth-execution-types.workspace = true +sha2.workspace = true # Ethereum revm-primitives.workspace = true diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 188ca0e21f25..b14a93fc572f 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -38,6 +38,8 @@ use reth_telos_rpc_engine_api::compare::compare_state_diffs; use revm_primitives::{Address, Account, AccountInfo, AccountStatus, Bytecode, HashMap, KECCAK_EMPTY}; #[cfg(feature = "telos")] use alloy_primitives::B256; +#[cfg(feature = "telos")] +use sha2::{Sha256, Digest}; /// Provides executors to execute regular ethereum blocks #[derive(Debug, Clone)] @@ -192,6 +194,7 @@ where // execute transactions let mut cumulative_gas_used = 0; + #[cfg(not(feature = "telos"))] let mut receipts = Vec::with_capacity(block.body.transactions.len()); for (sender, transaction) in block.transactions_with_sender() { #[cfg(feature = "telos")] @@ -233,6 +236,7 @@ where // append gas used cumulative_gas_used += result.gas_used(); + #[cfg(not(feature = "telos"))] // Push transaction changeset and calculate header bloom filter for receipt. receipts.push( #[allow(clippy::needless_update)] // side-effect of optimism fields @@ -259,23 +263,32 @@ where new_addresses_using_create_iter.next(); } - #[cfg(feature = "telos")] { - // Perform state diff comparision - let revm_state_diffs = evm.db_mut().transition_state.clone().unwrap_or_default().transitions; - let block_num = block.block.header.number; - println!( - "Compare: block {block_num} {}", - compare_state_diffs( - &mut evm, - revm_state_diffs, - unwrapped_telos_extra_fields.statediffs_account.unwrap_or_default(), - unwrapped_telos_extra_fields.statediffs_accountstate.unwrap_or_default(), - unwrapped_telos_extra_fields.new_addresses_using_create.unwrap_or_default(), - unwrapped_telos_extra_fields.new_addresses_using_openwallet.unwrap_or_default() - ) - ); + // #[cfg(feature = "telos")] + { + // Perform state diff comparision + let revm_state_diffs = evm.db_mut().transition_state.clone().unwrap_or_default().transitions; + let block_num = block.block.header.number; + println!( + "Compare: block {block_num} {}", + compare_state_diffs( + &mut evm, + revm_state_diffs, + unwrapped_telos_extra_fields.statediffs_account.clone().unwrap_or_default(), + unwrapped_telos_extra_fields.statediffs_accountstate.clone().unwrap_or_default(), + unwrapped_telos_extra_fields.new_addresses_using_create.clone().unwrap_or_default(), + unwrapped_telos_extra_fields.new_addresses_using_openwallet.clone().unwrap_or_default(), + false + ) + ); } + #[cfg(feature = "telos")] + let receipts = if unwrapped_telos_extra_fields.receipts.is_some() { + unwrapped_telos_extra_fields.receipts.clone().unwrap() + } else { + vec![] + }; + let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) { // Collect all EIP-6110 deposits let deposit_requests = @@ -288,7 +301,44 @@ where vec![] }; - Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used }) + // #[cfg(feature = "telos")] + // { + // let mut addr_to_accstate: HashMap> = HashMap::new(); + + // for sdiff_accstate in unwrapped_telos_extra_fields.clone().statediffs_accountstate.unwrap_or(vec![]) { + // if !addr_to_accstate.contains_key(&sdiff_accstate.address) { + // addr_to_accstate.insert(sdiff_accstate.address, HashMap::new()); + // } + // let mut acc_storage = addr_to_accstate.get_mut(&sdiff_accstate.address).unwrap(); + // acc_storage.insert(sdiff_accstate.key, EvmStorageSlot { original_value: Default::default(), present_value: sdiff_accstate.value, is_cold: false }); + // } + + // let mut state: HashMap = HashMap::new(); + + // for sdiff_acc in unwrapped_telos_extra_fields.clone().statediffs_account.unwrap_or(vec![]) { + // state.insert( + // sdiff_acc.address, + // Account { + // info: AccountInfo { + // balance: sdiff_acc.balance, + // nonce: sdiff_acc.nonce, + // code_hash: B256::from(Sha256::digest(sdiff_acc.code.as_ref()).as_ref()), + // code: Some(Bytecode::LegacyRaw(sdiff_acc.code)), + // }, + // storage: addr_to_accstate.get(&sdiff_acc.address).unwrap_or(&HashMap::new()).clone(), + // status: AccountStatus::Touched | AccountStatus::LoadedAsNotExisting, + // } + // ); + // } + + // evm.db_mut().commit(state); + // } + + Ok(EthExecuteOutput { + receipts, + requests, + gas_used: cumulative_gas_used + }) } } @@ -366,7 +416,12 @@ where let env = self.evm_env_for_block(&block.header, total_difficulty); let output = { let evm = self.executor.evm_config.evm_with_env(&mut self.state, env); - self.executor.execute_state_transitions(block, evm, #[cfg(feature = "telos")] telos_extra_fields) + self.executor.execute_state_transitions( + block, + evm, + #[cfg(feature = "telos")] + telos_extra_fields + ) }?; // 3. apply post execution changes diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 20edf96d810d..fcad61a6f62a 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -425,6 +425,11 @@ where number: BlockNumberOrTag, full: bool, ) -> RpcResult>> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber"); Ok(EthBlocks::rpc_block(self, number.into(), full).await?) } @@ -440,6 +445,11 @@ where &self, number: BlockNumberOrTag, ) -> RpcResult> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber"); Ok(EthBlocks::block_transaction_count(self, number.into()).await?.map(U256::from)) } @@ -455,6 +465,11 @@ where &self, number: BlockNumberOrTag, ) -> RpcResult> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber"); Ok(EthBlocks::ommers(self, number.into())?.map(|ommers| U256::from(ommers.len()))) } @@ -464,6 +479,11 @@ where &self, block_id: BlockId, ) -> RpcResult>>> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts"); Ok(EthBlocks::block_receipts(self, block_id).await?) } @@ -484,6 +504,11 @@ where number: BlockNumberOrTag, index: Index, ) -> RpcResult>> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex"); Ok(EthBlocks::ommer_by_block_and_index(self, number.into(), index).await?) } @@ -533,6 +558,11 @@ where number: BlockNumberOrTag, index: Index, ) -> RpcResult> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex"); Ok(EthTransactions::raw_transaction_by_block_and_tx_index( self, @@ -548,6 +578,11 @@ where number: BlockNumberOrTag, index: Index, ) -> RpcResult>> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex"); Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index.into()) .await?) @@ -575,6 +610,11 @@ where /// Handler for: `eth_getBalance` async fn balance(&self, address: Address, block_number: Option) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); Ok(EthState::balance(self, address, block_number).await?) } @@ -586,6 +626,11 @@ where index: JsonStorageKey, block_number: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); Ok(EthState::storage_at(self, address, index, block_number).await?) } @@ -596,18 +641,33 @@ where address: Address, block_number: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); Ok(EthState::transaction_count(self, address, block_number).await?) } /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_number: Option) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); Ok(EthState::get_code(self, address, block_number).await?) } /// Handler for: `eth_getHeaderByNumber` async fn header_by_number(&self, block_number: BlockNumberOrTag) -> RpcResult> { + #[cfg(feature = "telos")] + let block_number: BlockNumberOrTag = match block_number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => block_number, + }; trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?) } @@ -624,6 +684,11 @@ where payload: SimulatePayload, block_number: Option, ) -> RpcResult>>> { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?block_number, "Serving eth_simulateV1"); Ok(EthCall::simulate_v1(self, payload, block_number).await?) } @@ -636,6 +701,11 @@ where state_overrides: Option, block_overrides: Option>, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call"); Ok(EthCall::call( self, @@ -663,6 +733,11 @@ where request: TransactionRequest, block_number: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList"); Ok(EthCall::create_access_list_at(self, request, block_number).await?) } @@ -674,6 +749,11 @@ where block_number: Option, state_override: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas"); Ok(EthCall::estimate_gas_at( self, @@ -696,6 +776,11 @@ where address: Address, block: BlockId, ) -> RpcResult> { + #[cfg(feature = "telos")] + let block = match block { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block, + }; trace!(target: "rpc::eth", "Serving eth_getAccount"); Ok(EthState::get_account(self, address, block).await?) } @@ -727,6 +812,11 @@ where newest_block: BlockNumberOrTag, reward_percentiles: Option>, ) -> RpcResult { + #[cfg(feature = "telos")] + let newest_block = match newest_block { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => newest_block, + }; trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory"); Ok(EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?) } @@ -797,6 +887,11 @@ where keys: Vec, block_number: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); Ok(EthState::get_proof(self, address, keys, block_number)?.await?) } diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 5474d020a00f..ac5f70cf2b48 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -879,6 +879,11 @@ where { /// Handler for `debug_getRawHeader` async fn raw_header(&self, block_id: BlockId) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let header = match block_id { BlockId::Hash(hash) => self.inner.provider.header(&hash.into()).to_rpc_result()?, BlockId::Number(number_or_tag) => { @@ -902,6 +907,11 @@ where /// Handler for `debug_getRawBlock` async fn raw_block(&self, block_id: BlockId) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let block = self .inner .provider @@ -925,6 +935,11 @@ where /// Handler for `debug_getRawTransactions` /// Returns the bytes of the transaction for the given hash. async fn raw_transactions(&self, block_id: BlockId) -> RpcResult> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let block = self .inner .provider @@ -936,6 +951,11 @@ where /// Handler for `debug_getRawReceipts` async fn raw_receipts(&self, block_id: BlockId) -> RpcResult> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; Ok(self .inner .provider @@ -991,6 +1011,11 @@ where block: BlockNumberOrTag, opts: Option, ) -> RpcResult> { + #[cfg(feature = "telos")] + let block = match block { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => block, + }; let _permit = self.acquire_trace_permit().await; Self::debug_trace_block(self, block.into(), opts.unwrap_or_default()) .await @@ -1015,6 +1040,11 @@ where block: BlockNumberOrTag, include_preimages: bool, ) -> RpcResult { + #[cfg(feature = "telos")] + let block = match block { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => block, + }; let _permit = self.acquire_trace_permit().await; Self::debug_execution_witness(self, block, include_preimages).await.map_err(Into::into) } @@ -1026,6 +1056,11 @@ where block_id: Option, opts: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default()) .await diff --git a/crates/rpc/rpc/src/engine.rs b/crates/rpc/rpc/src/engine.rs index 928e2050a5c2..c2eb13cd594e 100644 --- a/crates/rpc/rpc/src/engine.rs +++ b/crates/rpc/rpc/src/engine.rs @@ -73,6 +73,11 @@ where state_overrides: Option, block_overrides: Option>, ) -> Result { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; self.eth .call(request, block_id, state_overrides, block_overrides) .instrument(engine_span!()) @@ -81,6 +86,11 @@ where /// Handler for: `eth_getCode` async fn get_code(&self, address: Address, block_id: Option) -> Result { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; self.eth.get_code(address, block_id).instrument(engine_span!()).await } @@ -99,6 +109,11 @@ where number: BlockNumberOrTag, full: bool, ) -> Result>> { + #[cfg(feature = "telos")] + let number = match number { + BlockNumberOrTag::Pending => BlockNumberOrTag::Latest, + _ => number, + }; self.eth.block_by_number(number, full).instrument(engine_span!()).await } @@ -119,6 +134,11 @@ where keys: Vec, block_number: Option, ) -> Result { + #[cfg(feature = "telos")] + let block_number = match block_number { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_number, + }; self.eth.get_proof(address, keys, block_number).instrument(engine_span!()).await } } diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 31db343a104f..d5d5fe4189b8 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -78,6 +78,11 @@ where /// Handler for `ots_hasCode` async fn has_code(&self, address: Address, block_id: Option) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; EthApiServer::get_code(&self.eth, address, block_id).await.map(|code| !code.is_empty()) } diff --git a/crates/rpc/rpc/src/reth.rs b/crates/rpc/rpc/src/reth.rs index 6d5897df1315..f98ddbe60836 100644 --- a/crates/rpc/rpc/src/reth.rs +++ b/crates/rpc/rpc/src/reth.rs @@ -5,6 +5,8 @@ use async_trait::async_trait; use jsonrpsee::core::RpcResult; use reth_errors::RethResult; use reth_primitives::BlockId; +#[cfg(feature = "telos")] +use reth_primitives::BlockNumberOrTag; use reth_provider::{BlockReaderIdExt, ChangeSetReader, StateProviderFactory}; use reth_rpc_api::RethApiServer; use reth_rpc_eth_types::{EthApiError, EthResult}; @@ -95,6 +97,11 @@ where &self, block_id: BlockId, ) -> RpcResult> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; Ok(Self::balance_changes_in_block(self, block_id).await?) } } diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 925ea0872862..1e9211e1929e 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -20,6 +20,8 @@ use reth_consensus_common::calc::{ }; use reth_evm::ConfigureEvmEnv; use reth_primitives::{BlockId, Header}; +#[cfg(feature = "telos")] +use reth_primitives::BlockNumberOrTag; use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::TraceApiServer; @@ -592,6 +594,11 @@ where state_overrides: Option, block_overrides: Option>, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; let request = TraceCallRequest { call, trace_types, block_id, state_overrides, block_overrides }; @@ -604,6 +611,11 @@ where calls: Vec<(TransactionRequest, HashSet)>, block_id: Option, ) -> RpcResult> { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Ok(Self::trace_call_many(self, calls, block_id).await.map_err(Into::into)?) } @@ -615,6 +627,11 @@ where trace_types: HashSet, block_id: Option, ) -> RpcResult { + #[cfg(feature = "telos")] + let block_id = match block_id { + Some(BlockId::Number(BlockNumberOrTag::Pending)) => Some(BlockId::Number(BlockNumberOrTag::Latest)), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Ok(Self::trace_raw_transaction(self, data, trace_types, block_id) .await @@ -627,6 +644,11 @@ where block_id: BlockId, trace_types: HashSet, ) -> RpcResult>> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Ok(Self::replay_block_transactions(self, block_id, trace_types) .await @@ -648,6 +670,11 @@ where &self, block_id: BlockId, ) -> RpcResult>> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Ok(Self::trace_block(self, block_id).await.map_err(Into::into)?) } @@ -695,6 +722,11 @@ where /// Handler for `trace_blockOpcodeGas` async fn trace_block_opcode_gas(&self, block_id: BlockId) -> RpcResult> { + #[cfg(feature = "telos")] + let block_id = match block_id { + BlockId::Number(BlockNumberOrTag::Pending) => BlockId::Number(BlockNumberOrTag::Latest), + _ => block_id, + }; let _permit = self.acquire_trace_permit().await; Ok(Self::trace_block_opcode_gas(self, block_id).await.map_err(Into::into)?) } diff --git a/crates/telos/bin/Cargo.toml b/crates/telos/bin/Cargo.toml index 462451dfb839..1669f380b311 100644 --- a/crates/telos/bin/Cargo.toml +++ b/crates/telos/bin/Cargo.toml @@ -16,6 +16,8 @@ reth-chainspec.workspace = true reth-provider.workspace = true reth-node-telos.workspace = true reth-telos-rpc.workspace = true +reth-db.workspace = true +alloy-primitives.workspace = true clap = { workspace = true, features = ["derive", "env"] } diff --git a/crates/telos/bin/src/main.rs b/crates/telos/bin/src/main.rs index 6e73d37e15bb..7f660ee0ee31 100644 --- a/crates/telos/bin/src/main.rs +++ b/crates/telos/bin/src/main.rs @@ -4,6 +4,7 @@ static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator(); use clap::Parser; +use tracing::{error, info, warn}; use reth::args::utils::EthereumChainSpecParser; use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher}; use reth::cli::Cli; @@ -11,10 +12,16 @@ use reth_node_telos::{TelosArgs, TelosNode}; use reth_node_telos::node::TelosAddOns; use reth_provider::providers::BlockchainProvider2; use reth_telos_rpc::TelosClient; +use reth::primitives::BlockId; +use reth::rpc::types::BlockNumberOrTag; +use reth_provider::{DatabaseProviderFactory, StateProviderFactory}; +use reth_db::{PlainAccountState, PlainStorageState}; #[cfg(feature = "telos")] fn main() { + use reth_provider::BlockNumReader; + reth_cli_util::sigsegv_handler::install(); // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. @@ -45,6 +52,10 @@ fn main() { handle.node_exit_future.await }, false => { + let two_way_storage_compare = telos_args.two_way_storage_compare.clone(); + let telos_rpc = telos_args.telos_endpoint.clone(); + let block_delta = telos_args.block_delta.clone(); + let handle = builder .node(TelosNode::new(telos_args.clone())) .extend_rpc_modules(move |ctx| { @@ -59,6 +70,36 @@ fn main() { .launch() .await?; + match two_way_storage_compare { + true => { + if telos_rpc.is_none() { + warn!("Telos RPC Endpoint is not specified, skipping two-way storage compare"); + } else if block_delta.is_none() { + warn!("Block delta is not specified, skipping two-way storage compare"); + } else { + info!("Fetching account and accountstate from Telos native RPC (Can take a long time)..."); + + let (account_table, accountstate_table, block_number) = reth_node_telos::two_way_storage_compare::get_telos_tables(telos_rpc.unwrap().as_str(), block_delta.unwrap()).await; + + if block_number.as_u64().unwrap() <= handle.node.provider.best_block_number().unwrap() { + info!("Two-way comparing state (Reth vs. Telos) at height: {:?}", block_number); + + let state_at_specific_height = handle.node.provider.state_by_block_id(BlockId::Number(BlockNumberOrTag::Number(block_number.as_u64().unwrap()))).unwrap(); + let plain_account_state = handle.node.provider.database_provider_ro().unwrap().table::().unwrap(); + let plain_storage_state = handle.node.provider.database_provider_ro().unwrap().table::().unwrap(); + + let match_counter = reth_node_telos::two_way_storage_compare::two_side_state_compare(account_table, accountstate_table, state_at_specific_height, plain_account_state, plain_storage_state).await; + match_counter.print(); + + info!("Comparing done"); + } else { + error!("Nodeos is ahead of reth, failed to compare state"); + } + } + } + _ => {} + } + handle.node_exit_future.await } } diff --git a/crates/telos/node/Cargo.toml b/crates/telos/node/Cargo.toml index b86cfe4183dd..d9a3f52d2a33 100644 --- a/crates/telos/node/Cargo.toml +++ b/crates/telos/node/Cargo.toml @@ -34,6 +34,9 @@ reth-stages.workspace = true reth-telos-rpc.workspace = true reth-tracing.workspace = true reth-transaction-pool.workspace = true +reth-telos-rpc-engine-api.workspace = true +alloy-primitives.workspace = true +reth-db.workspace = true clap.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/crates/telos/node/src/args.rs b/crates/telos/node/src/args.rs index f65912512ca2..8c66a55b837d 100644 --- a/crates/telos/node/src/args.rs +++ b/crates/telos/node/src/args.rs @@ -45,6 +45,14 @@ pub struct TelosArgs { /// a batch of downloaded blocks. #[arg(long = "engine.max-execute-block-batch-size", requires = "experimental", default_value_t = DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE)] pub max_execute_block_batch_size: usize, + + /// Enable Two-way storage compare between reth and telos + #[arg(long = "telos.two_way_storage_compare", default_value = "false")] + pub two_way_storage_compare: bool, + + /// Block delta between native and EVM + #[arg(long = "telos.block_delta")] + pub block_delta: Option, } impl From for TelosClientArgs { diff --git a/crates/telos/node/src/lib.rs b/crates/telos/node/src/lib.rs index 962a444aa9c1..3f432da1b519 100644 --- a/crates/telos/node/src/lib.rs +++ b/crates/telos/node/src/lib.rs @@ -11,6 +11,7 @@ pub mod args; pub mod node; +pub mod two_way_storage_compare; pub use crate::args::TelosArgs; pub use crate::node::TelosNode; diff --git a/crates/telos/node/src/two_way_storage_compare.rs b/crates/telos/node/src/two_way_storage_compare.rs new file mode 100644 index 000000000000..e39c03d63f6d --- /dev/null +++ b/crates/telos/node/src/two_way_storage_compare.rs @@ -0,0 +1,367 @@ +//! Two-way storage compare between Reth and Telos + +use antelope::serializer::{Decoder, Encoder, Packer}; +use antelope::chain::name::Name; +use std::collections::HashMap; +use alloy_primitives::{Address, B256, U256}; +use antelope::api::client::{APIClient, DefaultProvider}; +use antelope::api::v1::structs::{GetTableRowsParams, TableIndexType}; +use antelope::{name, StructPacker}; +use antelope::chain::checksum::{Checksum160, Checksum256}; +use serde::{Deserialize, Serialize}; +use tracing::{error, info}; +use reth::primitives::{Account, BlockId}; +use reth_db::common::KeyValue; +use reth::providers::StateProviderBox; +use reth_db::{PlainAccountState, PlainStorageState}; + +#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)] +struct AccountRow { + index: u64, + address: Checksum160, + account: Name, + nonce: u64, + code: Vec, + balance: Checksum256, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)] +struct AccountStateRow { + index: u64, + key: Checksum256, + value: Checksum256, +} + +/// This struct holds matching statistics +#[derive(Debug, Clone, Default)] +pub struct MatchCounter { + total_telos_accounts: u64, + total_telos_storages: u64, + mismatched_telos_accounts: u64, + mismatched_telos_storages: u64, + total_reth_accounts: u64, + total_reth_storages: u64, + mismatched_reth_accounts: u64, + mismatched_reth_storages: u64, +} +impl MatchCounter { + /// Creates a new match counter for two-way storage compare + pub fn new() -> Self { + Self { + total_telos_accounts: 0, + total_telos_storages: 0, + mismatched_telos_accounts: 0, + mismatched_telos_storages: 0, + total_reth_accounts: 0, + total_reth_storages: 0, + mismatched_reth_accounts: 0, + mismatched_reth_storages: 0, + } + } + + /// Prints the match counter + pub fn print(&self) { + info!("Comparing results:"); + info!("Total telos accounts: {}", self.total_telos_accounts); + info!("Total telos storages: {}", self.total_telos_storages); + info!("Mismatched telos accounts: {}", self.mismatched_telos_accounts); + info!("Mismatched telos storages: {}", self.mismatched_telos_storages); + info!("Total reth accounts: {}", self.total_reth_accounts); + info!("Total reth storages: {}", self.total_reth_storages); + info!("Mismatched reth accounts: {}", self.mismatched_reth_accounts); + info!("Mismatched reth storages: {}", self.mismatched_reth_storages); + info!("Matching result: {}",self.matches()); + } + + fn add_telos_total_account(&mut self) { + self.total_telos_accounts += 1; + } + + fn add_telos_total_storage(&mut self) { + self.total_telos_storages += 1; + } + + fn add_telos_mismatched_account(&mut self) { + self.mismatched_telos_accounts += 1; + } + + fn add_telos_mismatched_storage(&mut self) { + self.mismatched_telos_storages += 1; + } + + fn add_reth_total_account(&mut self) { + self.total_reth_accounts += 1; + } + + fn add_reth_total_storage(&mut self) { + self.total_reth_storages += 1; + } + + fn add_reth_mismatched_account(&mut self) { + self.mismatched_reth_accounts += 1; + } + + fn add_reth_mismatched_storage(&mut self) { + self.mismatched_reth_storages += 1; + } + + /// Check whether both sides matches + pub fn matches(&self) -> bool { + self.mismatched_telos_accounts == 0 + && self.mismatched_telos_storages == 0 + && self.mismatched_reth_accounts == 0 + && self.mismatched_reth_storages == 0 + } +} + +/// This function compares reth and telos state against each other at specific height +pub async fn two_side_state_compare( + account_table: HashMap, + accountstate_table: HashMap<(Address, B256), U256>, + state_at_specific_height: StateProviderBox, + plain_account_state: Vec>, + plain_storage_state: Vec>, +) -> MatchCounter { + + let mut match_counter = MatchCounter::new(); + + for (address, telos_account) in &account_table { + let account_at_specific_height = state_at_specific_height.basic_account(*address); + match account_at_specific_height { + Ok(reth_account) => { + match reth_account { + Some(reth_account) => { + if reth_account.balance != telos_account.balance || reth_account.nonce != telos_account.nonce { + match_counter.add_telos_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account); + error!("Reth side: {:?}", reth_account); + } + }, + None => { + if telos_account.balance != U256::ZERO || telos_account.nonce != 0 { + match_counter.add_telos_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account); + error!("Reth side: None"); + } + }, + } + }, + Err(_) => { + match_counter.add_telos_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account); + error!("Reth side: None"); + }, + } + match_counter.add_telos_total_account(); + } + + for ((address, key), telos_value) in &accountstate_table { + let storage_at_specific_height = state_at_specific_height.storage(*address, *key); + match storage_at_specific_height { + Ok(storage) => { + match storage { + Some(reth_value) => { + if reth_value != *telos_value { + match_counter.add_telos_mismatched_storage(); + error!("Difference in accountstate: {:?}, key: {:?}", address, key); + error!("Telos side: {:?}", telos_value); + error!("Reth side: {:?}", reth_value); + } + }, + None => { + match_counter.add_telos_mismatched_storage(); + error!("Difference in accountstate: {:?}, key: {:?}", address, key); + error!("Telos side: {:?}", telos_value); + error!("Reth side: None"); + }, + } + }, + Err(_) => { + match_counter.add_telos_mismatched_storage(); + error!("Difference in accountstate: {:?}, key: {:?}", address, key); + error!("Telos side: {:?}", telos_value); + error!("Reth side: None"); + }, + } + match_counter.add_telos_total_storage(); + } + + + for (address, _) in plain_account_state.iter() { + let account_at_specific_height = state_at_specific_height.basic_account(*address); + let telos_account = account_table.get(address); + match account_at_specific_height { + Ok(account) => { + match account { + Some(reth_account) => { + if telos_account.is_none() { + match_counter.add_reth_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: None"); + error!("Reth side: {:?}", reth_account); + } else { + let telos_account_unwrapped = telos_account.unwrap(); + if reth_account.balance != telos_account_unwrapped.balance || reth_account.nonce != telos_account_unwrapped.nonce { + match_counter.add_reth_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account); + error!("Reth side: {:?}", reth_account); + } + } + + }, + None => { + if telos_account.is_some() { + match_counter.add_reth_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account.unwrap()); + error!("Reth side: None"); + } + }, + } + }, + Err(_) => { + if telos_account.is_some() { + match_counter.add_reth_mismatched_account(); + error!("Difference in account: {:?}", address); + error!("Telos side: {:?}", telos_account.unwrap()); + error!("Reth side: None"); + } + }, + } + match_counter.add_reth_total_account(); + } + + for (address,storage_entry) in plain_storage_state.iter() { + let storage_at_specific_height = state_at_specific_height.storage(*address, storage_entry.key); + let telos_accountstate = accountstate_table.get(&(*address, storage_entry.key)); + match storage_at_specific_height { + Ok(storage) => { + match storage { + Some(reth_value) => { + if telos_accountstate.is_none() { + if reth_value != U256::ZERO { + match_counter.add_reth_mismatched_storage(); + error!("Difference in accountstate: {:?}", address); + error!("Telos side: None"); + error!("Reth side: {:?}", reth_value); + } + } else { + let telos_value = *telos_accountstate.unwrap(); + if reth_value != telos_value { + match_counter.add_reth_mismatched_storage(); + error!("Difference in accountstate: {:?}", address); + error!("Telos side: {:?}", telos_value); + error!("Reth side: {:?}", reth_value); + } + } + }, + None => { + if telos_accountstate.is_some() { + match_counter.add_reth_mismatched_storage(); + error!("Difference in accountstate: {:?}", address); + error!("Telos side: {:?}", telos_accountstate.unwrap()); + error!("Reth side: None"); + } + }, + } + }, + Err(_) => { + if telos_accountstate.is_some() { + match_counter.add_reth_mismatched_storage(); + error!("Difference in accountstate: {:?}", address); + error!("Telos side: {:?}", telos_accountstate.unwrap()); + error!("Reth side: None"); + } + }, + } + match_counter.add_reth_total_storage(); + } + + match_counter +} + +/// This function retrieves account and accountstate tables from native RPC +pub async fn get_telos_tables(telos_rpc: &str, block_delta: u32) -> (HashMap, HashMap<(Address, B256), U256>, BlockId) { + + let api_client = APIClient::::default_provider(telos_rpc.into(), Some(5)).unwrap(); + let info_start = api_client.v1_chain.get_info().await.unwrap(); + + let evm_block_num_start = info_start.head_block_num - block_delta; + + let mut has_more_account = true; + let mut lower_bound_account = Some(TableIndexType::UINT64(0)); + + let evm_block_id = BlockId::from(evm_block_num_start as u64); + + let mut account_table = HashMap::default(); + let mut accountstate_table = HashMap::default(); + + while has_more_account { + let query_params_account = GetTableRowsParams { + code: name!("eosio.evm"), + table: name!("account"), + scope: None, + lower_bound: lower_bound_account, + upper_bound: None, + limit: Some(5000), + reverse: None, + index_position: None, + show_payer: None, + }; + let account_rows = api_client.v1_chain.get_table_rows::(query_params_account).await; + if let Ok(account_rows) = account_rows { + lower_bound_account = account_rows.next_key; + has_more_account = lower_bound_account.is_some(); + for account_row in account_rows.rows { + let address = Address::from_slice(account_row.address.data.as_slice()); + lower_bound_account = Some(TableIndexType::UINT64(account_row.index + 1)); + account_table.insert(address,Account { + nonce: account_row.nonce, + balance: U256::from_be_bytes(account_row.balance.data), + bytecode_hash: None, + }); + let mut has_more_accountstate = true; + let mut lower_bound_accountstate = Some(TableIndexType::UINT64(0)); + while has_more_accountstate { + let query_params_accountstate = GetTableRowsParams { + code: name!("eosio.evm"), + table: name!("accountstate"), + scope: Some(Name::from_u64(account_row.index)), + lower_bound: lower_bound_accountstate, + upper_bound: None, + limit: Some(5000), + reverse: None, + index_position: None, + show_payer: None, + }; + let accountstate_rows = api_client.v1_chain.get_table_rows::(query_params_accountstate).await; + if let Ok(accountstate_rows) = accountstate_rows { + lower_bound_accountstate = accountstate_rows.next_key; + has_more_accountstate = lower_bound_accountstate.is_some(); + for accountstate_row in accountstate_rows.rows { + lower_bound_accountstate = Some(TableIndexType::UINT64(accountstate_row.index + 1)); + accountstate_table.insert((address,B256::from(accountstate_row.key.data)),U256::from_be_bytes(accountstate_row.value.data)); + } + } else { + panic!("Failed to fetch accountstate row"); + } + } + } + } else { + panic!("Failed to fetch account row"); + } + } + + let info_end = api_client.v1_chain.get_info().await.unwrap(); + let evm_block_num_end = info_end.head_block_num - block_delta; + + if evm_block_num_start != evm_block_num_end { + panic!("Nodeos is syncing, it is impossible to get an accurate state from a syncing native RPC"); + } + + (account_table, accountstate_table, evm_block_id) +} \ No newline at end of file diff --git a/crates/telos/node/tests/integration.rs b/crates/telos/node/tests/integration.rs index 0ad846523a07..ac77b3f51558 100644 --- a/crates/telos/node/tests/integration.rs +++ b/crates/telos/node/tests/integration.rs @@ -169,6 +169,8 @@ async fn testing_chain_sync() { persistence_threshold: 0, memory_block_buffer_target: 1, max_execute_block_batch_size: 100, + two_way_storage_compare: false, + block_delta: None, }; let node_handle = NodeBuilder::new(node_config.clone()) diff --git a/crates/telos/node/tests/main.rs b/crates/telos/node/tests/main.rs index c5818b75ca1a..545e604d2459 100644 --- a/crates/telos/node/tests/main.rs +++ b/crates/telos/node/tests/main.rs @@ -1,4 +1,5 @@ -mod integration; -pub mod live_test_runner; +// mod integration; +// pub mod live_test_runner; +pub mod storage_compare; const fn main() {} diff --git a/crates/telos/node/tests/state_bypass.rs b/crates/telos/node/tests/state_bypass.rs new file mode 100644 index 000000000000..88bfc9fd0d03 --- /dev/null +++ b/crates/telos/node/tests/state_bypass.rs @@ -0,0 +1,456 @@ +use std::{fmt, fs}; +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; +use std::str::FromStr; +use std::sync::Arc; +use alloy_provider::{Provider, ProviderBuilder}; +use reqwest::Url; +use serde_json::json; +use telos_consensus_client::execution_api_client::{ExecutionApiClient, RpcRequest}; +use telos_consensus_client::execution_api_client::ExecutionApiMethod::{ForkChoiceUpdatedV1, NewPayloadV1}; +use tracing::info; +use reth::args::RpcServerArgs; +use reth::builder::NodeConfig; +use alloy_primitives::{Address, B256, hex, U256, Bytes, map::HashMap}; +use alloy_primitives::hex::FromHex; +use alloy_rpc_types::engine::ExecutionPayloadV1; +use reth::primitives::revm_primitives::{Bytecode as RevmBytecode, LegacyAnalyzedBytecode}; +use reth::providers::ProviderError; +use reth::revm; +use reth::revm::db::{CacheDB, EmptyDBTyped, StorageWithOriginalValues, states::StorageSlot}; +use reth::revm::{Database, DatabaseCommit, DatabaseRef, Evm, State, TransitionAccount}; +use reth::revm::primitives::{AccountInfo, EvmStorageSlot}; +use reth::rpc::types::engine::ForkchoiceState; +use reth::tasks::TaskManager; +use reth_chainspec::{ChainSpec, ChainSpecBuilder, TEVMTESTNET}; +use reth_e2e_test_utils::node::NodeTestContext; +use reth_node_builder::NodeBuilder; +use reth_node_telos::{TelosArgs, TelosNode}; +use reth_primitives::constants::{EMPTY_ROOT_HASH, MIN_PROTOCOL_BASE_FEE}; +use reth_primitives::revm_primitives::AccountStatus; +use reth_telos_rpc::TelosClient; +use reth_telos_rpc_engine_api::compare::compare_state_diffs; +use reth_telos_rpc_engine_api::structs::{TelosAccountTableRow, TelosAccountStateTableRow, TelosEngineAPIExtraFields}; +use revm::primitives::Account; + +#[derive(Debug)] +enum MockDBError { + GenericError(String) +} + +impl Into for MockDBError { + fn into(self) -> ProviderError { + match self { + MockDBError::GenericError(msg) => { + ProviderError::NippyJar(msg) + } + } + } +} + +impl Display for MockDBError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + MockDBError::GenericError(msg) => { + f.write_str(&msg) + } + } + } +} + +fn init_reth() -> eyre::Result<(NodeConfig, String)> { + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(TEVMTESTNET.chain) + .genesis(TEVMTESTNET.genesis.clone()) + .frontier_activated() + .homestead_activated() + .tangerine_whistle_activated() + .spurious_dragon_activated() + .byzantium_activated() + .constantinople_activated() + .petersburg_activated() + .istanbul_activated() + .berlin_activated() + .build(), + ); + + let mut rpc_config = RpcServerArgs::default().with_unused_ports().with_http(); + rpc_config.auth_jwtsecret = Some(PathBuf::from("tests/assets/jwt.hex")); + + // Node setup + let node_config = NodeConfig::test().with_chain(chain_spec).with_rpc(rpc_config.clone()); + + let jwt = fs::read_to_string(node_config.rpc.auth_jwtsecret.clone().unwrap())?; + Ok((node_config, jwt)) +} + +#[tokio::test] +async fn test_integration_tevm_only() { + tracing_subscriber::fmt::init(); + + let (node_config, jwt_secret) = init_reth().unwrap(); + + let exec = TaskManager::current(); + let exec = exec.executor(); + + reth_tracing::init_test_tracing(); + + let telos_args = TelosArgs { + telos_endpoint: None, + signer_account: Some("rpc.evm".to_string()), + signer_permission: Some("active".to_string()), + signer_key: Some("5Jr65kdYmn33C3UabzhmWDm2PuqbRfPuDStts3ZFNSBLM7TqaiL".to_string()), + gas_cache_seconds: None, + experimental: false, + persistence_threshold: 0, + memory_block_buffer_target: 0, + max_execute_block_batch_size: 0, + }; + + let node_handle = NodeBuilder::new(node_config.clone()) + .testing_node(exec) + .node(TelosNode::new(telos_args.clone())) + .extend_rpc_modules(move |ctx| { + if telos_args.telos_endpoint.is_some() { + ctx.registry.eth_api().set_telos_client(TelosClient::new(telos_args.into())); + } + + Ok(()) + }) + .launch() + .await + .unwrap(); + + let execution_port = node_handle.node.auth_server_handle().local_addr().port(); + let rpc_port = node_handle.node.rpc_server_handles.rpc.http_local_addr().unwrap().port(); + println!("Starting Reth on RPC port {}!", rpc_port); + let _ = NodeTestContext::new(node_handle.node.clone()).await.unwrap(); + + let custom_balance = U256::from(80085); + + let exec_client = ExecutionApiClient::new(&format!("http://127.0.0.1:{}", execution_port), &jwt_secret).unwrap(); + + let execution_payload = ExecutionPayloadV1 { + parent_hash: B256::from_hex("b25034033c9ca7a40e879ddcc29cf69071a22df06688b5fe8cc2d68b4e0528f9").unwrap(), + fee_recipient: Default::default(), + state_root: EMPTY_ROOT_HASH, + receipts_root: EMPTY_ROOT_HASH, + logs_bloom: Default::default(), + prev_randao: Default::default(), + block_number: 1, + gas_limit: 0x7fffffff, + gas_used: 0, + timestamp: 1728067687, + extra_data: Default::default(), + base_fee_per_gas: U256::try_from(MIN_PROTOCOL_BASE_FEE).unwrap(), + block_hash: B256::from_hex("0a1d73423169c8b4124121d40c0e13eb078621e73effd2d183f9a1d8017537dd").unwrap(), + transactions: vec![], + }; + + let test_addr = Address::from_hex("00000000000000000000000000000000deadbeef").unwrap(); + + let extra_fields = TelosEngineAPIExtraFields { + statediffs_account: Some(vec![TelosAccountTableRow { + removed: false, + address: test_addr, + account: "eosio".to_string(), + nonce: 0, + code: Default::default(), + balance: custom_balance, + }]), + statediffs_accountstate: Some(vec![]), + revision_changes: None, + gasprice_changes: None, + new_addresses_using_create: Some(vec![]), + new_addresses_using_openwallet: Some(vec![]), + receipts: Some(vec![]), + }; + + let block_req = RpcRequest { + method: NewPayloadV1, + params: vec![ + json![execution_payload], + json![extra_fields] + ].into() + }; + + let new_block_result = exec_client.rpc(block_req).await.unwrap(); + + info!("new_block: {:#?}", new_block_result); + + let fork_choice_result = exec_client.rpc(RpcRequest { + method: ForkChoiceUpdatedV1, + params: json![vec![ForkchoiceState { + head_block_hash: execution_payload.block_hash, + safe_block_hash: execution_payload.block_hash, + finalized_block_hash: execution_payload.block_hash + }]] + }).await.unwrap(); + + info!("fork_choice: {:#?}", fork_choice_result); + + + let provider = ProviderBuilder::new() + //.network::() + .on_http(Url::from_str(format!("http://localhost:{}", rpc_port).as_str()).unwrap()); + + let balance = provider.get_balance(test_addr).await.unwrap(); + info!("balance: {:#?}", balance); + + assert_eq!(balance, custom_balance); +} + +#[test] +fn test_db_both_sides_present_but_dif() { + let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); + + let init_balance = U256::from(0); + let custom_balance = U256::from(80085); + + let init_nonce = 0; + let custom_nonce = 69; + + let revm_acc_info = AccountInfo { + balance: init_balance, + nonce: init_nonce, + code_hash: Default::default(), + code: None, + }; + + let mut db = CacheDB::new(EmptyDBTyped::::new()); + db.insert_account_info(test_addr, revm_acc_info); + + let mut state = State::builder().with_database(db).build(); + + let mut evm = Evm::builder().with_db(&mut state).build(); + + let statediffs_account = vec![TelosAccountTableRow { + removed: false, + address: test_addr, + account: "eosio".to_string(), + nonce: custom_nonce, + code: Default::default(), + balance: custom_balance, + }]; + + compare_state_diffs( + &mut evm, + HashMap::default(), + statediffs_account.clone(), + vec![], + vec![], + vec![], + false + ); + + let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap(); + assert_eq!(db_acc.nonce, statediffs_account[0].nonce); + assert_eq!(db_acc.balance, statediffs_account[0].balance); +} + +#[test] +fn test_db_both_sides_only_code() { + let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); + + let custom_code = Bytes::from(&hex!("ffff")); + let custom_bytecode = RevmBytecode::LegacyRaw(custom_code.clone()); + + let revm_acc_info = AccountInfo { + balance: U256::from(0), + nonce: 0, + code_hash: Default::default(), + code: None, + }; + + let mut db = CacheDB::new(EmptyDBTyped::::new()); + db.insert_account_info(test_addr, revm_acc_info); + + let mut state = State::builder().with_database(db).build(); + + let mut evm = Evm::builder().with_db(&mut state).build(); + + let statediffs_account = vec![TelosAccountTableRow { + removed: false, + address: test_addr, + account: "eosio".to_string(), + nonce: 0, + code: custom_code.clone(), + balance: U256::from(0), + }]; + + compare_state_diffs( + &mut evm, + HashMap::default(), + statediffs_account.clone(), + vec![], + vec![], + vec![], + false + ); + + let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap(); + assert_eq!(db_acc.code, Some(custom_bytecode)); +} + +#[test] +fn test_revm_state_both_sides_present_but_dif() { + let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); + + let revm_acc_info = AccountInfo { + balance: U256::from(1), + nonce: 0, + code_hash: Default::default(), + code: None, + }; + + let mut revm_state_diffs = HashMap::default(); + + let mut transition_account = TransitionAccount::new_empty_eip161(HashMap::default()); + + transition_account.info = Some(revm_acc_info); + + revm_state_diffs.insert(test_addr, transition_account); + + let mut db = CacheDB::new(EmptyDBTyped::::new()); + + let mut state = State::builder().with_database(db).build(); + + let mut evm = Evm::builder().with_db(&mut state).build(); + + let statediffs_account = vec![TelosAccountTableRow { + removed: false, + address: test_addr, + account: "eosio".to_string(), + nonce: 1, + code: Default::default(), + balance: U256::from(80085), + }]; + + compare_state_diffs( + &mut evm, + revm_state_diffs, + statediffs_account.clone(), + vec![], + vec![], + vec![], + false + ); + + let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap(); + assert_eq!(db_acc.nonce, statediffs_account[0].nonce); + assert_eq!(db_acc.balance, statediffs_account[0].balance); +} + +#[test] +fn test_tevm_only() { + let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); + + let mut db = CacheDB::new(EmptyDBTyped::::new()); + + let mut state = State::builder().with_database(db).build(); + + let mut evm = Evm::builder().with_db(&mut state).build(); + + let statediffs_account = vec![TelosAccountTableRow { + removed: false, + address: test_addr, + account: "eosio".to_string(), + nonce: 1, + code: Default::default(), + balance: U256::from(80085), + }]; + + compare_state_diffs( + &mut evm, + HashMap::default(), + statediffs_account.clone(), + vec![], + vec![], + vec![], + false + ); + + let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap(); + assert_eq!(db_acc.nonce, statediffs_account[0].nonce); + assert_eq!(db_acc.balance, statediffs_account[0].balance); +} + +#[test] +fn test_accstate_diff_from_storage() { + let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); + + let revm_acc_info = AccountInfo { + balance: U256::from(1), + nonce: 0, + code_hash: Default::default(), + code: None, + }; + + let key = U256::from(420); + let value = U256::from(0); + let custom_value = U256::from(80085); + + let mut db = CacheDB::new(EmptyDBTyped::::new()); + + let mut storage = HashMap::default(); + storage.insert(key, value); + + let mut state = State::builder().with_database(db).build(); + + state.insert_account_with_storage(test_addr, revm_acc_info, storage); + + let mut evm = Evm::builder().with_db(&mut state).build(); + + let statediffs_accountstate = vec![TelosAccountStateTableRow { + removed: false, + address: test_addr, + key, + value: custom_value + }]; + + compare_state_diffs( + &mut evm, + HashMap::default(), + vec![], + statediffs_accountstate.clone(), + vec![], + vec![], + false + ); + + let db_value = evm.db_mut().storage(test_addr, key).unwrap(); + assert_eq!(db_value, custom_value); +} +// #[test] +// fn test_accstate_telos_only() { +// let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap(); +// +// let key = U256::from(420); +// let custom_value = U256::from(80085); +// +// let mut db = CacheDB::new(EmptyDBTyped::::new()); +// +// let mut state = State::builder().with_database(db).build(); +// +// // state.insert_not_existing(test_addr); +// +// let mut evm = Evm::builder().with_db(&mut state).build(); +// +// let statediffs_accountstate = vec![TelosAccountStateTableRow { +// removed: false, +// address: test_addr, +// key, +// value: custom_value +// }]; +// +// compare_state_diffs( +// &mut evm, +// HashMap::default(), +// vec![], +// statediffs_accountstate.clone(), +// vec![], +// vec![], +// true +// ); +// } diff --git a/crates/telos/node/tests/storage_compare.rs b/crates/telos/node/tests/storage_compare.rs new file mode 100644 index 000000000000..2fc40cf1cd7b --- /dev/null +++ b/crates/telos/node/tests/storage_compare.rs @@ -0,0 +1,224 @@ +use std::str::FromStr; +use alloy_primitives::{Address, StorageValue, U256}; +use alloy_provider::{Provider, ProviderBuilder, ReqwestProvider}; +use alloy_rpc_types::BlockId; +use antelope::api::client::{APIClient, DefaultProvider}; +use antelope::api::v1::structs::{GetTableRowsParams, TableIndexType}; +use antelope::chain::name::Name; +use antelope::{name, StructPacker}; +use antelope::chain::{Encoder, Decoder, Packer}; +use antelope::chain::checksum::{Checksum160, Checksum256}; +use reqwest::Url; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)] +pub struct AccountRow { + pub index: u64, + pub address: Checksum160, + pub account: Name, + pub nonce: u64, + pub code: Vec, + pub balance: Checksum256, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)] +pub struct AccountStateRow { + pub index: u64, + pub key: Checksum256, + pub value: Checksum256, +} + +#[derive(Debug)] +struct MatchCounter { + evm_block_number: BlockId, + total_accounts: u64, + total_storage_rows: u64, + mismatched_accounts: u64, + mismatched_storage_rows: u64, +} + +impl MatchCounter { + pub fn new(evm_block_number: BlockId) -> Self { + Self { + evm_block_number, + total_accounts: 0, + total_storage_rows: 0, + mismatched_accounts: 0, + mismatched_storage_rows: 0, + } + } + + pub fn print(&self) { + println!("Compared at block: {:?}", self.evm_block_number); + println!("Mismatched accounts: {}", self.mismatched_accounts); + println!("Mismatched storage rows: {}", self.mismatched_storage_rows); + println!("Matching accounts: {}", self.total_accounts - self.mismatched_accounts); + println!("Matching storage rows: {}", self.total_storage_rows - self.mismatched_storage_rows); + println!("Total accounts: {}", self.total_accounts); + println!("Total storage rows: {}", self.total_storage_rows); + } + + pub fn add_matching_account(&mut self) { + self.total_accounts += 1; + } + + pub fn add_matching_account_storage(&mut self) { + self.total_storage_rows += 1; + } + + pub fn add_mismatched_account(&mut self) { + self.total_accounts += 1; + self.mismatched_accounts += 1; + } + + pub fn add_mismatched_account_storage(&mut self) { + self.total_storage_rows += 1; + self.mismatched_storage_rows += 1; + } + + pub fn matches(&self) -> bool { + self.mismatched_accounts == 0 && self.mismatched_storage_rows == 0 + } + +} + +#[tokio::test] +pub async fn compare() { + // let evm_rpc = "http://38.91.106.49:9545"; + let evm_rpc = "http://localhost:8545"; + // let telos_rpc = "http://192.168.0.20:8884"; + let telos_rpc = "http://38.91.106.49:8899"; + let block_delta = 57; + + assert!(storage_matches(evm_rpc, telos_rpc, block_delta).await); +} + +pub async fn storage_matches(evm_rpc: &str, telos_rpc: &str, block_delta: u32) -> bool { + let api_client = APIClient::::default_provider(telos_rpc.into(), Some(5)).unwrap(); + let info = api_client.v1_chain.get_info().await.unwrap(); + + let provider = ProviderBuilder::new() + .on_http(Url::from_str(evm_rpc).unwrap()); + + let evm_block_num = info.head_block_num - block_delta; + println!("Telos EVM Block Number: {:?}", evm_block_num); + + let mut has_more = true; + let mut lower_bound = Some(TableIndexType::UINT64(0)); + + let mut count = 0; + + let evm_block_id = BlockId::from(evm_block_num as u64); + let mut match_counter = MatchCounter::new(evm_block_id); + + while has_more { + let query_params = GetTableRowsParams { + code: name!("eosio.evm"), + table: name!("account"), + scope: None, + lower_bound, + upper_bound: None, + limit: Some(5000), + reverse: None, + index_position: None, + show_payer: None, + }; + let account_rows = api_client.v1_chain.get_table_rows::(query_params).await; + if let Ok(account_rows) = account_rows { + lower_bound = account_rows.next_key; + has_more = lower_bound.is_some(); + for account_row in account_rows.rows { + let address = Address::from_slice(account_row.address.data.as_slice()); + lower_bound = Some(TableIndexType::UINT64(account_row.index + 1)); + compare_account(&mut match_counter, &account_row, &api_client, &provider).await; + count += 1; + } + } else { + panic!("Failed to fetch account row"); + } + } + + match_counter.print(); + match_counter.matches() +} + +async fn compare_account(match_counter: &mut MatchCounter, account_row: &AccountRow, api_client: &APIClient, provider: &ReqwestProvider) { + let at_block = match_counter.evm_block_number; + let address = Address::from_slice(account_row.address.data.as_slice()); + let telos_balance = U256::from_be_slice(account_row.balance.data.as_slice()); + + let reth_balance = provider.get_balance(address).block_id(at_block).await.unwrap(); + let reth_nonce = provider.get_transaction_count(address).block_id(at_block).await.unwrap(); + let reth_code = provider.get_code_at(address).block_id(at_block).await.unwrap().to_vec(); + + let balance_missmatch = telos_balance != reth_balance; + let nonce_missmatch = account_row.nonce != reth_nonce; + let code_missmatch = account_row.code != reth_code; + + if balance_missmatch || nonce_missmatch || code_missmatch { + println!("ACCOUNT MISMATCH!!!"); + println!("Account: {:?}", address); + println!("Telos balance: {:?}", telos_balance); + println!("Telos nonce: {:?}", account_row.nonce); + println!("Telos code: {:?}", account_row.code); + println!("Reth balance: {:?}", reth_balance); + println!("Reth nonce: {:?}", reth_nonce); + println!("Reth code: {:?}", reth_code); + match_counter.add_mismatched_account(); + } else { + match_counter.add_matching_account(); + } + + compare_account_storage(match_counter, account_row, api_client, provider).await; +} + +async fn compare_account_storage(match_counter: &mut MatchCounter, account_row: &AccountRow, api_client: &APIClient, provider: &ReqwestProvider) { + let address = Address::from_slice(account_row.address.data.as_slice()); + + let mut has_more = true; + let mut lower_bound = Some(TableIndexType::UINT64(0)); + + let mut count = 0; + + while has_more { + let scope = if account_row.index == 0 { + Some(name!("")) + } else { + Some(Name::from_u64(account_row.index)) + }; + let query_params = GetTableRowsParams { + code: name!("eosio.evm"), + table: name!("accountstate"), + scope: Some(scope.unwrap()), + lower_bound, + upper_bound: None, + limit: Some(5000), + reverse: None, + index_position: None, + show_payer: None, + }; + let account_state_rows = api_client.v1_chain.get_table_rows::(query_params).await; + if let Ok(account_state_rows) = account_state_rows { + lower_bound = account_state_rows.next_key; + has_more = lower_bound.is_some(); + for account_state_row in account_state_rows.rows { + let key = U256::from_be_slice(account_state_row.key.data.as_slice()); + let telos_value: U256 = U256::from_be_slice(account_state_row.value.data.as_slice()); + let reth_value: U256 = provider.get_storage_at(address, key).block_id(match_counter.evm_block_number).await.unwrap(); + if telos_value != reth_value { + match_counter.add_mismatched_account_storage(); + println!("STORAGE MISMATCH!!!"); + println!("Storage account: {:?} with scope: {:?} and key: {:?}", address, scope.unwrap(), key); + println!("Telos Storage value: {:?}", telos_value); + println!("Reth storage value: {:?}", reth_value); + } else { + match_counter.add_matching_account_storage(); + } + lower_bound = Some(TableIndexType::UINT64(account_state_row.index + 1)); + count += 1; + } + } else { + panic!("Failed to fetch account state row"); + } + } +} \ No newline at end of file diff --git a/crates/telos/primitives-traits/Cargo.toml b/crates/telos/primitives-traits/Cargo.toml index 08755271599d..d728cd7a679a 100644 --- a/crates/telos/primitives-traits/Cargo.toml +++ b/crates/telos/primitives-traits/Cargo.toml @@ -14,6 +14,7 @@ alloy-consensus = { workspace = true } alloy-primitives = { version = "0.8.5", features = ["rlp"], default-features = false } alloy-eips = { version = "0.4", features = ["kzg-sidecar"], default-features = false } alloy-rlp = { version = "0.3", default-features = false } +alloy-rpc-types = { version = "0.4", default-features = false } alloy-serde = { version = "0.4", optional = true, default-features = false } serde = { version = "1.0", features = ["derive", "alloc"], default-features = false } serde_with = { version = "3.3.0", optional = true } diff --git a/crates/telos/primitives-traits/src/header.rs b/crates/telos/primitives-traits/src/header.rs index a16e63e25e6c..41777da226b1 100644 --- a/crates/telos/primitives-traits/src/header.rs +++ b/crates/telos/primitives-traits/src/header.rs @@ -15,6 +15,7 @@ use alloy_rlp::{ length_of_length, Buf, BufMut, Decodable, Encodable, EMPTY_LIST_CODE, EMPTY_STRING_CODE, }; use core::mem; +use alloy_rpc_types::ConversionError; use reth_codecs::Compact; use crate::TelosBlockExtension; @@ -946,3 +947,35 @@ impl Compact for TelosHeader { (alloy_header, buf) } } + +#[cfg(feature = "serde")] +impl TryFrom for TelosHeader { + type Error = ConversionError; + + fn try_from(header: alloy_rpc_types::Header) -> Result { + Ok(Self { + parent_hash: header.parent_hash, + ommers_hash: header.uncles_hash, + beneficiary: header.miner, + state_root: header.state_root, + transactions_root: header.transactions_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + difficulty: header.difficulty, + number: header.number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + mix_hash: header.mix_hash.unwrap_or_default(), + nonce: header.nonce.unwrap_or_default(), + base_fee_per_gas: header.base_fee_per_gas, + withdrawals_root: header.withdrawals_root, + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, + parent_beacon_block_root: header.parent_beacon_block_root, + requests_root: header.requests_root, + telos_block_extension: TelosBlockExtension::default(), + }) + } +} \ No newline at end of file diff --git a/crates/telos/rpc-engine-api/Cargo.toml b/crates/telos/rpc-engine-api/Cargo.toml index 30e0d56832e9..417f4537c268 100644 --- a/crates/telos/rpc-engine-api/Cargo.toml +++ b/crates/telos/rpc-engine-api/Cargo.toml @@ -16,6 +16,7 @@ reth-storage-errors.workspace = true revm.workspace = true revm-primitives.workspace = true tracing.workspace = true +sha2.workspace = true [lints] workspace = true diff --git a/crates/telos/rpc-engine-api/src/compare.rs b/crates/telos/rpc-engine-api/src/compare.rs index 5c0367763ed0..b11bed53ce1b 100644 --- a/crates/telos/rpc-engine-api/src/compare.rs +++ b/crates/telos/rpc-engine-api/src/compare.rs @@ -1,13 +1,112 @@ use std::collections::HashSet; use std::fmt::Display; -use alloy_primitives::{Address, B256, U256}; -use revm_primitives::HashMap; -use revm::db::AccountStatus; -use revm::{Database, Evm, State, TransitionAccount}; -use tracing::debug; +use alloy_primitives::{Address, B256, Bytes, U256}; +use revm_primitives::{Account, AccountInfo, Bytecode, EvmStorageSlot, HashMap}; +use revm::{Database, Evm, State, TransitionAccount, db::AccountStatus as DBAccountStatus}; +use revm_primitives::db::DatabaseCommit; +use revm_primitives::state::AccountStatus; +use sha2::{Digest, Sha256}; +use tracing::{debug, warn, info}; +use reth_primitives::KECCAK_EMPTY; use reth_storage_errors::provider::ProviderError; use crate::structs::{TelosAccountStateTableRow, TelosAccountTableRow}; +struct StateOverride { + accounts: HashMap +} + +impl StateOverride { + pub fn new() -> Self { + StateOverride { + accounts: HashMap::default() + } + } + + fn maybe_init_account (&mut self, revm_db: &mut &mut State, address: Address) { + let maybe_acc = self.accounts.get_mut(&address); + if maybe_acc.is_none() { + let mut status = AccountStatus::LoadedAsNotExisting | AccountStatus::Touched; + let info = match revm_db.basic(address) { + Ok(maybe_info) => { + maybe_info.unwrap_or_else(|| AccountInfo::default()) + }, + Err(_) => { + status = AccountStatus::Created | AccountStatus::Touched; + AccountInfo::default() + } + }; + + self.accounts.insert(address, Account { + info, + storage: Default::default(), + status, + }); + } + } + + pub fn override_account (&mut self, revm_db: &mut &mut State, telos_row: &TelosAccountTableRow) { + self.maybe_init_account(revm_db, telos_row.address); + let mut acc = self.accounts.get_mut(&telos_row.address).unwrap(); + acc.info.balance = telos_row.balance; + acc.info.nonce = telos_row.nonce; + if telos_row.code.len() > 0 { + acc.info.code_hash = B256::from_slice(Sha256::digest(telos_row.code.as_ref()).as_slice()); + acc.info.code = Some(Bytecode::LegacyRaw(telos_row.code.clone())); + } else { + acc.info.code_hash = KECCAK_EMPTY; + acc.info.code = None; + } + } + + pub fn override_balance (&mut self, revm_db: &mut &mut State, address: Address, balance: U256) { + self.maybe_init_account(revm_db, address); + let mut acc = self.accounts.get_mut(&address).unwrap(); + acc.info.balance = balance; + } + + pub fn override_nonce (&mut self, revm_db: &mut &mut State, address: Address, nonce: u64) { + self.maybe_init_account(revm_db, address); + let mut acc = self.accounts.get_mut(&address).unwrap(); + acc.info.nonce = nonce; + } + + pub fn override_code (&mut self, revm_db: &mut &mut State, address: Address, maybe_code: &Bytes) { + self.maybe_init_account(revm_db, address); + let mut acc = self.accounts.get_mut(&address).unwrap(); + if maybe_code.len() > 0 { + acc.info.code_hash = B256::from_slice(Sha256::digest(maybe_code.as_ref()).as_slice()); + acc.info.code = Some(Bytecode::LegacyRaw(maybe_code.clone())); + } else { + acc.info.code_hash = KECCAK_EMPTY; + acc.info.code = None; + } + } + + pub fn override_storage (&mut self, revm_db: &mut &mut State, address: Address, key: U256, new_val: U256, old_val: U256) { + self.maybe_init_account(revm_db, address); + let mut acc = self.accounts.get_mut(&address).unwrap(); + acc.storage.insert(key, EvmStorageSlot { + original_value: old_val, + present_value: new_val, + is_cold: false + }); + } + + pub fn apply (&self, revm_db: &mut &mut State) { + revm_db.commit(self.accounts.clone()); + } +} + +macro_rules! maybe_panic { + ($panic_mode:expr, $($arg:tt)*) => { + if $panic_mode { + panic!($($arg)*); + } else { + warn!($($arg)*); + } + }; +} + /// This function compares the state diffs between revm and Telos EVM contract pub fn compare_state_diffs( evm: &mut Evm<'_, Ext, &mut State>, @@ -16,6 +115,7 @@ pub fn compare_state_diffs( statediffs_accountstate: Vec, _new_addresses_using_create: Vec<(u64, U256)>, new_addresses_using_openwallet: Vec<(u64, U256)>, + panic_mode: bool ) -> bool where DB: Database, @@ -34,6 +134,8 @@ where let revm_db: &mut &mut State = evm.db_mut(); + let mut state_override = StateOverride::new(); + let mut new_addresses_using_openwallet_hashset = HashSet::new(); for row in &new_addresses_using_openwallet { new_addresses_using_openwallet_hashset.insert(Address::from_word(B256::from(row.1))); @@ -43,10 +145,10 @@ where for row in &statediffs_account { statediffs_account_hashmap.insert(row.address); } - let mut statediffs_accountstate_hashmap = HashSet::new(); - for row in &statediffs_accountstate { - statediffs_accountstate_hashmap.insert((row.address,row.key)); - } + // let mut statediffs_accountstate_hashmap = HashSet::new(); + // for row in &statediffs_accountstate { + // statediffs_accountstate_hashmap.insert((row.address,row.key)); + // } for row in &statediffs_account { // Skip if address is created using openwallet and is empty @@ -55,80 +157,138 @@ where } // Skip if row is removed if row.removed { + // TODO: Does the Telos EVM contract ever remove account rows, or should this be a panic?? continue } if let Ok(revm_row) = revm_db.basic(row.address) { if let Some(unwrapped_revm_row) = revm_row { // Check balance inequality if unwrapped_revm_row.balance != row.balance { - panic!("Difference in balance, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.balance,row.balance); + maybe_panic!(panic_mode, "Difference in balance, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.balance,row.balance); + state_override.override_balance(revm_db, row.address, row.balance); } // Check nonce inequality if unwrapped_revm_row.nonce != row.nonce { - panic!("Difference in nonce, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.nonce,row.nonce); + maybe_panic!(panic_mode, "Difference in nonce, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.nonce,row.nonce); + state_override.override_nonce(revm_db, row.address, row.nonce); } // Check code size inequality - if unwrapped_revm_row.clone().code.is_none() && row.code.len() != 0 || unwrapped_revm_row.clone().code.is_some() && !unwrapped_revm_row.clone().code.unwrap().is_empty() && row.code.len() == 0 { - match revm_db.code_by_hash(unwrapped_revm_row.code_hash) { - Ok(code_by_hash) => - if (code_by_hash.is_empty() && row.code.len() != 0) || (!code_by_hash.is_empty() && row.code.len() == 0) { - panic!("Difference in code existence, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code_by_hash,row.code) - }, - Err(_) => panic!("Difference in code existence, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.code,row.code), + let maybe_revm_code = unwrapped_revm_row.clone().code; + + match maybe_revm_code { + None => { + if row.code.len() != 0 { + match revm_db.code_by_hash(unwrapped_revm_row.code_hash()) { + Ok(bytecode) => { + if bytecode.len() != row.code.len() { + maybe_panic!(panic_mode, "Difference in code size, address: {:?} - revm: {} - tevm: {}",row.address,bytecode.len(),row.code.len()); + state_override.override_code(revm_db, row.address, &row.code); + } + } + Err(_) => { + maybe_panic!(panic_mode, "Difference in code existence, error while fetching db, address: {:?} - revm: Err - tevm: {}",row.address,row.code.len()); + state_override.override_code(revm_db, row.address, &row.code); + } + } + } + } + Some(revm_bytecode) => { + match revm_bytecode { + Bytecode::LegacyRaw(code) => { + if code.len() != row.code.len() { + maybe_panic!(panic_mode, "Difference in legacy code size, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code.len(),row.code.len()); + state_override.override_code(revm_db, row.address, &row.code); + } + } + Bytecode::LegacyAnalyzed(code) => { + if code.original_len() != row.code.len() { + maybe_panic!(panic_mode, "Difference in legacy (analyzed) code size, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code.original_len(),row.code.len()); + state_override.override_code(revm_db, row.address, &row.code); + } + } + Bytecode::Eof(_) => panic!("Eof not implemented!"), + Bytecode::Eip7702(_) => panic!("EIP7702 not implemented!") + } } } // // Check code content inequality // if unwrapped_revm_row.clone().unwrap().code.is_some() && !unwrapped_revm_row.clone().unwrap().code.unwrap().is_empty() && unwrapped_revm_row.clone().unwrap().code.unwrap().bytes() != row.code { - // panic!("Difference in code content, revm: {:?}, tevm: {:?}",unwrapped_revm_row.clone().unwrap().code.unwrap().bytes(),row.code); + // panic!(panic_mode, "Difference in code content, revm: {:?}, tevm: {:?}",unwrapped_revm_row.clone().unwrap().code.unwrap().bytes(),row.code); // } } else { // Skip if address is empty on both sides if !(row.balance == U256::ZERO && row.nonce == 0 && row.code.len() == 0) { if let Some(unwrapped_revm_state_diff) = revm_state_diffs.get(&row.address) { - if !(unwrapped_revm_state_diff.status == AccountStatus::Destroyed && row.nonce == 0 && row.balance == U256::ZERO && row.code.len() == 0) { - panic!("A modified `account` table row was found on both revm state and revm state diffs, but seems to be destroyed on just one side, address: {:?}",row.address); + if !(unwrapped_revm_state_diff.status == DBAccountStatus::Destroyed && row.nonce == 0 && row.balance == U256::ZERO && row.code.len() == 0) { + maybe_panic!(panic_mode, "A modified `account` table row was found on both revm state and revm state diffs, but seems to be destroyed on just one side, address: {:?}",row.address); + state_override.override_account(revm_db, &row); } } else { - panic!("A modified `account` table row was found on revm state, but contains no information, address: {:?}",row.address); + maybe_panic!(panic_mode, "A modified `account` table row was found on revm state, but contains no information, address: {:?}",row.address); + state_override.override_account(revm_db, &row); } } } } else { // Skip if address is empty on both sides if !(row.balance == U256::ZERO && row.nonce == 0 && row.code.len() == 0) { - panic!("A modified `account` table row was not found on revm state, address: {:?}",row.address); + maybe_panic!(panic_mode, "A modified `account` table row was not found on revm state, address: {:?}",row.address); + state_override.override_account(revm_db, &row); } } } - for row in &statediffs_accountstate { - if let Ok(revm_row) = revm_db.storage(row.address, row.key) { - // The values should match, but if it is removed, then the revm value should be zero - if !(revm_row == row.value) && !(revm_row != U256::ZERO || row.removed == true) { - panic!("Difference in value on revm storage, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}",row.address,row.key,revm_row,row); - } - } else { - panic!("Key was not found on revm storage, address: {:?}, key: {:?}",row.address,row.key); - } - } + // for row in &statediffs_accountstate { + // if let None = revm_db.cache.accounts.get_mut(&row.address) { + // let cached_account = revm_db.load_cache_account(row.address); + // match cached_account { + // Ok(cached_account) => { + // if cached_account.account.is_none() { + // panic!("An account state modification was made for an account that is not in revm storage, address: {:?}", row.address); + // } + // }, + // Err(_) => { + // panic!("An account state modification was made for an account that returned Err from load_cache_account, address: {:?}", row.address); + // } + // } + // } + // if let Ok(revm_row) = revm_db.storage(row.address, row.key) { + // // The values should match, but if it is removed, then the revm value should be zero + // if revm_row != row.value { + // if revm_row != U256::ZERO && row.removed == true { + // maybe_panic!(panic_mode, "Difference in value on revm storage, removed on Telos, non-ZERO on revm, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}", row.address, row.key, revm_row, row); + // state_override.override_storage(revm_db, row.address, row.key, U256::ZERO, revm_row); + // } + // if row.removed == false { + // maybe_panic!(panic_mode, "Difference in value on revm storage, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}", row.address, row.key, revm_row, row); + // state_override.override_storage(revm_db, row.address, row.key, row.value, revm_row); + // } + // } + // } else { + // maybe_panic!(panic_mode, "Key was not found on revm storage, address: {:?}, key: {:?}",row.address,row.key); + // state_override.override_storage(revm_db, row.address, row.key, row.value, U256::ZERO); + // } + // } for (address, account) in &revm_state_diffs { if let (Some(info),Some(previous_info)) = (account.info.clone(),account.previous_info.clone()) { if !(info.balance == previous_info.balance && info.nonce == previous_info.nonce && info.code_hash == previous_info.code_hash) { if statediffs_account_hashmap.get(address).is_none() { - panic!("A modified address was not found on tevm state diffs, address: {:?}",address); + panic!("A modified address was not found on tevm state diffs, address: {:?}",address); } } } else { if statediffs_account_hashmap.get(address).is_none() { - panic!("A modified address was not found on tevm state diffs, address: {:?}",address); - } - } - for (key,_) in account.storage.clone() { - if statediffs_accountstate_hashmap.get(&(*address,key)).is_none() { - panic!("A modified storage slot was not found on tevm state diffs, address: {:?}",address); + panic!("A modified address was not found on tevm state diffs, info/previous_info were not Some, address: {:?}",address); } } + // for (key,_) in account.storage.clone() { + // if statediffs_accountstate_hashmap.get(&(*address,key)).is_none() { + // panic!("A modified storage slot was not found on tevm state diffs, address: {:?}, key: {:?}", address, key); + // } + // } } - - return true + + state_override.apply(revm_db); + + true } diff --git a/crates/telos/rpc/src/eth/mod.rs b/crates/telos/rpc/src/eth/mod.rs index fd3227b6a0fa..42e4c8f06aeb 100644 --- a/crates/telos/rpc/src/eth/mod.rs +++ b/crates/telos/rpc/src/eth/mod.rs @@ -26,7 +26,7 @@ use reth_provider::{ BlockIdReader, BlockNumReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StageCheckpointReader, StateProviderFactory, }; -use reth_rpc::eth::{core::EthApiInner, DevSigner}; +use reth_rpc::eth::{core::EthApiInner, DevSigner, EthTxBuilder}; use reth_rpc_eth_api::{ helpers::{ AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadBlock, LoadFee, LoadState, @@ -104,7 +104,7 @@ where { type Error = TelosEthApiError; type NetworkTypes = AnyNetwork; - type TransactionCompat = (); + type TransactionCompat = EthTxBuilder; } impl EthApiSpec for TelosEthApi