mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-04-23 00:17:57 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec4ec43a5c | |||
| cec67056ae | |||
| 5eb3a0e1b5 | |||
| 772bd217c3 | |||
| 0513a4befb | |||
| de7c7d6703 |
@@ -99,9 +99,28 @@ jobs:
|
|||||||
- name: Install Geth on Ubuntu
|
- name: Install Geth on Ubuntu
|
||||||
if: matrix.os == 'ubuntu-24.04'
|
if: matrix.os == 'ubuntu-24.04'
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository -y ppa:ethereum/ethereum
|
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y ethereum protobuf-compiler
|
sudo apt-get install -y protobuf-compiler
|
||||||
|
|
||||||
|
# We were facing some issues in CI with the 1.16.* versions of geth, and specifically on
|
||||||
|
# Ubuntu. Eventually, we found out that the last version of geth that worked in our CI was
|
||||||
|
# version 1.15.11. Thus, this is the version that we want to use in CI. The PPA sadly does
|
||||||
|
# not have historic versions of Geth and therefore we need to resort to downloading pre
|
||||||
|
# built binaries for Geth and the surrounding tools which is what the following parts of
|
||||||
|
# the script do.
|
||||||
|
|
||||||
|
sudo apt-get install -y wget ca-certificates tar
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
if [ "$ARCH" = "x86_64" ]; then
|
||||||
|
URL="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.15.11-36b2371c.tar.gz"
|
||||||
|
elif [ "$ARCH" = "aarch64" ]; then
|
||||||
|
URL="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-arm64-1.15.11-36b2371c.tar.gz"
|
||||||
|
else
|
||||||
|
echo "Unsupported architecture: $ARCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
wget -qO- "$URL" | sudo tar xz -C /usr/local/bin --strip-components=1
|
||||||
|
geth --version
|
||||||
|
|
||||||
- name: Install Geth on macOS
|
- name: Install Geth on macOS
|
||||||
if: matrix.os == 'macos-14'
|
if: matrix.os == 'macos-14'
|
||||||
|
|||||||
@@ -3,3 +3,7 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/*.json
|
/*.json
|
||||||
|
|
||||||
|
# We do not want to commit any log files that we produce from running the code locally so this is
|
||||||
|
# added to the .gitignore file.
|
||||||
|
*.log
|
||||||
Generated
+47
-92
@@ -67,9 +67,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy"
|
name = "alloy"
|
||||||
version = "1.0.9"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0093d23bf026b580c1f66ed3a053d8209c104a446c5264d3ad99587f6edef24e"
|
checksum = "ae58d888221eecf621595e2096836ce7cfc37be06bfa39d7f64aa6a3ea4c9e5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-consensus",
|
"alloy-consensus",
|
||||||
"alloy-contract",
|
"alloy-contract",
|
||||||
@@ -162,9 +162,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-core"
|
name = "alloy-core"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3c5a28f166629752f2e7246b813cdea3243cca59aab2d4264b1fd68392c10eb"
|
checksum = "ad31216895d27d307369daa1393f5850b50bbbd372478a9fa951c095c210627e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-dyn-abi",
|
"alloy-dyn-abi",
|
||||||
"alloy-json-abi",
|
"alloy-json-abi",
|
||||||
@@ -175,9 +175,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-dyn-abi"
|
name = "alloy-dyn-abi"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6"
|
checksum = "7b95b3deca680efc7e9cba781f1a1db352fa1ea50e6384a514944dcf4419e652"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-json-abi",
|
"alloy-json-abi",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
@@ -260,9 +260,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-json-abi"
|
name = "alloy-json-abi"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9"
|
checksum = "15516116086325c157c18261d768a20677f0f699348000ed391d4ad0dcb82530"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
"alloy-sol-type-parser",
|
"alloy-sol-type-parser",
|
||||||
@@ -325,9 +325,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-primitives"
|
name = "alloy-primitives"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8"
|
checksum = "6177ed26655d4e84e00b65cb494d4e0b8830e7cae7ef5d63087d445a2600fb55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-rlp",
|
"alloy-rlp",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -575,9 +575,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-sol-macro"
|
name = "alloy-sol-macro"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383"
|
checksum = "a14f21d053aea4c6630687c2f4ad614bed4c81e14737a9b904798b24f30ea849"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-sol-macro-expander",
|
"alloy-sol-macro-expander",
|
||||||
"alloy-sol-macro-input",
|
"alloy-sol-macro-input",
|
||||||
@@ -589,9 +589,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-sol-macro-expander"
|
name = "alloy-sol-macro-expander"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74"
|
checksum = "34d99282e7c9ef14eb62727981a985a01869e586d1dec729d3bb33679094c100"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-json-abi",
|
"alloy-json-abi",
|
||||||
"alloy-sol-macro-input",
|
"alloy-sol-macro-input",
|
||||||
@@ -608,9 +608,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-sol-macro-input"
|
name = "alloy-sol-macro-input"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5"
|
checksum = "eda029f955b78e493360ee1d7bd11e1ab9f2a220a5715449babc79d6d0a01105"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-json-abi",
|
"alloy-json-abi",
|
||||||
"const-hex",
|
"const-hex",
|
||||||
@@ -626,9 +626,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-sol-type-parser"
|
name = "alloy-sol-type-parser"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837"
|
checksum = "10db1bd7baa35bc8d4a1b07efbf734e73e5ba09f2580fb8cee3483a36087ceb2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"winnow",
|
"winnow",
|
||||||
@@ -636,9 +636,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-sol-types"
|
name = "alloy-sol-types"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387"
|
checksum = "58377025a47d8b8426b3e4846a251f2c1991033b27f517aade368146f6ab1dfe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-json-abi",
|
"alloy-json-abi",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
@@ -2071,29 +2071,6 @@ dependencies = [
|
|||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_filter"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.11.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
|
|
||||||
dependencies = [
|
|
||||||
"anstream",
|
|
||||||
"anstyle",
|
|
||||||
"env_filter",
|
|
||||||
"jiff",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "environmental"
|
name = "environmental"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
@@ -2962,30 +2939,6 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jiff"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
|
||||||
dependencies = [
|
|
||||||
"jiff-static",
|
|
||||||
"log",
|
|
||||||
"portable-atomic",
|
|
||||||
"portable-atomic-util",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jiff-static"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.101",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.77"
|
version = "0.3.77"
|
||||||
@@ -3597,21 +3550,6 @@ dependencies = [
|
|||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "portable-atomic"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "portable-atomic-util"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
|
||||||
dependencies = [
|
|
||||||
"portable-atomic",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -3997,13 +3935,13 @@ name = "revive-dt-compiler"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
|
||||||
"revive-common",
|
"revive-common",
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
"revive-dt-solc-binaries",
|
"revive-dt-solc-binaries",
|
||||||
"revive-solc-json-interface",
|
"revive-solc-json-interface",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4024,8 +3962,6 @@ dependencies = [
|
|||||||
"alloy",
|
"alloy",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
|
||||||
"log",
|
|
||||||
"rayon",
|
"rayon",
|
||||||
"revive-dt-compiler",
|
"revive-dt-compiler",
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
@@ -4034,7 +3970,10 @@ dependencies = [
|
|||||||
"revive-dt-node-interaction",
|
"revive-dt-node-interaction",
|
||||||
"revive-dt-report",
|
"revive-dt-report",
|
||||||
"revive-solc-json-interface",
|
"revive-solc-json-interface",
|
||||||
|
"serde_json",
|
||||||
"temp-dir",
|
"temp-dir",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4042,11 +3981,13 @@ name = "revive-dt-format"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy",
|
"alloy",
|
||||||
|
"alloy-primitives",
|
||||||
|
"alloy-sol-types",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4055,13 +3996,14 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy",
|
"alloy",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
"revive-dt-node-interaction",
|
"revive-dt-node-interaction",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"temp-dir",
|
"temp-dir",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4070,9 +4012,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy",
|
"alloy",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4080,12 +4022,12 @@ name = "revive-dt-report"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
"revive-dt-format",
|
"revive-dt-format",
|
||||||
"revive-solc-json-interface",
|
"revive-solc-json-interface",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4094,11 +4036,11 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2 0.10.9",
|
"sha2 0.10.9",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5143,9 +5085,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn-solidity"
|
name = "syn-solidity"
|
||||||
version = "1.1.2"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e"
|
checksum = "b9ac494e7266fcdd2ad80bf4375d55d27a117ea5c866c26d0e97fe5b3caeeb75"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"paste",
|
"paste",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -5566,6 +5508,16 @@ dependencies = [
|
|||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-serde"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.19"
|
version = "0.3.19"
|
||||||
@@ -5576,6 +5528,8 @@ dependencies = [
|
|||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
@@ -5583,6 +5537,7 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
|
"tracing-serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+19
-7
@@ -4,9 +4,7 @@ members = ["crates/*"]
|
|||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = [
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
"Parity Technologies <admin@parity.io>",
|
|
||||||
]
|
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
repository = "https://github.com/paritytech/revive-differential-testing.git"
|
repository = "https://github.com/paritytech/revive-differential-testing.git"
|
||||||
@@ -23,24 +21,35 @@ revive-dt-node-pool = { version = "0.1.0", path = "crates/node-pool" }
|
|||||||
revive-dt-report = { version = "0.1.0", path = "crates/report" }
|
revive-dt-report = { version = "0.1.0", path = "crates/report" }
|
||||||
revive-dt-solc-binaries = { version = "0.1.0", path = "crates/solc-binaries" }
|
revive-dt-solc-binaries = { version = "0.1.0", path = "crates/solc-binaries" }
|
||||||
|
|
||||||
|
alloy-primitives = "1.2.1"
|
||||||
|
alloy-sol-types = "1.2.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
env_logger = "0.11.8"
|
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
reqwest = { version = "0.12.15", features = ["blocking", "json"] }
|
reqwest = { version = "0.12.15", features = ["blocking", "json"] }
|
||||||
log = "0.4.27"
|
|
||||||
once_cell = "1.21"
|
once_cell = "1.21"
|
||||||
rayon = { version = "1.10" }
|
rayon = { version = "1.10" }
|
||||||
semver = { version = "1.0", features = ["serde"] }
|
semver = { version = "1.0", features = ["serde"] }
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
serde_json = { version = "1.0", default-features = false, features = ["arbitrary_precision", "std"] }
|
serde_json = { version = "1.0", default-features = false, features = [
|
||||||
|
"arbitrary_precision",
|
||||||
|
"std",
|
||||||
|
] }
|
||||||
sha2 = { version = "0.10.9" }
|
sha2 = { version = "0.10.9" }
|
||||||
sp-core = "36.1.0"
|
sp-core = "36.1.0"
|
||||||
sp-runtime = "41.1.0"
|
sp-runtime = "41.1.0"
|
||||||
temp-dir = { version = "0.1.16" }
|
temp-dir = { version = "0.1.16" }
|
||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
|
tokio = { version = "1", default-features = false, features = [
|
||||||
|
"rt-multi-thread",
|
||||||
|
] }
|
||||||
uuid = { version = "1.8", features = ["v4"] }
|
uuid = { version = "1.8", features = ["v4"] }
|
||||||
|
tracing = "0.1.41"
|
||||||
|
tracing-subscriber = { version = "0.3.19", default-features = false, features = [
|
||||||
|
"fmt",
|
||||||
|
"json",
|
||||||
|
"env-filter",
|
||||||
|
] }
|
||||||
|
|
||||||
# revive compiler
|
# revive compiler
|
||||||
revive-solc-json-interface = { git = "https://github.com/paritytech/revive", rev = "3389865af7c3ff6f29a586d82157e8bc573c1a8e" }
|
revive-solc-json-interface = { git = "https://github.com/paritytech/revive", rev = "3389865af7c3ff6f29a586d82157e8bc573c1a8e" }
|
||||||
@@ -59,6 +68,9 @@ features = [
|
|||||||
"rpc-types",
|
"rpc-types",
|
||||||
"signer-local",
|
"signer-local",
|
||||||
"std",
|
"std",
|
||||||
|
"network",
|
||||||
|
"serde",
|
||||||
|
"rpc-types-eth",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.bench]
|
[profile.bench]
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ revive-dt-solc-binaries = { workspace = true }
|
|||||||
revive-common = { workspace = true }
|
revive-common = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ impl SolidityCompiler for Resolc {
|
|||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
let message = String::from_utf8_lossy(&stderr);
|
let message = String::from_utf8_lossy(&stderr);
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"resolc failed exit={} stderr={} JSON-in={} ",
|
"resolc failed exit={} stderr={} JSON-in={} ",
|
||||||
output.status,
|
output.status,
|
||||||
&message,
|
&message,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl SolidityCompiler for Solc {
|
|||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
let message = String::from_utf8_lossy(&output.stderr);
|
let message = String::from_utf8_lossy(&output.stderr);
|
||||||
log::error!("solc failed exit={} stderr={}", output.status, &message);
|
tracing::error!("solc failed exit={} stderr={}", output.status, &message);
|
||||||
return Ok(CompilerOutput {
|
return Ok(CompilerOutput {
|
||||||
input,
|
input,
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! The global configuration used accross all revive differential testing crates.
|
//! The global configuration used across all revive differential testing crates.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ revive-dt-report = { workspace = true }
|
|||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
env_logger = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
rayon = { workspace = true }
|
rayon = { workspace = true }
|
||||||
revive-solc-json-interface = { workspace = true }
|
revive-solc-json-interface = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
temp-dir = { workspace = true }
|
temp-dir = { workspace = true }
|
||||||
|
|||||||
+152
-53
@@ -1,12 +1,14 @@
|
|||||||
//! The test driver handles the compilation and execution of the test cases.
|
//! The test driver handles the compilation and execution of the test cases.
|
||||||
|
|
||||||
|
use alloy::json_abi::JsonAbi;
|
||||||
use alloy::primitives::Bytes;
|
use alloy::primitives::Bytes;
|
||||||
use alloy::rpc::types::TransactionInput;
|
use alloy::rpc::types::trace::geth::GethTrace;
|
||||||
|
use alloy::rpc::types::{TransactionInput, TransactionReceipt};
|
||||||
use alloy::{
|
use alloy::{
|
||||||
primitives::{Address, TxKind, map::HashMap},
|
primitives::{Address, TxKind, map::HashMap},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt, TransactionRequest,
|
TransactionRequest,
|
||||||
trace::geth::{AccountState, DiffMode, GethTrace},
|
trace::geth::{AccountState, DiffMode},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
||||||
@@ -15,6 +17,9 @@ use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode};
|
|||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
use revive_dt_report::reporter::{CompilationTask, Report, Span};
|
use revive_dt_report::reporter::{CompilationTask, Report, Span};
|
||||||
use revive_solc_json_interface::SolcStandardJsonOutput;
|
use revive_solc_json_interface::SolcStandardJsonOutput;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashMap as StdHashMap;
|
||||||
|
use tracing::Level;
|
||||||
|
|
||||||
use crate::Platform;
|
use crate::Platform;
|
||||||
|
|
||||||
@@ -27,7 +32,8 @@ pub struct State<'a, T: Platform> {
|
|||||||
config: &'a Arguments,
|
config: &'a Arguments,
|
||||||
span: Span,
|
span: Span,
|
||||||
contracts: Contracts<T>,
|
contracts: Contracts<T>,
|
||||||
deployed_contracts: HashMap<String, Address>,
|
deployed_contracts: StdHashMap<String, Address>,
|
||||||
|
deployed_abis: StdHashMap<String, JsonAbi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> State<'a, T>
|
impl<'a, T> State<'a, T>
|
||||||
@@ -40,6 +46,7 @@ where
|
|||||||
span,
|
span,
|
||||||
contracts: Default::default(),
|
contracts: Default::default(),
|
||||||
deployed_contracts: Default::default(),
|
deployed_contracts: Default::default(),
|
||||||
|
deployed_abis: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +74,7 @@ where
|
|||||||
.solc_optimizer(mode.solc_optimize());
|
.solc_optimizer(mode.solc_optimize());
|
||||||
|
|
||||||
for (file, _contract) in metadata.contract_sources()?.values() {
|
for (file, _contract) in metadata.contract_sources()?.values() {
|
||||||
log::debug!("contract source {}", file.display());
|
tracing::debug!("contract source {}", file.display());
|
||||||
compiler = compiler.with_source(file)?;
|
compiler = compiler.with_source(file)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,11 +97,13 @@ where
|
|||||||
if let Some(contracts) = &last_output.contracts {
|
if let Some(contracts) = &last_output.contracts {
|
||||||
for (file, contracts_map) in contracts {
|
for (file, contracts_map) in contracts {
|
||||||
for contract_name in contracts_map.keys() {
|
for contract_name in contracts_map.keys() {
|
||||||
log::debug!("Compiled contract: {contract_name} from file: {file}");
|
tracing::debug!(
|
||||||
|
"Compiled contract: {contract_name} from file: {file}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Compiled contracts field is None");
|
tracing::warn!("Compiled contracts field is None");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +111,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("Failed to compile contract: {:?}", error.to_string());
|
tracing::error!("Failed to compile contract: {:?}", error.to_string());
|
||||||
task.error = Some(error.to_string());
|
task.error = Some(error.to_string());
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
@@ -114,11 +123,11 @@ where
|
|||||||
input: &Input,
|
input: &Input,
|
||||||
node: &T::Blockchain,
|
node: &T::Blockchain,
|
||||||
) -> anyhow::Result<(TransactionReceipt, GethTrace, DiffMode)> {
|
) -> anyhow::Result<(TransactionReceipt, GethTrace, DiffMode)> {
|
||||||
log::trace!("Calling execute_input for input: {input:?}");
|
tracing::trace!("Calling execute_input for input: {input:?}");
|
||||||
|
|
||||||
let nonce = node.fetch_add_nonce(input.caller)?;
|
let nonce = node.fetch_add_nonce(input.caller)?;
|
||||||
|
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}",
|
"Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}",
|
||||||
&nonce,
|
&nonce,
|
||||||
&input.instance,
|
&input.instance,
|
||||||
@@ -126,22 +135,28 @@ where
|
|||||||
std::any::type_name::<T>()
|
std::any::type_name::<T>()
|
||||||
);
|
);
|
||||||
|
|
||||||
let tx =
|
let tx = match input.legacy_transaction(
|
||||||
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts)
|
self.config.network_id,
|
||||||
{
|
nonce,
|
||||||
Ok(tx) => tx,
|
&self.deployed_contracts,
|
||||||
|
&self.deployed_abis,
|
||||||
|
) {
|
||||||
|
Ok(tx) => {
|
||||||
|
tracing::debug!("Legacy transaction data: {tx:#?}");
|
||||||
|
tx
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Failed to construct legacy transaction: {err:?}");
|
tracing::error!("Failed to construct legacy transaction: {err:?}");
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!("Executing transaction for input: {input:?}");
|
tracing::trace!("Executing transaction for input: {input:?}");
|
||||||
|
|
||||||
let receipt = match node.execute_transaction(tx) {
|
let receipt = match node.execute_transaction(tx) {
|
||||||
Ok(receipt) => receipt,
|
Ok(receipt) => receipt,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"Failed to execute transaction when executing the contract: {}, {:?}",
|
"Failed to execute transaction when executing the contract: {}, {:?}",
|
||||||
&input.instance,
|
&input.instance,
|
||||||
err
|
err
|
||||||
@@ -150,14 +165,14 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!(
|
tracing::trace!(
|
||||||
"Transaction receipt for executed contract: {} - {:?}",
|
"Transaction receipt for executed contract: {} - {:?}",
|
||||||
&input.instance,
|
&input.instance,
|
||||||
receipt,
|
receipt,
|
||||||
);
|
);
|
||||||
|
|
||||||
let trace = node.trace_transaction(receipt.clone())?;
|
let trace = node.trace_transaction(receipt.clone())?;
|
||||||
log::trace!(
|
tracing::trace!(
|
||||||
"Trace result for contract: {} - {:?}",
|
"Trace result for contract: {} - {:?}",
|
||||||
&input.instance,
|
&input.instance,
|
||||||
trace
|
trace
|
||||||
@@ -169,7 +184,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
|
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Deploying contracts {}, having address {} on node: {}",
|
"Deploying contracts {}, having address {} on node: {}",
|
||||||
&input.instance,
|
&input.instance,
|
||||||
&input.caller,
|
&input.caller,
|
||||||
@@ -177,7 +192,7 @@ where
|
|||||||
);
|
);
|
||||||
for output in self.contracts.values() {
|
for output in self.contracts.values() {
|
||||||
let Some(contract_map) = &output.contracts else {
|
let Some(contract_map) = &output.contracts else {
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"No contracts in output — skipping deployment for this input {}",
|
"No contracts in output — skipping deployment for this input {}",
|
||||||
&input.instance
|
&input.instance
|
||||||
);
|
);
|
||||||
@@ -186,14 +201,11 @@ where
|
|||||||
|
|
||||||
for contracts in contract_map.values() {
|
for contracts in contract_map.values() {
|
||||||
for (contract_name, contract) in contracts {
|
for (contract_name, contract) in contracts {
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Contract name is: {:?} and the input name is: {:?}",
|
"Contract name is: {:?} and the input name is: {:?}",
|
||||||
&contract_name,
|
&contract_name,
|
||||||
&input.instance
|
&input.instance
|
||||||
);
|
);
|
||||||
if contract_name != &input.instance {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytecode = contract
|
let bytecode = contract
|
||||||
.evm
|
.evm
|
||||||
@@ -202,13 +214,13 @@ where
|
|||||||
.map(|b| b.object.clone());
|
.map(|b| b.object.clone());
|
||||||
|
|
||||||
let Some(code) = bytecode else {
|
let Some(code) = bytecode else {
|
||||||
log::error!("no bytecode for contract {contract_name}");
|
tracing::error!("no bytecode for contract {contract_name}");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let nonce = node.fetch_add_nonce(input.caller)?;
|
let nonce = node.fetch_add_nonce(input.caller)?;
|
||||||
|
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Calculated nonce {}, for contract {}, having address {} on node: {}",
|
"Calculated nonce {}, for contract {}, having address {} on node: {}",
|
||||||
&nonce,
|
&nonce,
|
||||||
&input.instance,
|
&input.instance,
|
||||||
@@ -230,7 +242,7 @@ where
|
|||||||
let receipt = match node.execute_transaction(tx) {
|
let receipt = match node.execute_transaction(tx) {
|
||||||
Ok(receipt) => receipt,
|
Ok(receipt) => receipt,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"Failed to execute transaction when deploying the contract on node : {:?}, {:?}, {:?}",
|
"Failed to execute transaction when deploying the contract on node : {:?}, {:?}, {:?}",
|
||||||
std::any::type_name::<T>(),
|
std::any::type_name::<T>(),
|
||||||
&contract_name,
|
&contract_name,
|
||||||
@@ -240,7 +252,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Deployment tx sent for {} with nonce {} → tx hash: {:?}, on node: {:?}",
|
"Deployment tx sent for {} with nonce {} → tx hash: {:?}, on node: {:?}",
|
||||||
contract_name,
|
contract_name,
|
||||||
nonce,
|
nonce,
|
||||||
@@ -248,7 +260,7 @@ where
|
|||||||
std::any::type_name::<T>(),
|
std::any::type_name::<T>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
log::trace!(
|
tracing::trace!(
|
||||||
"Deployed transaction receipt for contract: {} - {:?}, on node: {:?}",
|
"Deployed transaction receipt for contract: {} - {:?}, on node: {:?}",
|
||||||
&contract_name,
|
&contract_name,
|
||||||
receipt,
|
receipt,
|
||||||
@@ -256,7 +268,7 @@ where
|
|||||||
);
|
);
|
||||||
|
|
||||||
let Some(address) = receipt.contract_address else {
|
let Some(address) = receipt.contract_address else {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"contract {contract_name} deployment did not return an address"
|
"contract {contract_name} deployment did not return an address"
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@@ -264,17 +276,63 @@ where
|
|||||||
|
|
||||||
self.deployed_contracts
|
self.deployed_contracts
|
||||||
.insert(contract_name.clone(), address);
|
.insert(contract_name.clone(), address);
|
||||||
log::trace!(
|
tracing::trace!(
|
||||||
"deployed contract `{}` at {:?}, on node {:?}",
|
"deployed contract `{}` at {:?}, on node {:?}",
|
||||||
contract_name,
|
contract_name,
|
||||||
address,
|
address,
|
||||||
std::any::type_name::<T>()
|
std::any::type_name::<T>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(Value::String(metadata_json_str)) = &contract.metadata {
|
||||||
|
tracing::trace!(
|
||||||
|
"metadata found for contract {contract_name}, {metadata_json_str}"
|
||||||
|
);
|
||||||
|
|
||||||
|
match serde_json::from_str::<serde_json::Value>(metadata_json_str) {
|
||||||
|
Ok(metadata_json) => {
|
||||||
|
if let Some(abi_value) =
|
||||||
|
metadata_json.get("output").and_then(|o| o.get("abi"))
|
||||||
|
{
|
||||||
|
match serde_json::from_value::<JsonAbi>(abi_value.clone()) {
|
||||||
|
Ok(parsed_abi) => {
|
||||||
|
tracing::trace!(
|
||||||
|
"ABI found in metadata for contract {}",
|
||||||
|
&contract_name
|
||||||
|
);
|
||||||
|
self.deployed_abis
|
||||||
|
.insert(contract_name.clone(), parsed_abi);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Failed to parse ABI from metadata for contract {}: {}",
|
||||||
|
contract_name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
anyhow::bail!(
|
||||||
|
"No ABI found in metadata for contract {}",
|
||||||
|
contract_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Failed to parse metadata JSON string for contract {}: {}",
|
||||||
|
contract_name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
anyhow::bail!("No metadata found for contract {}", contract_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Available contracts: {:?}", self.deployed_contracts.keys());
|
tracing::debug!("Available contracts: {:?}", self.deployed_contracts.keys());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -307,28 +365,28 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_diff_mode(label: &str, diff: &DiffMode) {
|
pub fn trace_diff_mode(label: &str, diff: &DiffMode) {
|
||||||
log::trace!("{label} - PRE STATE:");
|
tracing::trace!("{label} - PRE STATE:");
|
||||||
for (addr, state) in &diff.pre {
|
for (addr, state) in &diff.pre {
|
||||||
Self::trace_account_state(" [pre]", addr, state);
|
Self::trace_account_state(" [pre]", addr, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trace!("{label} - POST STATE:");
|
tracing::trace!("{label} - POST STATE:");
|
||||||
for (addr, state) in &diff.post {
|
for (addr, state) in &diff.post {
|
||||||
Self::trace_account_state(" [post]", addr, state);
|
Self::trace_account_state(" [post]", addr, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_account_state(prefix: &str, addr: &Address, state: &AccountState) {
|
fn trace_account_state(prefix: &str, addr: &Address, state: &AccountState) {
|
||||||
log::trace!("{prefix} 0x{addr:x}");
|
tracing::trace!("{prefix} 0x{addr:x}");
|
||||||
|
|
||||||
if let Some(balance) = &state.balance {
|
if let Some(balance) = &state.balance {
|
||||||
log::trace!("{prefix} balance: {balance}");
|
tracing::trace!("{prefix} balance: {balance}");
|
||||||
}
|
}
|
||||||
if let Some(nonce) = &state.nonce {
|
if let Some(nonce) = &state.nonce {
|
||||||
log::trace!("{prefix} nonce: {nonce}");
|
tracing::trace!("{prefix} nonce: {nonce}");
|
||||||
}
|
}
|
||||||
if let Some(code) = &state.code {
|
if let Some(code) = &state.code {
|
||||||
log::trace!("{prefix} code: {code}");
|
tracing::trace!("{prefix} code: {code}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,34 +398,75 @@ where
|
|||||||
let mut follower_state = State::<F>::new(self.config, span);
|
let mut follower_state = State::<F>::new(self.config, span);
|
||||||
follower_state.build_contracts(&mode, self.metadata)?;
|
follower_state.build_contracts(&mode, self.metadata)?;
|
||||||
|
|
||||||
for case in &self.metadata.cases {
|
for (case_idx, case) in self.metadata.cases.iter().enumerate() {
|
||||||
for input in &case.inputs {
|
// Creating a tracing span to know which case within the metadata is being executed
|
||||||
log::debug!("Starting deploying contract {}", &input.instance);
|
// and which one we're getting logs for.
|
||||||
leader_state.deploy_contracts(input, self.leader_node)?;
|
let tracing_span = tracing::span!(
|
||||||
follower_state.deploy_contracts(input, self.follower_node)?;
|
Level::INFO,
|
||||||
|
"Executing case",
|
||||||
|
case = case.name,
|
||||||
|
case_idx = case_idx
|
||||||
|
);
|
||||||
|
let _guard = tracing_span.enter();
|
||||||
|
|
||||||
|
for input in &case.inputs {
|
||||||
|
tracing::debug!("Starting deploying contract {}", &input.instance);
|
||||||
|
if let Err(err) = leader_state.deploy_contracts(input, self.leader_node) {
|
||||||
|
tracing::error!("Leader deployment failed for {}: {err}", input.instance);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
tracing::debug!("Leader deployment succeeded for {}", &input.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = follower_state.deploy_contracts(input, self.follower_node) {
|
||||||
|
tracing::error!("Follower deployment failed for {}: {err}", input.instance);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
tracing::debug!("Follower deployment succeeded for {}", &input.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::debug!("Starting executing contract {}", &input.instance);
|
||||||
|
|
||||||
log::debug!("Starting executing contract {}", &input.instance);
|
|
||||||
let (leader_receipt, _, leader_diff) =
|
let (leader_receipt, _, leader_diff) =
|
||||||
leader_state.execute_input(input, self.leader_node)?;
|
match leader_state.execute_input(input, self.leader_node) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(
|
||||||
|
"Leader execution failed for {}: {err}",
|
||||||
|
input.instance
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (follower_receipt, _, follower_diff) =
|
let (follower_receipt, _, follower_diff) =
|
||||||
follower_state.execute_input(input, self.follower_node)?;
|
match follower_state.execute_input(input, self.follower_node) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(
|
||||||
|
"Follower execution failed for {}: {err}",
|
||||||
|
input.instance
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if leader_diff == follower_diff {
|
if leader_diff == follower_diff {
|
||||||
log::debug!("State diffs match between leader and follower.");
|
tracing::debug!("State diffs match between leader and follower.");
|
||||||
} else {
|
} else {
|
||||||
log::debug!("State diffs mismatch between leader and follower.");
|
tracing::debug!("State diffs mismatch between leader and follower.");
|
||||||
Self::trace_diff_mode("Leader", &leader_diff);
|
Self::trace_diff_mode("Leader", &leader_diff);
|
||||||
Self::trace_diff_mode("Follower", &follower_diff);
|
Self::trace_diff_mode("Follower", &follower_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if leader_receipt.logs() != follower_receipt.logs() {
|
if leader_receipt.logs() != follower_receipt.logs() {
|
||||||
log::debug!("Log/event mismatch between leader and follower.");
|
tracing::debug!("Log/event mismatch between leader and follower.");
|
||||||
log::trace!("Leader logs: {:?}", leader_receipt.logs());
|
tracing::trace!("Leader logs: {:?}", leader_receipt.logs());
|
||||||
log::trace!("Follower logs: {:?}", follower_receipt.logs());
|
tracing::trace!("Follower logs: {:?}", follower_receipt.logs());
|
||||||
}
|
}
|
||||||
|
|
||||||
if leader_receipt.status() != follower_receipt.status() {
|
if leader_receipt.status() != follower_receipt.status() {
|
||||||
log::debug!(
|
tracing::debug!(
|
||||||
"Mismatch in status: leader = {}, follower = {}",
|
"Mismatch in status: leader = {}, follower = {}",
|
||||||
leader_receipt.status(),
|
leader_receipt.status(),
|
||||||
follower_receipt.status()
|
follower_receipt.status()
|
||||||
|
|||||||
+43
-13
@@ -8,10 +8,12 @@ use revive_dt_core::{
|
|||||||
Geth, Kitchensink, Platform,
|
Geth, Kitchensink, Platform,
|
||||||
driver::{Driver, State},
|
driver::{Driver, State},
|
||||||
};
|
};
|
||||||
use revive_dt_format::{corpus::Corpus, metadata::Metadata};
|
use revive_dt_format::{corpus::Corpus, metadata::MetadataFile};
|
||||||
use revive_dt_node::pool::NodePool;
|
use revive_dt_node::pool::NodePool;
|
||||||
use revive_dt_report::reporter::{Report, Span};
|
use revive_dt_report::reporter::{Report, Span};
|
||||||
use temp_dir::TempDir;
|
use temp_dir::TempDir;
|
||||||
|
use tracing::Level;
|
||||||
|
use tracing_subscriber::{EnvFilter, FmtSubscriber, fmt::format::FmtSpan};
|
||||||
|
|
||||||
static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap());
|
static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap());
|
||||||
|
|
||||||
@@ -33,7 +35,14 @@ fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn init_cli() -> anyhow::Result<Arguments> {
|
fn init_cli() -> anyhow::Result<Arguments> {
|
||||||
env_logger::init();
|
let subscriber = FmtSubscriber::builder()
|
||||||
|
.with_thread_ids(true)
|
||||||
|
.with_thread_names(true)
|
||||||
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
.with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE)
|
||||||
|
.pretty()
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
|
||||||
let mut args = Arguments::parse();
|
let mut args = Arguments::parse();
|
||||||
|
|
||||||
@@ -51,7 +60,7 @@ fn init_cli() -> anyhow::Result<Arguments> {
|
|||||||
args.temp_dir = Some(&TEMP_DIR);
|
args.temp_dir = Some(&TEMP_DIR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::info!("workdir: {}", args.directory().display());
|
tracing::info!("workdir: {}", args.directory().display());
|
||||||
|
|
||||||
ThreadPoolBuilder::new()
|
ThreadPoolBuilder::new()
|
||||||
.num_threads(args.workers)
|
.num_threads(args.workers)
|
||||||
@@ -60,21 +69,21 @@ fn init_cli() -> anyhow::Result<Arguments> {
|
|||||||
Ok(args)
|
Ok(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<Metadata>>> {
|
fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<MetadataFile>>> {
|
||||||
let mut corpora = HashMap::new();
|
let mut corpora = HashMap::new();
|
||||||
|
|
||||||
for path in &args.corpus {
|
for path in &args.corpus {
|
||||||
let corpus = Corpus::try_from_path(path)?;
|
let corpus = Corpus::try_from_path(path)?;
|
||||||
log::info!("found corpus: {}", path.display());
|
tracing::info!("found corpus: {}", path.display());
|
||||||
let tests = corpus.enumerate_tests();
|
let tests = corpus.enumerate_tests();
|
||||||
log::info!("corpus '{}' contains {} tests", &corpus.name, tests.len());
|
tracing::info!("corpus '{}' contains {} tests", &corpus.name, tests.len());
|
||||||
corpora.insert(corpus, tests);
|
corpora.insert(corpus, tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(corpora)
|
Ok(corpora)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_driver<L, F>(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()>
|
fn run_driver<L, F>(args: &Arguments, tests: &[MetadataFile], span: Span) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
L: Platform,
|
L: Platform,
|
||||||
F: Platform,
|
F: Platform,
|
||||||
@@ -84,7 +93,22 @@ where
|
|||||||
let leader_nodes = NodePool::<L::Blockchain>::new(args)?;
|
let leader_nodes = NodePool::<L::Blockchain>::new(args)?;
|
||||||
let follower_nodes = NodePool::<F::Blockchain>::new(args)?;
|
let follower_nodes = NodePool::<F::Blockchain>::new(args)?;
|
||||||
|
|
||||||
tests.par_iter().for_each(|metadata| {
|
tests.par_iter().for_each(
|
||||||
|
|MetadataFile {
|
||||||
|
content: metadata,
|
||||||
|
path: metadata_file_path,
|
||||||
|
}| {
|
||||||
|
// Starting a new tracing span for this metadata file. This allows our logs to be clear
|
||||||
|
// about which metadata file the logs belong to. We can add other information into this
|
||||||
|
// as well to be able to associate the logs with the correct metadata file and case
|
||||||
|
// that's being executed.
|
||||||
|
let tracing_span = tracing::span!(
|
||||||
|
Level::INFO,
|
||||||
|
"Running driver",
|
||||||
|
metadata_file_path = metadata_file_path.display().to_string(),
|
||||||
|
);
|
||||||
|
let _guard = tracing_span.enter();
|
||||||
|
|
||||||
let mut driver = Driver::<L, F>::new(
|
let mut driver = Driver::<L, F>::new(
|
||||||
metadata,
|
metadata,
|
||||||
args,
|
args,
|
||||||
@@ -94,24 +118,25 @@ where
|
|||||||
|
|
||||||
match driver.execute(span) {
|
match driver.execute(span) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
log::info!(
|
tracing::info!(
|
||||||
"metadata {} success",
|
"metadata {} success",
|
||||||
metadata.directory().as_ref().unwrap().display()
|
metadata.directory().as_ref().unwrap().display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::warn!(
|
tracing::warn!(
|
||||||
"metadata {} failure: {error:?}",
|
"metadata {} failure: {error:?}",
|
||||||
metadata.file_path.as_ref().unwrap().display()
|
metadata.file_path.as_ref().unwrap().display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()> {
|
fn execute_corpus(args: &Arguments, tests: &[MetadataFile], span: Span) -> anyhow::Result<()> {
|
||||||
match (&args.leader, &args.follower) {
|
match (&args.leader, &args.follower) {
|
||||||
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
||||||
run_driver::<Geth, Kitchensink>(args, tests, span)?
|
run_driver::<Geth, Kitchensink>(args, tests, span)?
|
||||||
@@ -125,7 +150,12 @@ fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::R
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_corpus(config: &Arguments, tests: &[Metadata], platform: &TestingPlatform, span: Span) {
|
fn compile_corpus(
|
||||||
|
config: &Arguments,
|
||||||
|
tests: &[MetadataFile],
|
||||||
|
platform: &TestingPlatform,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
tests.par_iter().for_each(|metadata| {
|
tests.par_iter().for_each(|metadata| {
|
||||||
for mode in &metadata.solc_modes() {
|
for mode in &metadata.solc_modes() {
|
||||||
match platform {
|
match platform {
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ rust-version.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
|
alloy-primitives = { workspace = true }
|
||||||
|
alloy-sol-types = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::metadata::Metadata;
|
use crate::metadata::MetadataFile;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||||
pub struct Corpus {
|
pub struct Corpus {
|
||||||
@@ -21,7 +21,7 @@ impl Corpus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Scan the corpus base directory and return all tests found.
|
/// Scan the corpus base directory and return all tests found.
|
||||||
pub fn enumerate_tests(&self) -> Vec<Metadata> {
|
pub fn enumerate_tests(&self) -> Vec<MetadataFile> {
|
||||||
let mut tests = Vec::new();
|
let mut tests = Vec::new();
|
||||||
collect_metadata(&self.path, &mut tests);
|
collect_metadata(&self.path, &mut tests);
|
||||||
tests
|
tests
|
||||||
@@ -34,11 +34,11 @@ impl Corpus {
|
|||||||
/// Found tests are inserted into `tests`.
|
/// Found tests are inserted into `tests`.
|
||||||
///
|
///
|
||||||
/// `path` is expected to be a directory.
|
/// `path` is expected to be a directory.
|
||||||
pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) {
|
pub fn collect_metadata(path: &Path, tests: &mut Vec<MetadataFile>) {
|
||||||
let dir_entry = match std::fs::read_dir(path) {
|
let dir_entry = match std::fs::read_dir(path) {
|
||||||
Ok(dir_entry) => dir_entry,
|
Ok(dir_entry) => dir_entry,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("failed to read dir '{}': {error}", path.display());
|
tracing::error!("failed to read dir '{}': {error}", path.display());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -47,7 +47,7 @@ pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) {
|
|||||||
let entry = match entry {
|
let entry = match entry {
|
||||||
Ok(entry) => entry,
|
Ok(entry) => entry,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("error reading dir entry: {error}");
|
tracing::error!("error reading dir entry: {error}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -59,7 +59,7 @@ pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
if let Some(metadata) = Metadata::try_from_file(&path) {
|
if let Some(metadata) = MetadataFile::try_from_file(&path) {
|
||||||
tests.push(metadata)
|
tests.push(metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+321
-4
@@ -1,10 +1,13 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
json_abi::Function,
|
hex,
|
||||||
primitives::{Address, TxKind},
|
json_abi::{Function, JsonAbi},
|
||||||
rpc::types::TransactionRequest,
|
primitives::{Address, Bytes, TxKind},
|
||||||
|
rpc::types::{TransactionInput, TransactionRequest},
|
||||||
};
|
};
|
||||||
|
use alloy_primitives::U256;
|
||||||
|
use alloy_sol_types::SolValue;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use serde::{Deserialize, de::Deserializer};
|
use serde::{Deserialize, de::Deserializer};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -44,7 +47,15 @@ pub struct ExpectedOutput {
|
|||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Calldata {
|
pub enum Calldata {
|
||||||
Single(String),
|
Single(String),
|
||||||
Compound(Vec<String>),
|
Compound(Vec<CalldataArg>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum CalldataArg {
|
||||||
|
Literal(String),
|
||||||
|
/// For example: `Contract.address`
|
||||||
|
AddressRef(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify how the contract is called.
|
/// Specify how the contract is called.
|
||||||
@@ -102,12 +113,117 @@ impl Input {
|
|||||||
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
|
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encoded_input(
|
||||||
|
&self,
|
||||||
|
deployed_abis: &HashMap<String, JsonAbi>,
|
||||||
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
) -> anyhow::Result<Bytes> {
|
||||||
|
let Method::Function(selector) = self.method else {
|
||||||
|
return Ok(Bytes::default()); // fallback or deployer — no input
|
||||||
|
};
|
||||||
|
|
||||||
|
let abi = deployed_abis
|
||||||
|
.get(&self.instance)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("ABI for instance '{}' not found", &self.instance))?;
|
||||||
|
|
||||||
|
tracing::trace!("ABI found for instance: {}", &self.instance);
|
||||||
|
|
||||||
|
// Find function by selector
|
||||||
|
let function = abi
|
||||||
|
.functions()
|
||||||
|
.find(|f| f.selector().0 == selector)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"Function with selector {:?} not found in ABI for the instance {:?}",
|
||||||
|
selector,
|
||||||
|
&self.instance
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
tracing::trace!("Functions found for instance: {}", &self.instance);
|
||||||
|
|
||||||
|
let calldata_args = match &self.calldata {
|
||||||
|
Some(Calldata::Compound(args)) => args,
|
||||||
|
_ => anyhow::bail!("Expected compound calldata for function call"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if calldata_args.len() != function.inputs.len() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Function expects {} args, but got {}",
|
||||||
|
function.inputs.len(),
|
||||||
|
calldata_args.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::trace!(
|
||||||
|
"Starting encoding ABI's parameters for instance: {}",
|
||||||
|
&self.instance
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut encoded = selector.to_vec();
|
||||||
|
|
||||||
|
for (i, param) in function.inputs.iter().enumerate() {
|
||||||
|
let arg = calldata_args.get(i).unwrap();
|
||||||
|
let encoded_arg = match arg {
|
||||||
|
CalldataArg::Literal(value) => match param.ty.as_str() {
|
||||||
|
"uint256" | "uint" => {
|
||||||
|
let val: U256 = value.parse()?;
|
||||||
|
val.abi_encode()
|
||||||
|
}
|
||||||
|
"uint24" => {
|
||||||
|
let val: u32 = value.parse()?;
|
||||||
|
(val & 0xFFFFFF).abi_encode()
|
||||||
|
}
|
||||||
|
"bool" => {
|
||||||
|
let val: bool = value.parse()?;
|
||||||
|
val.abi_encode()
|
||||||
|
}
|
||||||
|
"address" => {
|
||||||
|
let addr: Address = value.parse()?;
|
||||||
|
addr.abi_encode()
|
||||||
|
}
|
||||||
|
"string" => value.abi_encode(),
|
||||||
|
"bytes32" => {
|
||||||
|
let val = hex::decode(value.trim_start_matches("0x"))?;
|
||||||
|
let mut fixed = [0u8; 32];
|
||||||
|
fixed[..val.len()].copy_from_slice(&val);
|
||||||
|
fixed.abi_encode()
|
||||||
|
}
|
||||||
|
"uint256[]" | "uint[]" => {
|
||||||
|
let nums: Vec<u64> = serde_json::from_str(value)?;
|
||||||
|
nums.abi_encode()
|
||||||
|
}
|
||||||
|
"bytes" => {
|
||||||
|
let val = hex::decode(value.trim_start_matches("0x"))?;
|
||||||
|
val.abi_encode()
|
||||||
|
}
|
||||||
|
_ => anyhow::bail!("Unsupported type: {}", param.ty),
|
||||||
|
},
|
||||||
|
CalldataArg::AddressRef(name) => {
|
||||||
|
let contract_name = name.trim_end_matches(".address");
|
||||||
|
let addr = deployed_contracts
|
||||||
|
.get(contract_name)
|
||||||
|
.copied()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::anyhow!("Address for '{}' not found", contract_name)
|
||||||
|
})?;
|
||||||
|
addr.abi_encode()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
encoded.extend(encoded_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Bytes::from(encoded))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse this input into a legacy transaction.
|
/// Parse this input into a legacy transaction.
|
||||||
pub fn legacy_transaction(
|
pub fn legacy_transaction(
|
||||||
&self,
|
&self,
|
||||||
chain_id: u64,
|
chain_id: u64,
|
||||||
nonce: u64,
|
nonce: u64,
|
||||||
deployed_contracts: &HashMap<String, Address>,
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
deployed_abis: &HashMap<String, JsonAbi>,
|
||||||
) -> anyhow::Result<TransactionRequest> {
|
) -> anyhow::Result<TransactionRequest> {
|
||||||
let to = match self.method {
|
let to = match self.method {
|
||||||
Method::Deployer => Some(TxKind::Create),
|
Method::Deployer => Some(TxKind::Create),
|
||||||
@@ -116,6 +232,8 @@ impl Input {
|
|||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let input_data = self.encoded_input(deployed_abis, deployed_contracts)?;
|
||||||
|
|
||||||
Ok(TransactionRequest {
|
Ok(TransactionRequest {
|
||||||
from: Some(self.caller),
|
from: Some(self.caller),
|
||||||
to,
|
to,
|
||||||
@@ -123,6 +241,7 @@ impl Input {
|
|||||||
chain_id: Some(chain_id),
|
chain_id: Some(chain_id),
|
||||||
gas_price: Some(5_000_000),
|
gas_price: Some(5_000_000),
|
||||||
gas: Some(5_000_000),
|
gas: Some(5_000_000),
|
||||||
|
input: TransactionInput::new(input_data),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -135,3 +254,201 @@ fn default_instance() -> String {
|
|||||||
fn default_caller() -> Address {
|
fn default_caller() -> Address {
|
||||||
"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap()
|
"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use alloy::json_abi::JsonAbi;
|
||||||
|
use alloy_primitives::{address, keccak256};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoded_input_uint256() {
|
||||||
|
let raw_metadata = r#"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [{"name": "value", "type": "uint256"}],
|
||||||
|
"name": "store",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let parsed_abi: JsonAbi = serde_json::from_str(raw_metadata).unwrap();
|
||||||
|
let selector = keccak256("store(uint256)".as_bytes())[0..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
instance: "Contract".to_string(),
|
||||||
|
method: Method::Function(selector),
|
||||||
|
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
|
||||||
|
"42".to_string(),
|
||||||
|
)])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut deployed_abis = HashMap::new();
|
||||||
|
deployed_abis.insert("Contract".to_string(), parsed_abi);
|
||||||
|
let deployed_contracts = HashMap::new();
|
||||||
|
|
||||||
|
let encoded = input
|
||||||
|
.encoded_input(&deployed_abis, &deployed_contracts)
|
||||||
|
.unwrap();
|
||||||
|
assert!(encoded.0.starts_with(&selector));
|
||||||
|
|
||||||
|
type T = (u64,);
|
||||||
|
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
||||||
|
assert_eq!(decoded.0, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoded_input_bool() {
|
||||||
|
let raw_abi = r#"[
|
||||||
|
{
|
||||||
|
"inputs": [{"name": "flag", "type": "bool"}],
|
||||||
|
"name": "toggle",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
|
||||||
|
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
||||||
|
let selector = keccak256("toggle(bool)".as_bytes())[0..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
instance: "Contract".to_string(),
|
||||||
|
method: Method::Function(selector),
|
||||||
|
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
|
||||||
|
"true".to_string(),
|
||||||
|
)])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut abis = HashMap::new();
|
||||||
|
abis.insert("Contract".to_string(), parsed_abi);
|
||||||
|
let contracts = HashMap::new();
|
||||||
|
|
||||||
|
let encoded = input.encoded_input(&abis, &contracts).unwrap();
|
||||||
|
assert!(encoded.0.starts_with(&selector));
|
||||||
|
|
||||||
|
type T = (bool,);
|
||||||
|
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
||||||
|
assert_eq!(decoded.0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoded_input_string() {
|
||||||
|
let raw_abi = r#"[
|
||||||
|
{
|
||||||
|
"inputs": [{"name": "msg", "type": "string"}],
|
||||||
|
"name": "echo",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
|
||||||
|
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
||||||
|
let selector = keccak256("echo(string)".as_bytes())[0..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
instance: "Contract".to_string(),
|
||||||
|
method: Method::Function(selector),
|
||||||
|
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
|
||||||
|
"hello".to_string(),
|
||||||
|
)])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut abis = HashMap::new();
|
||||||
|
abis.insert("Contract".to_string(), parsed_abi);
|
||||||
|
let contracts = HashMap::new();
|
||||||
|
|
||||||
|
let encoded = input.encoded_input(&abis, &contracts).unwrap();
|
||||||
|
assert!(encoded.0.starts_with(&selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoded_input_uint256_array() {
|
||||||
|
let raw_abi = r#"[
|
||||||
|
{
|
||||||
|
"inputs": [{"name": "arr", "type": "uint256[]"}],
|
||||||
|
"name": "sum",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
|
||||||
|
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
||||||
|
let selector = keccak256("sum(uint256[])".as_bytes())[0..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
instance: "Contract".to_string(),
|
||||||
|
method: Method::Function(selector),
|
||||||
|
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
|
||||||
|
"[1,2,3]".to_string(),
|
||||||
|
)])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut abis = HashMap::new();
|
||||||
|
abis.insert("Contract".to_string(), parsed_abi);
|
||||||
|
let contracts = HashMap::new();
|
||||||
|
|
||||||
|
let encoded = input.encoded_input(&abis, &contracts).unwrap();
|
||||||
|
assert!(encoded.0.starts_with(&selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoded_input_address() {
|
||||||
|
let raw_abi = r#"[
|
||||||
|
{
|
||||||
|
"inputs": [{"name": "recipient", "type": "address"}],
|
||||||
|
"name": "send",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
|
||||||
|
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
||||||
|
let selector = keccak256("send(address)".as_bytes())[0..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
instance: "Contract".to_string(),
|
||||||
|
method: Method::Function(selector),
|
||||||
|
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
|
||||||
|
"0x1000000000000000000000000000000000000001".to_string(),
|
||||||
|
)])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut abis = HashMap::new();
|
||||||
|
abis.insert("Contract".to_string(), parsed_abi);
|
||||||
|
let contracts = HashMap::new();
|
||||||
|
|
||||||
|
let encoded = input.encoded_input(&abis, &contracts).unwrap();
|
||||||
|
assert!(encoded.0.starts_with(&selector));
|
||||||
|
|
||||||
|
type T = (alloy_primitives::Address,);
|
||||||
|
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
decoded.0,
|
||||||
|
address!("0x1000000000000000000000000000000000000001")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fs::{File, read_to_string},
|
fs::{File, read_to_string},
|
||||||
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,6 +16,29 @@ pub const METADATA_FILE_EXTENSION: &str = "json";
|
|||||||
pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol";
|
pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol";
|
||||||
pub const SOLIDITY_CASE_COMMENT_MARKER: &str = "//!";
|
pub const SOLIDITY_CASE_COMMENT_MARKER: &str = "//!";
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)]
|
||||||
|
pub struct MetadataFile {
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub content: Metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetadataFile {
|
||||||
|
pub fn try_from_file(path: &Path) -> Option<Self> {
|
||||||
|
Metadata::try_from_file(path).map(|metadata| Self {
|
||||||
|
path: path.to_owned(),
|
||||||
|
content: metadata,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for MetadataFile {
|
||||||
|
type Target = Metadata;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)]
|
#[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub cases: Vec<Case>,
|
pub cases: Vec<Case>,
|
||||||
@@ -35,7 +59,7 @@ impl Metadata {
|
|||||||
.filter_map(|mode| match mode {
|
.filter_map(|mode| match mode {
|
||||||
Mode::Solidity(solc_mode) => Some(solc_mode),
|
Mode::Solidity(solc_mode) => Some(solc_mode),
|
||||||
Mode::Unknown(mode) => {
|
Mode::Unknown(mode) => {
|
||||||
log::debug!("compiler: ignoring unknown mode '{mode}'");
|
tracing::debug!("compiler: ignoring unknown mode '{mode}'");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -90,7 +114,7 @@ impl Metadata {
|
|||||||
assert!(path.is_file(), "not a file: {}", path.display());
|
assert!(path.is_file(), "not a file: {}", path.display());
|
||||||
|
|
||||||
let Some(file_extension) = path.extension() else {
|
let Some(file_extension) = path.extension() else {
|
||||||
log::debug!("skipping corpus file: {}", path.display());
|
tracing::debug!("skipping corpus file: {}", path.display());
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,14 +126,14 @@ impl Metadata {
|
|||||||
return Self::try_from_solidity(path);
|
return Self::try_from_solidity(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("ignoring invalid corpus file: {}", path.display());
|
tracing::debug!("ignoring invalid corpus file: {}", path.display());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_from_json(path: &Path) -> Option<Self> {
|
fn try_from_json(path: &Path) -> Option<Self> {
|
||||||
let file = File::open(path)
|
let file = File::open(path)
|
||||||
.inspect_err(|error| {
|
.inspect_err(|error| {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"opening JSON test metadata file '{}' error: {error}",
|
"opening JSON test metadata file '{}' error: {error}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
@@ -122,7 +146,7 @@ impl Metadata {
|
|||||||
Some(metadata)
|
Some(metadata)
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"parsing JSON test metadata file '{}' error: {error}",
|
"parsing JSON test metadata file '{}' error: {error}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
@@ -134,7 +158,7 @@ impl Metadata {
|
|||||||
fn try_from_solidity(path: &Path) -> Option<Self> {
|
fn try_from_solidity(path: &Path) -> Option<Self> {
|
||||||
let spec = read_to_string(path)
|
let spec = read_to_string(path)
|
||||||
.inspect_err(|error| {
|
.inspect_err(|error| {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"opening JSON test metadata file '{}' error: {error}",
|
"opening JSON test metadata file '{}' error: {error}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
@@ -163,7 +187,7 @@ impl Metadata {
|
|||||||
Some(metadata)
|
Some(metadata)
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"parsing Solidity test metadata file '{}' error: '{error}' from data: {spec}",
|
"parsing Solidity test metadata file '{}' error: '{error}' from data: {spec}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ rust-version.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|||||||
@@ -51,13 +51,13 @@ impl TokioRuntime {
|
|||||||
let nonce_task = spawn(interaction::<Nonce>(nonce_receiver));
|
let nonce_task = spawn(interaction::<Nonce>(nonce_receiver));
|
||||||
|
|
||||||
if let Err(error) = transaction_task.await {
|
if let Err(error) = transaction_task.await {
|
||||||
log::error!("tokio transaction task failed: {error}");
|
tracing::error!("tokio transaction task failed: {error}");
|
||||||
}
|
}
|
||||||
if let Err(error) = trace_task.await {
|
if let Err(error) = trace_task.await {
|
||||||
log::error!("tokio trace transaction task failed: {error}");
|
tracing::error!("tokio trace transaction task failed: {error}");
|
||||||
}
|
}
|
||||||
if let Err(error) = nonce_task.await {
|
if let Err(error) = nonce_task.await {
|
||||||
log::error!("tokio nonce task failed: {error}");
|
tracing::error!("tokio nonce task failed: {error}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ rust-version.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
tokio = { workspace = true }
|
||||||
|
|
||||||
revive-dt-node-interaction = { workspace = true }
|
revive-dt-node-interaction = { workspace = true }
|
||||||
revive-dt-config = { workspace = true }
|
revive-dt-config = { workspace = true }
|
||||||
|
|||||||
+79
-7
@@ -1,6 +1,7 @@
|
|||||||
//! The go-ethereum node implementation.
|
//! The go-ethereum node implementation.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
fs::{File, create_dir_all, remove_dir_all},
|
fs::{File, create_dir_all, remove_dir_all},
|
||||||
io::{BufRead, BufReader, Read, Write},
|
io::{BufRead, BufReader, Read, Write},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
@@ -15,7 +16,7 @@ use std::{
|
|||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
network::EthereumWallet,
|
network::EthereumWallet,
|
||||||
primitives::{Address, map::HashMap},
|
primitives::Address,
|
||||||
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt, TransactionRequest,
|
TransactionReceipt, TransactionRequest,
|
||||||
@@ -159,14 +160,84 @@ impl EthereumNode for Instance {
|
|||||||
let wallet = self.wallet.clone();
|
let wallet = self.wallet.clone();
|
||||||
|
|
||||||
execute_transaction(Box::pin(async move {
|
execute_transaction(Box::pin(async move {
|
||||||
Ok(ProviderBuilder::new()
|
let outer_span = tracing::debug_span!("Submitting transaction", ?transaction,);
|
||||||
|
let _outer_guard = outer_span.enter();
|
||||||
|
|
||||||
|
let provider = ProviderBuilder::new()
|
||||||
.wallet(wallet)
|
.wallet(wallet)
|
||||||
.connect(&connection_string)
|
.connect(&connection_string)
|
||||||
.await?
|
.await?;
|
||||||
.send_transaction(transaction)
|
|
||||||
.await?
|
let pending_transaction = provider.send_transaction(transaction).await?;
|
||||||
.get_receipt()
|
let transaction_hash = pending_transaction.tx_hash();
|
||||||
.await?)
|
|
||||||
|
let span = tracing::info_span!("Awaiting transaction receipt", ?transaction_hash);
|
||||||
|
let _guard = span.enter();
|
||||||
|
|
||||||
|
// The following is a fix for the "transaction indexing is in progress" error that we
|
||||||
|
// used to get. You can find more information on this in the following GH issue in geth
|
||||||
|
// https://github.com/ethereum/go-ethereum/issues/28877. To summarize what's going on,
|
||||||
|
// before we can get the receipt of the transaction it needs to have been indexed by the
|
||||||
|
// node's indexer. Just because the transaction has been confirmed it doesn't mean that
|
||||||
|
// it has been indexed. When we call alloy's `get_receipt` it checks if the transaction
|
||||||
|
// was confirmed. If it has been, then it will call `eth_getTransactionReceipt` method
|
||||||
|
// which _might_ return the above error if the tx has not yet been indexed yet. So, we
|
||||||
|
// need to implement a retry mechanism for the receipt to keep retrying to get it until
|
||||||
|
// it eventually works, but we only do that if the error we get back is the "transaction
|
||||||
|
// indexing is in progress" error or if the receipt is None.
|
||||||
|
//
|
||||||
|
// At the moment we do not allow for the 60 seconds to be modified and we take it as
|
||||||
|
// being an implementation detail that's invisible to anything outside of this module.
|
||||||
|
//
|
||||||
|
// We allow a total of 60 retries for getting the receipt with one second between each
|
||||||
|
// retry and the next which means that we allow for a total of 60 seconds of waiting
|
||||||
|
// before we consider that we're unable to get the transaction receipt.
|
||||||
|
let mut retries = 0;
|
||||||
|
loop {
|
||||||
|
match provider.get_transaction_receipt(*transaction_hash).await {
|
||||||
|
Ok(Some(receipt)) => {
|
||||||
|
tracing::info!("Obtained the transaction receipt");
|
||||||
|
break Ok(receipt);
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
if retries == 60 {
|
||||||
|
tracing::error!(
|
||||||
|
"Polled for transaction receipt for 60 seconds but failed to get it"
|
||||||
|
);
|
||||||
|
break Err(anyhow::anyhow!("Failed to get the transaction receipt"));
|
||||||
|
} else {
|
||||||
|
tracing::trace!(
|
||||||
|
retries,
|
||||||
|
"Sleeping for 1 second and trying to get the receipt again"
|
||||||
|
);
|
||||||
|
retries += 1;
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
let error_string = error.to_string();
|
||||||
|
if error_string.contains("transaction indexing is in progress") {
|
||||||
|
if retries == 60 {
|
||||||
|
tracing::error!(
|
||||||
|
"Polled for transaction receipt for 60 seconds but failed to get it"
|
||||||
|
);
|
||||||
|
break Err(error.into());
|
||||||
|
} else {
|
||||||
|
tracing::trace!(
|
||||||
|
retries,
|
||||||
|
"Sleeping for 1 second and trying to get the receipt again"
|
||||||
|
);
|
||||||
|
retries += 1;
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break Err(error.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +338,7 @@ impl Node for Instance {
|
|||||||
|
|
||||||
impl Drop for Instance {
|
impl Drop for Instance {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
tracing::info!(id = self.id, "Dropping node");
|
||||||
if let Some(child) = self.handle.as_mut() {
|
if let Some(child) = self.handle.as_mut() {
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
fs::create_dir_all,
|
fs::create_dir_all,
|
||||||
io::BufRead,
|
io::BufRead,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
@@ -13,7 +14,7 @@ use std::{
|
|||||||
use alloy::{
|
use alloy::{
|
||||||
hex,
|
hex,
|
||||||
network::EthereumWallet,
|
network::EthereumWallet,
|
||||||
primitives::{Address, map::HashMap},
|
primitives::Address,
|
||||||
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
providers::{Provider, ProviderBuilder, ext::DebugApi},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt,
|
TransactionReceipt,
|
||||||
@@ -251,7 +252,10 @@ impl EthereumNode for KitchensinkNode {
|
|||||||
let url = self.rpc_url.clone();
|
let url = self.rpc_url.clone();
|
||||||
let wallet = self.wallet.clone();
|
let wallet = self.wallet.clone();
|
||||||
|
|
||||||
execute_transaction(Box::pin(async move {
|
tracing::debug!("Submitting transaction: {transaction:#?}");
|
||||||
|
|
||||||
|
tracing::info!("Submitting tx to kitchensink");
|
||||||
|
let receipt = execute_transaction(Box::pin(async move {
|
||||||
Ok(ProviderBuilder::new()
|
Ok(ProviderBuilder::new()
|
||||||
.wallet(wallet)
|
.wallet(wallet)
|
||||||
.connect(&url)
|
.connect(&url)
|
||||||
@@ -260,7 +264,9 @@ impl EthereumNode for KitchensinkNode {
|
|||||||
.await?
|
.await?
|
||||||
.get_receipt()
|
.get_receipt()
|
||||||
.await?)
|
.await?)
|
||||||
}))
|
}));
|
||||||
|
tracing::info!(?receipt, "Submitted tx to kitchensink");
|
||||||
|
receipt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_transaction(
|
fn trace_transaction(
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ where
|
|||||||
|
|
||||||
fn spawn_node<T: Node + Send>(args: &Arguments, genesis: String) -> anyhow::Result<T> {
|
fn spawn_node<T: Node + Send>(args: &Arguments, genesis: String) -> anyhow::Result<T> {
|
||||||
let mut node = T::new(args);
|
let mut node = T::new(args);
|
||||||
log::info!("starting node: {}", node.connection_string());
|
tracing::info!("starting node: {}", node.connection_string());
|
||||||
node.spawn(genesis)?;
|
node.spawn(genesis)?;
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ revive-dt-config = { workspace = true }
|
|||||||
revive-dt-format = { workspace = true }
|
revive-dt-format = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
revive-solc-json-interface = { workspace = true }
|
revive-solc-json-interface = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ impl Report {
|
|||||||
let file = File::create(&path).context(path.display().to_string())?;
|
let file = File::create(&path).context(path.display().to_string())?;
|
||||||
serde_json::to_writer_pretty(file, &self)?;
|
serde_json::to_writer_pretty(file, &self)?;
|
||||||
|
|
||||||
log::info!("report written to: {}", path.display());
|
tracing::info!("report written to: {}", path.display());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ rust-version.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
log = { workspace = true }
|
tracing = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ pub(crate) fn get_or_download(
|
|||||||
|
|
||||||
let mut cache = SOLC_CACHER.lock().unwrap();
|
let mut cache = SOLC_CACHER.lock().unwrap();
|
||||||
if cache.contains(&target_file) {
|
if cache.contains(&target_file) {
|
||||||
log::debug!("using cached solc: {}", target_file.display());
|
tracing::debug!("using cached solc: {}", target_file.display());
|
||||||
return Ok(target_file);
|
return Ok(target_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +37,10 @@ pub(crate) fn get_or_download(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn download_to_file(path: &Path, downloader: &GHDownloader) -> anyhow::Result<()> {
|
fn download_to_file(path: &Path, downloader: &GHDownloader) -> anyhow::Result<()> {
|
||||||
log::info!("caching file: {}", path.display());
|
tracing::info!("caching file: {}", path.display());
|
||||||
|
|
||||||
let Ok(file) = File::create_new(path) else {
|
let Ok(file) = File::create_new(path) else {
|
||||||
log::debug!("cache file already exists: {}", path.display());
|
tracing::debug!("cache file already exists: {}", path.display());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ impl GHDownloader {
|
|||||||
/// Errors out if the download fails or the digest of the downloaded file
|
/// Errors out if the download fails or the digest of the downloaded file
|
||||||
/// mismatches the expected digest from the release [List].
|
/// mismatches the expected digest from the release [List].
|
||||||
pub fn download(&self) -> anyhow::Result<Vec<u8>> {
|
pub fn download(&self) -> anyhow::Result<Vec<u8>> {
|
||||||
log::info!("downloading solc: {self:?}");
|
tracing::info!("downloading solc: {self:?}");
|
||||||
let expected_digest = List::download(self.list)?
|
let expected_digest = List::download(self.list)?
|
||||||
.builds
|
.builds
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
Reference in New Issue
Block a user