diff --git a/.agents/skills/gravity-oracle-demo/SKILL.md b/.agents/skills/gravity-oracle-demo/SKILL.md new file mode 100644 index 000000000..922265ac8 --- /dev/null +++ b/.agents/skills/gravity-oracle-demo/SKILL.md @@ -0,0 +1,29 @@ +--- +name: gravity-oracle-demo +description: Run, demo, or debug the Gravity Binance and Polymarket Oracle E2E suites. +--- + +# Gravity Oracle Demo + +Use `gravity_e2e/docs/ORACLE_E2E.md` as the canonical suite matrix and +runbook. Do not duplicate its commands or revision table here. + +## Routing + +- Use `oracle_demo` for deterministic review or the combined local frontend. +- Use `polymarket_mock` for three-outcome match settlement and claim behavior. +- Use `binance_price_feed_multivalidator` for explicitly approved live Binance + validation and voting-power quorum. + +## Safety + +- Ask before public API or RPC traffic unless the user approved that exact run. +- Never commit credentials, `.env` files, private RPC URLs, user-specific + absolute paths, generated runtime config, or cluster artifacts. +- Use `--force-init` after changing genesis or a pinned contracts revision. +- Stop clusters started by the current task unless `--keep-running` was + explicitly requested. + +For real Polymarket mirrors, require a reviewed manifest with frozen rules, +condition and question IDs, CTF address, outcome labels, slot mapping, source +block range, and metadata hashes. diff --git a/.agents/workflows/build-and-test.md b/.agents/workflows/build-and-test.md index e03cf8f3a..3d5c31df3 100644 --- a/.agents/workflows/build-and-test.md +++ b/.agents/workflows/build-and-test.md @@ -131,7 +131,14 @@ Genesis artifacts are cached in `cluster_test_cases//artifacts/`. Use `-- --- -## 4. Bridge E2E Test Details +## 4. Oracle E2E + +Use `gravity_e2e/docs/ORACLE_E2E.md` for the canonical suite matrix, commands, +live-network approval boundary, frontend mode, and pinned revisions. + +--- + +## 5. Bridge E2E Test Details Suite directory: `gravity_e2e/cluster_test_cases/bridge/` @@ -162,7 +169,7 @@ Suite directory: `gravity_e2e/cluster_test_cases/bridge/` --- -## 5. Running Contract Unit Tests +## 6. Running Contract Unit Tests Working directory: `gravity_chain_core_contracts` @@ -179,4 +186,4 @@ forge test --match-path test/unit/integration/ConsensusEngineFlow.t.sol -vvv Run specific test function: ```bash forge test --match-test testBridgeFlow -vvv -``` \ No newline at end of file +``` diff --git a/.gitignore b/.gitignore index 184015286..a46bb93f8 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ lib/ # Hardhat (if ever used) artifacts/ +mock_polymarket_metadata.json cache/ typechain-types/ diff --git a/Cargo.lock b/Cargo.lock index db20a623e..b51befc3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "abstract-domain-derive" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "proc-macro2", "quote", @@ -50,7 +50,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "generic-array", ] @@ -62,7 +62,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -151,15 +151,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.30" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" +checksum = "c36ddb69f5e41407e7a93aead3480f7c8ff076e73d01a951ae8f7ea4542c1ca0" dependencies = [ "alloy-primitives", "alloy-rlp", "num_enum", + "phf 0.14.0", "serde", - "strum 0.27.2", ] [[package]] @@ -168,13 +168,40 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59094911f05dbff1cf5b29046a00ef26452eccc8d47136d50a47c0cf22f00c85" dependencies = [ - "alloy-eips", + "alloy-eips 1.0.37", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 1.0.37", + "alloy-trie", + "alloy-tx-macros 1.0.37", + "auto_impl", + "c-kzg", + "derive_more 2.1.1", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1 0.30.0", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-consensus" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83447eeb17816e172f1dfc0db1f9dc0b7c5d069bd1f7cecbecceb382bf931015" +dependencies = [ + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 2.0.5", "alloy-trie", - "alloy-tx-macros", + "alloy-tx-macros 2.0.5", "auto_impl", + "borsh", "c-kzg", "derive_more 2.1.1", "either", @@ -194,11 +221,25 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "903cb8f728107ca27c816546f15be38c688df3c381d7bd1a4a9f215effc1ddb4" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.0.37", + "alloy-eips 1.0.37", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.37", + "serde", +] + +[[package]] +name = "alloy-consensus-any" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5406343e306856dc2be762700e98a16904de45dee14a07f233e742ce68daff2f" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 2.0.5", "serde", ] @@ -208,16 +249,16 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03df5cb3b428ac96b386ad64c11d5c6e87a5505682cf1fbd6f8f773e9eda04f6" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.0.37", "alloy-dyn-abi", "alloy-json-abi", - "alloy-network", - "alloy-network-primitives", + "alloy-network 1.0.37", + "alloy-network-primitives 1.0.37", "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", + "alloy-provider 1.0.37", + "alloy-rpc-types-eth 1.0.37", "alloy-sol-types", - "alloy-transport", + "alloy-transport 1.0.41", "futures", "futures-util", "serde_json", @@ -226,9 +267,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f56873f3cac7a2c63d8e98a4314b8311aa96adb1a0f82ae923eb2119809d2c" +checksum = "a475bb02d9cef2dbb99065c1664ab3fe1f9352e21d6d5ed3f02cdbfc06ed1abc" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -238,7 +279,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.7.14", + "winnow 1.0.4", ] [[package]] @@ -256,29 +297,59 @@ dependencies = [ [[package]] name = "alloy-eip2930" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" +checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" dependencies = [ "alloy-primitives", "alloy-rlp", + "borsh", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" dependencies = [ "alloy-primitives", "alloy-rlp", + "borsh", "k256", "serde", "serde_with", "thiserror 2.0.18", ] +[[package]] +name = "alloy-eip7928" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "once_cell", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-eip7928" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b12337f74cbfa451cb04dac173974814a6ff463079e1793aa09600ba8813ab" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "once_cell", + "serde", + "thiserror 2.0.18", +] + [[package]] name = "alloy-eips" version = "1.0.37" @@ -290,8 +361,32 @@ dependencies = [ "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.0.37", + "auto_impl", + "c-kzg", + "derive_more 2.1.1", + "either", + "serde", + "serde_with", + "sha2 0.10.9", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-eips" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dca4c89ace90684b4b77366d00631ed498c9af962079af2a5dbc593a0618a77" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928 0.3.7", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 2.0.5", "auto_impl", + "borsh", "c-kzg", "derive_more 2.1.1", "either", @@ -300,50 +395,48 @@ dependencies = [ "serde", "serde_with", "sha2 0.10.9", - "thiserror 2.0.18", ] [[package]] name = "alloy-evm" -version = "0.21.3" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1bfade4de9f464719b5aca30cf5bb02b9fda7036f0cf43addc3a0e66a0340c" +checksum = "a6e494529570a4d25eb4d1a7456d8f969c3202aceaf703e4006cec5f730aee96" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-hardforks", "alloy-primitives", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-sol-types", "auto_impl", "derive_more 2.1.1", - "op-alloy-consensus", - "op-alloy-rpc-types-engine", - "op-revm", "revm", "thiserror 2.0.18", + "tracing", ] [[package]] name = "alloy-genesis" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1421f6c9d15e5b86afbfe5865ca84dea3b9f77173a0963c1a2ee4e626320ada9" +checksum = "ab0e0fe9e6d1120ad7bb9254c3fc2b9bc80a8df42a033fb626be6559c13d5153" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-serde", + "alloy-serde 2.0.5", "alloy-trie", + "borsh", "serde", "serde_with", ] [[package]] name = "alloy-hardforks" -version = "0.3.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "889eb3949b58368a09d4f16931c660275ef5fb08e5fbd4a96573b19c7085c41f" +checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -355,9 +448,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "125a1c373261b252e53e04d6e92c37d881833afc1315fceab53fd46045695640" +checksum = "7c36c9d7f9021601b04bfef14a4b64849f6d73116a4e91e071d7fbfe10247901" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -380,22 +473,63 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-json-rpc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0a82e56b1843bce483942d54fcadea92e676f1bde162e93c7d3b621fabc4e1" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "http 1.4.0", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", +] + [[package]] name = "alloy-network" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f59a869fa4b4c3a7f08b1c8cb79aec61c29febe6e24a24fe0fcfded8a9b5703" dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", + "alloy-consensus 1.0.37", + "alloy-consensus-any 1.0.37", + "alloy-eips 1.0.37", + "alloy-json-rpc 1.0.41", + "alloy-network-primitives 1.0.37", + "alloy-primitives", + "alloy-rpc-types-any 1.0.37", + "alloy-rpc-types-eth 1.0.37", + "alloy-serde 1.0.37", + "alloy-signer 1.0.41", + "alloy-sol-types", + "async-trait", + "auto_impl", + "derive_more 2.1.1", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-network" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7db7b095b0b1db1d18ce7e91dcd2e82007f2d52bfb8125e6b64633a74a06bc3" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-consensus-any 2.0.5", + "alloy-eips 2.0.5", + "alloy-json-rpc 2.0.5", + "alloy-network-primitives 2.0.5", "alloy-primitives", - "alloy-rpc-types-any", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", + "alloy-rpc-types-any 2.0.5", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", + "alloy-signer 2.0.5", "alloy-sol-types", "async-trait", "auto_impl", @@ -412,27 +546,41 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46e9374c667c95c41177602ebe6f6a2edd455193844f011d973d374b65501b38" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.0.37", + "alloy-eips 1.0.37", "alloy-primitives", - "alloy-serde", + "alloy-serde 1.0.37", + "serde", +] + +[[package]] +name = "alloy-network-primitives" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd28d9bfd11729037d194f2b1d43db8642eb3f342032691f4ca96bb745479c3c" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-primitives", + "alloy-serde 2.0.5", "serde", ] [[package]] name = "alloy-primitives" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9485c56de23438127a731a6b4c87803d49faf1a7068dcd1d8768aca3a9edb9" +checksum = "4885c1409b6936c4898e646ef58baf6ec54edaf6d8179f79df805a7b85b7cf3e" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more 2.1.1", - "foldhash 0.1.5", - "getrandom 0.3.4", - "hashbrown 0.15.5", + "fixed-cache", + "foldhash 0.2.0", + "getrandom 0.4.3", + "hashbrown 0.17.1", "indexmap 2.13.0", "itoa", "k256", @@ -440,11 +588,12 @@ dependencies = [ "paste", "proptest", "rand 0.9.2", + "rapidhash", "ruint", "rustc-hash 2.1.1", + "secp256k1 0.31.1", "serde", - "sha3 0.10.8", - "tiny-keccak", + "sha3 0.11.0", ] [[package]] @@ -454,32 +603,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77818b7348bd5486491a5297579dbfe5f706a81f8e1f5976393025f1e22a7c7d" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", + "alloy-consensus 1.0.37", + "alloy-eips 1.0.37", + "alloy-json-rpc 1.0.41", + "alloy-network 1.0.37", + "alloy-network-primitives 1.0.37", + "alloy-primitives", + "alloy-rpc-client 1.0.37", + "alloy-rpc-types-eth 1.0.37", + "alloy-signer 1.0.41", + "alloy-sol-types", + "alloy-transport 1.0.41", + "alloy-transport-http 1.0.37", + "async-stream", + "async-trait", + "auto_impl", + "dashmap 6.2.1", + "either", + "futures", + "futures-utils-wasm", + "lru 0.13.0", + "parking_lot 0.12.5", + "pin-project", + "reqwest 0.12.28", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-provider" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8955ab30418343de57b356de2ea60200f9fb8016a7ea3bc7f5c6176f01a8b1cf" +dependencies = [ + "alloy-chains", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-json-rpc 2.0.5", + "alloy-network 2.0.5", + "alloy-network-primitives 2.0.5", "alloy-primitives", "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types-eth", - "alloy-signer", + "alloy-rpc-client 2.0.5", + "alloy-rpc-types-debug", + "alloy-rpc-types-eth 2.0.5", + "alloy-rpc-types-trace", + "alloy-signer 2.0.5", "alloy-sol-types", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 2.0.5", + "alloy-transport-http 2.0.5", "alloy-transport-ipc", "alloy-transport-ws", "async-stream", "async-trait", "auto_impl", - "dashmap 6.1.0", + "dashmap 6.2.1", "either", "futures", "futures-utils-wasm", - "lru 0.13.0", + "lru 0.16.4", "parking_lot 0.12.5", "pin-project", - "reqwest 0.12.28", + "reqwest 0.13.1", "serde", "serde_json", "thiserror 2.0.18", @@ -491,13 +681,13 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.0.41" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e45a68423e732900a0c824b8e22237db461b79d2e472dd68b7547c16104427" +checksum = "7cd85cfea1fa8ebd20d3475e961fe3a3624c0eb4659ea137715c0c83c8aeaff0" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 2.0.5", "alloy-primitives", - "alloy-transport", + "alloy-transport 2.0.5", "auto_impl", "bimap", "futures", @@ -539,16 +729,39 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2430d5623e428dd012c6c2156ae40b7fe638d6fca255e3244e0fba51fa698e93" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 1.0.41", + "alloy-primitives", + "alloy-transport 1.0.41", + "alloy-transport-http 1.0.37", + "futures", + "pin-project", + "reqwest 0.12.28", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.5.3", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-client" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f461f091dc8f657e73b5dea18fd63d5c7049720cd252f1eade4a7ebed6a7e1" +dependencies = [ + "alloy-json-rpc 2.0.5", "alloy-primitives", "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 2.0.5", + "alloy-transport-http 2.0.5", "alloy-transport-ipc", "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.28", + "reqwest 0.13.1", "serde", "serde_json", "tokio", @@ -564,19 +777,31 @@ name = "alloy-rpc-types" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e131624d08a25cfc40557041e7dc42e1182fa1153e7592d120f769a1edce56" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth 1.0.37", + "alloy-serde 1.0.37", + "serde", +] + +[[package]] +name = "alloy-rpc-types" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052c031d1f7c5611997056bbcb8814e5cbf20f7efeee8c3de690555172038cf2" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "serde", ] [[package]] name = "alloy-rpc-types-admin" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59407723b1850ebaa49e46d10c2ba9c10c10b3aedf2f7e97015ee23c3f4e639" +checksum = "ef669b370940e7945a3a384cc4024038cd69ee658b71270d59c20b78dd8d20d4" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -586,13 +811,13 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65e3266095e6d8e8028aab5f439c6b8736c5147314f7e606c61597e014cb8a0" +checksum = "2ff111a54268dc0bbd3b17f98571a7e27cc661dc081ad2999d91888647eb2e11" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "serde", ] @@ -602,20 +827,36 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07429a1099cd17227abcddb91b5e38c960aaeb02a6967467f5bb561fbe716ac6" dependencies = [ - "alloy-consensus-any", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-consensus-any 1.0.37", + "alloy-rpc-types-eth 1.0.37", + "alloy-serde 1.0.37", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6561ed4759c974d9c144500a59e3fb8c1d87327a12900d5ce455c0cae6dcb6" +dependencies = [ + "alloy-consensus-any 2.0.5", + "alloy-network-primitives 2.0.5", + "alloy-primitives", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", + "serde", + "serde_json", ] [[package]] name = "alloy-rpc-types-beacon" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e0e876b20eb9debf316d3e875536f389070635250f22b5a678cf4632a3e0cf" +checksum = "9a62f6ce2d95f59ed310bd90d5fd1566a29d1ec45cc219abbc5dcc807d31f136" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", + "derive_more 2.1.1", "ethereum_ssz", "ethereum_ssz_derive", "serde", @@ -628,11 +869,12 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.0.41" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388cf910e66bd4f309a81ef746dcf8f9bca2226e3577890a8d56c5839225cf46" +checksum = "5ff0a296b58194c7464aa56f2bdad065c5a24b43a6de5d62b8a985ae3969ecd0" dependencies = [ "alloy-primitives", + "alloy-rlp", "derive_more 2.1.1", "serde", "serde_with", @@ -640,19 +882,19 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222ecadcea6aac65e75e32b6735635ee98517aa63b111849ee01ae988a71d685" +checksum = "7eba59e1c069f168a01982f42a57797736923b76aa854194df4930be17867e1c" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 2.0.5", "derive_more 2.1.1", "ethereum_ssz", "ethereum_ssz_derive", - "jsonwebtoken 9.3.1", + "jsonwebtoken 10.4.0", "rand 0.8.5", "serde", "strum 0.27.2", @@ -664,13 +906,34 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db46b0901ee16bbb68d986003c66dcb74a12f9d9b3c44f8e85d51974f2458f0f" dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-network-primitives", + "alloy-consensus 1.0.37", + "alloy-consensus-any 1.0.37", + "alloy-eips 1.0.37", + "alloy-network-primitives 1.0.37", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 1.0.37", + "alloy-sol-types", + "itertools 0.14.0", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175a2a5b6017d7f61b5e4b800d21215fe8e94fe729d00828e13bb6d93dcf3492" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-consensus-any 2.0.5", + "alloy-eips 2.0.5", + "alloy-network-primitives 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 2.0.5", "alloy-sol-types", "itertools 0.14.0", "serde", @@ -681,28 +944,28 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a60d4baadd3f278faa4e2305cca095dfd4ab286e071b768ff09181d8ae215" +checksum = "ed1004c1d68bfaee001712f83356f88031ab74a727b8560fb7fc738d1281ebe5" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "serde", "serde_json", ] [[package]] name = "alloy-rpc-types-trace" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f10620724bd45f80c79668a8cdbacb6974f860686998abce28f6196ae79444" +checksum = "514b4b1ce3354f65067b4fc7eb75358e0f2ec8be3340c96dea65d6894f9ca435" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "serde", "serde_json", "thiserror 2.0.18", @@ -710,13 +973,13 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.0.37" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864f41befa90102d4e02327679699a7e9510930e2924c529e31476086609fa89" +checksum = "76e34a42ebb4a71ab0bfdebc6d2f3c7bf809f01edf154d08fed159d10d1ef1d4" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "serde", ] @@ -731,6 +994,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-serde" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc21a8772af7d78bba286726aa245bd2ff81cd9abe230afea2e91578996831c9" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-signer" version = "1.0.41" @@ -746,31 +1020,65 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "alloy-signer" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ffbce94c50dd9d4d1f83e044c5595bbd3ada981bd3057ce28b3a5470e77385d" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "either", + "elliptic-curve", + "k256", + "thiserror 2.0.18", +] + [[package]] name = "alloy-signer-local" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6006c4cbfa5d08cadec1fcabea6cb56dc585a30a9fce40bcf81e307d6a71c8e" dependencies = [ - "alloy-consensus", - "alloy-network", + "alloy-consensus 1.0.37", + "alloy-network 1.0.37", "alloy-primitives", - "alloy-signer", + "alloy-signer 1.0.41", "async-trait", "k256", "rand 0.8.5", "thiserror 2.0.18", ] +[[package]] +name = "alloy-signer-local" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48366d2c42b8d95ef951101bafa28486590f21b7a1e68b6b2d069746557bbe3" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-network 2.0.5", + "alloy-primitives", + "alloy-signer 2.0.5", + "async-trait", + "coins-bip32", + "coins-bip39", + "k256", + "rand 0.8.5", + "thiserror 2.0.18", + "zeroize", +] + [[package]] name = "alloy-sol-macro" -version = "1.5.4" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fa1ca7e617c634d2bd9fa71f9ec8e47c07106e248b9fcbd3eaddc13cabd625" +checksum = "b5655c38d5f84955bf727b2eeb62fddd91ebb98fd1d7ae6eb77f73ea88f9b9cf" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error2", + "proc-macro-error3", "proc-macro2", "quote", "syn 2.0.114", @@ -778,27 +1086,27 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.5.4" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c00c0c3a75150a9dc7c8c679ca21853a137888b4e1c5569f92d7e2b15b5102" +checksum = "6277c780e07b76951e09a59788dde230d1582612324177d11a43a61e21a6bb83" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", "indexmap 2.13.0", - "proc-macro-error2", + "proc-macro-error3", "proc-macro2", "quote", - "sha3 0.10.8", + "sha3 0.11.0", "syn 2.0.114", "syn-solidity", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.4" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297db260eb4d67c105f68d6ba11b8874eec681caec5505eab8fbebee97f790bc" +checksum = "9762b2ad3e5a0c09886de54fe549ab0056681df843cb082e2df7e1c0eb270d30" dependencies = [ "const-hex", "dunce", @@ -812,19 +1120,19 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.5.4" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b91b13181d3bcd23680fd29d7bc861d1f33fbe90fdd0af67162434aeba902d" +checksum = "da4c7130f0f01f4719678bda3db3bc7267fc2f7f9d0565e3bd964cd2bb45050d" dependencies = [ "serde", - "winnow 0.7.14", + "winnow 1.0.4", ] [[package]] name = "alloy-sol-types" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5383d34ea00079e6dd89c652bcbdb764db160cef84e6250926961a0b2295d04" +checksum = "384cf252de0db2dec52821eac037a7f57e2aa33fe5b900ce6fe39973402341f1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -838,7 +1146,7 @@ version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "025a940182bddaeb594c26fe3728525ae262d0806fe6a4befdf5d7bc13d54bce" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 1.0.41", "alloy-primitives", "auto_impl", "base64 0.22.1", @@ -856,14 +1164,37 @@ dependencies = [ "wasmtimer", ] +[[package]] +name = "alloy-transport" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86052fdcec72d37ca4aa4b66254601e7453c45a6e1c70aa4561033d002fb80cc" +dependencies = [ + "alloy-json-rpc 2.0.5", + "auto_impl", + "base64 0.22.1", + "derive_more 2.1.1", + "futures", + "futures-utils-wasm", + "parking_lot 0.12.5", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower 0.5.3", + "tracing", + "url", + "wasmtimer", +] + [[package]] name = "alloy-transport-http" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2f8a6338d594f6c6481292215ee8f2fd7b986c80aba23f3f44e761a8658de78" dependencies = [ - "alloy-json-rpc", - "alloy-transport", + "alloy-json-rpc 1.0.41", + "alloy-transport 1.0.41", "reqwest 0.12.28", "serde_json", "tower 0.5.3", @@ -871,15 +1202,34 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-transport-http" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b273587487921274f4f5d0ef2c7ef36944dcbb75a4e2318e69eae822bd263f91" +dependencies = [ + "alloy-json-rpc 2.0.5", + "alloy-transport 2.0.5", + "itertools 0.14.0", + "opentelemetry", + "opentelemetry-http", + "reqwest 0.13.1", + "serde_json", + "tower 0.5.3", + "tracing", + "tracing-opentelemetry", + "url", +] + [[package]] name = "alloy-transport-ipc" -version = "1.0.41" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d47962f3f1d9276646485458dc842b4e35675f42111c9d814ae4711c664c8300" +checksum = "bfb89df168b24773ef603af14f2449c05a7d3f27d05d3eceaea6bf96cccae168" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 2.0.5", "alloy-pubsub", - "alloy-transport", + "alloy-transport 2.0.5", "bytes", "futures", "interprocess", @@ -893,19 +1243,20 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.0.41" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9476a36a34e2fb51b6746d009c53d309a186a825aa95435407f0e07149f4ad2d" +checksum = "33e32e0b47d3b3bf5770b7c132090c614b008d307c5e1544f1925f5b7e9e9af6" dependencies = [ "alloy-pubsub", - "alloy-transport", + "alloy-transport 2.0.5", "futures", "http 1.4.0", "rustls 0.23.36", "serde_json", "tokio", - "tokio-tungstenite 0.26.2", + "tokio-tungstenite 0.28.0", "tracing", + "url", "ws_stream_wasm", ] @@ -938,6 +1289,18 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "alloy-tx-macros" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a0035943b75fe1e249f52e688492d7a1b1826bc2d19b8e1d5d3c24a2ad8f50" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "ambassador" version = "0.4.2" @@ -1010,7 +1373,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1021,7 +1384,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1074,7 +1437,7 @@ dependencies = [ [[package]] name = "api-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "async-trait", @@ -1093,10 +1456,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "aptos-abstract-gas-usage" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-gas-algebra", @@ -1109,7 +1481,7 @@ dependencies = [ [[package]] name = "aptos-accumulator" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -1119,7 +1491,7 @@ dependencies = [ [[package]] name = "aptos-aggregator" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-types", "bcs 0.1.4", @@ -1132,7 +1504,7 @@ dependencies = [ [[package]] name = "aptos-api" version = "0.2.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-api-types", @@ -1143,7 +1515,7 @@ dependencies = [ "aptos-gas-schedule", "aptos-global-constants", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-metrics-core", "aptos-runtimes", "aptos-sdk", @@ -1173,7 +1545,7 @@ dependencies = [ [[package]] name = "aptos-api-types" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-config", @@ -1203,7 +1575,7 @@ dependencies = [ [[package]] name = "aptos-bcs-utils" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "hex", @@ -1212,7 +1584,7 @@ dependencies = [ [[package]] name = "aptos-bitvec" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "proptest", "serde", @@ -1222,7 +1594,7 @@ dependencies = [ [[package]] name = "aptos-block-executor" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ambassador", "anyhow", @@ -1260,7 +1632,7 @@ dependencies = [ [[package]] name = "aptos-block-partitioner" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-logger", @@ -1283,7 +1655,7 @@ dependencies = [ [[package]] name = "aptos-bounded-executor" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "futures", "rustversion", @@ -1293,7 +1665,7 @@ dependencies = [ [[package]] name = "aptos-build-info" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "shadow-rs", ] @@ -1301,7 +1673,7 @@ dependencies = [ [[package]] name = "aptos-cached-packages" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-framework", @@ -1315,7 +1687,7 @@ dependencies = [ [[package]] name = "aptos-channels" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-infallible", @@ -1326,12 +1698,12 @@ dependencies = [ [[package]] name = "aptos-collections" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "aptos-compression" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-logger", "aptos-metrics-core", @@ -1343,7 +1715,7 @@ dependencies = [ [[package]] name = "aptos-config" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -1436,7 +1808,7 @@ dependencies = [ [[package]] name = "aptos-consensus" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bitvec", @@ -1445,25 +1817,25 @@ dependencies = [ "aptos-collections", "aptos-config", "aptos-consensus-notifications", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-crypto-derive", "aptos-dkg", "aptos-enum-conversion-derive", "aptos-event-notifications", - "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-experimental-runtimes", "aptos-fallible", "aptos-infallible", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-metrics-core", "aptos-network", "aptos-peer-monitoring-service-types", "aptos-reliable-broadcast", "aptos-runtimes", - "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-schemadb", "aptos-secure-storage", "aptos-short-hex-str", @@ -1514,7 +1886,7 @@ dependencies = [ [[package]] name = "aptos-consensus-notifications" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-runtimes", @@ -1552,13 +1924,13 @@ dependencies = [ [[package]] name = "aptos-consensus-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bitvec", "aptos-crypto", "aptos-crypto-derive", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-infallible", "aptos-logger", "aptos-short-hex-str", @@ -1580,7 +1952,7 @@ dependencies = [ [[package]] name = "aptos-crash-handler" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-logger", "backtrace", @@ -1592,7 +1964,7 @@ dependencies = [ [[package]] name = "aptos-crypto" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aes-gcm", "anyhow", @@ -1646,7 +2018,7 @@ dependencies = [ [[package]] name = "aptos-crypto-derive" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "proc-macro2", "quote", @@ -1656,7 +2028,7 @@ dependencies = [ [[package]] name = "aptos-data-client" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-config", "aptos-crypto", @@ -1687,7 +2059,7 @@ dependencies = [ [[package]] name = "aptos-data-streaming-service" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-channels", "aptos-config", @@ -1713,7 +2085,7 @@ dependencies = [ [[package]] name = "aptos-db" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-accumulator", @@ -1721,7 +2093,7 @@ dependencies = [ "aptos-crypto", "aptos-db-indexer", "aptos-db-indexer-schemas", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-experimental-runtimes", "aptos-infallible", "aptos-jellyfish-merkle", @@ -1759,7 +2131,7 @@ dependencies = [ [[package]] name = "aptos-db-indexer" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-config", @@ -1781,7 +2153,7 @@ dependencies = [ [[package]] name = "aptos-db-indexer-schemas" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -1798,7 +2170,7 @@ dependencies = [ [[package]] name = "aptos-dkg" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -1830,13 +2202,13 @@ dependencies = [ [[package]] name = "aptos-dkg-runtime" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bounded-executor", "aptos-channels", "aptos-config", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-crypto-derive", "aptos-enum-conversion-derive", @@ -1847,7 +2219,7 @@ dependencies = [ "aptos-network", "aptos-reliable-broadcast", "aptos-runtimes", - "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-time-service", "aptos-types", "aptos-validator-transaction-pool", @@ -1869,7 +2241,7 @@ dependencies = [ [[package]] name = "aptos-drop-helper" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-infallible", "aptos-metrics-core", @@ -1880,7 +2252,7 @@ dependencies = [ [[package]] name = "aptos-enum-conversion-derive" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "quote", "syn 1.0.109", @@ -1889,7 +2261,7 @@ dependencies = [ [[package]] name = "aptos-event-notifications" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "api-types", @@ -1919,15 +2291,15 @@ dependencies = [ [[package]] name = "aptos-executor" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-block-executor", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-drop-helper", "aptos-executor-service", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-experimental-runtimes", "aptos-indexer-grpc-table-info", "aptos-infallible", @@ -1950,7 +2322,7 @@ dependencies = [ [[package]] name = "aptos-executor-service" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-block-executor", "aptos-block-partitioner", @@ -1981,16 +2353,16 @@ dependencies = [ [[package]] name = "aptos-executor-test-helpers" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-cached-packages", "aptos-config", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-db", - "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-sdk", "aptos-storage-interface", "aptos-temppath", @@ -2014,7 +2386,7 @@ dependencies = [ [[package]] name = "aptos-executor-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -2039,7 +2411,7 @@ dependencies = [ [[package]] name = "aptos-experimental-layered-map" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ahash 0.8.12", "aptos-crypto", @@ -2054,7 +2426,7 @@ dependencies = [ [[package]] name = "aptos-experimental-runtimes" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-runtimes", "core_affinity", @@ -2067,7 +2439,7 @@ dependencies = [ [[package]] name = "aptos-fallible" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "thiserror 1.0.69", ] @@ -2075,7 +2447,7 @@ dependencies = [ [[package]] name = "aptos-framework" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-aggregator", @@ -2146,7 +2518,7 @@ dependencies = [ [[package]] name = "aptos-gas-algebra" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "either", "move-core-types", @@ -2155,7 +2527,7 @@ dependencies = [ [[package]] name = "aptos-gas-meter" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-algebra", "aptos-gas-schedule", @@ -2170,7 +2542,7 @@ dependencies = [ [[package]] name = "aptos-gas-profiling" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-gas-algebra", @@ -2190,7 +2562,7 @@ dependencies = [ [[package]] name = "aptos-gas-schedule" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-algebra", "aptos-global-constants", @@ -2203,17 +2575,17 @@ dependencies = [ [[package]] name = "aptos-global-constants" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "aptos-id-generator" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "aptos-indexer-grpc-fullnode" version = "1.0.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-api", @@ -2222,7 +2594,7 @@ dependencies = [ "aptos-config", "aptos-indexer-grpc-utils", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-metrics-core", "aptos-moving-average", "aptos-protos", @@ -2242,14 +2614,14 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tonic", + "tonic 0.12.3", "tonic-reflection", ] [[package]] name = "aptos-indexer-grpc-table-info" version = "1.0.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-api", @@ -2259,7 +2631,7 @@ dependencies = [ "aptos-indexer-grpc-fullnode", "aptos-indexer-grpc-utils", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-metrics-core", "aptos-runtimes", "aptos-storage-interface", @@ -2281,7 +2653,7 @@ dependencies = [ [[package]] name = "aptos-indexer-grpc-utils" version = "1.0.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-metrics-core", @@ -2300,7 +2672,7 @@ dependencies = [ "lz4", "once_cell", "prometheus", - "prost", + "prost 0.13.5", "redis", "redis-test", "ripemd", @@ -2308,7 +2680,7 @@ dependencies = [ "serde_json", "tokio", "tokio-util", - "tonic", + "tonic 0.12.3", "tracing", "url", "warp", @@ -2317,12 +2689,12 @@ dependencies = [ [[package]] name = "aptos-infallible" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "aptos-inspection-service" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-build-info", @@ -2348,7 +2720,7 @@ dependencies = [ [[package]] name = "aptos-jellyfish-merkle" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -2376,7 +2748,7 @@ dependencies = [ [[package]] name = "aptos-jwk-consensus" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "api-types", @@ -2384,7 +2756,7 @@ dependencies = [ "aptos-bounded-executor", "aptos-channels", "aptos-config", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-enum-conversion-derive", "aptos-event-notifications", @@ -2395,7 +2767,7 @@ dependencies = [ "aptos-network", "aptos-reliable-broadcast", "aptos-runtimes", - "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-time-service", "aptos-types", "aptos-validator-transaction-pool", @@ -2414,7 +2786,7 @@ dependencies = [ [[package]] name = "aptos-jwk-utils" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-types", @@ -2429,7 +2801,7 @@ dependencies = [ [[package]] name = "aptos-keygen" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-types", @@ -2439,7 +2811,7 @@ dependencies = [ [[package]] name = "aptos-language-e2e-tests" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-abstract-gas-usage", @@ -2485,7 +2857,7 @@ dependencies = [ [[package]] name = "aptos-ledger" version = "0.2.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-types", @@ -2498,7 +2870,7 @@ dependencies = [ [[package]] name = "aptos-log-derive" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "proc-macro2", "quote", @@ -2508,7 +2880,7 @@ dependencies = [ [[package]] name = "aptos-logger" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-infallible", @@ -2534,7 +2906,7 @@ dependencies = [ [[package]] name = "aptos-memory-usage-tracker" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-algebra", "aptos-gas-meter", @@ -2575,13 +2947,13 @@ dependencies = [ [[package]] name = "aptos-mempool" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bounded-executor", "aptos-channels", "aptos-config", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-event-notifications", "aptos-infallible", @@ -2616,7 +2988,7 @@ dependencies = [ [[package]] name = "aptos-mempool-notifications" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-types", "async-trait", @@ -2629,7 +3001,7 @@ dependencies = [ [[package]] name = "aptos-memsocket" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-infallible", "bytes", @@ -2640,7 +3012,7 @@ dependencies = [ [[package]] name = "aptos-metrics-core" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "prometheus", @@ -2649,7 +3021,7 @@ dependencies = [ [[package]] name = "aptos-move-stdlib" version = "0.1.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-schedule", "aptos-native-interface", @@ -2674,7 +3046,7 @@ dependencies = [ [[package]] name = "aptos-mvhashmap" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-aggregator", @@ -2695,7 +3067,7 @@ dependencies = [ [[package]] name = "aptos-native-interface" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-algebra", "aptos-gas-schedule", @@ -2712,7 +3084,7 @@ dependencies = [ [[package]] name = "aptos-netcore" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-memsocket", "aptos-proxy", @@ -2729,7 +3101,7 @@ dependencies = [ [[package]] name = "aptos-network" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bitvec", @@ -2778,7 +3150,7 @@ dependencies = [ [[package]] name = "aptos-network-builder" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-channels", "aptos-config", @@ -2801,7 +3173,7 @@ dependencies = [ [[package]] name = "aptos-network-discovery" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-channels", @@ -2826,7 +3198,7 @@ dependencies = [ [[package]] name = "aptos-node-resource-metrics" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-build-info", "aptos-infallible", @@ -2843,7 +3215,7 @@ dependencies = [ [[package]] name = "aptos-num-variants" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "proc-macro2", "quote", @@ -2853,7 +3225,7 @@ dependencies = [ [[package]] name = "aptos-openapi" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "percent-encoding", "poem", @@ -2865,7 +3237,7 @@ dependencies = [ [[package]] name = "aptos-package-builder" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-framework", @@ -2878,7 +3250,7 @@ dependencies = [ [[package]] name = "aptos-peer-monitoring-service-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-config", "aptos-types", @@ -2890,7 +3262,7 @@ dependencies = [ [[package]] name = "aptos-proptest-helpers" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "crossbeam", "proptest", @@ -2900,18 +3272,18 @@ dependencies = [ [[package]] name = "aptos-protos" version = "1.3.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "pbjson", - "prost", + "prost 0.13.5", "serde", - "tonic", + "tonic 0.12.3", ] [[package]] name = "aptos-proxy" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ipnet", ] @@ -2919,7 +3291,7 @@ dependencies = [ [[package]] name = "aptos-push-metrics" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-logger", "aptos-metrics-core", @@ -2931,11 +3303,11 @@ dependencies = [ [[package]] name = "aptos-reliable-broadcast" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-bounded-executor", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-enum-conversion-derive", "aptos-infallible", "aptos-logger", @@ -2953,7 +3325,7 @@ dependencies = [ [[package]] name = "aptos-resource-viewer" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-types", @@ -2968,7 +3340,7 @@ dependencies = [ [[package]] name = "aptos-rest-client" version = "0.0.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-api-types", @@ -2991,7 +3363,7 @@ dependencies = [ [[package]] name = "aptos-rocksdb-options" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-config", "rocksdb", @@ -3000,7 +3372,7 @@ dependencies = [ [[package]] name = "aptos-runtimes" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "rayon", "tokio", @@ -3028,10 +3400,10 @@ dependencies = [ [[package]] name = "aptos-safety-rules" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-config", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-global-constants", "aptos-infallible", @@ -3052,7 +3424,7 @@ dependencies = [ [[package]] name = "aptos-schemadb" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-drop-helper", @@ -3069,7 +3441,7 @@ dependencies = [ [[package]] name = "aptos-scratchpad" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-drop-helper", @@ -3089,7 +3461,7 @@ dependencies = [ [[package]] name = "aptos-sdk" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-cached-packages", @@ -3115,7 +3487,7 @@ dependencies = [ [[package]] name = "aptos-sdk-builder" version = "0.2.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-types", @@ -3133,7 +3505,7 @@ dependencies = [ [[package]] name = "aptos-secure-net" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-logger", "aptos-metrics-core", @@ -3144,14 +3516,14 @@ dependencies = [ "serde", "thiserror 1.0.69", "tokio", - "tonic", + "tonic 0.12.3", "tonic-reflection", ] [[package]] name = "aptos-secure-storage" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-infallible", @@ -3172,7 +3544,7 @@ dependencies = [ [[package]] name = "aptos-short-hex-str" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "mirai-annotations", "serde", @@ -3183,7 +3555,7 @@ dependencies = [ [[package]] name = "aptos-speculative-state-helper" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-infallible", @@ -3194,7 +3566,7 @@ dependencies = [ [[package]] name = "aptos-state-sync-driver" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-config", @@ -3203,7 +3575,7 @@ dependencies = [ "aptos-data-client", "aptos-data-streaming-service", "aptos-event-notifications", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-infallible", "aptos-logger", "aptos-mempool-notifications", @@ -3227,7 +3599,7 @@ dependencies = [ [[package]] name = "aptos-storage-interface" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-crypto", @@ -3255,7 +3627,7 @@ dependencies = [ [[package]] name = "aptos-storage-service-client" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-config", "aptos-network", @@ -3266,7 +3638,7 @@ dependencies = [ [[package]] name = "aptos-storage-service-notifications" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-channels", "async-trait", @@ -3278,7 +3650,7 @@ dependencies = [ [[package]] name = "aptos-storage-service-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-compression", "aptos-config", @@ -3294,7 +3666,7 @@ dependencies = [ [[package]] name = "aptos-table-natives" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-gas-schedule", "aptos-native-interface", @@ -3312,17 +3684,17 @@ dependencies = [ [[package]] name = "aptos-telemetry" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-api", "aptos-config", - "aptos-consensus 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crypto", "aptos-db", "aptos-infallible", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-metrics-core", "aptos-network", "aptos-node-resource-metrics", @@ -3351,7 +3723,7 @@ dependencies = [ [[package]] name = "aptos-telemetry-service" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-config", @@ -3391,7 +3763,7 @@ dependencies = [ [[package]] name = "aptos-temppath" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "hex", "rand 0.7.3", @@ -3400,7 +3772,7 @@ dependencies = [ [[package]] name = "aptos-time-service" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-infallible", "enum_dispatch", @@ -3413,7 +3785,7 @@ dependencies = [ [[package]] name = "aptos-transaction-filter" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-protos", @@ -3421,7 +3793,7 @@ dependencies = [ "derive_builder", "memchr", "once_cell", - "prost", + "prost 0.13.5", "serde", "serde_json", "serde_yaml 0.8.26", @@ -3431,7 +3803,7 @@ dependencies = [ [[package]] name = "aptos-types" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "api-types", @@ -3495,12 +3867,12 @@ dependencies = [ [[package]] name = "aptos-utils" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "aptos-validator-transaction-pool" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-channels", "aptos-crypto", @@ -3513,7 +3885,7 @@ dependencies = [ [[package]] name = "aptos-vault-client" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "base64 0.13.1", @@ -3529,7 +3901,7 @@ dependencies = [ [[package]] name = "aptos-vm" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-aggregator", @@ -3581,7 +3953,7 @@ dependencies = [ [[package]] name = "aptos-vm-environment" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-framework", "aptos-gas-algebra", @@ -3604,7 +3976,7 @@ dependencies = [ [[package]] name = "aptos-vm-genesis" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-cached-packages", "aptos-crypto", @@ -3628,7 +4000,7 @@ dependencies = [ [[package]] name = "aptos-vm-logging" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "aptos-crypto", "aptos-logger", @@ -3643,7 +4015,7 @@ dependencies = [ [[package]] name = "aptos-vm-types" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ambassador", "anyhow", @@ -3666,7 +4038,7 @@ dependencies = [ [[package]] name = "aptos-vm-validator" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "aptos-logger", @@ -3715,6 +4087,12 @@ dependencies = [ "rustversion", ] +[[package]] +name = "archery" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" + [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -4302,24 +4680,26 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.4" +version = "1.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" dependencies = [ "aws-lc-sys", + "untrusted 0.7.1", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.37.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" +checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -4515,6 +4895,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bellpepper" version = "0.4.1" @@ -4605,7 +4991,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "cexpr", "clang-sys", "itertools 0.12.1", @@ -4613,7 +4999,7 @@ dependencies = [ "quote", "regex", "rustc-hash 2.1.1", - "shlex", + "shlex 1.3.0", "syn 2.0.114", ] @@ -4656,9 +5042,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] @@ -4672,6 +5058,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitmaps" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" + [[package]] name = "bitvec" version = "0.20.4" @@ -4738,6 +5130,20 @@ dependencies = [ "constant_time_eq 0.4.2", ] +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec 0.7.6", + "cc", + "cfg-if", + "constant_time_eq 0.4.2", + "cpufeatures 0.3.0", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -4757,6 +5163,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block-buffer-manager" version = "0.1.0" @@ -4826,11 +5241,11 @@ dependencies = [ [[package]] name = "boa_ast" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c340fe0f0b267787095cbe35240c6786ff19da63ec7b69367ba338eace8169b" +checksum = "6339a700715bda376f5ea65c76e8fe8fc880930d8b0638cea68e7f3da6538e0a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "boa_interner", "boa_macros", "boa_string", @@ -4841,84 +5256,92 @@ dependencies = [ [[package]] name = "boa_engine" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f620c3f06f51e65c0504ddf04978be1b814ac6586f0b45f6019801ab5efd37f9" +checksum = "1521be326f8a5c8887e95d4ce7f002917a002a23f7b93b9a6a2bf50ed4157824" dependencies = [ + "aligned-vec", "arrayvec 0.7.6", - "bitflags 2.10.0", + "bitflags 2.13.1", "boa_ast", "boa_gc", "boa_interner", "boa_macros", "boa_parser", - "boa_profiler", "boa_string", "bytemuck", "cfg-if", - "dashmap 6.1.0", + "cow-utils", + "dashmap 6.2.1", + "dynify", "fast-float2", - "hashbrown 0.15.5", - "icu_normalizer 1.5.0", + "float16", + "futures-channel", + "futures-concurrency", + "futures-lite", + "hashbrown 0.16.1", + "icu_normalizer", "indexmap 2.13.0", "intrusive-collections", - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", "num-integer", "num-traits", "num_enum", - "once_cell", - "pollster", + "paste", "portable-atomic", - "rand 0.8.5", + "rand 0.9.2", "regress", "rustc-hash 2.1.1", "ryu-js", "serde", "serde_json", - "sptr", + "small_btree", "static_assertions", + "tag_ptr", "tap", "thin-vec", "thiserror 2.0.18", "time", + "xsum", ] [[package]] name = "boa_gc" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2425c0b7720d42d73eaa6a883fbb77a5c920da8694964a3d79a67597ac55cce2" +checksum = "17323a98cf2e631afacf1a6d659c1212c48a68bacfa85afab0a66ade80582e51" dependencies = [ "boa_macros", - "boa_profiler", "boa_string", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "thin-vec", ] [[package]] name = "boa_interner" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42407a3b724cfaecde8f7d4af566df4b56af32a2f11f0956f5570bb974e7f749" +checksum = "20510b8b02bcde9b0a01cf34c0c308c56156503d1d91cdab4c8cfbd292b747ea" dependencies = [ "boa_gc", "boa_macros", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "indexmap 2.13.0", "once_cell", - "phf 0.11.3", + "phf 0.13.1", "rustc-hash 2.1.1", "static_assertions", ] [[package]] name = "boa_macros" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd3f870829131332587f607a7ff909f1af5fc523fd1b192db55fbbdf52e8d3c" +checksum = "5822cb4f146d243060e588bc5a5f2e709683fdad3d7111f42c48e6b5c921d23d" dependencies = [ + "cfg-if", + "cow-utils", "proc-macro2", "quote", "syn 2.0.114", @@ -4927,42 +5350,60 @@ dependencies = [ [[package]] name = "boa_parser" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc142dac798cdc6e2dbccfddeb50f36d2523bb977a976e19bdb3ae19b740804" +checksum = "35bd957fa9fa93e3a001a8aba5a5cd40c2bbfde486378be4c4b472fd304aaddb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "boa_ast", "boa_interner", "boa_macros", - "boa_profiler", "fast-float2", - "icu_properties 1.5.1", + "icu_properties", "num-bigint 0.4.6", "num-traits", "regress", "rustc-hash 2.1.1", ] -[[package]] -name = "boa_profiler" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4064908e7cdf9b6317179e9b04dcb27f1510c1c144aeab4d0394014f37a0f922" - [[package]] name = "boa_string" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7debc13fbf7997bf38bf8e9b20f1ad5e2a7d27a900e1f6039fe244ce30f589b5" +checksum = "ca2da1d7f4a76fd9040788a122f0d807910800a7b86f5952e9244848c36511de" dependencies = [ "fast-float2", + "itoa", "paste", "rustc-hash 2.1.1", - "sptr", + "ryu-js", "static_assertions", ] +[[package]] +name = "borsh" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f347189c62a579b8cd5f80714efa178f52e461dc2e6d701d264f5ff22e566c" +dependencies = [ + "once_cell", + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "boyer-moore-magiclen" version = "0.2.22" @@ -4999,6 +5440,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ + "sha2 0.10.9", "tinyvec", ] @@ -5052,6 +5494,12 @@ version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "byte-slice-cast" version = "1.2.3" @@ -5117,9 +5565,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.5" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" +checksum = "38d04308254695569fdb9bfe3bacc1c91837a670d0806605eb82d63748fbd3a6" dependencies = [ "blst", "cc", @@ -5214,14 +5662,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.55" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 2.0.1", ] [[package]] @@ -5251,6 +5699,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.43" @@ -5336,7 +5795,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] @@ -5498,6 +5957,57 @@ dependencies = [ "unicode-width 0.1.14", ] +[[package]] +name = "coins-bip32" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2073678591747aed4000dd468b97b14d7007f7936851d3f2f01846899f5ebf08" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.9", + "thiserror 1.0.69", +] + +[[package]] +name = "coins-bip39" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b169b26623ff17e9db37a539fe4f15342080df39f129ef7631df7683d6d9d4" +dependencies = [ + "bitvec 1.0.1", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.9", + "thiserror 1.0.69", +] + +[[package]] +name = "coins-core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b962ad8545e43a28e14e87377812ba9ae748dd4fd963f4c10e9fcc6d13475b" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "const-hex", + "digest 0.10.7", + "generic-array", + "ripemd", + "serde", + "sha2 0.10.9", + "sha3 0.10.8", + "thiserror 1.0.69", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -5541,9 +6051,9 @@ dependencies = [ [[package]] name = "compact_str" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ "castaway", "cfg-if", @@ -5610,7 +6120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -5671,15 +6181,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "convert_case" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "convert_case" version = "0.10.0" @@ -5773,6 +6274,12 @@ dependencies = [ "ciborium-io", ] +[[package]] +name = "cow-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" + [[package]] name = "cpp_demangle" version = "0.5.1" @@ -5791,6 +6298,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -5945,33 +6461,21 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "crossterm" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" -dependencies = [ - "bitflags 2.10.0", - "crossterm_winapi", - "mio 1.1.1", - "parking_lot 0.12.5", - "rustix 0.38.44", - "signal-hook", - "signal-hook-mio", - "winapi 0.3.9", -] - [[package]] name = "crossterm" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "crossterm_winapi", + "derive_more 2.1.1", "document-features", + "mio 1.2.2", "parking_lot 0.12.5", "rustix 1.1.3", + "signal-hook", + "signal-hook-mio", "winapi 0.3.9", ] @@ -6023,6 +6527,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -6104,7 +6617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", @@ -6204,6 +6717,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", + "serde", "strsim 0.11.1", "syn 2.0.114", ] @@ -6255,9 +6769,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.1.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -6528,10 +7042,20 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid 0.9.6", - "crypto-common", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", +] + [[package]] name = "dirs" version = "5.0.1" @@ -6576,9 +7100,8 @@ dependencies = [ [[package]] name = "discv5" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b4e7798d2ff74e29cee344dc490af947ae657d6ab5273dde35d58ce06a4d71" +version = "0.10.4" +source = "git+https://github.com/sigp/discv5?rev=7663c00#7663c00ee0837ea98547caaedede95d9d6736f4d" dependencies = [ "aes", "aes-gcm", @@ -6594,13 +7117,12 @@ dependencies = [ "hkdf 0.12.4", "lazy_static", "libp2p-identity", - "lru 0.12.5", "more-asserts", "multiaddr", "parking_lot 0.12.5", "rand 0.8.5", "smallvec", - "socket2 0.5.10", + "socket2 0.6.5", "tokio", "tracing", "uint 0.10.0", @@ -6613,7 +7135,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -6675,6 +7197,26 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "dynify" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81acb15628a3e22358bf73de5e7e62360b8a777dbcb5fc9ac7dfa9ae73723747" +dependencies = [ + "dynify-macros", +] + +[[package]] +name = "dynify-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec431cd708430d5029356535259c5d645d60edd3d39c54e5eea9782d46caa7d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -6766,9 +7308,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" dependencies = [ "serde", ] @@ -6829,18 +7371,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "enum-ordinalize" version = "4.3.2" @@ -6947,7 +7477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6961,11 +7491,11 @@ dependencies = [ [[package]] name = "ethereum_hashing" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c853bd72c9e5787f8aafc3df2907c2ed03cff3150c3acd94e2e53a98ab70a8ab" +checksum = "5aa93f58bb1eb3d1e556e4f408ef1dac130bad01ac37db4e7ade45de40d1c86a" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", "ring 0.17.14", "sha2 0.10.9", ] @@ -6985,13 +7515,13 @@ dependencies = [ [[package]] name = "ethereum_ssz" -version = "0.9.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dcddb2554d19cde19b099fadddde576929d7a4d0c1cd3512d1fd95cf174375c" +checksum = "e462875ad8693755ea8913d6e905715c76ea4836e2254e18c9cf0f7a8f8c2a13" dependencies = [ "alloy-primitives", "ethereum_serde_utils", - "itertools 0.13.0", + "itertools 0.14.0", "serde", "serde_derive", "smallvec", @@ -7000,11 +7530,11 @@ dependencies = [ [[package]] name = "ethereum_ssz_derive" -version = "0.9.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a657b6b3b7e153637dc6bdc6566ad9279d9ee11a15b12cfb24a2e04360637e9f" +checksum = "daf022360bdbe9456eda5f35718a50476d5b2a0d51a97ed4eae27420737a6fba" dependencies = [ - "darling 0.20.10", + "darling 0.23.0", "proc-macro2", "quote", "syn 2.0.114", @@ -7016,6 +7546,17 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" +[[package]] +name = "evmap" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8874945f036109c72242964c1174cf99434e30cfa45bf45fedc983f50046f8" +dependencies = [ + "hashbag", + "left-right", + "smallvec", +] + [[package]] name = "eyre" version = "0.6.12" @@ -7043,6 +7584,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "2.3.0" @@ -7156,6 +7703,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "fixed-cache" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fe63500644ef0269fe6b744e7e5dc5c20b5eebf3d881bc2be53f194636f6583" +dependencies = [ + "equivalent", + "rapidhash", + "typeid", +] + [[package]] name = "fixed-hash" version = "0.7.0" @@ -7180,6 +7738,27 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-map" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ed19add84e8cb9e8cc5f7074de0324247149ffef0b851e215fb0edc50c229b" +dependencies = [ + "fixed-map-derive", + "serde", +] + +[[package]] +name = "fixed-map-derive" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc7a9cb3326bafb80642c5ce99b39a2c0702d4bfa8ee8a3e773791a6cbe2407" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "fixedbitset" version = "0.2.0" @@ -7188,9 +7767,15 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" @@ -7244,6 +7829,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "float16" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bffafbd079d520191c7c2779ae9cf757601266cf4167d3f659ff09617ff8483" +dependencies = [ + "cfg-if", + "rustc_version 0.2.3", +] + [[package]] name = "fnv" version = "1.0.7" @@ -7360,6 +7955,19 @@ dependencies = [ "futures-sink", ] +[[package]] +name = "futures-concurrency" +version = "7.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175cd8cca9e1d45b87f18ffa75088f2099e3c4fe5e2f83e42de112560bea8ea6" +dependencies = [ + "fixedbitset 0.5.7", + "futures-core", + "futures-lite", + "pin-project", + "smallvec", +] + [[package]] name = "futures-core" version = "0.3.31" @@ -7383,6 +7991,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -7452,7 +8073,7 @@ dependencies = [ [[package]] name = "gaptos" version = "0.0.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "api-types", "aptos-bitvec", @@ -7463,9 +8084,9 @@ dependencies = [ "aptos-collections", "aptos-compression", "aptos-config", - "aptos-consensus 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-consensus-notifications", - "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-consensus-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-crash-handler", "aptos-crypto", "aptos-crypto-derive", @@ -7473,9 +8094,9 @@ dependencies = [ "aptos-dkg-runtime", "aptos-enum-conversion-derive", "aptos-event-notifications", - "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-executor-test-helpers", - "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-executor-types 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-experimental-runtimes", "aptos-fallible", "aptos-global-constants", @@ -7486,7 +8107,7 @@ dependencies = [ "aptos-keygen", "aptos-log-derive", "aptos-logger", - "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-mempool 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-mempool-notifications", "aptos-memsocket", "aptos-metrics-core", @@ -7502,7 +8123,7 @@ dependencies = [ "aptos-reliable-broadcast", "aptos-rest-client", "aptos-runtimes", - "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e)", + "aptos-safety-rules 0.1.0 (git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6)", "aptos-schemadb", "aptos-secure-net", "aptos-secure-storage", @@ -7547,13 +8168,27 @@ dependencies = [ "yup-oauth2", ] +[[package]] +name = "generator" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", +] + [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "serde", "typenum", "version_check", "zeroize", @@ -7616,11 +8251,23 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", +] + [[package]] name = "ghash" version = "0.5.1" @@ -7643,7 +8290,7 @@ version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "libc", "libgit2-sys", "log", @@ -7675,7 +8322,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "ignore", "walkdir", ] @@ -7726,16 +8373,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gmp-mpfr-sys" -version = "1.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f8970a75c006bb2f8ae79c6768a116dd215fa8346a87aed99bf9d82ca43394" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - [[package]] name = "goldenfile" version = "1.10.0" @@ -7804,7 +8441,7 @@ dependencies = [ "thiserror 1.0.69", "tokio", "tokio-retry2", - "tonic", + "tonic 0.12.3", "tower 0.4.13", "tracing", ] @@ -7815,9 +8452,9 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "886aa8ec755382a1fdf4651f6e6ec01f2f3bf49f2cb0f068b9a74cafd574a715" dependencies = [ - "prost", + "prost 0.13.5", "prost-types", - "tonic", + "tonic 0.12.3", ] [[package]] @@ -7900,8 +8537,8 @@ dependencies = [ [[package]] name = "gravity-precompiles" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "blst", @@ -7912,8 +8549,8 @@ dependencies = [ [[package]] name = "gravity-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" [[package]] name = "gravity-sdk" @@ -7926,8 +8563,8 @@ dependencies = [ [[package]] name = "gravity-storage" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "async-trait", @@ -7953,17 +8590,17 @@ dependencies = [ name = "gravity_cli" version = "0.1.0" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.0.37", "alloy-contract", - "alloy-network", + "alloy-network 1.0.37", "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", - "alloy-signer", - "alloy-signer-local", + "alloy-provider 1.0.37", + "alloy-rpc-types 1.0.37", + "alloy-signer 1.0.41", + "alloy-signer-local 1.0.37", "alloy-sol-macro", "alloy-sol-types", - "alloy-transport-http", + "alloy-transport-http 1.0.37", "anyhow", "aptos-consensus 0.1.0", "async-trait", @@ -7998,13 +8635,13 @@ dependencies = [ name = "gravity_node" version = "0.1.0" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-genesis", "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-transport-http", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", + "alloy-transport-http 2.0.5", "anyhow", "api", "async-trait", @@ -8048,13 +8685,13 @@ dependencies = [ [[package]] name = "greth" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "async-trait", "gravity-primitives", "gravity-storage", - "reqwest 0.12.28", + "reqwest 0.13.1", "reth", "reth-basic-payload-builder", "reth-chainspec", @@ -8090,13 +8727,13 @@ dependencies = [ [[package]] name = "grevm" version = "2.2.2" -source = "git+https://github.com/Galxe/grevm?rev=2a42859a56f03197fce5be4ceb475d9f1a7d7c3d#2a42859a56f03197fce5be4ceb475d9f1a7d7c3d" +source = "git+https://github.com/Galxe/grevm?rev=eecc6fc8bfcc07916517ac15f41a70c8036381bb#eecc6fc8bfcc07916517ac15f41a70c8036381bb" dependencies = [ "ahash 0.8.12", "alloy-evm", "atomic", "auto_impl", - "dashmap 6.1.0", + "dashmap 6.2.1", "futures", "lazy_static", "metrics", @@ -8195,6 +8832,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "hashbag" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7040a10f52cba493ddb09926e15d10a9d8a28043708a405931fe4c6f19fac064" + [[package]] name = "hashbrown" version = "0.12.3" @@ -8232,7 +8875,6 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.1.5", - "serde", ] [[package]] @@ -8246,13 +8888,26 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "serde", + "serde_core", +] + [[package]] name = "hashlink" -version = "0.9.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.16.1", ] [[package]] @@ -8378,48 +9033,72 @@ dependencies = [ ] [[package]] -name = "hickory-proto" -version = "0.25.2" +name = "hickory-net" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183" dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", + "hickory-proto", + "idna 1.1.0", + "ipnet", + "jni 0.22.4", + "rand 0.10.2", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-proto" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643" +dependencies = [ + "data-encoding", "idna 1.1.0", "ipnet", + "jni 0.22.4", "once_cell", - "rand 0.9.2", + "prefix-trie", + "rand 0.10.2", "ring 0.17.14", "serde", "thiserror 2.0.18", "tinyvec", - "tokio", "tracing", "url", ] [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni 0.22.4", "moka", + "ndk-context", "once_cell", "parking_lot 0.12.5", - "rand 0.9.2", + "rand 0.10.2", "resolv-conf", "serde", "smallvec", + "system-configuration 0.7.0", "thiserror 2.0.18", "tokio", "tracing", @@ -8620,6 +9299,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "0.14.32" @@ -8761,7 +9449,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2 0.6.5", "system-configuration 0.7.0", "tokio", "tower-service", @@ -8781,7 +9469,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -8795,27 +9483,15 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke 0.7.5", - "zerofrom", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", - "yoke 0.8.1", + "yoke", "zerofrom", - "zerovec 0.11.5", + "zerovec", ] [[package]] @@ -8825,146 +9501,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", - "litemap 0.8.1", - "tinystr 0.8.2", - "writeable 0.6.2", - "zerovec 0.11.5", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap 0.7.5", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", ] -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "8b24a59706036ba941c9476a55cd57b82b77f38a3c667d637ee7cabbc85eaedc" dependencies = [ "displaydoc", - "icu_collections 1.5.0", - "icu_normalizer_data 1.5.1", - "icu_properties 1.5.1", - "icu_provider 1.5.0", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", "smallvec", "utf16_iter", - "utf8_iter", "write16", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections 2.1.1", - "icu_normalizer_data 2.1.1", - "icu_properties 2.1.2", - "icu_provider 2.1.1", - "smallvec", - "zerovec 0.11.5", + "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "f5a97b8ac6235e69506e8dacfb2adf38461d2ce6d3e9bd9c94c4cbc3cd4400a4" dependencies = [ "displaydoc", - "icu_collections 1.5.0", - "icu_locid_transform", - "icu_properties_data 1.5.1", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections 2.1.1", + "icu_collections", "icu_locale_core", - "icu_properties_data 2.1.2", - "icu_provider 2.1.1", + "icu_properties_data", + "icu_provider", + "potential_utf", "zerotrie", - "zerovec 0.11.5", + "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr 0.7.6", - "writeable 0.5.5", - "yoke 0.7.5", - "zerofrom", - "zerovec 0.10.4", -] +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -8974,22 +9561,13 @@ checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "writeable 0.6.2", - "yoke 0.8.1", + "serde", + "stable_deref_trait", + "writeable", + "yoke", "zerofrom", "zerotrie", - "zerovec 0.11.5", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "zerovec", ] [[package]] @@ -9025,15 +9603,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "icu_normalizer 2.1.1", - "icu_properties 2.1.2", + "icu_normalizer", + "icu_properties", ] [[package]] name = "if-addrs" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b2eeee38fef3aa9b4cc5f1beea8a2444fc00e7377cafae396de3f5c2065e24" +checksum = "bf39cc0423ee66021dc5eccface85580e4a001e0c5288bae8bea7ecb69225e90" dependencies = [ "libc", "windows-sys 0.59.0", @@ -9061,7 +9639,7 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ - "bitmaps", + "bitmaps 2.1.0", "rand_core 0.6.4", "rand_xoshiro 0.6.0", "sized-chunks", @@ -9069,6 +9647,32 @@ dependencies = [ "version_check", ] +[[package]] +name = "imbl" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ea8d4c37ee560727e824d62804183624d371e632019b0e9e3532bce64a33e5" +dependencies = [ + "archery", + "bitmaps 3.2.1", + "equivalent", + "imbl-sized-chunks", + "rand_core 0.9.5", + "rand_xoshiro 0.7.0", + "serde_core", + "version_check", + "wide", +] + +[[package]] +name = "imbl-sized-chunks" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4241005618a62f8d57b2febd02510fb96e0137304728543dfc5fd6f052c22d" +dependencies = [ + "bitmaps 3.2.1", +] + [[package]] name = "impl-codec" version = "0.5.1" @@ -9204,7 +9808,7 @@ dependencies = [ "clap 4.5.57", "crossbeam-channel", "crossbeam-utils", - "dashmap 6.1.0", + "dashmap 6.2.1", "env_logger 0.11.8", "indexmap 2.13.0", "is-terminal", @@ -9234,7 +9838,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "inotify-sys", "libc", ] @@ -9298,9 +9902,9 @@ dependencies = [ [[package]] name = "interprocess" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69" +checksum = "069323743400cb7ab06a8fe5c1ed911d36b6919ec531661d034c89083629595b" dependencies = [ "doctest-file", "futures-core", @@ -9308,7 +9912,7 @@ dependencies = [ "recvmsg", "tokio", "widestring 1.2.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -9348,6 +9952,9 @@ name = "ipnet" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +dependencies = [ + "serde", +] [[package]] name = "iri-string" @@ -9367,7 +9974,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi 0.5.2", "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -9433,19 +10040,68 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.0", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "simd_cesu8", + "syn 2.0.114", +] + [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.114", +] + [[package]] name = "jobserver" version = "0.1.34" @@ -9505,7 +10161,7 @@ dependencies = [ "pin-project", "rustls 0.23.36", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.5.3", "soketto", "thiserror 2.0.18", "tokio", @@ -9557,7 +10213,7 @@ dependencies = [ "jsonrpsee-core", "jsonrpsee-types", "rustls 0.23.36", - "rustls-platform-verifier", + "rustls-platform-verifier 0.5.3", "serde", "serde_json", "thiserror 2.0.18", @@ -9687,6 +10343,24 @@ dependencies = [ "simple_asn1 0.6.3", ] +[[package]] +name = "jsonwebtoken" +version = "10.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" +dependencies = [ + "aws-lc-rs", + "base64 0.22.1", + "getrandom 0.2.17", + "js-sys", + "pem 3.0.6", + "serde", + "serde_json", + "signature 2.2.0", + "simple_asn1 0.6.3", + "zeroize", +] + [[package]] name = "k256" version = "0.13.4" @@ -9702,13 +10376,34 @@ dependencies = [ "signature 2.2.0", ] +[[package]] +name = "kasuari" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.18", +] + [[package]] name = "keccak" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", ] [[package]] @@ -9787,11 +10482,22 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "left-right" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bc015ded5d9b3054dbbdb63332cdd6ee42352ccef19e911e25117490e2f48ee" +dependencies = [ + "crossbeam-utils", + "loom", + "slab", +] + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libgit2-sys" @@ -9857,7 +10563,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "libc", "redox_syscall 0.7.0", ] @@ -9937,6 +10643,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "line-clipping" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.13.1", +] + [[package]] name = "linemux" version = "0.3.0" @@ -9970,24 +10685,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "litemap" version = "0.8.1" @@ -10019,6 +10722,19 @@ dependencies = [ "serde_core", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber 0.3.22", +] + [[package]] name = "lru" version = "0.7.8" @@ -10030,20 +10746,29 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ "hashbrown 0.15.5", ] [[package]] name = "lru" -version = "0.13.0" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", +] + +[[package]] +name = "lru" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" +dependencies = [ + "hashbrown 0.17.1", ] [[package]] @@ -10073,9 +10798,9 @@ dependencies = [ [[package]] name = "lz4_flex" -version = "0.11.5" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" +checksum = "90071f8077f8e40adfc4b7fe9cd495ce316263f19e75c2211eeff3fdf475a3d9" [[package]] name = "mach" @@ -10086,6 +10811,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1b95cd5421ec55b445b5ae102f5ea0e768de1f82bd3001e11f426c269c3aea" +dependencies = [ + "libc", +] + [[package]] name = "mach2" version = "0.6.0" @@ -10094,9 +10828,9 @@ checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" [[package]] name = "macro-string" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" dependencies = [ "proc-macro2", "quote", @@ -10171,19 +10905,19 @@ version = "3.0.0" source = "git+https://github.com/aptos-labs/merlin#3454ccc85e37355c729ba40e6dac6e867ddf59f5" dependencies = [ "byteorder", - "keccak", + "keccak 0.1.5", "rand_core 0.6.4", "zeroize", ] [[package]] name = "metrics" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8" +checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2" dependencies = [ - "ahash 0.8.12", "portable-atomic", + "rapidhash", ] [[package]] @@ -10199,16 +10933,17 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.16.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7399781913e5393588a8d8c6a2867bf85fb38eaf2502fdce465aad2dc6f034" +checksum = "1db0d8f1fc9e62caebd0319e11eaec5822b0186c171568f0480b46a0137f9108" dependencies = [ "base64 0.22.1", + "evmap", "indexmap 2.13.0", "metrics", "metrics-util", "quanta 0.12.6", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -10219,27 +10954,28 @@ checksum = "4268d87f64a752f5a651314fc683f04da10be65701ea3e721ba4d74f79163cac" dependencies = [ "libc", "libproc", - "mach2", + "mach2 0.6.0", "metrics", "once_cell", "procfs 0.18.0", "rlimit 0.11.0", - "windows 0.62.2", + "windows", ] [[package]] name = "metrics-util" -version = "0.19.1" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8496cc523d1f94c1385dd8f0f0c2c480b2b8aeccb5b7e4485ad6365523ae376" +checksum = "96f8722f8562635f92f8ed992f26df0532266eb03d5202607c20c0d7e9745e13" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "metrics", "quanta 0.12.6", "rand 0.9.2", "rand_xoshiro 0.7.0", + "rapidhash", "sketches-ddsketch", ] @@ -10304,9 +11040,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -10349,9 +11085,9 @@ dependencies = [ [[package]] name = "modular-bitfield" -version = "0.11.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +checksum = "2956e537fc68236d2aa048f55704f231cc93f1c4de42fe1ecb5bd7938061fc4a" dependencies = [ "modular-bitfield-impl", "static_assertions", @@ -10359,13 +11095,13 @@ dependencies = [ [[package]] name = "modular-bitfield-impl" -version = "0.11.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +checksum = "59b43b4fd69e3437618106f7754f34021b831a514f9e1a98ae863cabcd8d8dad" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -10394,7 +11130,7 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "move-abigen" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bcs 0.1.4", @@ -10411,7 +11147,7 @@ dependencies = [ [[package]] name = "move-binary-format" version = "0.0.3" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "backtrace", @@ -10426,12 +11162,12 @@ dependencies = [ [[package]] name = "move-borrow-graph" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" [[package]] name = "move-bytecode-source-map" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bcs 0.1.4", @@ -10446,7 +11182,7 @@ dependencies = [ [[package]] name = "move-bytecode-spec" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "once_cell", "quote", @@ -10456,7 +11192,7 @@ dependencies = [ [[package]] name = "move-bytecode-utils" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "move-binary-format", @@ -10468,7 +11204,7 @@ dependencies = [ [[package]] name = "move-bytecode-verifier" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "fail", "move-binary-format", @@ -10482,7 +11218,7 @@ dependencies = [ [[package]] name = "move-bytecode-viewer" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "clap 4.5.57", @@ -10497,7 +11233,7 @@ dependencies = [ [[package]] name = "move-cli" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "clap 4.5.57", @@ -10527,7 +11263,7 @@ dependencies = [ [[package]] name = "move-command-line-common" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "difference", @@ -10544,7 +11280,7 @@ dependencies = [ [[package]] name = "move-compiler" version = "0.0.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bcs 0.1.4", @@ -10567,7 +11303,7 @@ dependencies = [ [[package]] name = "move-compiler-v2" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "abstract-domain-derive", "anyhow", @@ -10601,7 +11337,7 @@ dependencies = [ [[package]] name = "move-core-types" version = "0.0.4" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "arbitrary", @@ -10627,7 +11363,7 @@ dependencies = [ [[package]] name = "move-coverage" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bcs 0.1.4", @@ -10646,7 +11382,7 @@ dependencies = [ [[package]] name = "move-disassembler" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "clap 4.5.57", @@ -10663,7 +11399,7 @@ dependencies = [ [[package]] name = "move-docgen" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "clap 4.5.57", @@ -10682,7 +11418,7 @@ dependencies = [ [[package]] name = "move-errmapgen" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "move-command-line-common", @@ -10694,7 +11430,7 @@ dependencies = [ [[package]] name = "move-ir-compiler" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bcs 0.1.4", @@ -10710,7 +11446,7 @@ dependencies = [ [[package]] name = "move-ir-to-bytecode" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "codespan-reporting", @@ -10728,7 +11464,7 @@ dependencies = [ [[package]] name = "move-ir-to-bytecode-syntax" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "hex", @@ -10741,7 +11477,7 @@ dependencies = [ [[package]] name = "move-ir-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "hex", "move-command-line-common", @@ -10754,7 +11490,7 @@ dependencies = [ [[package]] name = "move-model" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "codespan", @@ -10781,7 +11517,7 @@ dependencies = [ [[package]] name = "move-package" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "clap 4.5.57", @@ -10815,7 +11551,7 @@ dependencies = [ [[package]] name = "move-prover" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "atty", @@ -10842,7 +11578,7 @@ dependencies = [ [[package]] name = "move-prover-boogie-backend" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "async-trait", @@ -10871,7 +11607,7 @@ dependencies = [ [[package]] name = "move-prover-bytecode-pipeline" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "abstract-domain-derive", "anyhow", @@ -10887,7 +11623,7 @@ dependencies = [ [[package]] name = "move-prover-lab" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "chrono", @@ -10905,7 +11641,7 @@ dependencies = [ [[package]] name = "move-resource-viewer" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "hex", @@ -10918,7 +11654,7 @@ dependencies = [ [[package]] name = "move-stackless-bytecode" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "abstract-domain-derive", "anyhow", @@ -10940,7 +11676,7 @@ dependencies = [ [[package]] name = "move-stdlib" version = "0.1.1" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "hex", @@ -10963,7 +11699,7 @@ dependencies = [ [[package]] name = "move-symbol-pool" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "once_cell", "serde", @@ -10972,7 +11708,7 @@ dependencies = [ [[package]] name = "move-table-extension" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "better_any", "bytes", @@ -10987,7 +11723,7 @@ dependencies = [ [[package]] name = "move-unit-test" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "better_any", @@ -11019,7 +11755,7 @@ dependencies = [ [[package]] name = "move-vm-metrics" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "once_cell", "prometheus", @@ -11028,7 +11764,7 @@ dependencies = [ [[package]] name = "move-vm-runtime" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ambassador", "better_any", @@ -11053,7 +11789,7 @@ dependencies = [ [[package]] name = "move-vm-test-utils" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "anyhow", "bytes", @@ -11070,7 +11806,7 @@ dependencies = [ [[package]] name = "move-vm-types" version = "0.1.0" -source = "git+https://github.com/Galxe/gravity-aptos.git?rev=b1f68dc85781ef0d28a568d9d64604b153be9d9e#b1f68dc85781ef0d28a568d9d64604b153be9d9e" +source = "git+https://github.com/Galxe/gravity-aptos.git?rev=d163fa649970c7c8446dbc41a367c2d0b960cca6#d163fa649970c7c8446dbc41a367c2d0b960cca6" dependencies = [ "ambassador", "bcs 0.1.4", @@ -11199,6 +11935,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "neptune" version = "13.0.0" @@ -11235,7 +11977,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", @@ -11263,6 +12005,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" +dependencies = [ + "serde", +] + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -11292,13 +12043,13 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "fsevent-sys", "inotify 0.11.1", "kqueue", "libc", "log", - "mio 1.1.1", + "mio 1.2.2", "notify-types", "walkdir", "windows-sys 0.60.2", @@ -11310,7 +12061,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", ] [[package]] @@ -11337,7 +12088,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -11580,12 +12331,31 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", +] + [[package]] name = "objc2-encode" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.37.3" @@ -11597,9 +12367,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" dependencies = [ "critical-section", "portable-atomic", @@ -11617,53 +12387,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "op-alloy-consensus" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a501241474c3118833d6195312ae7eb7cc90bbb0d5f524cbb0b06619e49ff67" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "derive_more 2.1.1", - "serde", - "serde_with", - "thiserror 2.0.18", -] - -[[package]] -name = "op-alloy-rpc-types-engine" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e50c94013a1d036a529df259151991dbbd6cf8dc215e3b68b784f95eec60e6" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-engine", - "derive_more 2.1.1", - "ethereum_ssz", - "ethereum_ssz_derive", - "op-alloy-consensus", - "snap", - "thiserror 2.0.18", -] - -[[package]] -name = "op-revm" -version = "10.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826f43a5b1613c224f561847c152bfbaefcb593a9ae2c612ff4dc4661c6e625f" -dependencies = [ - "auto_impl", - "revm", - "serde", -] - [[package]] name = "opaque-debug" version = "0.3.1" @@ -11676,7 +12399,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "cfg-if", "foreign-types", "libc", @@ -11730,6 +12453,86 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http 1.4.0", + "opentelemetry", + "reqwest 0.12.28", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" +dependencies = [ + "http 1.4.0", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost 0.14.4", + "reqwest 0.12.28", + "thiserror 2.0.18", + "tokio", + "tonic 0.14.6", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost 0.14.4", + "tonic 0.14.6", + "tonic-prost", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.2", + "thiserror 2.0.18", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -11780,6 +12583,16 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "pairing" version = "0.23.0" @@ -11789,6 +12602,30 @@ dependencies = [ "group", ] +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "parity-scale-codec" version = "2.3.1" @@ -11844,6 +12681,12 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.11.2" @@ -11907,7 +12750,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "499cff8432e71c5f8784d9645aac0f9fca604d67f59b68a606170b5e229c6538" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "ciborium", "coset", "data-encoding", @@ -11957,9 +12800,19 @@ dependencies = [ name = "pbkdf2" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac 0.8.0", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "crypto-mac 0.8.0", + "digest 0.10.7", + "hmac 0.12.1", ] [[package]] @@ -12095,9 +12948,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros", "phf_shared 0.11.3", - "serde", ] [[package]] @@ -12109,13 +12960,33 @@ dependencies = [ "phf_shared 0.12.1", ] +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" +dependencies = [ + "phf_shared 0.14.0", +] + [[package]] name = "phf_codegen" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator", + "phf_generator 0.11.3", "phf_shared 0.11.3", ] @@ -12129,14 +13000,24 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator", - "phf_shared 0.11.3", + "phf_generator 0.13.1", + "phf_shared 0.13.1", "proc-macro2", "quote", "syn 2.0.114", @@ -12160,20 +13041,38 @@ dependencies = [ "siphasher 1.0.2", ] +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher 1.0.2", +] + +[[package]] +name = "phf_shared" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" +dependencies = [ + "siphasher 1.0.2", +] + [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -12368,12 +13267,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "pollster" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" - [[package]] name = "polyval" version = "0.6.2" @@ -12381,7 +13274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] @@ -12428,7 +13321,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "zerovec 0.11.5", + "zerovec", ] [[package]] @@ -12500,6 +13393,17 @@ dependencies = [ "termtree", ] +[[package]] +name = "prefix-trie" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" +dependencies = [ + "either", + "ipnet", + "num-traits", +] + [[package]] name = "pretty" version = "0.10.0" @@ -12605,6 +13509,16 @@ dependencies = [ "quote", ] +[[package]] +name = "proc-macro-error-attr3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82366fd7d8b7a440d66d13418820c69df9b3908bcb1a0476d7f5ce5d12f5a04d" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro-error2" version = "2.0.1" @@ -12614,6 +13528,17 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b511283ea8a74b4b39447b128c5d00f03a356b7424554b13e298a5550100d9ac" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", "syn 2.0.114", ] @@ -12653,40 +13578,17 @@ dependencies = [ "rustix 0.36.17", ] -[[package]] -name = "procfs" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" -dependencies = [ - "bitflags 2.10.0", - "chrono", - "flate2", - "hex", - "procfs-core 0.17.0", - "rustix 0.38.44", -] - [[package]] name = "procfs" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" dependencies = [ - "bitflags 2.10.0", - "procfs-core 0.18.0", - "rustix 1.1.3", -] - -[[package]] -name = "procfs-core" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" -dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "chrono", - "hex", + "flate2", + "procfs-core", + "rustix 1.1.3", ] [[package]] @@ -12695,7 +13597,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", + "chrono", "hex", ] @@ -12729,7 +13632,7 @@ checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.13.1", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -12758,7 +13661,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.5", +] + +[[package]] +name = "prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive 0.14.4", ] [[package]] @@ -12774,13 +13687,26 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "prost-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "prost-types" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ - "prost", + "prost 0.13.5", ] [[package]] @@ -12830,7 +13756,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "memchr", "unicase", ] @@ -12934,7 +13860,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls 0.23.36", - "socket2 0.6.2", + "socket2 0.6.5", "thiserror 2.0.18", "tokio", "tracing", @@ -12947,6 +13873,7 @@ version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ + "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", @@ -12971,7 +13898,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.2", + "socket2 0.6.5", "tracing", "windows-sys 0.60.2", ] @@ -12991,6 +13918,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.6.2" @@ -13040,6 +13973,17 @@ dependencies = [ "serde", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -13098,6 +14042,12 @@ dependencies = [ "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_hc" version = "0.2.0" @@ -13152,24 +14102,79 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "getrandom 0.3.4", + "rustversion", +] + [[package]] name = "ratatui" -version = "0.29.0" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d" dependencies = [ - "bitflags 2.10.0", - "cassowary", + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-widgets", + "serde", +] + +[[package]] +name = "ratatui-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" +dependencies = [ + "bitflags 2.13.1", "compact_str", - "crossterm 0.28.1", + "hashbrown 0.17.1", + "itertools 0.14.0", + "kasuari", + "lru 0.18.1", + "palette", + "serde", + "strum 0.28.0", + "thiserror 2.0.18", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0" +dependencies = [ + "cfg-if", + "crossterm 0.29.0", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" +dependencies = [ + "bitflags 2.13.1", + "hashbrown 0.17.1", "indoc 2.0.7", "instability", - "itertools 0.13.0", - "lru 0.12.5", - "paste", - "strum 0.26.3", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "serde", + "strum 0.28.0", + "time", "unicode-segmentation", - "unicode-truncate", "unicode-width 0.2.0", ] @@ -13188,7 +14193,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", ] [[package]] @@ -13276,7 +14281,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", ] [[package]] @@ -13285,7 +14290,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", ] [[package]] @@ -13444,6 +14449,47 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls 0.26.4", + "tower 0.5.3", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.6", +] + +[[package]] +name = "reqwest" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls 0.27.7", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.36", + "rustls-pki-types", + "rustls-platform-verifier 0.6.2", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", "tokio-util", "tower 0.5.3", "tower-http", @@ -13502,10 +14548,11 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-rpc-types", + "alloy-primitives", + "alloy-rpc-types 2.0.5", "aquamarine", "clap 4.5.57", "eyre", @@ -13528,7 +14575,7 @@ dependencies = [ "reth-node-metrics", "reth-payload-builder", "reth-payload-primitives", - "reth-primitives", + "reth-primitives-traits", "reth-provider", "reth-ress-protocol", "reth-ress-provider", @@ -13548,16 +14595,17 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "futures-core", "futures-util", "metrics", "reth-chain-state", + "reth-execution-cache", "reth-metrics", "reth-payload-builder", "reth-payload-builder-primitives", @@ -13566,17 +14614,19 @@ dependencies = [ "reth-revm", "reth-storage-api", "reth-tasks", + "reth-trie-parallel", + "serde", "tokio", "tracing", ] [[package]] name = "reth-chain-state" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "derive_more 2.1.1", "metrics", @@ -13601,12 +14651,12 @@ dependencies = [ [[package]] name = "reth-chainspec" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-evm", "alloy-genesis", "alloy-primitives", @@ -13621,8 +14671,8 @@ dependencies = [ [[package]] name = "reth-cli" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-genesis", "clap 4.5.57", @@ -13630,23 +14680,23 @@ dependencies = [ "reth-cli-runner", "reth-db", "serde_json", - "shellexpand", ] [[package]] name = "reth-cli-commands" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "backon", + "blake3", "clap 4.5.57", "comfy-table", - "crossterm 0.28.1", + "crossterm 0.29.0", "eyre", "fdlimit", "futures", @@ -13656,7 +14706,8 @@ dependencies = [ "itertools 0.14.0", "lz4", "ratatui", - "reqwest 0.12.28", + "rayon", + "reqwest 0.13.1", "reth-chainspec", "reth-cli", "reth-cli-runner", @@ -13692,10 +14743,14 @@ dependencies = [ "reth-primitives-traits", "reth-provider", "reth-prune", + "reth-prune-types", "reth-revm", "reth-stages", + "reth-stages-types", "reth-static-file", "reth-static-file-types", + "reth-storage-api", + "reth-tasks", "reth-trie", "reth-trie-common", "reth-trie-db", @@ -13705,15 +14760,16 @@ dependencies = [ "tar", "tokio", "tokio-stream", - "toml 0.8.23", + "toml 0.9.11+spec-1.1.0", "tracing", + "url", "zstd", ] [[package]] name = "reth-cli-runner" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "reth-tasks", "tokio", @@ -13722,10 +14778,10 @@ dependencies = [ [[package]] name = "reth-cli-util" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "cfg-if", "eyre", @@ -13735,22 +14791,24 @@ dependencies = [ "secp256k1 0.30.0", "serde", "thiserror 2.0.18", + "tikv-jemalloc-sys", "tikv-jemallocator", ] [[package]] name = "reth-codecs" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98afe24504bdbdf20f746794e1708886c21cb4a59826652c9047cba7dfc716d4" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-genesis", "alloy-primitives", "alloy-trie", "bytes", "modular-bitfield", - "op-alloy-consensus", + "parity-scale-codec 3.7.5", "reth-codecs-derive", "reth-zstd-compressors", "serde", @@ -13758,10 +14816,10 @@ dependencies = [ [[package]] name = "reth-codecs-derive" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceeb8dab90194305d3f7e3f043a22d2db1fb54b6dcf5d8e75c5a4fa8540e1f57" dependencies = [ - "convert_case 0.7.1", "proc-macro2", "quote", "syn 2.0.114", @@ -13769,25 +14827,27 @@ dependencies = [ [[package]] name = "reth-config" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "eyre", "humantime-serde", "reth-network-types", "reth-prune-types", "reth-stages-types", + "reth-static-file-types", "serde", - "toml 0.8.23", + "toml 0.9.11+spec-1.1.0", "url", ] [[package]] name = "reth-consensus" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", + "alloy-eip7928 0.4.5", "alloy-primitives", "auto_impl", "reth-execution-types", @@ -13797,11 +14857,12 @@ dependencies = [ [[package]] name = "reth-consensus-common" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-primitives", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -13809,23 +14870,22 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-json-rpc 2.0.5", "alloy-primitives", - "alloy-provider", + "alloy-provider 2.0.5", "alloy-rpc-types-engine", - "alloy-transport", + "alloy-transport 2.0.5", "auto_impl", "derive_more 2.1.1", "eyre", "futures", - "reqwest 0.12.28", + "reqwest 0.13.1", "reth-node-api", - "reth-primitives-traits", "reth-tracing", "ringbuffer", "serde", @@ -13835,31 +14895,34 @@ dependencies = [ [[package]] name = "reth-db" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "derive_more 2.1.1", "eyre", + "libc", "metrics", + "page_size", "parking_lot 0.12.5", "reth-db-api", "reth-fs-util", + "reth-libmdbx", "reth-nippy-jar", "reth-static-file-types", "reth-storage-errors", "reth-tracing", "rocksdb", - "sysinfo 0.33.1", + "sysinfo 0.38.4", "thiserror 2.0.18", ] [[package]] name = "reth-db-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-genesis", "alloy-primitives", "bytes", @@ -13877,14 +14940,15 @@ dependencies = [ "reth-trie-common", "roaring", "serde", + "serde_json", ] [[package]] name = "reth-db-common" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-genesis", "alloy-primitives", "boyer-moore-magiclen", @@ -13912,10 +14976,10 @@ dependencies = [ [[package]] name = "reth-db-models" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "bytes", "modular-bitfield", @@ -13926,14 +14990,13 @@ dependencies = [ [[package]] name = "reth-discv4" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", "discv5", "enr", - "generic-array", "itertools 0.14.0", "parking_lot 0.12.5", "rand 0.8.5", @@ -13952,8 +15015,8 @@ dependencies = [ [[package]] name = "reth-discv5" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -13976,15 +15039,15 @@ dependencies = [ [[package]] name = "reth-dns-discovery" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", + "dashmap 6.2.1", "data-encoding", "enr", "hickory-resolver", "linked_hash_set", - "parking_lot 0.12.5", "reth-ethereum-forks", "reth-network-peers", "reth-tokio-util", @@ -14000,13 +15063,14 @@ dependencies = [ [[package]] name = "reth-downloaders" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", + "async-compression", "futures", "futures-util", "itertools 0.14.0", @@ -14030,8 +15094,8 @@ dependencies = [ [[package]] name = "reth-ecies" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "aes", "alloy-primitives", @@ -14043,28 +15107,25 @@ dependencies = [ "ctr", "digest 0.10.7", "futures", - "generic-array", "hmac 0.12.1", "pin-project", "rand 0.8.5", "reth-network-peers", "secp256k1 0.30.0", "sha2 0.10.9", - "sha3 0.10.8", "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", "tracing", - "typenum", ] [[package]] name = "reth-engine-local" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "eyre", @@ -14074,7 +15135,8 @@ dependencies = [ "reth-ethereum-engine-primitives", "reth-payload-builder", "reth-payload-primitives", - "reth-provider", + "reth-primitives-traits", + "reth-storage-api", "reth-transaction-pool", "tokio", "tokio-stream", @@ -14083,11 +15145,11 @@ dependencies = [ [[package]] name = "reth-engine-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", @@ -14106,45 +15168,25 @@ dependencies = [ "tokio", ] -[[package]] -name = "reth-engine-service" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" -dependencies = [ - "futures", - "pin-project", - "reth-chainspec", - "reth-consensus", - "reth-engine-primitives", - "reth-engine-tree", - "reth-ethereum-primitives", - "reth-evm", - "reth-network-p2p", - "reth-node-types", - "reth-payload-builder", - "reth-provider", - "reth-prune", - "reth-stages-api", - "reth-tasks", - "thiserror 2.0.18", -] - [[package]] name = "reth-engine-tree" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-evm", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", + "crossbeam-channel", "derive_more 2.1.1", "futures", "gravity-primitives", + "indexmap 2.13.0", "metrics", "mini-moka", + "moka", "parking_lot 0.12.5", "rayon", "reth-chain-state", @@ -14183,10 +15225,12 @@ dependencies = [ [[package]] name = "reth-engine-util" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", + "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-engine", "eyre", "futures", @@ -14211,30 +15255,31 @@ dependencies = [ [[package]] name = "reth-era" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "ethereum_ssz", "ethereum_ssz_derive", - "reth-ethereum-primitives", + "sha2 0.10.9", "snap", "thiserror 2.0.18", ] [[package]] name = "reth-era-downloader" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "bytes", "eyre", "futures-util", - "reqwest 0.12.28", + "reqwest 0.13.1", + "reth-era", "reth-fs-util", "sha2 0.10.9", "tokio", @@ -14242,10 +15287,10 @@ dependencies = [ [[package]] name = "reth-era-utils" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "eyre", "futures-util", @@ -14264,8 +15309,8 @@ dependencies = [ [[package]] name = "reth-errors" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -14275,8 +15320,8 @@ dependencies = [ [[package]] name = "reth-eth-wire" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-chains", "alloy-primitives", @@ -14303,12 +15348,13 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eip7928 0.4.5", + "alloy-eips 2.0.5", "alloy-hardforks", "alloy-primitives", "alloy-rlp", @@ -14324,8 +15370,8 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "clap 4.5.57", "eyre", @@ -14340,17 +15386,18 @@ dependencies = [ "reth-node-ethereum", "reth-node-metrics", "reth-rpc-server-types", + "reth-tasks", "reth-tracing", "tracing", ] [[package]] name = "reth-ethereum-consensus" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -14362,26 +15409,24 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-rlp", "alloy-rpc-types-engine", "reth-engine-primitives", "reth-ethereum-primitives", "reth-payload-primitives", "reth-primitives-traits", "serde", - "sha2 0.10.9", "thiserror 2.0.18", ] [[package]] name = "reth-ethereum-forks" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -14393,11 +15438,11 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -14408,6 +15453,7 @@ dependencies = [ "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", + "reth-execution-cache", "reth-payload-builder", "reth-payload-builder-primitives", "reth-payload-primitives", @@ -14422,27 +15468,22 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-serde", - "modular-bitfield", + "alloy-rpc-types-eth 2.0.5", "reth-codecs", "reth-primitives-traits", - "reth-zstd-compressors", "serde", - "serde_with", ] [[package]] name = "reth-etl" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "rayon", "reth-db-api", @@ -14451,17 +15492,19 @@ dependencies = [ [[package]] name = "reth-evm" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eip7928 0.4.5", + "alloy-eips 2.0.5", "alloy-evm", "alloy-primitives", "auto_impl", "derive_more 2.1.1", "futures-util", "metrics", + "rayon", "reth-execution-errors", "reth-execution-types", "reth-metrics", @@ -14474,14 +15517,15 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", + "derive_more 2.1.1", "gravity-primitives", "grevm", "reth-chainspec", @@ -14494,10 +15538,28 @@ dependencies = [ "revm", ] +[[package]] +name = "reth-execution-cache" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" +dependencies = [ + "alloy-primitives", + "fixed-cache", + "metrics", + "parking_lot 0.12.5", + "reth-errors", + "reth-metrics", + "reth-primitives-traits", + "reth-provider", + "reth-revm", + "reth-trie", + "tracing", +] + [[package]] name = "reth-execution-errors" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-evm", "alloy-primitives", @@ -14509,13 +15571,14 @@ dependencies = [ [[package]] name = "reth-execution-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-evm", "alloy-primitives", + "alloy-rlp", "derive_more 2.1.1", "reth-ethereum-primitives", "reth-primitives-traits", @@ -14527,11 +15590,11 @@ dependencies = [ [[package]] name = "reth-exex" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "eyre", "futures", @@ -14565,10 +15628,10 @@ dependencies = [ [[package]] name = "reth-exex-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "reth-chain-state", "reth-execution-types", @@ -14579,8 +15642,8 @@ dependencies = [ [[package]] name = "reth-fs-util" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "serde", "serde_json", @@ -14589,10 +15652,10 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-debug", @@ -14608,6 +15671,7 @@ dependencies = [ "reth-rpc-api", "reth-tracing", "reth-trie", + "revm", "revm-bytecode", "revm-database", "serde", @@ -14616,8 +15680,8 @@ dependencies = [ [[package]] name = "reth-ipc" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "bytes", "futures", @@ -14634,34 +15698,62 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-libmdbx" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" +dependencies = [ + "bitflags 2.13.1", + "byteorder", + "crossbeam-queue", + "dashmap 6.2.1", + "derive_more 2.1.1", + "parking_lot 0.12.5", + "reth-mdbx-sys", + "smallvec", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "reth-mdbx-sys" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" +dependencies = [ + "bindgen", + "cc", +] + [[package]] name = "reth-metrics" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "futures", "metrics", "metrics-derive", + "reth-primitives-traits", "tokio", "tokio-util", ] [[package]] name = "reth-net-banlist" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", + "ipnet", ] [[package]] name = "reth-net-nat" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "futures-util", "if-addrs", - "reqwest 0.12.28", + "reqwest 0.13.1", "serde_with", "thiserror 2.0.18", "tokio", @@ -14670,11 +15762,11 @@ dependencies = [ [[package]] name = "reth-network" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "aquamarine", @@ -14689,6 +15781,7 @@ dependencies = [ "pin-project", "rand 0.8.5", "rand 0.9.2", + "rayon", "reth-chainspec", "reth-consensus", "reth-discv4", @@ -14716,6 +15809,7 @@ dependencies = [ "secp256k1 0.30.0", "serde", "smallvec", + "socket2 0.6.5", "thiserror 2.0.18", "tokio", "tokio-stream", @@ -14725,13 +15819,13 @@ dependencies = [ [[package]] name = "reth-network-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "alloy-rpc-types-admin", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "auto_impl", "derive_more 2.1.1", "enr", @@ -14750,11 +15844,11 @@ dependencies = [ [[package]] name = "reth-network-p2p" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "auto_impl", "derive_more 2.1.1", @@ -14772,8 +15866,8 @@ dependencies = [ [[package]] name = "reth-network-peers" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -14787,8 +15881,8 @@ dependencies = [ [[package]] name = "reth-network-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -14801,8 +15895,8 @@ dependencies = [ [[package]] name = "reth-nippy-jar" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "anyhow", "bincode", @@ -14818,8 +15912,8 @@ dependencies = [ [[package]] name = "reth-node-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-rpc-types-engine", "eyre", @@ -14842,14 +15936,14 @@ dependencies = [ [[package]] name = "reth-node-builder" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", + "alloy-provider 2.0.5", + "alloy-rpc-types 2.0.5", "alloy-rpc-types-engine", "aquamarine", "eyre", @@ -14857,11 +15951,11 @@ dependencies = [ "futures", "gravity-primitives", "jsonrpsee 0.26.0", + "parking_lot 0.12.5", "rayon", "reth-basic-payload-builder", "reth-chain-state", "reth-chainspec", - "reth-cli-util", "reth-config", "reth-consensus", "reth-consensus-debug-client", @@ -14871,7 +15965,6 @@ dependencies = [ "reth-downloaders", "reth-engine-local", "reth-engine-primitives", - "reth-engine-service", "reth-engine-tree", "reth-engine-util", "reth-evm", @@ -14902,6 +15995,7 @@ dependencies = [ "reth-tokio-util", "reth-tracing", "reth-transaction-pool", + "reth-trie-db", "secp256k1 0.30.0", "serde_json", "tokio", @@ -14911,11 +16005,11 @@ dependencies = [ [[package]] name = "reth-node-core" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "clap 4.5.57", @@ -14925,6 +16019,7 @@ dependencies = [ "futures", "gravity-primitives", "humantime", + "ipnet", "rand 0.9.2", "reth-chainspec", "reth-cli-util", @@ -14936,6 +16031,7 @@ dependencies = [ "reth-engine-local", "reth-engine-primitives", "reth-ethereum-forks", + "reth-net-banlist", "reth-net-nat", "reth-network", "reth-network-p2p", @@ -14948,14 +16044,15 @@ dependencies = [ "reth-stages-types", "reth-storage-api", "reth-storage-errors", + "reth-tasks", "reth-tracing", + "reth-tracing-otlp", "reth-transaction-pool", "secp256k1 0.30.0", "serde", - "shellexpand", "strum 0.27.2", "thiserror 2.0.18", - "toml 0.8.23", + "toml 0.9.11+spec-1.1.0", "tracing", "url", "vergen", @@ -14964,14 +16061,19 @@ dependencies = [ [[package]] name = "reth-node-ethereum" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", - "alloy-network", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", + "alloy-network 2.0.5", + "alloy-primitives", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", + "ethereum_ssz", "eyre", + "http-body-util", + "jsonrpsee 0.26.0", "reth-chainspec", "reth-engine-local", "reth-engine-primitives", @@ -14984,6 +16086,7 @@ dependencies = [ "reth-network", "reth-node-api", "reth-node-builder", + "reth-node-core", "reth-payload-primitives", "reth-primitives-traits", "reth-provider", @@ -14997,15 +16100,18 @@ dependencies = [ "reth-tracing", "reth-transaction-pool", "revm", + "serde", + "serde_json", "tokio", + "tower 0.5.3", ] [[package]] name = "reth-node-ethstats" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "chrono", "futures-util", @@ -15019,18 +16125,18 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-stream", - "tokio-tungstenite 0.26.2", + "tokio-tungstenite 0.28.0", "tracing", "url", ] [[package]] name = "reth-node-events" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "derive_more 2.1.1", @@ -15050,17 +16156,20 @@ dependencies = [ [[package]] name = "reth-node-metrics" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ + "bytes", "eyre", "http 1.4.0", + "http-body-util", "jsonrpsee-server", "metrics", "metrics-exporter-prometheus", "metrics-process", "metrics-util", - "procfs 0.17.0", + "procfs 0.18.0", + "reqwest 0.13.1", "reth-metrics", "reth-tasks", "tikv-jemalloc-ctl", @@ -15071,8 +16180,8 @@ dependencies = [ [[package]] name = "reth-node-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "reth-chainspec", "reth-db-api", @@ -15083,20 +16192,23 @@ dependencies = [ [[package]] name = "reth-payload-builder" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", - "alloy-rpc-types", + "alloy-rpc-types 2.0.5", + "derive_more 2.1.1", "futures-util", "metrics", "reth-chain-state", "reth-ethereum-engine-primitives", + "reth-execution-cache", "reth-metrics", "reth-payload-builder-primitives", "reth-payload-primitives", "reth-primitives-traits", + "reth-trie-parallel", "tokio", "tokio-stream", "tracing", @@ -15104,8 +16216,8 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "pin-project", "reth-payload-primitives", @@ -15116,38 +16228,41 @@ dependencies = [ [[package]] name = "reth-payload-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-engine", "auto_impl", "either", - "op-alloy-rpc-types-engine", - "reth-chain-state", "reth-chainspec", "reth-errors", + "reth-execution-types", "reth-primitives-traits", + "reth-trie-common", "serde", + "sha2 0.10.9", "thiserror 2.0.18", "tokio", ] [[package]] name = "reth-payload-validator" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-rpc-types-engine", "reth-primitives-traits", ] [[package]] name = "reth-pipe-exec-layer-event-bus" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "reth-chain-state", @@ -15159,13 +16274,13 @@ dependencies = [ [[package]] name = "reth-pipe-exec-layer-ext-v2" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-sol-macro", "alloy-sol-types", "api-types", @@ -15206,21 +16321,21 @@ dependencies = [ [[package]] name = "reth-pipe-exec-layer-relayer" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-network", + "alloy-network 2.0.5", "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", + "alloy-provider 2.0.5", + "alloy-rpc-types 2.0.5", "alloy-sol-macro", "alloy-sol-types", - "alloy-transport", + "alloy-transport 2.0.5", "anyhow", "api-types", "async-trait", "chrono", - "reqwest 0.12.28", + "reqwest 0.13.1", "serde", "serde_json", "tokio", @@ -15230,10 +16345,10 @@ dependencies = [ [[package]] name = "reth-primitives" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "once_cell", "reth-ethereum-forks", "reth-ethereum-primitives", @@ -15243,23 +16358,23 @@ dependencies = [ [[package]] name = "reth-primitives-traits" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "0.4.1" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-trie", - "auto_impl", "byteorder", "bytes", + "dashmap 6.2.1", "derive_more 2.1.1", "modular-bitfield", "once_cell", - "op-alloy-consensus", + "quanta 0.12.6", "rayon", "reth-codecs", "revm-bytecode", @@ -15273,14 +16388,14 @@ dependencies = [ [[package]] name = "reth-provider" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", - "dashmap 6.1.0", + "dashmap 6.2.1", "eyre", "gravity-primitives", "itertools 0.14.0", @@ -15316,11 +16431,11 @@ dependencies = [ [[package]] name = "reth-prune" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "itertools 0.14.0", "metrics", @@ -15344,23 +16459,25 @@ dependencies = [ [[package]] name = "reth-prune-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "derive_more 2.1.1", "modular-bitfield", "reth-codecs", "serde", + "strum 0.27.2", "thiserror 2.0.18", + "tracing", ] [[package]] name = "reth-ress-protocol" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "alloy-rlp", "futures", @@ -15376,10 +16493,10 @@ dependencies = [ [[package]] name = "reth-ress-provider" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "eyre", "futures", @@ -15403,10 +16520,12 @@ dependencies = [ [[package]] name = "reth-revm" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-debug", "reth-primitives-traits", "reth-storage-api", "reth-storage-errors", @@ -15416,42 +16535,38 @@ dependencies = [ [[package]] name = "reth-rpc" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-dyn-abi", - "alloy-eips", + "alloy-eips 2.0.5", "alloy-evm", "alloy-genesis", - "alloy-network", + "alloy-network 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-rpc-client", - "alloy-rpc-types", + "alloy-rpc-client 2.0.5", + "alloy-rpc-types 2.0.5", "alloy-rpc-types-admin", "alloy-rpc-types-beacon", "alloy-rpc-types-debug", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-rpc-types-mev", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde", - "alloy-signer", - "alloy-signer-local", + "alloy-serde 2.0.5", + "alloy-signer 2.0.5", + "alloy-signer-local 2.0.5", "async-trait", "derive_more 2.1.1", "dyn-clone", "futures", "gravity-precompiles", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", "itertools 0.14.0", "jsonrpsee 0.26.0", "jsonrpsee-types", - "jsonwebtoken 9.3.1", "parking_lot 0.12.5", "pin-project", "reth-chain-state", @@ -15460,6 +16575,8 @@ dependencies = [ "reth-consensus-common", "reth-engine-primitives", "reth-errors", + "reth-ethereum-engine-primitives", + "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", "reth-execution-types", @@ -15489,46 +16606,47 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-stream", - "tower 0.5.3", "tracing", "tracing-futures", ] [[package]] name = "reth-rpc-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-genesis", - "alloy-json-rpc", + "alloy-json-rpc 2.0.5", "alloy-primitives", - "alloy-rpc-types", + "alloy-rpc-types 2.0.5", "alloy-rpc-types-admin", "alloy-rpc-types-anvil", "alloy-rpc-types-beacon", "alloy-rpc-types-debug", "alloy-rpc-types-engine", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-rpc-types-mev", "alloy-rpc-types-trace", "alloy-rpc-types-txpool", - "alloy-serde", + "alloy-serde 2.0.5", "jsonrpsee 0.26.0", "reth-chain-state", "reth-engine-primitives", "reth-network-peers", "reth-rpc-eth-api", "reth-trie-common", + "serde", + "serde_json", ] [[package]] name = "reth-rpc-builder" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-network", - "alloy-provider", + "alloy-network 2.0.5", + "alloy-provider 2.0.5", "dyn-clone", "http 1.4.0", "jsonrpsee 0.26.0", @@ -15537,20 +16655,24 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-consensus", + "reth-engine-primitives", "reth-evm", "reth-ipc", "reth-metrics", "reth-network-api", "reth-node-core", + "reth-payload-primitives", "reth-primitives-traits", "reth-rpc", "reth-rpc-api", + "reth-rpc-engine-api", "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-layer", "reth-rpc-server-types", "reth-storage-api", "reth-tasks", + "reth-tokio-util", "reth-transaction-pool", "serde", "thiserror 2.0.18", @@ -15563,41 +16685,42 @@ dependencies = [ [[package]] name = "reth-rpc-convert" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-json-rpc", - "alloy-network", + "alloy-consensus 2.0.5", + "alloy-evm", + "alloy-json-rpc 2.0.5", + "alloy-network 2.0.5", "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-signer", + "alloy-rpc-types-eth 2.0.5", "auto_impl", "dyn-clone", "jsonrpsee-types", "reth-ethereum-primitives", "reth-evm", "reth-primitives-traits", - "revm-context", + "reth-rpc-traits", "thiserror 2.0.18", ] [[package]] name = "reth-rpc-engine-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-engine", "async-trait", "jsonrpsee-core", "jsonrpsee-types", "metrics", - "parking_lot 0.12.5", "reth-chainspec", "reth-engine-primitives", "reth-metrics", + "reth-network-api", "reth-payload-builder", "reth-payload-builder-primitives", "reth-payload-primitives", @@ -15614,20 +16737,21 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-dyn-abi", - "alloy-eips", + "alloy-eip7928 0.4.5", + "alloy-eips 2.0.5", "alloy-evm", - "alloy-json-rpc", - "alloy-network", + "alloy-json-rpc 2.0.5", + "alloy-network 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-rpc-types-mev", - "alloy-serde", + "alloy-serde 2.0.5", "async-trait", "auto_impl", "dyn-clone", @@ -15642,6 +16766,7 @@ dependencies = [ "reth-network-api", "reth-node-api", "reth-primitives-traits", + "reth-prune-types", "reth-revm", "reth-rpc-convert", "reth-rpc-eth-types", @@ -15658,18 +16783,20 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-chains", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-evm", - "alloy-network", + "alloy-network 2.0.5", "alloy-primitives", - "alloy-rpc-client", - "alloy-rpc-types-eth", + "alloy-rpc-client 2.0.5", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "alloy-sol-types", - "alloy-transport", + "alloy-transport 2.0.5", "derive_more 2.1.1", "futures", "itertools 0.14.0", @@ -15677,7 +16804,7 @@ dependencies = [ "jsonrpsee-types", "metrics", "rand 0.9.2", - "reqwest 0.12.28", + "reqwest 0.13.1", "reth-chain-state", "reth-chainspec", "reth-errors", @@ -15701,12 +16828,13 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "url", ] [[package]] name = "reth-rpc-layer" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-rpc-types-engine", "http 1.4.0", @@ -15719,10 +16847,10 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "jsonrpsee-core", @@ -15733,21 +16861,35 @@ dependencies = [ "strum 0.27.2", ] +[[package]] +name = "reth-rpc-traits" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "947a4e5cec5166505ea078c9164f06bf691fd83d3850e72851b58a9f1900cb6d" +dependencies = [ + "alloy-consensus 2.0.5", + "alloy-network 2.0.5", + "alloy-primitives", + "alloy-rpc-types-eth 2.0.5", + "alloy-signer 2.0.5", + "reth-primitives-traits", + "thiserror 2.0.18", +] + [[package]] name = "reth-stages" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", "alloy-primitives", - "bincode", + "alloy-rlp", "eyre", "futures-util", "itertools 0.14.0", "num-traits", "rayon", - "reqwest 0.12.28", + "reqwest 0.13.1", "reth-codecs", "reth-config", "reth-consensus", @@ -15770,6 +16912,7 @@ dependencies = [ "reth-stages-api", "reth-static-file-types", "reth-storage-errors", + "reth-tasks", "reth-trie", "reth-trie-parallel", "thiserror 2.0.18", @@ -15779,15 +16922,16 @@ dependencies = [ [[package]] name = "reth-stages-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "aquamarine", "auto_impl", "futures-util", "metrics", + "reth-codecs", "reth-consensus", "reth-errors", "reth-metrics", @@ -15806,8 +16950,8 @@ dependencies = [ [[package]] name = "reth-stages-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "bytes", @@ -15819,8 +16963,8 @@ dependencies = [ [[package]] name = "reth-static-file" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "parking_lot 0.12.5", @@ -15839,27 +16983,29 @@ dependencies = [ [[package]] name = "reth-static-file-types" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "clap 4.5.57", "derive_more 2.1.1", + "fixed-map", "serde", "strum 0.27.2", + "tracing", ] [[package]] name = "reth-storage-api" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", - "dashmap 6.1.0", + "dashmap 6.2.1", "gravity-primitives", "metrics", "metrics-derive", @@ -15881,33 +17027,38 @@ dependencies = [ [[package]] name = "reth-storage-errors" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "derive_more 2.1.1", + "reth-codecs", "reth-primitives-traits", "reth-prune-types", "reth-static-file-types", "revm-database-interface", + "revm-state", "thiserror 2.0.18", ] [[package]] name = "reth-tasks" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "auto_impl", - "dyn-clone", + "crossbeam-utils", + "dashmap 6.2.1", "futures-util", + "libc", "metrics", + "parking_lot 0.12.5", "pin-project", "rayon", "reth-metrics", "thiserror 2.0.18", + "thread-priority", "tokio", "tracing", "tracing-futures", @@ -15915,8 +17066,8 @@ dependencies = [ [[package]] name = "reth-tokio-util" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "tokio", "tokio-stream", @@ -15925,33 +17076,55 @@ dependencies = [ [[package]] name = "reth-tracing" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "clap 4.5.57", "eyre", + "reth-tracing-otlp", "rolling-file", "tracing", "tracing-appender", + "tracing-chrome", "tracing-journald", "tracing-logfmt", + "tracing-samply", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "reth-tracing-otlp" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" +dependencies = [ + "base64 0.22.1", + "clap 4.5.57", + "eyre", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "tracing", + "tracing-opentelemetry", "tracing-subscriber 0.3.22", + "url", ] [[package]] name = "reth-transaction-pool" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "aquamarine", "auto_impl", - "bitflags 2.10.0", + "bitflags 2.13.1", "futures-util", "gravity-primitives", + "imbl", "metrics", "parking_lot 0.12.5", "pin-project", @@ -15960,6 +17133,8 @@ dependencies = [ "reth-chainspec", "reth-eth-wire-types", "reth-ethereum-primitives", + "reth-evm", + "reth-evm-ethereum", "reth-execution-types", "reth-fs-util", "reth-metrics", @@ -15967,6 +17142,7 @@ dependencies = [ "reth-primitives-traits", "reth-storage-api", "reth-tasks", + "revm", "revm-interpreter", "revm-primitives", "rustc-hash 2.1.1", @@ -15982,17 +17158,18 @@ dependencies = [ [[package]] name = "reth-trie" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 2.0.5", + "alloy-eips 2.0.5", "alloy-primitives", "alloy-rlp", "alloy-trie", "auto_impl", "itertools 0.14.0", "metrics", + "parking_lot 0.12.5", "reth-execution-errors", "reth-metrics", "reth-primitives-traits", @@ -16006,14 +17183,14 @@ dependencies = [ [[package]] name = "reth-trie-common" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ - "alloy-consensus", + "alloy-consensus 2.0.5", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 2.0.5", + "alloy-serde 2.0.5", "alloy-trie", "bytes", "derive_more 2.1.1", @@ -16033,8 +17210,8 @@ dependencies = [ [[package]] name = "reth-trie-db" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -16052,11 +17229,14 @@ dependencies = [ [[package]] name = "reth-trie-parallel" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ + "alloy-eip7928 0.4.5", + "alloy-evm", "alloy-primitives", "alloy-rlp", + "crossbeam-channel", "derive_more 2.1.1", "itertools 0.14.0", "metrics", @@ -16070,6 +17250,7 @@ dependencies = [ "reth-trie-common", "reth-trie-db", "reth-trie-sparse", + "revm-state", "thiserror 2.0.18", "tokio", "tracing", @@ -16077,8 +17258,8 @@ dependencies = [ [[package]] name = "reth-trie-sparse" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -16090,14 +17271,16 @@ dependencies = [ "reth-metrics", "reth-primitives-traits", "reth-trie-common", + "serde", + "serde_json", "smallvec", "tracing", ] [[package]] name = "reth-trie-sparse-parallel" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "2.3.0" +source = "git+https://github.com/Galxe/gravity-reth?rev=a5cf019429d772cd2f4964fc0705676d84464953#a5cf019429d772cd2f4964fc0705676d84464953" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -16114,8 +17297,9 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" -version = "1.8.3" -source = "git+https://github.com/Galxe/gravity-reth?rev=b49b4864aeaa3c35c6871a77d7133bb9486edbf1#b49b4864aeaa3c35c6871a77d7133bb9486edbf1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395b92a7cf863f70bd109e35f70a2fe36033187de06f6840e0ccf61c8008375d" dependencies = [ "zstd", ] @@ -16133,9 +17317,9 @@ dependencies = [ [[package]] name = "revm" -version = "29.0.1" +version = "40.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718d90dce5f07e115d0e66450b1b8aa29694c1cf3f89ebddaddccc2ccbd2f13e" +checksum = "823da6e5509bb8e5dcd91295870e494917a030ad506fc83301f3f08ad8b15b17" dependencies = [ "revm-bytecode", "revm-context", @@ -16152,21 +17336,21 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "6.2.2" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c52031b73cae95d84cd1b07725808b5fd1500da3e5e24574a3b2dc13d9f16d" +checksum = "d8b378c2653331fe60969d9745e802cd773d82a20d8aaced914dfcf26ab8f0d9" dependencies = [ "bitvec 1.0.1", - "phf 0.11.3", + "phf 0.13.1", "revm-primitives", "serde", ] [[package]] name = "revm-context" -version = "9.1.0" +version = "18.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a20c98e7008591a6f012550c2a00aa36cba8c14cc88eb88dec32eb9102554b4" +checksum = "bafa298114f3cab706945de14c04e73e6e6d7896302e4183dae273f968e52f80" dependencies = [ "bitvec 1.0.1", "cfg-if", @@ -16181,9 +17365,9 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "10.2.0" +version = "19.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50d241ed1ce647b94caf174fcd0239b7651318b2c4c06b825b59b973dfb8495" +checksum = "db9c13f1dfc79425931fd184b6bd373dfac7baba50859b01107d5c0e20549cbb" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -16197,11 +17381,12 @@ dependencies = [ [[package]] name = "revm-database" -version = "7.0.5" +version = "15.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" +checksum = "a69c3ce73454a09ef89a66177239d7c4f5f697227ae27254c99451866603b19d" dependencies = [ - "alloy-eips", + "alloy-eips 2.0.5", + "derive_more 2.1.1", "revm-bytecode", "revm-database-interface", "revm-primitives", @@ -16211,22 +17396,23 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "7.0.5" +version = "12.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c523c77e74eeedbac5d6f7c092e3851dbe9c7fec6f418b85992bd79229db361" +checksum = "4a2656187f9f9c22ef9dd9300ed71aeaeca3506a6a0a229a07f264649b960d68" dependencies = [ "auto_impl", "either", "revm-primitives", "revm-state", "serde", + "thiserror 2.0.18", ] [[package]] name = "revm-handler" -version = "10.0.1" +version = "20.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "550331ea85c1d257686e672081576172fe3d5a10526248b663bbf54f1bef226a" +checksum = "3ce1d66037ca1394128313bb995fa9f50d834927a389386bb34f8f0ef914648f" dependencies = [ "auto_impl", "derive-where", @@ -16243,9 +17429,9 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "10.0.1" +version = "21.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0a6e9ccc2ae006f5bed8bd80cd6f8d3832cd55c5e861b9402fdd556098512f" +checksum = "9fe3635d3411e8318849546570ca0220e783443319e28f5397c9f80b05bf4344" dependencies = [ "auto_impl", "either", @@ -16261,12 +17447,12 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.30.1" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de23199c4b6181a6539e4131cf7e31cde4df05e1192bcdce491c34a511241588" +checksum = "15e0cdc845c8dbf41255c9add80923b45df7bf1dd0473e41483ac398005dba12" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth", + "alloy-rpc-types-eth 2.0.5", "alloy-rpc-types-trace", "alloy-sol-types", "anstyle", @@ -16281,21 +17467,22 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "25.0.3" +version = "37.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06575dc51b1d8f5091daa12a435733a90b4a132dca7ccee0666c7db3851bc30c" +checksum = "bae56c57ddca1f5c4abd443f826f1b3e49a86a528e7e1ea0fc207cdc4671a37e" dependencies = [ "revm-bytecode", "revm-context-interface", "revm-primitives", + "revm-state", "serde", ] [[package]] name = "revm-precompile" -version = "27.0.0" +version = "36.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b57d4bd9e6b5fe469da5452a8a137bc2d030a3cd47c46908efc615bbc699da" +checksum = "191db865091e07ecb80b12ce3048192c76071ca3d2b0a315b111b271cd4ced37" dependencies = [ "ark-bls12-381 0.5.0", "ark-bn254 0.5.0", @@ -16304,38 +17491,39 @@ dependencies = [ "ark-serialize 0.5.0", "arrayref", "aurora-engine-modexp", + "aws-lc-rs", "blst", "c-kzg", "cfg-if", "k256", - "libsecp256k1", "p256", + "revm-context-interface", "revm-primitives", "ripemd", - "rug", "secp256k1 0.31.1", "sha2 0.10.9", ] [[package]] name = "revm-primitives" -version = "20.2.1" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa29d9da06fe03b249b6419b33968ecdf92ad6428e2f012dc57bcd619b5d94e" +checksum = "fe5102d804892908d4ebf68da29b8562895922dffa26c230ff2c4dadcf93916f" dependencies = [ "alloy-primitives", - "num_enum", "once_cell", "serde", ] [[package]] name = "revm-state" -version = "7.0.5" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" +checksum = "40eff6067185cf80932e06f6a9c8045b012ecb6f99a8d6edc618ec2792373e14" dependencies = [ - "bitflags 2.10.0", + "alloy-eip7928 0.4.5", + "bitflags 2.13.1", + "nonmax", "revm-bytecode", "revm-primitives", "serde", @@ -16400,9 +17588,9 @@ dependencies = [ [[package]] name = "ringbuffer" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53" +checksum = "57b0b88a509053cbfd535726dcaaceee631313cef981266119527a1d110f6d2b" [[package]] name = "ripemd" @@ -16462,9 +17650,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.12" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" +checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" dependencies = [ "bytemuck", "byteorder", @@ -16545,18 +17733,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rug" -version = "1.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de190ec858987c79cad4da30e19e546139b3339331282832af004d0ea7829639" -dependencies = [ - "az", - "gmp-mpfr-sys", - "libc", - "libm", -] - [[package]] name = "ruint" version = "1.17.2" @@ -16618,6 +17794,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.3.3" @@ -16650,30 +17835,17 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -16778,7 +17950,7 @@ checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.21.1", "log", "once_cell", "rustls 0.23.36", @@ -16791,6 +17963,27 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni 0.21.1", + "log", + "once_cell", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.9", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs 1.0.6", + "windows-sys 0.52.0", +] + [[package]] name = "rustls-platform-verifier-android" version = "0.1.1" @@ -16860,6 +18053,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -17003,7 +18205,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -17016,7 +18218,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -17033,13 +18235,22 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser", + "semver-parser 0.10.3", ] [[package]] @@ -17052,6 +18263,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "semver-parser" version = "0.10.3" @@ -17078,11 +18295,11 @@ name = "sentinel" version = "0.1.0" dependencies = [ "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", + "alloy-provider 1.0.37", + "alloy-rpc-types 1.0.37", "alloy-sol-macro", "alloy-sol-types", - "alloy-transport-http", + "alloy-transport-http 1.0.37", "anyhow", "chrono", "csv", @@ -17242,6 +18459,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -17327,7 +18553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -17345,7 +18571,7 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", ] @@ -17357,7 +18583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -17369,7 +18595,7 @@ checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", - "keccak", + "keccak 0.1.5", "opaque-debug", ] @@ -17380,7 +18606,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", - "keccak", + "keccak 0.1.5", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.0", ] [[package]] @@ -17418,19 +18654,16 @@ dependencies = [ ] [[package]] -name = "shellexpand" -version = "3.1.2" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" -dependencies = [ - "dirs", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" @@ -17450,7 +18683,7 @@ checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio 0.8.11", - "mio 1.1.1", + "mio 1.2.2", "signal-hook", ] @@ -17486,6 +18719,22 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version 0.4.1", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "similar" version = "2.7.0" @@ -17558,7 +18807,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ - "bitmaps", + "bitmaps 2.1.0", "typenum", ] @@ -17599,6 +18848,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "small_btree" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba60d2df92ba73864714808ca68c059734853e6ab722b40e1cf543ebb3a057a" +dependencies = [ + "arrayvec 0.7.6", +] + [[package]] name = "smallbitvec" version = "2.6.0" @@ -17672,9 +18930,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.60.2", @@ -17737,12 +18995,6 @@ dependencies = [ "der 0.7.10", ] -[[package]] -name = "sptr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" - [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -17824,20 +19076,20 @@ dependencies = [ [[package]] name = "strum" -version = "0.26.3" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros 0.26.4", + "strum_macros 0.27.2", ] [[package]] name = "strum" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ - "strum_macros 0.27.2", + "strum_macros 0.28.0", ] [[package]] @@ -17868,22 +19120,21 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "rustversion", "syn 2.0.114", ] [[package]] name = "strum_macros" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -17926,6 +19177,12 @@ dependencies = [ "symbolic-common", ] +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -17948,11 +19205,22 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn-solidity" -version = "1.5.4" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2379beea9476b89d0237078be761cf8e012d92d5ae4ae0c9a329f974838870fc" +checksum = "083be3061e64d362cbe6ef12cfe1307ba3884326d8856448fe8a120fa2c44ebf" dependencies = [ "paste", "proc-macro2", @@ -18003,15 +19271,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.1" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "windows 0.57.0", + "objc2-core-foundation", + "objc2-io-kit", + "windows", ] [[package]] @@ -18031,7 +19300,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.1", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -18056,6 +19325,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tag_ptr" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0e973b34477b7823833469eb0f5a3a60370fef7a453e02d751b59180d0a5a05" + [[package]] name = "tagptr" version = "0.2.0" @@ -18070,9 +19345,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.44" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" dependencies = [ "filetime", "libc", @@ -18098,7 +19373,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -18224,6 +19499,20 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "thread-priority" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2e834949be5111506bb252643498af1514f600d9e1dceedaa42afae155b67f" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -18281,7 +19570,6 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", - "js-sys", "libc", "num-conv", "num_threads", @@ -18316,7 +19604,7 @@ dependencies = [ "anyhow", "hmac 0.8.1", "once_cell", - "pbkdf2", + "pbkdf2 0.4.0", "rand 0.7.3", "rustc-hash 1.1.0", "sha2 0.9.9", @@ -18335,16 +19623,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec 0.10.4", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -18352,7 +19630,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", - "zerovec 0.11.5", + "serde_core", + "zerovec", ] [[package]] @@ -18382,30 +19661,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ + "backtrace", "bytes", "libc", - "mio 1.1.1", + "mio 1.2.2", "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2 0.6.5", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 3.0.3", ] [[package]] @@ -18507,9 +19787,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", @@ -18518,7 +19798,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", - "tungstenite 0.26.2", + "tungstenite 0.28.0", "webpki-roots 0.26.11", ] @@ -18544,7 +19824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_edit 0.19.15", ] @@ -18556,11 +19836,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.14", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -18587,7 +19882,7 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -18600,7 +19895,7 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_write", "winnow 0.7.14", @@ -18633,6 +19928,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + [[package]] name = "tonic" version = "0.12.3" @@ -18654,7 +19955,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", + "prost 0.13.5", "rustls-native-certs 0.8.3", "rustls-pemfile 2.2.0", "socket2 0.5.10", @@ -18669,17 +19970,54 @@ dependencies = [ "zstd", ] +[[package]] +name = "tonic" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "sync_wrapper 1.0.2", + "tokio", + "tokio-stream", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost 0.14.4", + "tonic 0.14.6", +] + [[package]] name = "tonic-reflection" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "878d81f52e7fcfd80026b7fdb6a9b578b3c3653ba987f87f0dce4b64043cba27" dependencies = [ - "prost", + "prost 0.13.5", "prost-types", "tokio", "tokio-stream", - "tonic", + "tonic 0.12.3", ] [[package]] @@ -18736,7 +20074,7 @@ checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "async-compression", "base64 0.22.1", - "bitflags 2.10.0", + "bitflags 2.13.1", "bytes", "futures-core", "futures-util", @@ -18785,11 +20123,12 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", + "symlink", "thiserror 2.0.18", "time", "tracing-subscriber 0.3.22", @@ -18806,6 +20145,17 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "tracing-chrome" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber 0.3.22", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -18871,6 +20221,38 @@ dependencies = [ "tracing-subscriber 0.3.22", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" +dependencies = [ + "js-sys", + "opentelemetry", + "smallvec", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber 0.3.22", + "web-time", +] + +[[package]] +name = "tracing-samply" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c175f7ecc002b6ef04776a39f440503e4e788790ddbdbfac8259b7a069526334" +dependencies = [ + "cfg-if", + "itoa", + "libc", + "mach2 0.5.0", + "memmap2", + "smallvec", + "tracing-core", + "tracing-subscriber 0.3.22", +] + [[package]] name = "tracing-serde" version = "0.2.0" @@ -18941,9 +20323,9 @@ dependencies = [ [[package]] name = "tree_hash" -version = "0.10.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee44f4cef85f88b4dea21c0b1f58320bdf35715cf56d840969487cff00613321" +checksum = "f7fd51aa83d2eb83b04570808430808b5d24fdbf479a4d5ac5dee4a2e2dd2be4" dependencies = [ "alloy-primitives", "ethereum_hashing", @@ -18954,11 +20336,11 @@ dependencies = [ [[package]] name = "tree_hash_derive" -version = "0.10.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bee2ea1551f90040ab0e34b6fb7f2fa3bad8acc925837ac654f2c78a13e3089" +checksum = "8840ad4d852e325d3afa7fde8a50b2412f89dce47d7eb291c0cc7f87cd040f38" dependencies = [ - "darling 0.20.10", + "darling 0.23.0", "proc-macro2", "quote", "syn 2.0.114", @@ -19034,9 +20416,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", @@ -19066,6 +20448,12 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.19.0" @@ -19206,13 +20594,13 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" -version = "1.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "unicode-segmentation", - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] @@ -19239,7 +20627,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "subtle", ] @@ -19681,6 +21069,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "widestring" version = "0.5.1" @@ -19727,7 +21125,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -19736,16 +21134,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.62.2" @@ -19753,7 +21141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.62.2", + "windows-core", "windows-future", "windows-numerics", ] @@ -19764,19 +21152,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.2", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -19785,10 +21161,10 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.4.1", + "windows-result", "windows-strings", ] @@ -19798,22 +21174,11 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link", "windows-threading", ] -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "windows-implement" version = "0.60.2" @@ -19825,17 +21190,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "windows-interface" version = "0.59.3" @@ -19859,7 +21213,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link", ] @@ -19870,19 +21224,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ "windows-link", - "windows-result 0.4.1", + "windows-result", "windows-strings", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.4.1" @@ -20225,6 +21570,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -20247,12 +21601,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "writeable" version = "0.6.2" @@ -20315,6 +21663,12 @@ dependencies = [ "rustix 1.1.3", ] +[[package]] +name = "xsum" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0637d3a5566a82fa5214bae89087bc8c9fb94cd8e8a3c07feb691bb8d9c632db" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -20339,18 +21693,6 @@ dependencies = [ "time", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive 0.7.5", - "zerofrom", -] - [[package]] name = "yoke" version = "0.8.1" @@ -20358,22 +21700,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", - "yoke-derive 0.8.1", + "yoke-derive", "zerofrom", ] -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "synstructure", -] - [[package]] name = "yoke-derive" version = "0.8.1" @@ -20492,19 +21822,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", - "yoke 0.8.1", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke 0.7.5", + "yoke", "zerofrom", - "zerovec-derive 0.10.3", ] [[package]] @@ -20513,20 +21832,10 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ - "yoke 0.8.1", + "serde", + "yoke", "zerofrom", - "zerovec-derive 0.11.2", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "zerovec-derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d107656f9..b71082291 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ unexpected_cfgs = { level = "allow", check-cfg = ["cfg(mirai)"] } aptos-consensus = { path = "./aptos-core/consensus" } # from aptos ======================= -gaptos = { git = "https://github.com/Galxe/gravity-aptos.git", rev = "b1f68dc85781ef0d28a568d9d64604b153be9d9e" } +gaptos = { git = "https://github.com/Galxe/gravity-aptos.git", rev = "d163fa649970c7c8446dbc41a367c2d0b960cca6" } aptos-executor-types = { path = "dependencies/aptos-executor-types" } aptos-executor = { path = "dependencies/aptos-executor" } api = { path = "./crates/api" } @@ -496,6 +496,7 @@ debug-assertions = true debug = true [patch.crates-io] +reth-primitives-traits = { git = "https://github.com/Galxe/gravity-reth", rev = "a5cf019429d772cd2f4964fc0705676d84464953" } serde-reflection = { git = "https://github.com/aptos-labs/serde-reflection", rev = "73b6bbf748334b71ff6d7d09d06a29e3062ca075" } merlin = { git = "https://github.com/aptos-labs/merlin" } tonic = { git = "https://github.com/aptos-labs/tonic.git", rev = "0da1ba8b1751d6e19eb55be24cccf9ae933c666e" } @@ -507,4 +508,3 @@ alloy-tx-macros = { git = "https://github.com/alloy-rs/alloy", tag = "v1.0.37" } # into a `continue` via `unwrap_or_continue!`, producing a pure-user-space # 100% CPU spin). Upstream issue: https://github.com/jmagnuson/linemux/issues/57 linemux = { git = "https://github.com/Galxe/linemux.git", rev = "0194e0222134c587dcd50039a1ff9c8a14fae550" } - diff --git a/bin/gravity_node/Cargo.toml b/bin/gravity_node/Cargo.toml index 5f60c3a34..ed05e5dc2 100644 --- a/bin/gravity_node/Cargo.toml +++ b/bin/gravity_node/Cargo.toml @@ -20,7 +20,7 @@ futures-util = "0.3.30" clap = { version = "4.5.17", features = ["derive", "env"] } futures = "0.3.30" dirs = "5.0.1" -tokio = "1.40.0" +tokio = { version = "=1.52.3", features = ["taskdump"] } tokio-stream = "0.1.16" eyre = "0.6.12" tracing = "0.1.40" @@ -33,15 +33,16 @@ sha2.workspace = true bincode = "1.3" time = "0.3.36" anyhow = "1.0.87" -greth = { git = "https://github.com/Galxe/gravity-reth", rev = "b49b4864aeaa3c35c6871a77d7133bb9486edbf1" } +# Pin the exact oracle integration revision validated by this SDK branch. +greth = { git = "https://github.com/Galxe/gravity-reth", rev = "a5cf019429d772cd2f4964fc0705676d84464953" } reqwest = "0.12.9" -alloy-primitives = { version = "=1.3.1", default-features = false, features = ["map-foldhash"] } -alloy-eips = { version = "^1.0.37", default-features = false } -alloy-consensus = { version = "=1.0.37" } -alloy-genesis = { version = "=1.0.37", default-features = false } -alloy-serde = { version = "=1.0.37" } -alloy-transport-http = "=1.0.37" -alloy-rpc-types-eth = "=1.0.37" +alloy-primitives = { version = "=1.6.0", default-features = false, features = ["map-foldhash"] } +alloy-eips = { version = "=2.0.5", default-features = false } +alloy-consensus = { version = "=2.0.5" } +alloy-genesis = { version = "=2.0.5", default-features = false } +alloy-serde = { version = "=2.0.5" } +alloy-transport-http = "=2.0.5" +alloy-rpc-types-eth = "=2.0.5" async-trait.workspace = true api.workspace = true gaptos = { workspace = true, features = ["gcp-secret-manager"] } diff --git a/bin/gravity_node/src/cli.rs b/bin/gravity_node/src/cli.rs index 23be0591f..f8f0fd15c 100644 --- a/bin/gravity_node/src/cli.rs +++ b/bin/gravity_node/src/cli.rs @@ -12,7 +12,7 @@ use greth::{ reth_node_builder::{NodeBuilder, WithLaunchContext}, reth_node_core::args::LogArgs, reth_node_ethereum::{consensus::EthBeaconConsensus, EthEvmConfig, EthereumNode}, - reth_tracing::FileWorkerGuard, + reth_tracing::TracingGuards, }; use std::{ collections::BTreeMap, @@ -159,6 +159,7 @@ impl, Ext: clap::Args + fmt::Debug> Cl debug!(target: "reth::cli", "Initialized tracing, log directory: {}, log level {:?}", self.logs.log_file_directory, self.logs.verbosity); let runner = CliRunner::try_default_runtime()?; + let runtime = runner.runtime(); let components = |spec: Arc| { (EthEvmConfig::ethereum(spec.clone()), Arc::new(EthBeaconConsensus::new(spec))) }; @@ -171,18 +172,20 @@ impl, Ext: clap::Args + fmt::Debug> Cl } Commands::Init(command) => { println!("Running init command"); - runner.run_blocking_until_ctrl_c(command.execute::()) + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::InitState(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()), Commands::Db(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + runner.run_blocking_command_until_exit(|ctx| command.execute::(ctx)) } Commands::P2P(command) => runner.run_until_ctrl_c(command.execute::()), Commands::Config(command) => runner.run_until_ctrl_c(command.execute()), - Commands::Prune(command) => runner.run_until_ctrl_c(command.execute::()), + Commands::Prune(command) => { + runner.run_command_until_exit(|ctx| command.execute::(ctx)) + } Commands::Stage(command) => { println!("Running stage command"); runner.run_command_until_exit(|ctx| { @@ -197,7 +200,7 @@ impl, Ext: clap::Args + fmt::Debug> Cl /// /// If file logging is enabled, this function returns a guard that must be kept alive to ensure /// that all logs are flushed to disk. - pub fn init_tracing(&self) -> eyre::Result> { + pub fn init_tracing(&self) -> eyre::Result { let guard = self.logs.init_tracing()?; Ok(guard) } diff --git a/bin/gravity_node/src/relayer.rs b/bin/gravity_node/src/relayer.rs index 0b84de20e..2d2b96af6 100644 --- a/bin/gravity_node/src/relayer.rs +++ b/bin/gravity_node/src/relayer.rs @@ -9,7 +9,7 @@ use gaptos::api_types::{ relayer::{PollResult, Relayer}, ExecError, }; -use greth::reth_pipe_exec_layer_relayer::OracleRelayerManager; +use greth::reth_pipe_exec_layer_relayer::{parse_oracle_uri, OracleRelayerManager}; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use tracing::{info, warn}; @@ -37,19 +37,17 @@ impl RelayerConfig { } } -/// Sanitize a URL for safe logging: keep only scheme://host[:port], redact path and query. -/// e.g. "https://mainnet.infura.io/v3/SECRET_KEY" → "https://mainnet.infura.io/***" +/// Keep only scheme and host for logging; redact userinfo, path, query, and fragment. fn sanitize_url(url: &str) -> String { - if let Some(scheme_end) = url.find("://") { - let scheme = &url[..scheme_end]; - let rest = &url[scheme_end + 3..]; - // Host ends at the first '/' or '?' or end of string - let host_end = rest.find('/').or_else(|| rest.find('?')).unwrap_or(rest.len()); - let host_port = &rest[..host_end]; - format!("{scheme}://{host_port}/***") - } else { - "***".to_string() - } + let Ok(parsed) = reqwest::Url::parse(url) else { + return "***".to_string(); + }; + let Some(host) = parsed.host_str() else { + return "***".to_string(); + }; + let host = if host.contains(':') { format!("[{host}]") } else { host.to_string() }; + let port = parsed.port().map(|value| format!(":{value}")).unwrap_or_default(); + format!("{}://{}{} /***", parsed.scheme(), host, port) } #[derive(Debug, Clone, Default)] @@ -100,7 +98,10 @@ impl RelayerWrapper { let config = config_path .and_then(|path| match RelayerConfig::from_file(&path) { Ok(cfg) => { - info!("Loaded relayer config from {:?}", path); + info!( + file = %path.file_name().and_then(|name| name.to_str()).unwrap_or(""), + "Loaded relayer config" + ); Some(cfg) } Err(e) => { @@ -119,7 +120,7 @@ impl RelayerWrapper { } /// Fetch oracle source states from on-chain storage - async fn get_oracle_source_states() -> Vec { + async fn get_oracle_source_states() -> Result, ExecError> { let block_number = get_block_buffer_manager().latest_commit_block_number().await; info!("get_oracle_source_states latest commit block number: {}", block_number); @@ -130,50 +131,43 @@ impl RelayerWrapper { { Some(bytes) => bytes, None => { - warn!("Failed to fetch OracleState config"); - return vec![]; + let message = format!("OracleState unavailable at committed block {block_number}"); + warn!("{message}"); + return Err(ExecError::Other(message)); } }; let bytes: Bytes = match config_bytes.try_into() { Ok(b) => b, Err(e) => { - warn!("Failed to convert OracleState config bytes: {:?}", e); - return vec![]; + let message = format!("Failed to convert OracleState config bytes: {e:?}"); + warn!("{message}"); + return Err(ExecError::Other(message)); } }; - match bcs::from_bytes::>(&bytes) { - Ok(states) => { - info!("Fetched {} oracle source states", states.len()); - states - } - Err(e) => { - warn!("Failed to deserialize OracleSourceStates: {:?}", e); - vec![] - } - } + let states = Self::decode_oracle_source_states(&bytes).map_err(|error| { + warn!("{error:?}"); + error + })?; + info!("Fetched {} oracle source states", states.len()); + Ok(states) } - /// Parse URI to extract source_type and source_id - /// URI format: gravity:////? - fn parse_source_from_uri(uri: &str) -> Option<(u32, u64)> { - if !uri.starts_with("gravity://") { - return None; - } - - let rest = &uri[10..]; // len("gravity://") = 10 - let parts: Vec<&str> = rest.split('/').collect(); - if parts.len() < 2 { - return None; - } - - let source_type: u32 = parts[0].parse().ok()?; - // Remove query string from source_id if present - let source_id_str = parts[1].split('?').next()?; - let source_id: u64 = source_id_str.parse().ok()?; + fn decode_oracle_source_states(bytes: &[u8]) -> Result, ExecError> { + bcs::from_bytes(bytes).map_err(|error| { + ExecError::Other(format!("Failed to deserialize OracleSourceStates: {error}")) + }) + } - Some((source_type, source_id)) + /// Parse only the source identity used to reconcile on-chain state. + /// + /// The reth relayer validates the task type and provider-specific parameters when the URI is + /// added. Keeping this helper limited to `(source_type, source_id)` avoids duplicating those + /// rules in the SDK wrapper. + fn parse_source_from_uri(uri: &str) -> Option<(u32, u64)> { + let task = parse_oracle_uri(uri).ok()?; + Some((task.source_type, task.source_id)) } /// Find oracle state for a URI by matching source_type and source_id @@ -185,15 +179,34 @@ impl RelayerWrapper { states.iter().find(|s| s.source_type == source_type && s.source_id == source_id) } + fn require_oracle_state_for_uri<'a>( + uri: &str, + states: &'a [OracleSourceState], + ) -> Result<&'a OracleSourceState, ExecError> { + Self::find_oracle_state_for_uri(uri, states).ok_or_else(|| { + let available_sources = states + .iter() + .map(|state| format!("{}:{}", state.source_type, state.source_id)) + .collect::>() + .join(", "); + ExecError::Other(format!( + "Oracle state not found for URI: {uri}. Available source identities: [{available_sources}]" + )) + }) + } + + fn source_position_u64(state: &OracleSourceState) -> Result { + u64::try_from(state.latest_position).map_err(|_| { + ExecError::Other(format!( + "Oracle source position exceeds u64 for {}:{}", + state.source_type, state.source_id + )) + }) + } + /// Block poll if we returned data and on-chain hasn't caught up - fn should_block_poll(state: &ProviderState, onchain_nonce: Option) -> bool { - if let Some(fetched) = state.fetched_nonce { - if let Some(onchain) = onchain_nonce { - // Block if we returned data and on-chain nonce hasn't caught up - return state.last_had_update && fetched > onchain; - } - } - false + fn should_block_poll(state: &ProviderState, onchain_nonce: u128) -> bool { + state.last_had_update && state.fetched_nonce.is_some_and(|fetched| fetched > onchain_nonce) } /// Submission-side dedup guard (gravity-audit subtask 2). Returns true when the observed @@ -233,18 +246,18 @@ impl RelayerWrapper { &self, uri: &str, onchain_nonce: Option, - onchain_block_number: Option, + onchain_position: Option, state: &ProviderState, ) -> Result { info!( - "Polling uri: {} (onchain_nonce: {:?}, onchain_block: {:?}, fetched_nonce: {:?}, last_had_update: {})", - uri, onchain_nonce, onchain_block_number, state.fetched_nonce, state.last_had_update + "Polling uri: {} (onchain_nonce: {:?}, onchain_position: {:?}, fetched_nonce: {:?}, last_had_update: {})", + uri, onchain_nonce, onchain_position, state.fetched_nonce, state.last_had_update ); // Pass onchain state to poll_uri for reconciliation let result = self .manager - .poll_uri(uri, onchain_nonce, onchain_block_number) + .poll_uri(uri, onchain_nonce, onchain_position) .await .map_err(|e| ExecError::Other(e.to_string()))?; @@ -270,31 +283,24 @@ impl Relayer for RelayerWrapper { .ok_or_else(|| ExecError::Other(format!("Provider {uri} not found in local config")))?; // Get onchain state for this URI using source_type/source_id from URI - let oracle_states = Self::get_oracle_source_states().await; - info!("Oracle states: {:?}", oracle_states); - let oracle_state = - Self::find_oracle_state_for_uri(uri, &oracle_states).ok_or_else(|| { - ExecError::Other(format!( - "Oracle state not found for URI: {uri}. Available states: {oracle_states:?}" - )) - })?; - - // Extract nonce and block_number from oracle state + let oracle_states = Self::get_oracle_source_states().await?; + let oracle_state = Self::require_oracle_state_for_uri(uri, &oracle_states)?; + + // Extract fixed-size progress from the authoritative oracle snapshot. let onchain_nonce = oracle_state.latest_nonce; - let onchain_block_number = - oracle_state.latest_record.as_ref().map(|r| r.block_number).unwrap_or(0); + let onchain_position = Self::source_position_u64(oracle_state)?; info!( - "Adding URI: {}, RPC URL: {}, onchain_nonce: {}, onchain_block: {}", + "Adding URI: {}, RPC URL: {}, onchain_nonce: {}, onchain_position: {}", uri, sanitize_url(actual_url), onchain_nonce, - onchain_block_number + onchain_position ); // Pass onchain state to manager for warm-start self.manager - .add_uri(uri, actual_url, onchain_nonce, onchain_block_number) + .add_uri(uri, actual_url, onchain_nonce, onchain_position) .await .map_err(|e| ExecError::Other(e.to_string())) } @@ -302,23 +308,18 @@ impl Relayer for RelayerWrapper { // All URIs starting with gravity:// are definitely UnsupportedJWK async fn get_last_state(&self, uri: &str) -> Result { // Get onchain state for this URI using source_type/source_id from URI - let oracle_states = Self::get_oracle_source_states().await; - let oracle_state = Self::find_oracle_state_for_uri(uri, &oracle_states); - - // Extract nonce and block_number for reconciliation - let (onchain_nonce, onchain_block_number) = if let Some(state) = oracle_state { - let nonce = Some(state.latest_nonce); - let block = state.latest_record.as_ref().map(|r| r.block_number); - (nonce, block) - } else { - (None, None) - }; + let oracle_states = Self::get_oracle_source_states().await?; + let oracle_state = Self::require_oracle_state_for_uri(uri, &oracle_states)?; + + // Extract fixed-size progress from an authoritative OracleState snapshot. + let onchain_nonce = oracle_state.latest_nonce; + let onchain_position = Some(Self::source_position_u64(oracle_state)?); let state = self.tracker.get_state(uri).await; info!( - "get_last_state - uri: {}, onchain_nonce: {:?}, onchain_block: {:?}, fetched_nonce: {:?}, last_had_update: {}", - uri, onchain_nonce, onchain_block_number, state.fetched_nonce, state.last_had_update + "get_last_state - uri: {}, onchain_nonce: {:?}, onchain_position: {:?}, fetched_nonce: {:?}, last_had_update: {}", + uri, onchain_nonce, onchain_position, state.fetched_nonce, state.last_had_update ); if Self::should_block_poll(&state, onchain_nonce) { @@ -336,11 +337,11 @@ impl Relayer for RelayerWrapper { } let result = - self.poll_and_update_state(uri, onchain_nonce, onchain_block_number, &state).await?; + self.poll_and_update_state(uri, Some(onchain_nonce), onchain_position, &state).await?; // Subtask 2: never surface an observation whose nonce is already committed on-chain — it // would inject a guaranteed-revert oracle `recordBatch`. See `guard_already_committed`. - Ok(Self::guard_already_committed(uri, result, onchain_nonce)) + Ok(Self::guard_already_committed(uri, result, Some(onchain_nonce))) } } @@ -368,6 +369,83 @@ mod tests { PollResult { jwk_structs: vec![], max_block_number: 100, nonce: Some(nonce), updated } } + #[test] + fn oracle_state_decoder_distinguishes_empty_from_invalid() { + let authoritative_empty = bcs::to_bytes(&Vec::::new()).unwrap(); + assert!(RelayerWrapper::decode_oracle_source_states(&authoritative_empty) + .unwrap() + .is_empty()); + + assert!(RelayerWrapper::decode_oracle_source_states(&[0xff]).is_err()); + } + + #[test] + fn oracle_state_decoder_preserves_fixed_size_progress() { + let encoded = bcs::to_bytes(&vec![OracleSourceState { + source_type: 3, + source_id: 1001, + latest_nonce: 7, + latest_position: 1_710_000_419_999, + }]) + .unwrap(); + + let decoded = RelayerWrapper::decode_oracle_source_states(&encoded).unwrap(); + assert_eq!(decoded.len(), 1); + assert_eq!(decoded[0].latest_nonce, 7); + assert_eq!(decoded[0].latest_position, 1_710_000_419_999); + assert_eq!(RelayerWrapper::source_position_u64(&decoded[0]).unwrap(), 1_710_000_419_999); + } + + #[test] + fn source_position_overflow_is_rejected() { + let state = OracleSourceState { + source_type: 0, + source_id: 1, + latest_nonce: 1, + latest_position: u128::from(u64::MAX) + 1, + }; + assert!(RelayerWrapper::source_position_u64(&state).is_err()); + } + + #[test] + fn missing_source_in_authoritative_snapshot_is_an_error() { + let error = RelayerWrapper::require_oracle_state_for_uri( + "gravity://3/1001/price_feed?provider=binance_index_kline_v1", + &[], + ) + .unwrap_err(); + + assert!( + matches!(error, ExecError::Other(message) if message.contains("Oracle state not found")) + ); + } + + #[tokio::test] + async fn failed_snapshot_decode_does_not_mutate_pending_tracker() { + let tracker = ProviderProgressTracker::new(); + let uri = "gravity://6/42/polymarket_settlement"; + tracker.update_state(uri, &poll_result(8, true)).await; + + assert!(RelayerWrapper::decode_oracle_source_states(&[0xff]).is_err()); + + let pending = tracker.get_state(uri).await; + assert_eq!(pending.fetched_nonce, Some(8)); + assert!(pending.last_had_update); + assert_eq!(pending.last_result.unwrap().nonce, Some(8)); + } + + #[test] + fn pending_result_blocks_poll_until_authoritative_nonce_catches_up() { + let state = ProviderState { + fetched_nonce: Some(8), + last_had_update: true, + last_result: Some(poll_result(8, true)), + }; + + assert!(RelayerWrapper::should_block_poll(&state, 7)); + assert!(!RelayerWrapper::should_block_poll(&state, 8)); + } + #[test] fn guard_suppresses_an_already_committed_duplicate() { // Artificial duplicate: an observation whose nonce (7) is already committed on-chain (7). @@ -395,4 +473,36 @@ mod tests { ); assert!(fresh.updated, "a genuinely-new observation (8 > 7) must NOT be suppressed"); } + + #[test] + fn test_parse_price_feed_source_uri() { + let uri = "gravity://3/1001/price_feed?provider=binance_index_kline_v1"; + assert_eq!(RelayerWrapper::parse_source_from_uri(uri), Some((3, 1001))); + } + + #[test] + fn test_parse_blockchain_source_uri() { + let uri = "gravity://0/31337/events?contract=0x0000000000000000000000000000000000000001"; + assert_eq!(RelayerWrapper::parse_source_from_uri(uri), Some((0, 31337))); + } + + #[test] + fn test_parse_source_accepts_identity_only_uri() { + assert_eq!(RelayerWrapper::parse_source_from_uri("gravity://3/1001"), Some((3, 1001))); + } + + #[test] + fn test_parse_source_rejects_unroutable_uri() { + assert_eq!(RelayerWrapper::parse_source_from_uri("gravity://price/1001"), None); + assert_eq!(RelayerWrapper::parse_source_from_uri("https://oracle.example/3/1001"), None); + } + + #[test] + fn test_sanitize_url_removes_credentials_and_path() { + let sanitized = sanitize_url("https://user:secret@polygon.example:8443/v1/key?token=abc"); + assert_eq!(sanitized, "https://polygon.example:8443 /***"); + assert!(!sanitized.contains("user")); + assert!(!sanitized.contains("secret")); + assert!(!sanitized.contains("token")); + } } diff --git a/bin/gravity_node/src/reth_cli.rs b/bin/gravity_node/src/reth_cli.rs index 1db745e4a..4a7f4027c 100644 --- a/bin/gravity_node/src/reth_cli.rs +++ b/bin/gravity_node/src/reth_cli.rs @@ -69,17 +69,10 @@ static GCEI_COINBASE_FALLBACK_TOTAL: Lazy = Lazy::new(|| { pub(crate) type RethBlockChainProvider = BlockchainProvider>>; -pub(crate) type RethTransactionPool = greth::reth_transaction_pool::Pool< - greth::reth_transaction_pool::TransactionValidationTaskExecutor< - greth::reth_transaction_pool::EthTransactionValidator< - RethBlockChainProvider, - greth::reth_transaction_pool::EthPooledTransaction, - >, - >, - greth::reth_transaction_pool::CoinbaseTipOrdering< - greth::reth_transaction_pool::EthPooledTransaction, - >, +pub(crate) type RethTransactionPool = greth::reth_transaction_pool::EthTransactionPool< + RethBlockChainProvider, greth::reth_transaction_pool::blobstore::DiskFileBlobStore, + greth::reth_node_ethereum::EthEvmConfig, >; pub(crate) trait RethEthCall: @@ -360,8 +353,8 @@ impl RethCli { let mut start_ordered_block = self .provider .recover_block_number() - .map_err(|e| format!("Failed to recover block number: {e}"))? + - 1; + .map_err(|e| format!("Failed to recover block number: {e}"))? + + 1; // Initialize current_epoch from block buffer manager let buffer_epoch = get_block_buffer_manager().get_current_epoch().await; self.current_epoch.store(buffer_epoch, Ordering::SeqCst); @@ -381,8 +374,8 @@ impl RethCli { }; if let Err(e) = exec_blocks { let from = start_ordered_block; - if e.to_string().contains("Buffer is in epoch change") || - current_epoch != get_block_buffer_manager().get_current_epoch().await + if e.to_string().contains("Buffer is in epoch change") + || current_epoch != get_block_buffer_manager().get_current_epoch().await { // consume_epoch_change returns (new_epoch, epoch_change_block_number) // and resets latest_epoch_change_block_number to 0 atomically. @@ -493,8 +486,8 @@ impl RethCli { let mut start_commit_num = self .provider .recover_block_number() - .map_err(|e| format!("Failed to recover block number: {e}"))? + - 1; + .map_err(|e| format!("Failed to recover block number: {e}"))? + + 1; let mut shutdown = self.shutdown.resubscribe(); loop { let epoch = self.current_epoch.load(Ordering::SeqCst); diff --git a/cluster/deploy.sh b/cluster/deploy.sh index 5e258758a..1a4b37422 100755 --- a/cluster/deploy.sh +++ b/cluster/deploy.sh @@ -432,9 +432,9 @@ done < <(jq -r '.env_vars | to_entries[] | .key, .value' "$reth_config") export RUST_BACKTRACE=1 pid=$( - env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ + nohup setsid env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ ${reth_args_array[*]} \ - > "${WORKSPACE}/logs/debug.log" 2>&1 & + > "${WORKSPACE}/logs/debug.log" 2>&1 < /dev/null & echo $! ) echo $pid > "${WORKSPACE}/script/node.pid" @@ -558,9 +558,9 @@ done < <(jq -r '.env_vars | to_entries[] | .key, .value' "$reth_config") export RUST_BACKTRACE=1 pid=$( - env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ + nohup setsid env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ ${reth_args_array[*]} \ - > "${WORKSPACE}/logs/debug.log" 2>&1 & + > "${WORKSPACE}/logs/debug.log" 2>&1 < /dev/null & echo $! ) echo $pid > "${WORKSPACE}/script/node.pid" @@ -689,9 +689,9 @@ done < <(jq -r '.env_vars | to_entries[] | .key, .value' "$reth_config") export RUST_BACKTRACE=1 pid=$( - env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ + nohup setsid env ${env_vars_array[*]} ${WORKSPACE}/bin/gravity_node node \ ${reth_args_array[*]} \ - > "${WORKSPACE}/logs/debug.log" 2>&1 & + > "${WORKSPACE}/logs/debug.log" 2>&1 < /dev/null & echo $! ) echo $pid > "${WORKSPACE}/script/node.pid" @@ -868,6 +868,7 @@ main() { export VFN_PORT=$(echo "$node" | jq -r '.vfn_port // "null"') export PUBLIC_PORT=$(echo "$node" | jq -r '.public_port // "null"') export RPC_PORT=$(echo "$node" | jq -r '.rpc_port') + export API_PORT=$(echo "$node" | jq -r '.api_port // 8080') export WS_PORT=$(echo "$node" | jq -r '.ws_port // "null"') export METRICS_PORT=$(echo "$node" | jq -r '.metrics_port') export INSPECTION_PORT=$(echo "$node" | jq -r '.inspection_port') diff --git a/cluster/genesis.sh b/cluster/genesis.sh index 4bb6a3013..ee4fcb688 100755 --- a/cluster/genesis.sh +++ b/cluster/genesis.sh @@ -36,10 +36,27 @@ main() { # Step 1: Clone/update external dependencies log_info "Step 1: Checking external dependencies..." + GENESIS_PATH=$(echo "$config_json" | jq -r '.dependencies.genesis_contracts.path // empty') GENESIS_REPO=$(echo "$config_json" | jq -r '.dependencies.genesis_contracts.repo // "https://github.com/Galxe/gravity_chain_core_contracts.git"') GENESIS_REF=$(echo "$config_json" | jq -r '.dependencies.genesis_contracts.ref // "main"') - - GENESIS_CONTRACT_DIR="$EXTERNAL_DIR/gravity_chain_core_contracts" + + GENESIS_CONTRACT_SOURCE_DIR="" + if [ -n "$GENESIS_PATH" ]; then + if [[ "$GENESIS_PATH" == /* ]]; then + GENESIS_CONTRACT_SOURCE_DIR="$GENESIS_PATH" + else + GENESIS_CONTRACT_SOURCE_DIR="$(cd "$(dirname "$GENESIS_CONFIG_FILE")" && realpath "$GENESIS_PATH")" + fi + if ! git -C "$GENESIS_CONTRACT_SOURCE_DIR" rev-parse --is-inside-work-tree &>/dev/null; then + log_error "Local genesis_contracts.path is not a git checkout: $GENESIS_CONTRACT_SOURCE_DIR" + exit 1 + fi + GENESIS_REPO="$GENESIS_CONTRACT_SOURCE_DIR" + GENESIS_CONTRACT_DIR="$EXTERNAL_DIR/gravity_chain_core_contracts_local" + log_info "Using local genesis contracts source: $GENESIS_CONTRACT_SOURCE_DIR" + else + GENESIS_CONTRACT_DIR="$EXTERNAL_DIR/gravity_chain_core_contracts" + fi if [ ! -d "$GENESIS_CONTRACT_DIR" ]; then log_warn "gravity_chain_core_contracts not found. Cloning from $GENESIS_REPO..." @@ -47,6 +64,13 @@ main() { git clone "$GENESIS_REPO" "$GENESIS_CONTRACT_DIR" fi + if [ -n "$GENESIS_CONTRACT_SOURCE_DIR" ]; then + ( + cd "$GENESIS_CONTRACT_DIR" + git remote set-url origin "$GENESIS_REPO" + ) + fi + # Checkout specified ref and pull latest (critical for branches to avoid stale bytecode) log_info "Checking out ref: $GENESIS_REF..." ( @@ -79,6 +103,13 @@ if p.exists(): " cd - ) + + if [ -n "$GENESIS_CONTRACT_SOURCE_DIR" ] \ + && [ ! -d "$GENESIS_CONTRACT_DIR/node_modules" ] \ + && [ -d "$GENESIS_CONTRACT_SOURCE_DIR/node_modules" ]; then + log_info "Reusing node_modules from local genesis contracts source..." + cp -a "$GENESIS_CONTRACT_SOURCE_DIR/node_modules" "$GENESIS_CONTRACT_DIR/node_modules" + fi # Install dependencies if missing if [ ! -d "$GENESIS_CONTRACT_DIR/node_modules" ]; then diff --git a/cluster/templates/validator.yaml.tpl b/cluster/templates/validator.yaml.tpl index 47f7418f9..ea5443d33 100644 --- a/cluster/templates/validator.yaml.tpl +++ b/cluster/templates/validator.yaml.tpl @@ -56,6 +56,9 @@ ${DISCOVERY_METHOD_FULLNODE_BLOCK} storage: dir: "${STORAGE_DIR}" +api: + address: 127.0.0.1:${API_PORT} + log_file_path: "${LOG_DIR}/consensus_log/validator.log" inspection_service: diff --git a/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/README.md b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/README.md new file mode 100644 index 000000000..618a529d3 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/README.md @@ -0,0 +1,32 @@ +# Four-Validator Live Binance E2E + +The public-network gate for four Binance observers, at least three equal-power +certifiers per feed, JWK voting-power quorum, onchain execution, and four-RPC +replication. A slower validator may fast-forward from the committed nonce. It +never accepts the local Binance mock and is excluded from the default suite +run. + +Run: + +```bash +BINANCE_PRICE_FEED_MODE=live \ +BINANCE_PRICE_FEED_BASE_URL=https://testnet.binancefuture.com \ +BINANCE_PRICE_FEED_LAG_MINUTES=4 \ +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh \ + binance_price_feed_multivalidator \ + --force-init \ + --log-cli-level=INFO +``` + +Use `https://fapi.binance.com` for production index prices. Binance may return +HTTP 451 when the process egress is not eligible for the production service; +that is an egress-policy failure, not an `indexPriceKlines` or symbol failure. +Use an approved eligible egress or the futures testnet. When wrapping the +suite in a process-level proxy, bypass loopback and private networks so +validator consensus and local RPC traffic remain local. + +The suite supports `--keep-running --demo-config-out ` for the live +frontend. See [`../../docs/ORACLE_E2E.md`](../../docs/ORACLE_E2E.md) for +approval requirements, assertions, replay parameters, revisions, and the last +verified result. diff --git a/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/cluster.toml b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/cluster.toml new file mode 100644 index 000000000..e3a15cbb1 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/cluster.toml @@ -0,0 +1,73 @@ +# Four-validator live Binance price-feed integration test. +# Keep fixed listeners below Linux's default ephemeral source-port range. + +[cluster] +name = "gravity-devnet-binance-price-feed-multivalidator" +base_dir = "/tmp/gravity-cluster-binance-price-feed-multivalidator" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26080 +vfn_port = 26090 +rpc_port = 26100 +api_port = 26110 +metrics_port = 26120 +inspection_port = 26130 +https_port = 26140 +authrpc_port = 26150 +reth_p2p_port = 26160 + +[[nodes]] +id = "node2" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26081 +vfn_port = 26091 +rpc_port = 26101 +api_port = 26111 +metrics_port = 26121 +inspection_port = 26131 +https_port = 26141 +authrpc_port = 26151 +reth_p2p_port = 26161 + +[[nodes]] +id = "node3" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26082 +vfn_port = 26092 +rpc_port = 26102 +api_port = 26112 +metrics_port = 26122 +inspection_port = 26132 +https_port = 26142 +authrpc_port = 26152 +reth_p2p_port = 26162 + +[[nodes]] +id = "node4" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26083 +vfn_port = 26093 +rpc_port = 26103 +api_port = 26113 +metrics_port = 26123 +inspection_port = 26133 +https_port = 26143 +authrpc_port = 26153 +reth_p2p_port = 26163 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/genesis.toml b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/genesis.toml new file mode 100644 index 000000000..d94775c94 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/genesis.toml @@ -0,0 +1,103 @@ +# Four-validator live Binance price-feed integration test. + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +# Equal voting power means a JWK QC requires matching signatures from at least +# three of the four validators. +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 26080 +vfn_port = 26090 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node2" +address = "0x7b254Bd44F6CE45e00a912b2460D47F3Be56fAD7" +host = "127.0.0.1" +validator_port = 26081 +vfn_port = 26091 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node3" +address = "0x9B2C25E77a97d3e84DC0Cb7F83fb676ddC4F24b9" +host = "127.0.0.1" +validator_port = 26082 +vfn_port = 26092 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node4" +address = "0x18c23753385ce7A60B15d171302E48b6AFf0BDC5" +host = "127.0.0.1" +validator_port = 26083 +vfn_port = 26093 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 30000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 3] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", +] + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/hooks.py b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/hooks.py new file mode 100644 index 000000000..02a7df09f --- /dev/null +++ b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/hooks.py @@ -0,0 +1,54 @@ +"""Prepare an explicit closed Binance bucket for the live four-validator suite.""" + +import json +import time +from pathlib import Path + +INTERVAL_MS = 60_000 +DEFAULT_GRACE_MS = 120_000 +DEFAULT_BASE_URL = "https://fapi.binance.com" +FEEDS = ((1001, "NVDAUSDT"), (1002, "TSLAUSDT")) + + +def _bucket_start_ms(env: dict) -> int: + configured = env.get("BINANCE_PRICE_FEED_BUCKET_START_MS") + if configured: + return int(configured) + + grace_ms = int(env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_GRACE_MS))) + minimum_lag = (grace_ms + INTERVAL_MS - 1) // INTERVAL_MS + 1 + lag_minutes = int(env.get("BINANCE_PRICE_FEED_LAG_MINUTES", str(minimum_lag))) + now_ms = int(time.time() * 1000) + return ((now_ms // INTERVAL_MS) - lag_minutes) * INTERVAL_MS + + +def _uri(feed_id: int, pair: str, bucket_start_ms: int, grace_ms: int) -> str: + return ( + f"gravity://3/{feed_id}/price_feed?" + f"provider=binance_index_kline_v1&pair={pair}&interval=1m&" + f"bucketStartMs={bucket_start_ms}&decimals=8&graceMs={grace_ms}" + ) + + +def pre_deploy(test_dir: Path, env: dict, pytest_args: list[str]): + requested_mode = env.get("BINANCE_PRICE_FEED_MODE", "live").strip().lower() + if requested_mode != "live": + raise RuntimeError("binance_price_feed_multivalidator only supports live mode") + + base_url = env.get("BINANCE_PRICE_FEED_BASE_URL", DEFAULT_BASE_URL) + grace_ms = int(env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_GRACE_MS))) + bucket_start_ms = _bucket_start_ms(env) + uris = { + _uri(feed_id, pair, bucket_start_ms, grace_ms): base_url + for feed_id, pair in FEEDS + } + + config_path = test_dir / "artifacts" / "relayer_config.live.json" + config_path.parent.mkdir(parents=True, exist_ok=True) + config_path.write_text(json.dumps({"uri_mappings": uris}, indent=2) + "\n") + + env["BINANCE_PRICE_FEED_MODE"] = "live" + env["BINANCE_PRICE_FEED_BASE_URL"] = base_url + env["BINANCE_PRICE_FEED_BUCKET_START_MS"] = str(bucket_start_ms) + env["BINANCE_PRICE_FEED_GRACE_MS"] = str(grace_ms) + env["RELAYER_CONFIG_TPL"] = str(config_path) diff --git a/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/test_binance_price_feed_multivalidator.py b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/test_binance_price_feed_multivalidator.py new file mode 100644 index 000000000..99961b270 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/test_binance_price_feed_multivalidator.py @@ -0,0 +1,434 @@ +"""Four-validator E2E against live Binance closed index-price klines.""" + +import asyncio +from decimal import Decimal +import json +import logging +import os +from pathlib import Path +import time +from urllib.parse import urlencode +from urllib.request import urlopen + +import pytest + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support + +try: + import tomllib +except ImportError: + import tomli as tomllib + + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent +FEEDS = { + support.NVDA_FEED_ID: "NVDAUSDT", + support.TSLA_FEED_ID: "TSLAUSDT", +} +TARGET_NONCE = 1 +QUORUM_VALIDATORS = 3 + + +def _bucket_start_ms() -> int: + value = os.environ.get("BINANCE_PRICE_FEED_BUCKET_START_MS") + assert value, "live bucket was not prepared by hooks.py" + return int(value) + + +def _genesis_quorum() -> tuple[int, int, int]: + config = tomllib.loads((SUITE_DIR / "genesis.toml").read_text()) + validators = config["genesis_validators"] + powers = [int(validator["voting_power"]) for validator in validators] + assert len(validators) == 4 + assert len(set(powers)) == 1 and powers[0] > 0 + total_power = sum(powers) + return len(validators), total_power, total_power * 2 // 3 + 1 + + +def _fetch_live_price(base_url: str, pair: str, bucket_start_ms: int) -> int: + bucket_end_ms = bucket_start_ms + support.INTERVAL_MS - 1 + query = urlencode( + { + "pair": pair, + "interval": "1m", + "startTime": bucket_start_ms, + "endTime": bucket_end_ms, + "limit": 1, + } + ) + with urlopen(f"{base_url}/fapi/v1/indexPriceKlines?{query}", timeout=15) as response: + rows = json.loads(response.read()) + + assert len(rows) == 1, f"Binance returned {len(rows)} rows for {pair}" + row = rows[0] + assert row[0] == bucket_start_ms + assert row[6] == bucket_end_ms + scaled = Decimal(row[4]) * (10**support.DECIMALS) + assert scaled == scaled.to_integral_value() + return int(scaled) + + +def _write_demo_config( + cluster: Cluster, + resolver_address: str, + chain_id: int, + base_url: str, + rounds: dict[int, tuple], + bucket_start_ms: int, + round_id: int, + resolved_at: int, +): + output = os.environ.get("GRAVITY_DEMO_CONFIG_OUT") + if not output: + return + + def feed(feed_id: int, pair: str): + price = int(rounds[feed_id][4]) + return { + "feedId": feed_id, + "label": f"{pair.removesuffix('USDT')} Binance index", + "pair": pair, + "sourceType": support.SOURCE_TYPE_PRICE_FEED, + "decimals": support.DECIMALS, + "expectedDeliveryNonce": TARGET_NONCE, + "expectedRoundId": round_id, + "expectedResolvedAt": resolved_at, + "expectedPrice": str(price), + "expectedDisplayPrice": support.format_price(price), + } + + config = { + "version": 1, + "mode": "live-binance-index-kline", + "network": { + "chainId": chain_id, + "rpcUrl": cluster.get_node("node1").url, + "rpcProxyPath": "/rpc", + }, + "contracts": { + "priceFeedResolver": resolver_address, + "multiSourceOracleResolver": resolver_address, + "nativeOracle": support.NATIVE_ORACLE_ADDRESS, + "oracleTaskConfig": support.ORACLE_TASK_CONFIG_ADDRESS, + }, + "provider": { + "kind": "live-binance", + "name": "Binance USD-M indexPriceKlines", + "baseUrl": base_url, + "endpoint": "/fapi/v1/indexPriceKlines", + "interval": "1m", + "live": True, + }, + "feeds": [feed(feed_id, pair) for feed_id, pair in FEEDS.items()], + "demo": { + "providerMode": "live", + "bucketStartMs": bucket_start_ms, + "intervalMs": support.INTERVAL_MS, + "targetDeliveryNonce": TARGET_NONCE, + "targetRoundId": round_id, + "targetResolvedAt": resolved_at, + }, + } + + output_path = Path(output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(json.dumps(config, indent=2) + "\n") + LOG.info("Wrote live price feed demo config to %s", output_path) + + +def _consensus_log(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "consensus_log" / "validator.log" + + +def _relayer_state(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "data" / "reth" / "relayer_state.json" + + +def _line_matches(content: str, marker: str, issuer_prefix: str) -> bool: + return any( + marker in line and issuer_prefix in line + for line in content.splitlines() + ) + + +async def _wait_for_block(w3, block_number: int, timeout: int = 60): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if w3.eth.block_number >= block_number: + return + await asyncio.sleep(1) + raise TimeoutError(f"RPC did not reach Gravity block {block_number}") + + +async def _wait_for_consensus_evidence( + cluster: Cluster, + feed_ids: list[int], + timeout: int = 180, +): + missing_observers = { + (node_id, feed_id) + for node_id in cluster.nodes + for feed_id in feed_ids + } + certifiers = {feed_id: set() for feed_id in feed_ids} + missing_quorums = set(feed_ids) + deadline = time.monotonic() + timeout + + while time.monotonic() < deadline: + logs = {} + for node_id in cluster.nodes: + path = _consensus_log(cluster, node_id) + logs[node_id] = path.read_text(errors="replace") if path.exists() else "" + + for node_id, feed_id in list(missing_observers): + if _line_matches( + logs[node_id], + "JWKObserver spawned.", + f"gravity://3/{feed_id}", + ): + missing_observers.remove((node_id, feed_id)) + + for feed_id in feed_ids: + for node_id, content in logs.items(): + if _line_matches( + content, + "Start certifying update.", + f"gravity://3/{feed_id}", + ): + certifiers[feed_id].add(node_id) + + for feed_id in list(missing_quorums): + issuer = f"gravity://3/{feed_id}" + if any( + any( + "Peer vote aggregated." in line + and issuer in line + and ( + "threshold_exceeded=true" in line + or '"threshold_exceeded":true' in line + ) + for line in content.splitlines() + ) + for content in logs.values() + ): + missing_quorums.remove(feed_id) + + if ( + not missing_observers + and all( + len(certifiers[feed_id]) >= QUORUM_VALIDATORS + for feed_id in feed_ids + ) + and not missing_quorums + ): + return + await asyncio.sleep(2) + + certifier_summary = { + feed_id: sorted(nodes) for feed_id, nodes in certifiers.items() + } + raise AssertionError( + "missing validator oracle evidence: " + f"observers={sorted(missing_observers)}, " + f"certifiers={certifier_summary}, " + f"quorums={sorted(missing_quorums)}" + ) + + +def _assert_independent_relayer_state( + cluster: Cluster, + uris: dict[int, str], +): + for node_id in cluster.nodes: + state_path = _relayer_state(cluster, node_id) + assert state_path.exists(), f"{node_id} has no relayer state" + state = json.loads(state_path.read_text()) + for feed_id, uri in uris.items(): + source = state["sources"].get(uri) + assert source is not None, f"{node_id} has no state for feedId={feed_id}" + assert source["source_type"] == support.SOURCE_TYPE_PRICE_FEED + assert source["source_id"] == feed_id + assert int(source["last_nonce"]) >= TARGET_NONCE + + +@pytest.mark.asyncio +async def test_four_validators_certify_live_binance_prices(cluster: Cluster): + assert support.is_live_mode(), "this suite must never use the local mock" + assert len(cluster.nodes) == 4 + assert await cluster.set_full_live(timeout=120) + assert await cluster.check_block_increasing(timeout=60) + + validator_count, total_power, quorum_power = _genesis_quorum() + validator_set = await cluster.validator_list() + assert {node.id for node in validator_set.active} == set(cluster.nodes) + LOG.info( + "Active validators=%s totalVotingPower=%s JWKQuorumPower=%s", + validator_count, + total_power, + quorum_power, + ) + + node1 = cluster.get_node("node1") + assert node1 is not None and node1.w3.is_connected() + w3 = node1.w3 + + required = [ + ("PriceFeedResolver.sol", "PriceFeedResolver"), + ("NativeOracle.sol", "NativeOracle"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ] + contracts_out = support.ensure_contracts_out(SUITE_DIR, required, "Price feed") + resolver_artifact = support.load_artifact( + contracts_out, "PriceFeedResolver.sol", "PriceFeedResolver" + ) + native_artifact = support.load_artifact( + contracts_out, "NativeOracle.sol", "NativeOracle" + ) + task_artifact = support.load_artifact( + contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig" + ) + + resolver = support.deploy_contract(w3, resolver_artifact, support.FAUCET_KEY) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + task_config = w3.eth.contract( + address=support.ORACLE_TASK_CONFIG_ADDRESS, + abi=task_artifact["abi"], + ) + pool_addr = support.pool0_voted_by_faucet(w3) + + bucket_start_ms = _bucket_start_ms() + base_url = support.binance_base_url().rstrip("/") + uris = { + feed_id: support.price_feed_uri(feed_id, pair, bucket_start_ms) + for feed_id, pair in FEEDS.items() + } + + setup_data = [ + support.function_calldata( + native_oracle.functions.setDefaultCallback( + support.SOURCE_TYPE_PRICE_FEED, + resolver.address, + ) + ) + ] + targets = [support.NATIVE_ORACLE_ADDRESS] + for feed_id, uri in uris.items(): + targets.append(support.ORACLE_TASK_CONFIG_ADDRESS) + setup_data.append( + support.function_calldata( + task_config.functions.setTask( + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + support.TASK_PRICE_FEED, + uri.encode(), + ) + ) + ) + + await support.execute_governance_proposal( + w3, + pool_addr, + targets, + setup_data, + "live-binance-four-validator-e2e", + ) + + for feed_id in FEEDS: + assert await support.poll_oracle_delivered( + w3, + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + timeout=300, + ) + await support.wait_for_latest_price( + native_oracle, + resolver, + feed_id, + TARGET_NONCE, + timeout=300, + ) + + await _wait_for_consensus_evidence(cluster, list(FEEDS), timeout=180) + _assert_independent_relayer_state(cluster, uris) + + snapshot_block = w3.eth.block_number + node1_rounds = {} + node1_progress = {} + expected_prices = {} + for feed_id, pair in FEEDS.items(): + progress = tuple( + native_oracle.functions.getSourceProgress( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call(block_identifier=snapshot_block) + ) + stored = tuple( + resolver.functions.latestPrice(feed_id).call( + block_identifier=snapshot_block + ) + ) + assert progress[0] >= TARGET_NONCE + assert progress[1] == stored[2] + expected_bucket_start = support.round_start_ms( + bucket_start_ms, progress[0] + ) + assert stored[1] == support.round_id(bucket_start_ms, progress[0]) + assert stored[2] == support.round_end_ms(bucket_start_ms, progress[0]) + expected_price = await asyncio.to_thread( + _fetch_live_price, + base_url, + pair, + expected_bucket_start, + ) + assert stored[3] == support.DECIMALS + assert stored[4] == expected_price + node1_progress[feed_id] = progress + node1_rounds[feed_id] = stored + expected_prices[feed_id] = expected_price + + for node_id, node in cluster.nodes.items(): + assert node.w3.is_connected(), f"{node_id} RPC disconnected" + await _wait_for_block(node.w3, snapshot_block) + replica = node.w3.eth.contract( + address=resolver.address, + abi=resolver_artifact["abi"], + ) + replica_native = node.w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + for feed_id, expected_round in node1_rounds.items(): + progress = tuple( + replica_native.functions.getSourceProgress( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call(block_identifier=snapshot_block) + ) + stored = tuple( + replica.functions.latestPrice(feed_id).call( + block_identifier=snapshot_block + ) + ) + assert progress == node1_progress[feed_id] + assert stored == expected_round + + first_round = node1_rounds[next(iter(FEEDS))] + _write_demo_config( + cluster, + resolver.address, + w3.eth.chain_id, + base_url, + node1_rounds, + bucket_start_ms, + first_round[1], + first_round[2], + ) + + LOG.info( + "Four-validator live Binance QC stored latest rounds=%s prices=%s", + {feed_id: value[1] for feed_id, value in node1_rounds.items()}, + expected_prices, + ) diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/README.md b/gravity_e2e/cluster_test_cases/oracle_demo/README.md new file mode 100644 index 000000000..27ae727de --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/README.md @@ -0,0 +1,19 @@ +# Combined Oracle Demo + +The deterministic review gate for Binance price rounds and a binary +Polymarket settlement in one local Gravity cluster. It also writes the +combined frontend runtime config when `--demo-config-out` is supplied. + +The binary market has no Gravity-local oracle deadline. After the reviewed +Polygon CTF payout reaches the resolver, anyone may call `finalizeMarket`; +missing, pending, or invalid observations leave the market locked. + +Run: + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh oracle_demo --force-init +``` + +See [`../../docs/ORACLE_E2E.md`](../../docs/ORACLE_E2E.md) for the coverage +matrix, frontend mode, stop command, pinned revisions, and scope. diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/cluster.toml b/gravity_e2e/cluster_test_cases/oracle_demo/cluster.toml new file mode 100644 index 000000000..c222f7a22 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/cluster.toml @@ -0,0 +1,27 @@ +# Gravity Cluster Configuration - combined oracle dashboard demo + +[cluster] +name = "gravity-devnet-oracle-demo" +base_dir = "/tmp/gravity-cluster-oracle-demo" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 45482 +vfn_port = 45492 +rpc_port = 48855 +api_port = 48380 +metrics_port = 49303 +inspection_port = 40202 +https_port = 41224 +authrpc_port = 48875 +reth_p2p_port = 52326 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/genesis.toml b/gravity_e2e/cluster_test_cases/oracle_demo/genesis.toml new file mode 100644 index 000000000..8acc52ea0 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/genesis.toml @@ -0,0 +1,81 @@ +# Gravity Genesis Configuration - combined oracle dashboard demo + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 45482 +vfn_port = 45492 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +# Keep the demo fast: governance-updated price feed tasks are picked up when +# the JWK consensus epoch manager rebuilds providers for the next epoch. +epoch_interval_micros = 30000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 + +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 3, 6] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000", +] + +[[genesis.oracle_config.tasks]] +source_type = 6 +source_id = 7202626 +task_name = "polymarket_settlement" +config = "gravity://6/7202626/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20" + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/hooks.py b/gravity_e2e/cluster_test_cases/oracle_demo/hooks.py new file mode 100644 index 000000000..022eddb00 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/hooks.py @@ -0,0 +1,158 @@ +"""Hooks for the combined oracle dashboard demo suite.""" + +import json +import logging +import os +import signal +import subprocess +import sys +import time +import urllib.request +from pathlib import Path + +LOG = logging.getLogger(__name__) + +E2E_ROOT = Path(__file__).resolve().parents[2] + +if str(E2E_ROOT) not in sys.path: + sys.path.insert(0, str(E2E_ROOT)) + +from gravity_e2e.utils.mock_polymarket_polygon import MockPolymarketPolygon +from gravity_e2e.utils.mock_binance_index import BUCKET_START_MS, INTERVAL_MS, MOCK_BINANCE_PORT + +_poly_mock = None + + +def _pid_file(test_dir: Path) -> Path: + return test_dir / "artifacts" / "mock_binance.pid" + + +def _log_file(test_dir: Path) -> Path: + return test_dir / "artifacts" / "mock_binance.log" + + +def _process_alive(pid: int) -> bool: + try: + os.kill(pid, 0) + return True + except OSError: + return False + + +def _read_pid(path: Path) -> int | None: + if not path.exists(): + return None + try: + return int(path.read_text().strip()) + except ValueError: + return None + + +def _wait_for_binance_ready(timeout: int = 10): + start_time = BUCKET_START_MS + end_time = start_time + INTERVAL_MS - 1 + url = ( + f"http://127.0.0.1:{MOCK_BINANCE_PORT}/fapi/v1/indexPriceKlines" + f"?pair=NVDAUSDT&interval=1m&startTime={start_time}&endTime={end_time}&limit=1" + ) + deadline = time.monotonic() + timeout + last_error = None + while time.monotonic() < deadline: + try: + with urllib.request.urlopen(url, timeout=2) as resp: + json.loads(resp.read()) + return + except Exception as exc: + last_error = exc + time.sleep(0.25) + raise RuntimeError(f"mock Binance server did not become ready: {last_error}") + + +def _start_binance_mock(test_dir: Path, env: dict): + pid_path = _pid_file(test_dir) + pid = _read_pid(pid_path) + if pid is not None and _process_alive(pid): + env["BINANCE_PRICE_FEED_EXTERNAL_MOCK"] = "1" + _wait_for_binance_ready() + return + + log_path = _log_file(test_dir) + log_path.parent.mkdir(parents=True, exist_ok=True) + mock_env = env.copy() + python_path = mock_env.get("PYTHONPATH") + mock_env["PYTHONPATH"] = ( + f"{E2E_ROOT}{os.pathsep}{python_path}" if python_path else str(E2E_ROOT) + ) + with open(log_path, "ab") as log: + process = subprocess.Popen( + [ + sys.executable, + "-m", + "gravity_e2e.utils.mock_binance_index", + "--port", + str(MOCK_BINANCE_PORT), + "--pid-file", + str(pid_path), + ], + cwd=E2E_ROOT, + env=mock_env, + stdout=log, + stderr=subprocess.STDOUT, + start_new_session=True, + ) + env["BINANCE_PRICE_FEED_EXTERNAL_MOCK"] = "1" + _wait_for_binance_ready() + pid = _read_pid(pid_path) + if process.poll() is not None or pid != process.pid: + raise RuntimeError( + "mock Binance readiness was satisfied by another process; " + f"expected pid {process.pid}, found {pid}" + ) + + +def _stop_binance_mock(test_dir: Path): + pid = _read_pid(_pid_file(test_dir)) + if pid is None or not _process_alive(pid): + return + os.kill(pid, signal.SIGTERM) + deadline = time.monotonic() + 5 + while time.monotonic() < deadline: + if not _process_alive(pid): + return + time.sleep(0.25) + os.kill(pid, signal.SIGKILL) + + +def pre_start(test_dir: Path, env: dict, pytest_args: list = None): + global _poly_mock + + LOG.info("[hook] Starting combined oracle demo mocks") + env["BINANCE_PRICE_FEED_MODE"] = "mock" + env.pop("BINANCE_PRICE_FEED_BASE_URL", None) + env.pop("BINANCE_PRICE_FEED_BUCKET_START_MS", None) + _start_binance_mock(test_dir, env) + + _poly_mock = MockPolymarketPolygon(port=8546) + _poly_mock.start() + metadata = { + "rpc_url": _poly_mock.rpc_url, + "winning_slot": None, + "payout_numerators": None, + "source_log": None, + } + (test_dir / "mock_polymarket_metadata.json").write_text(json.dumps(metadata, indent=2)) + + +def post_stop(test_dir: Path, env: dict): + global _poly_mock + + _stop_binance_mock(test_dir) + + if _poly_mock is not None: + LOG.info("[hook] Stopping MockPolymarketPolygon") + _poly_mock.stop() + _poly_mock = None + + metadata_path = test_dir / "mock_polymarket_metadata.json" + if metadata_path.exists(): + metadata_path.unlink() diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/relayer_config.json b/gravity_e2e/cluster_test_cases/oracle_demo/relayer_config.json new file mode 100644 index 000000000..852aaba01 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/relayer_config.json @@ -0,0 +1,7 @@ +{ + "uri_mappings": { + "gravity://3/1001/price_feed?provider=binance_index_kline_v1&pair=NVDAUSDT&interval=1m&bucketStartMs=1783252500000&decimals=8&graceMs=120000": "http://127.0.0.1:18547", + "gravity://3/1002/price_feed?provider=binance_index_kline_v1&pair=TSLAUSDT&interval=1m&bucketStartMs=1783252500000&decimals=8&graceMs=120000": "http://127.0.0.1:18547", + "gravity://6/7202626/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20": "http://localhost:8546" + } +} diff --git a/gravity_e2e/cluster_test_cases/oracle_demo/test_oracle_demo.py b/gravity_e2e/cluster_test_cases/oracle_demo/test_oracle_demo.py new file mode 100644 index 000000000..d7ba7ec4c --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_demo/test_oracle_demo.py @@ -0,0 +1,504 @@ +"""Combined Binance price-feed and Polymarket mirror dashboard e2e.""" + +import asyncio +from decimal import Decimal +import json +import logging +import os +import time +import urllib.request +from pathlib import Path + +import pytest +from eth_abi import encode +from eth_account import Account +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support +from gravity_e2e.utils.mock_polymarket_polygon import ( + CTF_ADDRESS, + FED_BINARY_BLOCK, + FED_BINARY_CONDITION_ID, + FED_BINARY_LOG_INDEX, + FED_BINARY_MARKET_ID, + FED_BINARY_QUESTION_ID, + FED_BINARY_TX_HASH, + POLYGON_CHAIN_ID, + UMA_ORACLE, +) +from gravity_e2e.utils.mock_binance_index import mock_close_price + +LOG = logging.getLogger(__name__) + +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_POLYMARKET_SETTLEMENT = 6 +SOURCE_TYPE_PRICE_FEED = 3 +SETTLEMENT_KIND_CTF_CONDITION_RESOLUTION = 1 +CALLBACK_GAS_LIMIT = 2_000_000 +STAKE_UNIT = 10**18 +USER_STARTING_BALANCE = 1_000 * STAKE_UNIT +NO_STAKE = 100 * STAKE_UNIT +YES_STAKE = 200 * STAKE_UNIT +TOTAL_BINARY_POOL = NO_STAKE + YES_STAKE +SPEC_HASH = Web3.keccak(text="Fed July binary Polymarket mirror demo") +RESOLVED_WINNER_STATUS = 2 +BINARY_MARKET_STATUS_INDEX = 4 +BINARY_MARKET_WINNING_OUTCOME_INDEX = 5 +BINARY_MARKET_TOTAL_POOL_INDEX = 6 + +NATIVE_ORACLE_ADDRESS = support.NATIVE_ORACLE_ADDRESS +ORACLE_TASK_CONFIG_ADDRESS = support.ORACLE_TASK_CONFIG_ADDRESS +FAUCET_KEY = support.FAUCET_KEY + + +def _ensure_contracts_out() -> Path: + required = [ + ("PriceFeedResolver.sol", "PriceFeedResolver"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ("NativeOracle.sol", "NativeOracle"), + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("PolymarketBinaryMarket.sol", "PolymarketBinaryMarket"), + ("MockGToken.sol", "MockGToken"), + ] + return support.ensure_contracts_out(SUITE_DIR, required, "Oracle demo") + + +def _mock_set_binary_winning_slot(rpc_url: str, winning_slot: int) -> dict: + payload = json.dumps( + { + "jsonrpc": "2.0", + "method": "mock_setBinaryWinningSlot", + "params": [winning_slot], + "id": 1, + } + ).encode() + req = urllib.request.Request( + rpc_url, + data=payload, + headers={"Content-Type": "application/json"}, + ) + with urllib.request.urlopen(req, timeout=5) as resp: + body = json.loads(resp.read()) + if "error" in body: + raise RuntimeError(f"mock_setBinaryWinningSlot failed: {body['error']}") + return body["result"] + + +async def _wait_for_resolver_settlement(resolver, timeout: int = 120): + condition_id = bytes.fromhex(FED_BINARY_CONDITION_ID[2:]) + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + settlement = resolver.functions.getSettlement(FED_BINARY_MARKET_ID, condition_id).call() + if settlement[0]: + return settlement + await asyncio.sleep(2) + raise TimeoutError("binary Polymarket resolver settlement was not stored") + + +def _send_contract_tx(w3: Web3, contract, fn, sender_key: str, gas: int = 1_000_000) -> dict: + return support.send_contract_tx(w3, contract, fn, sender_key, gas=gas) + + +def _format_price(value: int) -> str: + return support.format_price(value) + + +def _write_demo_config( + cluster: Cluster, + chain_id: int, + price_resolver: str, + poly_resolver: str, + binary_market: str, + token: str, + market_id: int, + market_state: tuple, + release: dict, + observed_progress: dict[int, tuple], + observed_rounds: dict[int, tuple], + target_round_id: int, + target_resolved_at: int, + claimable_yes: int, +): + output = os.environ.get("GRAVITY_DEMO_CONFIG_OUT") + if not output: + return + + def feed_config(feed_id: int, pair: str, label: str): + observed = observed_rounds[feed_id] + progress = observed_progress[feed_id] + observed_price = int(observed[4]) + return { + "feedId": feed_id, + "label": label, + "pair": pair, + "sourceType": SOURCE_TYPE_PRICE_FEED, + "decimals": support.DECIMALS, + "expectedDeliveryNonce": int(progress[0]), + "expectedRoundId": int(observed[1]), + "expectedResolvedAt": int(observed[2]), + "expectedPrice": str(observed_price), + "expectedDisplayPrice": _format_price(observed_price), + } + + demo_config = { + "version": 2, + "mode": "local-combined-oracle-demo", + "network": { + "chainId": chain_id, + "rpcUrl": cluster.get_node("node1").url, + "rpcProxyPath": "/rpc", + }, + "contracts": { + "priceFeedResolver": price_resolver, + "multiSourceOracleResolver": price_resolver, + "polymarketSettlementResolver": poly_resolver, + "polymarketBinaryMarket": binary_market, + "collateral": token, + "nativeOracle": NATIVE_ORACLE_ADDRESS, + "oracleTaskConfig": ORACLE_TASK_CONFIG_ADDRESS, + }, + "provider": { + "kind": "local-mock", + "name": "Local deterministic Binance index-kline mock", + "baseUrl": f"http://127.0.0.1:{support.MOCK_BINANCE_PORT}", + "endpoint": "/fapi/v1/indexPriceKlines", + "interval": "1m", + "live": False, + }, + "feeds": [ + feed_config(support.NVDA_FEED_ID, "NVDAUSDT", "NVDA mock index"), + feed_config(support.TSLA_FEED_ID, "TSLAUSDT", "TSLA mock index"), + ], + "polymarket": { + "kind": "binary", + "title": "Will the Fed cut rates in July?", + "subtitle": "Local Polymarket CTF mirror fixture", + "sourceType": SOURCE_TYPE_POLYMARKET_SETTLEMENT, + "mirrorId": FED_BINARY_MARKET_ID, + "marketId": market_id, + "conditionId": FED_BINARY_CONDITION_ID, + "questionId": FED_BINARY_QUESTION_ID, + "ctf": CTF_ADDRESS, + "polygonChainId": POLYGON_CHAIN_ID, + "outcomeLabels": ["NO", "YES"], + "slotLabels": ["YES", "NO"], + "slotToOutcome": [1, 0], + "winningSlot": release["winning_slot"], + "winningOutcome": int( + market_state[BINARY_MARKET_WINNING_OUTCOME_INDEX] + ), + "payoutNumerators": release["payout_numerators"], + "settlementTxHash": FED_BINARY_TX_HASH, + "settlementBlock": FED_BINARY_BLOCK, + "settlementLogIndex": FED_BINARY_LOG_INDEX, + "totalPool": str(market_state[BINARY_MARKET_TOTAL_POOL_INDEX]), + "yesAccount": { + "address": release["yesAccount"], + "claimable": str(claimable_yes), + }, + }, + "demo": { + "providerMode": "mock", + "bucketStartMs": support.BUCKET_START_MS, + "intervalMs": support.INTERVAL_MS, + "targetDeliveryNonce": support.TARGET_DELIVERY_NONCE, + "targetRoundId": target_round_id, + "targetResolvedAt": target_resolved_at, + }, + } + + output_path = Path(output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(json.dumps(demo_config, indent=2) + "\n") + LOG.info("Wrote combined oracle demo config to %s", output_path) + + +@pytest.mark.asyncio +async def test_combined_oracle_demo_resolves_price_and_polymarket(cluster: Cluster): + os.environ["BINANCE_PRICE_FEED_MODE"] = "mock" + os.environ.pop("BINANCE_PRICE_FEED_BASE_URL", None) + os.environ.pop("BINANCE_PRICE_FEED_BUCKET_START_MS", None) + + metadata_path = SUITE_DIR / "mock_polymarket_metadata.json" + metadata = json.loads(metadata_path.read_text()) + + LOG.info("Verifying gravity node is live") + assert await cluster.set_full_live(timeout=120), "Gravity node failed to become live" + assert await cluster.check_block_increasing(timeout=60), "Gravity chain is not producing blocks" + + node = cluster.get_node("node1") + assert node is not None, "node1 not found in cluster" + w3 = node.w3 + assert w3 is not None and w3.is_connected(), "node1 web3 not connected" + + contracts_out = _ensure_contracts_out() + price_resolver_artifact = support.load_artifact( + contracts_out, + "PriceFeedResolver.sol", + "PriceFeedResolver", + ) + poly_resolver_artifact = support.load_artifact( + contracts_out, + "PolymarketSettlementResolver.sol", + "PolymarketSettlementResolver", + ) + binary_market_artifact = support.load_artifact( + contracts_out, + "PolymarketBinaryMarket.sol", + "PolymarketBinaryMarket", + ) + token_artifact = support.load_artifact(contracts_out, "MockGToken.sol", "MockGToken") + native_artifact = support.load_artifact(contracts_out, "NativeOracle.sol", "NativeOracle") + task_artifact = support.load_artifact(contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig") + + price_resolver = support.deploy_contract(w3, price_resolver_artifact, FAUCET_KEY) + poly_resolver = support.deploy_contract(w3, poly_resolver_artifact, FAUCET_KEY) + binary_market = support.deploy_contract(w3, binary_market_artifact, FAUCET_KEY) + token = support.deploy_contract(w3, token_artifact, FAUCET_KEY) + native_oracle = w3.eth.contract(address=NATIVE_ORACLE_ADDRESS, abi=native_artifact["abi"]) + task_config = w3.eth.contract(address=ORACLE_TASK_CONFIG_ADDRESS, abi=task_artifact["abi"]) + + pool_addr = support.pool0_voted_by_faucet(w3) + condition_id = bytes.fromhex(FED_BINARY_CONDITION_ID[2:]) + ctf = Web3.to_checksum_address(CTF_ADDRESS) + + now_ts = w3.eth.get_block("latest")["timestamp"] + closes_at = now_ts + 20 + settlement_ref = ( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + condition_id, + poly_resolver.address, + ctf, + POLYGON_CHAIN_ID, + 2, + [1, 0], + 0, + ) + create_params = ( + SPEC_HASH, + now_ts, + closes_at, + token.address, + settlement_ref, + ) + + nvda_uri = support.price_feed_uri(support.NVDA_FEED_ID, "NVDAUSDT", support.BUCKET_START_MS) + tsla_uri = support.price_feed_uri(support.TSLA_FEED_ID, "TSLAUSDT", support.BUCKET_START_MS) + + setup_datas = [ + support.function_calldata( + native_oracle.functions.setDefaultCallback( + SOURCE_TYPE_PRICE_FEED, + price_resolver.address, + ) + ), + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_PRICE_FEED, + support.NVDA_FEED_ID, + support.TASK_PRICE_FEED, + nvda_uri.encode(), + ) + ), + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_PRICE_FEED, + support.TSLA_FEED_ID, + support.TASK_PRICE_FEED, + tsla_uri.encode(), + ) + ), + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + poly_resolver.address, + ) + ), + support.function_calldata( + poly_resolver.functions.registerMirror( + FED_BINARY_MARKET_ID, + POLYGON_CHAIN_ID, + ctf, + condition_id, + 2, + ) + ), + support.function_calldata(binary_market.functions.createMarket(create_params)), + ] + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + [ + NATIVE_ORACLE_ADDRESS, + ORACLE_TASK_CONFIG_ADDRESS, + ORACLE_TASK_CONFIG_ADDRESS, + NATIVE_ORACLE_ADDRESS, + poly_resolver.address, + binary_market.address, + ], + setup_datas, + "combined-oracle-demo-setup", + gas=8_000_000, + ) + market_id = support.market_id_from_receipt(receipt) + + no_account = Account.create("oracle-demo-no") + yes_account = Account.create("oracle-demo-yes") + for account in [no_account, yes_account]: + support.send_tx(w3, account.address, b"", FAUCET_KEY, gas=21_000, value=STAKE_UNIT) + _send_contract_tx(w3, token, token.functions.mint(account.address, USER_STARTING_BALANCE), FAUCET_KEY) + _send_contract_tx(w3, token, token.functions.approve(binary_market.address, USER_STARTING_BALANCE), account.key) + + _send_contract_tx( + w3, + binary_market, + binary_market.functions.placeBet(market_id, 0, NO_STAKE), + no_account.key, + gas=1_500_000, + ) + _send_contract_tx( + w3, + binary_market, + binary_market.functions.placeBet(market_id, 1, YES_STAKE), + yes_account.key, + gas=1_500_000, + ) + assert ( + binary_market.functions.getMarket(market_id).call()[ + BINARY_MARKET_TOTAL_POOL_INDEX + ] + == TOTAL_BINARY_POOL + ) + + observed_progress = {} + observed_rounds = {} + target_round_id = support.round_id(support.BUCKET_START_MS, support.TARGET_DELIVERY_NONCE) + target_resolved_at = support.round_end_ms(support.BUCKET_START_MS, support.TARGET_DELIVERY_NONCE) + for feed_id, pair in [ + (support.NVDA_FEED_ID, "NVDAUSDT"), + (support.TSLA_FEED_ID, "TSLAUSDT"), + ]: + logs = await support.poll_oracle_delivered( + w3, + SOURCE_TYPE_PRICE_FEED, + feed_id, + timeout=240, + ) + assert logs, f"No sourceType=3 OracleDelivered event observed for feedId={feed_id}" + progress, stored = await support.wait_for_latest_price( + native_oracle, + price_resolver, + feed_id, + support.TARGET_DELIVERY_NONCE, + timeout=240, + ) + assert progress[0] >= support.TARGET_DELIVERY_NONCE + assert progress[1] == stored[2] + expected_round_id = support.round_id(support.BUCKET_START_MS, progress[0]) + expected_resolved_at = support.round_end_ms( + support.BUCKET_START_MS, progress[0] + ) + expected_price = int( + Decimal(mock_close_price(pair, progress[0] - 1)) + * (10**support.DECIMALS) + ) + support.assert_price_round( + stored, + expected_price, + expected_round_id, + expected_resolved_at, + ) + observed_progress[feed_id] = progress + observed_rounds[feed_id] = stored + LOG.info( + "Price feed resolved: feedId=%s nonce=%s roundId=%s price=%s", + feed_id, + progress[0], + stored[1], + int(stored[4]), + ) + + await support.wait_for_chain_time(w3, closes_at) + _send_contract_tx(w3, binary_market, binary_market.functions.lockMarket(market_id), FAUCET_KEY) + + release = _mock_set_binary_winning_slot(metadata["rpc_url"], 0) + release["yesAccount"] = yes_account.address + metadata.update(release) + metadata_path.write_text(json.dumps(metadata, indent=2)) + LOG.info("Released mock binary Polymarket settlement: payout=%s", release["payout_numerators"]) + + logs = await support.poll_oracle_delivered( + w3, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + timeout=180, + ) + assert logs, "No Polymarket sourceType=6 OracleDelivered event observed" + progress = await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + 1, + timeout=60, + ) + assert progress == (1, FED_BINARY_BLOCK) + settlement = await _wait_for_resolver_settlement(poly_resolver, timeout=60) + assert settlement[0] is True + assert settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_checksum_address(settlement[3]) == ctf + assert settlement[6] == 2 + assert settlement[9] == SETTLEMENT_KIND_CTF_CONDITION_RESOLUTION + assert poly_resolver.functions.getPayoutNumerators(FED_BINARY_MARKET_ID, condition_id).call() == [1, 0] + + observation = poly_resolver.functions.getSettlementObservation( + FED_BINARY_MARKET_ID, condition_id + ).call() + assert observation[0] == RESOLVED_WINNER_STATUS + assert observation[1] == 0 + assert observation[2] > 0 + assert observation[3] > 0 + assert Web3.to_hex(observation[4]).lower() == FED_BINARY_TX_HASH.lower() + assert observation[5] == FED_BINARY_LOG_INDEX + + _send_contract_tx( + w3, + binary_market, + binary_market.functions.finalizeMarket(market_id), + FAUCET_KEY, + gas=2_000_000, + ) + market_state = binary_market.functions.getMarket(market_id).call() + market_status = market_state[BINARY_MARKET_STATUS_INDEX] + winning_outcome = market_state[BINARY_MARKET_WINNING_OUTCOME_INDEX] + assert market_status == 2, f"binary market did not settle: status={market_status}" + assert winning_outcome == 1, f"winning outcome should be YES, got {winning_outcome}" + claimable_yes = binary_market.functions.claimable(market_id, yes_account.address).call() + assert claimable_yes == TOTAL_BINARY_POOL + + _write_demo_config( + cluster, + w3.eth.chain_id, + price_resolver.address, + poly_resolver.address, + binary_market.address, + token.address, + market_id, + market_state, + release, + observed_progress, + observed_rounds, + target_round_id, + target_resolved_at, + claimable_yes, + ) + + LOG.info( + "Combined oracle demo resolved: NVDA/TSLA roundId=%s, polymarket marketId=%s YES claimable=%s", + target_round_id, + market_id, + claimable_yes, + ) diff --git a/gravity_e2e/cluster_test_cases/oracle_live_soak/README.md b/gravity_e2e/cluster_test_cases/oracle_live_soak/README.md new file mode 100644 index 000000000..64ca11f09 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_live_soak/README.md @@ -0,0 +1,98 @@ +# Four-Validator Live Oracle Soak + +This manual public-network suite runs four equal-power validators against a +continuous Binance NVDA index-price feed and one real finalized Polymarket +settlement. Neither task exists at genesis. One Gravity governance proposal: + +1. registers the NVDA `sourceType=3` task and its resolver callback; +2. registers a `sourceType=6` Polymarket mirror and callback; +3. registers the corresponding Gravity settlement mirror. + +Observers must remain absent in proposal epoch `E`. They start in `E+1`, and +at least three validators must certify both sources and form JWK quorum. The +test then verifies the resolver settlement and enters the configured soak +period. Binary-market accounting remains covered by the focused Polymarket +suite. + +The default run lasts 24 hours. Every heartbeat checks: + +- all four Gravity RPC replicas are connected and agree at one block; +- NVDA source progress is monotonic and matches `latestPrice`; +- the feed has not stalled for more than six minutes; +- at least three relayer state files reached the committed NVDA nonce; +- the Polymarket progress and settlement remain immutable; +- all four Gravity block heights continue advancing. + +For runs of at least one hour, `node4` restarts halfway through by default and +must catch up. At completion, the final onchain NVDA price is compared with the +exact Binance `indexPriceKlines` close, and the Polymarket source must have +exactly one successful delivery. + +## Prerequisites + +- A current `gravity_node` and `gravity_cli` quick-release build. +- Approved outbound access to `https://fapi.binance.com`, the Polymarket Gamma + API, and the configured Polygon RPC. +- `POLYGON_RPC_URL` or `POLYGON_QUICKNONE_HTTP_URL`. +- An egress region eligible for Binance production futures data. + +The public Binance endpoint does not require an API key. The suite rejects +local, private-address, and non-HTTPS Binance base URLs so it cannot silently +become a mock test. + +## Run For One Day + +Run this from a terminal multiplexer or another session that will not be +suspended with the interactive shell: + +```bash +export POLYGON_RPC_URL="..." +export BINANCE_PRICE_FEED_BASE_URL=https://fapi.binance.com +export ORACLE_SOAK_DURATION_SECONDS=86400 +export GRAVITY_E2E_SKIP_GLOBAL_PKILL=1 +export PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" + +./gravity_e2e/run_test.sh \ + oracle_live_soak \ + --force-init \ + --log-cli-level=INFO +``` + +Do not add `--keep-running`: the pytest process itself is the 24-hour monitor +and performs the final assertions and cleanup. + +## Short Validation + +A three-minute development run can validate setup and at least one new minute: + +```bash +ORACLE_SOAK_DURATION_SECONDS=180 \ +ORACLE_SOAK_POLL_SECONDS=10 \ +ORACLE_SOAK_STALL_TIMEOUT_SECONDS=180 \ +ORACLE_SOAK_MIN_ADVANCES=1 \ +ORACLE_SOAK_RESTART_AFTER_SECONDS=0 \ + ./gravity_e2e/run_test.sh \ + oracle_live_soak \ + --force-init \ + --log-cli-level=INFO +``` + +## Controls And Evidence + +| Variable | Default | Meaning | +| --- | ---: | --- | +| `ORACLE_SOAK_DURATION_SECONDS` | `86400` | Monitored soak duration | +| `ORACLE_SOAK_POLL_SECONDS` | `15` | Onchain heartbeat interval | +| `ORACLE_SOAK_STALL_TIMEOUT_SECONDS` | `360` | Maximum price or chain stall | +| `ORACLE_SOAK_MIN_ADVANCES` | 80% of expected minutes | Required NVDA nonce advances | +| `ORACLE_SOAK_RESTART_AFTER_SECONDS` | Halfway for runs >= 1 hour | Restart time; `0` disables | +| `ORACLE_SOAK_RESTART_NODE` | `node4` | Validator selected for restart | + +Runtime evidence is written to ignored files: + +- `artifacts/oracle_live_soak_heartbeat.jsonl` +- `artifacts/oracle_live_soak_summary.json` + +The generated relayer configuration can contain an RPC credential and is also +ignored. Normal teardown removes that configuration and source metadata while +retaining heartbeat and summary evidence. diff --git a/gravity_e2e/cluster_test_cases/oracle_live_soak/cluster.toml b/gravity_e2e/cluster_test_cases/oracle_live_soak/cluster.toml new file mode 100644 index 000000000..08ea537f2 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_live_soak/cluster.toml @@ -0,0 +1,73 @@ +# Four-validator live Binance and Polymarket soak test. +# Keep fixed listeners below Linux's default ephemeral source-port range. + +[cluster] +name = "gravity-devnet-oracle-live-soak" +base_dir = "/tmp/gravity-cluster-oracle-live-soak" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26680 +vfn_port = 26690 +rpc_port = 26700 +api_port = 26710 +metrics_port = 26720 +inspection_port = 26730 +https_port = 26740 +authrpc_port = 26750 +reth_p2p_port = 26760 + +[[nodes]] +id = "node2" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26681 +vfn_port = 26691 +rpc_port = 26701 +api_port = 26711 +metrics_port = 26721 +inspection_port = 26731 +https_port = 26741 +authrpc_port = 26751 +reth_p2p_port = 26761 + +[[nodes]] +id = "node3" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26682 +vfn_port = 26692 +rpc_port = 26702 +api_port = 26712 +metrics_port = 26722 +inspection_port = 26732 +https_port = 26742 +authrpc_port = 26752 +reth_p2p_port = 26762 + +[[nodes]] +id = "node4" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26683 +vfn_port = 26693 +rpc_port = 26703 +api_port = 26713 +metrics_port = 26723 +inspection_port = 26733 +https_port = 26743 +authrpc_port = 26753 +reth_p2p_port = 26763 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/oracle_live_soak/genesis.toml b/gravity_e2e/cluster_test_cases/oracle_live_soak/genesis.toml new file mode 100644 index 000000000..c203d7e68 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_live_soak/genesis.toml @@ -0,0 +1,105 @@ +# Four-validator live Oracle soak test. SourceType 3 and 6 tasks are added by +# governance during the test, never at genesis. + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +# Equal voting power means a JWK QC requires matching signatures from at least +# three of the four validators. +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 26680 +vfn_port = 26690 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node2" +address = "0x7b254Bd44F6CE45e00a912b2460D47F3Be56fAD7" +host = "127.0.0.1" +validator_port = 26681 +vfn_port = 26691 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node3" +address = "0x9B2C25E77a97d3e84DC0Cb7F83fb676ddC4F24b9" +host = "127.0.0.1" +validator_port = 26682 +vfn_port = 26692 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node4" +address = "0x18c23753385ce7A60B15d171302E48b6AFf0BDC5" +host = "127.0.0.1" +validator_port = 26683 +vfn_port = 26693 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 60000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 3, 6] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000", +] + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/oracle_live_soak/hooks.py b/gravity_e2e/cluster_test_cases/oracle_live_soak/hooks.py new file mode 100644 index 000000000..68636c178 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_live_soak/hooks.py @@ -0,0 +1,170 @@ +"""Prepare real Binance and Polygon sources for the live Oracle soak.""" + +import importlib.util +import ipaddress +import json +import logging +import os +from pathlib import Path +import time +from urllib.parse import urlparse + + +LOG = logging.getLogger(__name__) + +INTERVAL_MS = 60_000 +DEFAULT_GRACE_MS = 120_000 +DEFAULT_BINANCE_BASE_URL = "https://fapi.binance.com" +NVDA_FEED_ID = 1001 +NVDA_PAIR = "NVDAUSDT" + +_METADATA_FILE = "oracle_live_soak_metadata.json" +_RELAYER_FILE = "relayer_config.live.json" +_HEARTBEAT_FILE = "oracle_live_soak_heartbeat.jsonl" +_SUMMARY_FILE = "oracle_live_soak_summary.json" + + +def _bucket_start_ms(env: dict) -> int: + configured = env.get("BINANCE_PRICE_FEED_BUCKET_START_MS") + if configured: + bucket_start_ms = int(configured) + else: + grace_ms = int( + env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_GRACE_MS)) + ) + minimum_lag = (grace_ms + INTERVAL_MS - 1) // INTERVAL_MS + 1 + lag_minutes = int( + env.get("BINANCE_PRICE_FEED_LAG_MINUTES", str(minimum_lag)) + ) + bucket_start_ms = ( + (int(time.time() * 1000) // INTERVAL_MS) - lag_minutes + ) * INTERVAL_MS + + if bucket_start_ms <= 0 or bucket_start_ms % INTERVAL_MS != 0: + raise RuntimeError( + "BINANCE_PRICE_FEED_BUCKET_START_MS must be a positive aligned minute" + ) + return bucket_start_ms + + +def _require_public_https_url(value: str, name: str) -> str: + parsed = urlparse(value) + if parsed.scheme != "https" or not parsed.hostname: + raise RuntimeError(f"{name} must be an https URL with a hostname") + hostname = parsed.hostname.lower() + if hostname == "localhost" or hostname.endswith(".localhost"): + raise RuntimeError(f"{name} must not use a loopback host") + try: + address = ipaddress.ip_address(hostname) + except ValueError: + address = None + if address is not None and not address.is_global: + raise RuntimeError(f"{name} must not use a private or loopback address") + return value.rstrip("/") + + +def _price_uri(bucket_start_ms: int, grace_ms: int) -> str: + return ( + f"gravity://3/{NVDA_FEED_ID}/price_feed?" + f"provider=binance_index_kline_v1&pair={NVDA_PAIR}&interval=1m&" + f"bucketStartMs={bucket_start_ms}&decimals=8&graceMs={grace_ms}" + ) + + +def _polymarket_hooks(test_dir: Path): + hook_path = test_dir.parent / "polymarket_live_dynamic_mirror" / "hooks.py" + spec = importlib.util.spec_from_file_location( + "gravity_e2e_soak_polymarket_hooks", hook_path + ) + if spec is None or spec.loader is None: + raise RuntimeError(f"cannot load live Polymarket helpers from {hook_path}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def pre_deploy(test_dir: Path, env: dict, pytest_args: list[str]): + requested_mode = env.get("BINANCE_PRICE_FEED_MODE", "live").strip().lower() + if requested_mode != "live": + raise RuntimeError("oracle_live_soak only supports live Binance mode") + + binance_base_url = _require_public_https_url( + env.get("BINANCE_PRICE_FEED_BASE_URL", DEFAULT_BINANCE_BASE_URL), + "BINANCE_PRICE_FEED_BASE_URL", + ) + grace_ms = int( + env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_GRACE_MS)) + ) + if grace_ms < 0: + raise RuntimeError("BINANCE_PRICE_FEED_GRACE_MS must be non-negative") + bucket_start_ms = _bucket_start_ms(env) + price_uri = _price_uri(bucket_start_ms, grace_ms) + + polygon_rpc_url = ( + env.get("POLYGON_RPC_URL") + or env.get("POLYGON_QUICKNONE_HTTP_URL") + or os.environ.get("POLYGON_RPC_URL") + or os.environ.get("POLYGON_QUICKNONE_HTTP_URL") + ) + if not polygon_rpc_url: + raise RuntimeError("POLYGON_RPC_URL is required for oracle_live_soak") + + polymarket = _polymarket_hooks(test_dir) + gamma_url = env.get("POLYMARKET_GAMMA_URL", polymarket.DEFAULT_GAMMA_URL) + market = polymarket._discover_market(polygon_rpc_url, gamma_url) + + artifacts = test_dir / "artifacts" + artifacts.mkdir(parents=True, exist_ok=True) + for name in (_HEARTBEAT_FILE, _SUMMARY_FILE): + (artifacts / name).unlink(missing_ok=True) + relayer_path = artifacts / _RELAYER_FILE + relayer_path.write_text( + json.dumps( + { + "uri_mappings": { + price_uri: binance_base_url, + market["taskUri"]: polygon_rpc_url, + } + }, + indent=2, + ) + + "\n" + ) + + metadata_path = artifacts / _METADATA_FILE + metadata_path.write_text( + json.dumps( + { + "binance": { + "baseUrl": binance_base_url, + "feedId": NVDA_FEED_ID, + "pair": NVDA_PAIR, + "bucketStartMs": bucket_start_ms, + "graceMs": grace_ms, + "taskUri": price_uri, + }, + "polymarket": market, + }, + indent=2, + ensure_ascii=False, + ) + + "\n" + ) + + env["BINANCE_PRICE_FEED_MODE"] = "live" + env["BINANCE_PRICE_FEED_BASE_URL"] = binance_base_url + env["BINANCE_PRICE_FEED_BUCKET_START_MS"] = str(bucket_start_ms) + env["BINANCE_PRICE_FEED_GRACE_MS"] = str(grace_ms) + env["RELAYER_CONFIG_TPL"] = str(relayer_path) + LOG.info( + "[hook] Prepared NVDA anchor=%s and Polymarket mirrorId=%s block=%s", + bucket_start_ms, + market["mirrorId"], + market["blockNumber"], + ) + + +def post_stop(test_dir: Path, env: dict): + artifacts = test_dir / "artifacts" + for name in (_METADATA_FILE, _RELAYER_FILE): + (artifacts / name).unlink(missing_ok=True) diff --git a/gravity_e2e/cluster_test_cases/oracle_live_soak/test_oracle_live_soak.py b/gravity_e2e/cluster_test_cases/oracle_live_soak/test_oracle_live_soak.py new file mode 100644 index 000000000..188a6c10b --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_live_soak/test_oracle_live_soak.py @@ -0,0 +1,961 @@ +"""Long-running four-validator Oracle soak against Binance and Polygon.""" + +import asyncio +from dataclasses import dataclass +from decimal import Decimal +import json +import logging +import os +from pathlib import Path +import time +from urllib.parse import urlencode +from urllib.request import urlopen + +import pytest +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support + + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_POLYMARKET = 6 +POLYGON_CHAIN_ID = 137 +CTF_ADDRESS = Web3.to_checksum_address( + "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +) +POLYMARKET_TASK = Web3.keccak(text="polymarket_settlement") +RECONFIGURATION_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F2003" +) +SEL_CURRENT_EPOCH = Web3.keccak(text="currentEpoch()")[:4] +SEL_REMAINING_TIME = Web3.keccak(text="getRemainingTimeSeconds()")[:4] + +DEFAULT_SOAK_SECONDS = 24 * 60 * 60 +DEFAULT_POLL_SECONDS = 15 +DEFAULT_STALL_SECONDS = 6 * 60 +EPOCH_TIMEOUT_SECONDS = 180 +ORACLE_TIMEOUT_SECONDS = 360 +MIN_PROPOSAL_WINDOW_SECONDS = 40 +QUORUM_VALIDATORS = 3 + +_HEARTBEAT_FILE = "oracle_live_soak_heartbeat.jsonl" +_SUMMARY_FILE = "oracle_live_soak_summary.json" + + +@dataclass(frozen=True) +class SoakSettings: + duration_seconds: int + poll_seconds: int + stall_seconds: int + minimum_advances: int + restart_after_seconds: int + restart_node: str + + +def _env_int(name: str, default: int, minimum: int = 0) -> int: + value = int(os.environ.get(name, str(default))) + if value < minimum: + raise ValueError(f"{name} must be at least {minimum}") + return value + + +def _soak_settings() -> SoakSettings: + duration = _env_int( + "ORACLE_SOAK_DURATION_SECONDS", DEFAULT_SOAK_SECONDS, minimum=1 + ) + poll_seconds = _env_int( + "ORACLE_SOAK_POLL_SECONDS", DEFAULT_POLL_SECONDS, minimum=1 + ) + stall_seconds = _env_int( + "ORACLE_SOAK_STALL_TIMEOUT_SECONDS", + DEFAULT_STALL_SECONDS, + minimum=poll_seconds * 2, + ) + configured_minimum = os.environ.get("ORACLE_SOAK_MIN_ADVANCES") + if configured_minimum is None: + minimum_advances = ( + 0 if duration < 120 else max(1, (duration // 60) * 8 // 10) + ) + else: + minimum_advances = int(configured_minimum) + if minimum_advances < 0: + raise ValueError("ORACLE_SOAK_MIN_ADVANCES must be non-negative") + + configured_restart = os.environ.get("ORACLE_SOAK_RESTART_AFTER_SECONDS") + if configured_restart is None: + restart_after = duration // 2 if duration >= 60 * 60 else 0 + else: + restart_after = int(configured_restart) + if restart_after < 0 or restart_after >= duration: + raise ValueError( + "ORACLE_SOAK_RESTART_AFTER_SECONDS must be zero or less than duration" + ) + + return SoakSettings( + duration_seconds=duration, + poll_seconds=poll_seconds, + stall_seconds=stall_seconds, + minimum_advances=minimum_advances, + restart_after_seconds=restart_after, + restart_node=os.environ.get("ORACLE_SOAK_RESTART_NODE", "node4"), + ) + + +def _metadata() -> dict: + path = SUITE_DIR / "artifacts" / "oracle_live_soak_metadata.json" + return json.loads(path.read_text()) + + +def _current_epoch(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_CURRENT_EPOCH} + ), + "big", + ) + + +def _remaining_epoch_seconds(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_REMAINING_TIME} + ), + "big", + ) + + +async def _wait_for_epoch_advance( + cluster: Cluster, start_epoch: int +) -> int: + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + node1 = cluster.get_node("node1") + while time.monotonic() < deadline: + epoch = _current_epoch(node1.w3) + if epoch > start_epoch: + for node_id, node in cluster.nodes.items(): + while _current_epoch(node.w3) < epoch: + if time.monotonic() >= deadline: + raise TimeoutError( + f"{node_id} did not reach epoch {epoch}" + ) + await asyncio.sleep(1) + return epoch + await asyncio.sleep(1) + raise TimeoutError(f"chain did not advance past epoch {start_epoch}") + + +async def _wait_for_proposal_window(cluster: Cluster) -> int: + node1 = cluster.get_node("node1") + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + while time.monotonic() < deadline: + remaining = _remaining_epoch_seconds(node1.w3) + if remaining >= MIN_PROPOSAL_WINDOW_SECONDS: + return _current_epoch(node1.w3) + current = _current_epoch(node1.w3) + LOG.info( + "Only %ss remain in epoch %s; waiting for a proposal window", + remaining, + current, + ) + await _wait_for_epoch_advance(cluster, current) + raise TimeoutError("no epoch had enough time for governance activation") + + +def _validator_log(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "consensus_log" / "validator.log" + + +def _log_contains( + cluster: Cluster, node_id: str, marker: str, issuer: str +) -> bool: + path = _validator_log(cluster, node_id) + content = path.read_text(errors="replace") if path.exists() else "" + return any( + marker in line and issuer in line for line in content.splitlines() + ) + + +async def _wait_for_consensus_evidence( + cluster: Cluster, issuers: list[str] +) -> None: + missing_observers = { + (node_id, issuer) + for node_id in cluster.nodes + for issuer in issuers + } + certifiers = {issuer: set() for issuer in issuers} + missing_quorums = set(issuers) + deadline = time.monotonic() + ORACLE_TIMEOUT_SECONDS + + while time.monotonic() < deadline: + logs = {} + for node_id in cluster.nodes: + path = _validator_log(cluster, node_id) + logs[node_id] = ( + path.read_text(errors="replace") if path.exists() else "" + ) + + for node_id, issuer in list(missing_observers): + if any( + "JWKObserver spawned." in line and issuer in line + for line in logs[node_id].splitlines() + ): + missing_observers.remove((node_id, issuer)) + + for issuer in issuers: + for node_id, content in logs.items(): + lines = content.splitlines() + if any( + "Start certifying update." in line and issuer in line + for line in lines + ): + certifiers[issuer].add(node_id) + if any( + "Peer vote aggregated." in line + and issuer in line + and ( + "threshold_exceeded=true" in line + or '"threshold_exceeded":true' in line + ) + for line in lines + ): + missing_quorums.discard(issuer) + + if ( + not missing_observers + and not missing_quorums + and all( + len(certifiers[issuer]) >= QUORUM_VALIDATORS + for issuer in issuers + ) + ): + return + await asyncio.sleep(2) + + raise AssertionError( + "missing consensus evidence: " + f"observers={sorted(missing_observers)} " + f"certifiers=" + f"{ {key: sorted(value) for key, value in certifiers.items()} } " + f"quorums={sorted(missing_quorums)}" + ) + + +async def _wait_for_block(w3: Web3, block_number: int, timeout: int = 90): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + try: + if w3.eth.block_number >= block_number: + return + except Exception: + pass + await asyncio.sleep(1) + raise TimeoutError(f"RPC did not reach Gravity block {block_number}") + + +async def _wait_for_settlement( + resolver, mirror_id: int, condition_id: bytes +) -> tuple: + deadline = time.monotonic() + ORACLE_TIMEOUT_SECONDS + while time.monotonic() < deadline: + settlement = tuple( + resolver.functions.getSettlement(mirror_id, condition_id).call() + ) + if settlement[0]: + return settlement + await asyncio.sleep(2) + raise TimeoutError(f"Polymarket mirror {mirror_id} was not settled") + + +def _oracle_delivered_logs( + w3: Web3, + source_type: int, + source_id: int, + from_block: int, + to_block: int | str = "latest", +) -> list: + return w3.eth.get_logs( + { + "fromBlock": from_block, + "toBlock": to_block, + "address": support.NATIVE_ORACLE_ADDRESS, + "topics": [ + support.ORACLE_DELIVERED_TOPIC0, + support.topic(source_type), + support.topic(source_id), + ], + } + ) + + +def _fetch_binance_price( + base_url: str, pair: str, bucket_start_ms: int +) -> int: + bucket_end_ms = bucket_start_ms + support.INTERVAL_MS - 1 + query = urlencode( + { + "pair": pair, + "interval": "1m", + "startTime": bucket_start_ms, + "endTime": bucket_end_ms, + "limit": 1, + } + ) + with urlopen( + f"{base_url}/fapi/v1/indexPriceKlines?{query}", timeout=20 + ) as response: + rows = json.loads(response.read()) + assert len(rows) == 1, f"Binance returned {len(rows)} rows for {pair}" + assert int(rows[0][0]) == bucket_start_ms + assert int(rows[0][6]) == bucket_end_ms + scaled = Decimal(rows[0][4]) * (10**support.DECIMALS) + assert scaled == scaled.to_integral_value() + return int(scaled) + + +async def _fetch_binance_price_with_retry( + base_url: str, + pair: str, + bucket_start_ms: int, + timeout: int = 120, +) -> int: + deadline = time.monotonic() + timeout + last_error = None + while time.monotonic() < deadline: + try: + return await asyncio.to_thread( + _fetch_binance_price, base_url, pair, bucket_start_ms + ) + except (AssertionError, OSError, ValueError) as error: + last_error = error + await asyncio.sleep(5) + raise TimeoutError( + f"Binance did not return the exact closed {pair} bucket" + ) from last_error + + +def _relayer_sources(cluster: Cluster, node_id: str) -> dict: + path = ( + cluster.base_dir + / node_id + / "data" + / "reth" + / "relayer_state.json" + ) + if not path.exists(): + return {} + try: + return json.loads(path.read_text()).get("sources", {}) + except (OSError, json.JSONDecodeError): + return {} + + +def _relayer_quorum( + cluster: Cluster, uri: str, minimum_nonce: int +) -> list[str]: + reached = [] + for node_id in cluster.nodes: + raw_nonce = ( + _relayer_sources(cluster, node_id) + .get(uri, {}) + .get("last_nonce") + ) + try: + nonce = int(raw_nonce or 0) + except (TypeError, ValueError): + nonce = 0 + if nonce >= minimum_nonce: + reached.append(node_id) + return sorted(reached) + + +async def _replicated_snapshot( + cluster: Cluster, + native_artifact: dict, + price_artifact: dict, + polymarket_artifact: dict, + price_resolver_address: str, + polymarket_resolver_address: str, + feed_id: int, + bucket_start_ms: int, + mirror_id: int, + condition_id: bytes, +) -> dict: + node1 = cluster.get_node("node1") + snapshot_block = node1.w3.eth.block_number + heights = {} + for node_id, node in cluster.nodes.items(): + assert node.w3.is_connected(), f"{node_id} RPC disconnected" + await _wait_for_block(node.w3, snapshot_block) + heights[node_id] = node.w3.eth.block_number + + native_oracle = node1.w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + price_resolver = node1.w3.eth.contract( + address=price_resolver_address, + abi=price_artifact["abi"], + ) + polymarket_resolver = node1.w3.eth.contract( + address=polymarket_resolver_address, + abi=polymarket_artifact["abi"], + ) + price_progress = tuple( + native_oracle.functions.getSourceProgress( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call(block_identifier=snapshot_block) + ) + latest_price = tuple( + price_resolver.functions.latestPrice(feed_id).call( + block_identifier=snapshot_block + ) + ) + polymarket_progress = tuple( + native_oracle.functions.getSourceProgress( + SOURCE_TYPE_POLYMARKET, mirror_id + ).call(block_identifier=snapshot_block) + ) + settlement = tuple( + polymarket_resolver.functions.getSettlement( + mirror_id, condition_id + ).call(block_identifier=snapshot_block) + ) + + assert price_progress[0] >= 1 + assert latest_price[0] + assert latest_price[1] == support.round_id( + bucket_start_ms, price_progress[0] + ) + assert latest_price[2] == support.round_end_ms( + bucket_start_ms, price_progress[0] + ) + assert price_progress[1] == latest_price[2] + assert latest_price[3] == support.DECIMALS + assert latest_price[4] > 0 + assert polymarket_progress[0] == 1 + assert settlement[0] + + for node_id, node in cluster.nodes.items(): + replica_native = node.w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + replica_price = node.w3.eth.contract( + address=price_resolver_address, + abi=price_artifact["abi"], + ) + replica_polymarket = node.w3.eth.contract( + address=polymarket_resolver_address, + abi=polymarket_artifact["abi"], + ) + assert tuple( + replica_native.functions.getSourceProgress( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call(block_identifier=snapshot_block) + ) == price_progress, f"{node_id} price progress diverged" + assert tuple( + replica_price.functions.latestPrice(feed_id).call( + block_identifier=snapshot_block + ) + ) == latest_price, f"{node_id} latest price diverged" + assert tuple( + replica_native.functions.getSourceProgress( + SOURCE_TYPE_POLYMARKET, mirror_id + ).call(block_identifier=snapshot_block) + ) == polymarket_progress, f"{node_id} Polymarket progress diverged" + assert tuple( + replica_polymarket.functions.getSettlement( + mirror_id, condition_id + ).call(block_identifier=snapshot_block) + ) == settlement, f"{node_id} Polymarket settlement diverged" + + return { + "block": snapshot_block, + "heights": heights, + "priceProgress": price_progress, + "latestPrice": latest_price, + "polymarketProgress": polymarket_progress, + "settlement": settlement, + } + + +def _append_json_line(path: Path, payload: dict) -> None: + with path.open("a") as output: + output.write(json.dumps(payload, sort_keys=True) + "\n") + + +async def _restart_validator( + cluster: Cluster, node_id: str, target_block: int +) -> float: + node = cluster.get_node(node_id) + if node is None: + raise AssertionError(f"unknown restart node {node_id}") + started = time.monotonic() + assert await node.restart(), f"failed to restart {node_id}" + await _wait_for_block(node.w3, target_block, timeout=180) + assert await cluster.check_block_increasing(timeout=60) + return time.monotonic() - started + + +async def _run_soak( + cluster: Cluster, + settings: SoakSettings, + native_artifact: dict, + price_artifact: dict, + polymarket_artifact: dict, + price_resolver_address: str, + polymarket_resolver_address: str, + binance: dict, + polymarket: dict, + expected_settlement: tuple, +) -> dict: + feed_id = int(binance["feedId"]) + mirror_id = int(polymarket["mirrorId"]) + condition_id = bytes.fromhex(polymarket["conditionId"][2:]) + heartbeat_path = SUITE_DIR / "artifacts" / _HEARTBEAT_FILE + heartbeat_path.unlink(missing_ok=True) + + initial = await _replicated_snapshot( + cluster, + native_artifact, + price_artifact, + polymarket_artifact, + price_resolver_address, + polymarket_resolver_address, + feed_id, + int(binance["bucketStartMs"]), + mirror_id, + condition_id, + ) + initial_nonce = int(initial["priceProgress"][0]) + last_nonce = initial_nonce + started = time.monotonic() + deadline = started + settings.duration_seconds + last_price_advance = started + max_price_gap = 0.0 + last_height_change = {node_id: started for node_id in cluster.nodes} + previous_heights = dict(initial["heights"]) + restart_done = False + restart_recovery_seconds = None + samples = 0 + final = initial + + while True: + now = time.monotonic() + if now >= deadline: + break + if ( + settings.restart_after_seconds + and not restart_done + and now - started >= settings.restart_after_seconds + ): + restart_recovery_seconds = await _restart_validator( + cluster, settings.restart_node, int(final["block"]) + ) + restart_done = True + + final = await _replicated_snapshot( + cluster, + native_artifact, + price_artifact, + polymarket_artifact, + price_resolver_address, + polymarket_resolver_address, + feed_id, + int(binance["bucketStartMs"]), + mirror_id, + condition_id, + ) + now = time.monotonic() + nonce = int(final["priceProgress"][0]) + assert nonce >= last_nonce, "Binance source nonce regressed" + if nonce > last_nonce: + max_price_gap = max(max_price_gap, now - last_price_advance) + last_price_advance = now + last_nonce = nonce + assert now - last_price_advance <= settings.stall_seconds, ( + f"NVDA price feed stalled at nonce {nonce} for " + f"{now - last_price_advance:.1f}s" + ) + + for node_id, height in final["heights"].items(): + assert height >= previous_heights[node_id], ( + f"{node_id} block height regressed" + ) + if height > previous_heights[node_id]: + last_height_change[node_id] = now + previous_heights[node_id] = height + assert now - last_height_change[node_id] <= settings.stall_seconds, ( + f"{node_id} chain height stalled for " + f"{now - last_height_change[node_id]:.1f}s" + ) + + assert tuple(final["polymarketProgress"]) == ( + 1, + int(polymarket["blockNumber"]), + ) + assert tuple(final["settlement"]) == expected_settlement + relayer_nodes = _relayer_quorum(cluster, binance["taskUri"], nonce) + assert len(relayer_nodes) >= QUORUM_VALIDATORS, ( + f"only {relayer_nodes} persisted NVDA nonce {nonce}" + ) + + samples += 1 + heartbeat = { + "elapsedSeconds": round(now - started, 3), + "gravityBlock": int(final["block"]), + "nodeHeights": final["heights"], + "nvdaNonce": nonce, + "nvdaPosition": int(final["priceProgress"][1]), + "nvdaRound": int(final["latestPrice"][1]), + "nvdaPrice": str(final["latestPrice"][4]), + "relayerQuorumNodes": relayer_nodes, + "polymarketNonce": int(final["polymarketProgress"][0]), + "restartCompleted": restart_done, + } + _append_json_line(heartbeat_path, heartbeat) + LOG.info("Oracle soak heartbeat: %s", heartbeat) + await asyncio.sleep( + min(settings.poll_seconds, max(0.0, deadline - time.monotonic())) + ) + + final = await _replicated_snapshot( + cluster, + native_artifact, + price_artifact, + polymarket_artifact, + price_resolver_address, + polymarket_resolver_address, + feed_id, + int(binance["bucketStartMs"]), + mirror_id, + condition_id, + ) + final_nonce = int(final["priceProgress"][0]) + advances = final_nonce - initial_nonce + assert advances >= settings.minimum_advances, ( + f"NVDA advanced {advances} rounds; expected at least " + f"{settings.minimum_advances}" + ) + if settings.restart_after_seconds: + assert restart_done, "configured validator restart did not run" + + final_bucket = support.round_start_ms( + int(binance["bucketStartMs"]), final_nonce + ) + max_price_gap = max(max_price_gap, time.monotonic() - last_price_advance) + expected_price = await _fetch_binance_price_with_retry( + binance["baseUrl"], + binance["pair"], + final_bucket, + ) + assert int(final["latestPrice"][4]) == expected_price + return { + "status": "passed", + "configuredDurationSeconds": settings.duration_seconds, + "actualDurationSeconds": round(time.monotonic() - started, 3), + "samples": samples, + "initialNonce": initial_nonce, + "finalNonce": final_nonce, + "advances": advances, + "minimumAdvances": settings.minimum_advances, + "maxObservedPriceGapSeconds": round(max_price_gap, 3), + "finalGravityBlock": int(final["block"]), + "restartNode": settings.restart_node + if settings.restart_after_seconds + else None, + "restartRecoverySeconds": restart_recovery_seconds, + "polymarketMirrorId": mirror_id, + "polymarketNonce": int(final["polymarketProgress"][0]), + } + + +def _write_summary(payload: dict) -> None: + path = SUITE_DIR / "artifacts" / _SUMMARY_FILE + path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n") + + +@pytest.mark.asyncio +async def test_governance_activated_oracles_soak_for_configured_duration( + cluster: Cluster, +): + settings = _soak_settings() + metadata = _metadata() + binance = metadata["binance"] + polymarket = metadata["polymarket"] + feed_id = int(binance["feedId"]) + mirror_id = int(polymarket["mirrorId"]) + condition_id = bytes.fromhex(polymarket["conditionId"][2:]) + + assert support.is_live_mode(), "oracle_live_soak must use live Binance" + assert len(cluster.nodes) == 4 + assert await cluster.set_full_live(timeout=180) + assert await cluster.check_block_increasing(timeout=60) + active = await cluster.validator_list() + assert {node.id for node in active.active} == set(cluster.nodes) + + node1 = cluster.get_node("node1") + w3 = node1.w3 + required = [ + ("PriceFeedResolver.sol", "PriceFeedResolver"), + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("NativeOracle.sol", "NativeOracle"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ] + contracts_out = support.ensure_contracts_out( + SUITE_DIR, required, "live Oracle soak" + ) + price_artifact = support.load_artifact( + contracts_out, "PriceFeedResolver.sol", "PriceFeedResolver" + ) + polymarket_artifact = support.load_artifact( + contracts_out, + "PolymarketSettlementResolver.sol", + "PolymarketSettlementResolver", + ) + native_artifact = support.load_artifact( + contracts_out, "NativeOracle.sol", "NativeOracle" + ) + task_artifact = support.load_artifact( + contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig" + ) + + price_resolver = support.deploy_contract( + w3, price_artifact, support.FAUCET_KEY + ) + polymarket_resolver = support.deploy_contract( + w3, polymarket_artifact, support.FAUCET_KEY + ) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + task_config = w3.eth.contract( + address=support.ORACLE_TASK_CONFIG_ADDRESS, + abi=task_artifact["abi"], + ) + pool_addr = support.pool0_voted_by_faucet(w3) + + assert not task_config.functions.hasTask( + support.SOURCE_TYPE_PRICE_FEED, feed_id, support.TASK_PRICE_FEED + ).call() + assert not task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET, mirror_id, POLYMARKET_TASK + ).call() + + setup_epoch = await _wait_for_proposal_window(cluster) + targets = [ + support.NATIVE_ORACLE_ADDRESS, + support.ORACLE_TASK_CONFIG_ADDRESS, + support.ORACLE_TASK_CONFIG_ADDRESS, + support.NATIVE_ORACLE_ADDRESS, + polymarket_resolver.address, + ] + datas = [ + support.function_calldata( + native_oracle.functions.setDefaultCallback( + support.SOURCE_TYPE_PRICE_FEED, price_resolver.address + ) + ), + support.function_calldata( + task_config.functions.setTask( + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + support.TASK_PRICE_FEED, + binance["taskUri"].encode(), + ) + ), + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_POLYMARKET, + mirror_id, + POLYMARKET_TASK, + polymarket["taskUri"].encode(), + ) + ), + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET, + mirror_id, + polymarket_resolver.address, + ) + ), + support.function_calldata( + polymarket_resolver.functions.registerMirror( + mirror_id, + POLYGON_CHAIN_ID, + CTF_ADDRESS, + condition_id, + 2, + ) + ), + ] + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + targets, + datas, + "activate-live-nvda-and-polymarket-soak", + gas=8_000_000, + ) + assert _current_epoch(w3) == setup_epoch + for source_type, source_id, task_name, expected_uri in ( + ( + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + support.TASK_PRICE_FEED, + binance["taskUri"], + ), + ( + SOURCE_TYPE_POLYMARKET, + mirror_id, + POLYMARKET_TASK, + polymarket["taskUri"], + ), + ): + assert task_config.functions.hasTask( + source_type, source_id, task_name + ).call() + task = task_config.functions.getTask( + source_type, source_id, task_name + ).call() + assert bytes(task[0]).decode() == expected_uri + assert native_oracle.functions.getLatestNonce( + source_type, source_id + ).call() == 0 + + issuers = [f"gravity://3/{feed_id}", f"gravity://6/{mirror_id}"] + for node_id in cluster.nodes: + for issuer in issuers: + assert not _log_contains( + cluster, node_id, "JWKObserver spawned.", issuer + ), f"{node_id} started {issuer} before the epoch boundary" + + activation_epoch = await _wait_for_epoch_advance(cluster, setup_epoch) + assert activation_epoch == setup_epoch + 1 + price_progress, initial_price = await support.wait_for_latest_price( + native_oracle, + price_resolver, + feed_id, + 1, + timeout=ORACLE_TIMEOUT_SECONDS, + ) + polymarket_progress = tuple( + await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET, + mirror_id, + 1, + timeout=ORACLE_TIMEOUT_SECONDS, + ) + ) + assert polymarket_progress == (1, int(polymarket["blockNumber"])) + settlement = await _wait_for_settlement( + polymarket_resolver, mirror_id, condition_id + ) + assert settlement[1] == 1 + assert settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_checksum_address(settlement[3]) == CTF_ADDRESS + assert Web3.to_checksum_address(settlement[4]) == Web3.to_checksum_address( + polymarket["oracle"] + ) + assert Web3.to_hex(settlement[5]).lower() == polymarket[ + "questionId" + ].lower() + assert settlement[6] == 2 + assert Web3.to_hex(settlement[7]).lower() == polymarket[ + "transactionHash" + ].lower() + assert settlement[8] == int(polymarket["logIndex"]) + assert polymarket_resolver.functions.getPayoutNumerators( + mirror_id, condition_id + ).call() == polymarket["payoutNumerators"] + + first_bucket = support.round_start_ms( + int(binance["bucketStartMs"]), int(price_progress[0]) + ) + expected_initial_price = await _fetch_binance_price_with_retry( + binance["baseUrl"], + binance["pair"], + first_bucket, + ) + assert int(initial_price[4]) == expected_initial_price + await _wait_for_consensus_evidence(cluster, issuers) + assert len( + _relayer_quorum(cluster, binance["taskUri"], int(price_progress[0])) + ) >= QUORUM_VALIDATORS + + try: + summary = await _run_soak( + cluster, + settings, + native_artifact, + price_artifact, + polymarket_artifact, + price_resolver.address, + polymarket_resolver.address, + binance, + polymarket, + settlement, + ) + except BaseException as error: + _write_summary( + { + "status": "failed", + "errorType": type(error).__name__, + "error": str(error), + "configuredDurationSeconds": settings.duration_seconds, + "polymarketMirrorId": mirror_id, + } + ) + raise + + price_delivery_count = len( + _oracle_delivered_logs( + w3, + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + receipt["blockNumber"], + summary["finalGravityBlock"], + ) + ) + assert price_delivery_count == summary["finalNonce"], ( + "NVDA delivery event count does not match final source nonce" + ) + polymarket_delivery_count = len( + _oracle_delivered_logs( + w3, + SOURCE_TYPE_POLYMARKET, + mirror_id, + receipt["blockNumber"], + summary["finalGravityBlock"], + ) + ) + assert polymarket_delivery_count == 1, ( + "Polymarket settlement was delivered more than once" + ) + for source_type, source_id, task_name in ( + ( + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + support.TASK_PRICE_FEED, + ), + (SOURCE_TYPE_POLYMARKET, mirror_id, POLYMARKET_TASK), + ): + assert task_config.functions.hasTask( + source_type, source_id, task_name + ).call() + summary.update( + { + "activationEpoch": activation_epoch, + "governanceBlock": receipt["blockNumber"], + "priceDeliveryEvents": price_delivery_count, + "polymarketDeliveryEvents": polymarket_delivery_count, + } + ) + _write_summary(summary) + LOG.info("Oracle live soak passed: %s", summary) diff --git a/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/README.md b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/README.md new file mode 100644 index 000000000..51e6970d2 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/README.md @@ -0,0 +1,85 @@ +# Rolling Oracle Activation E2E + +This suite proves the operational rollout sequence for new relayer-backed +Oracle source types without enabling them on partially upgraded validators: + +1. Start four equal-power validators on an old `gravity_node` binary. +2. Process a sourceType `0` bridge event on the all-old cluster. +3. Upgrade one validator at a time. After each replacement, process another + bridge event while old and new binaries coexist. +4. After all four validators run the new binary, use governance to add + production-data Binance sourceType `3` tasks and one finalized + Polygon/Polymarket sourceType `6` task. +5. Prove the tasks are visible immediately but their nonces remain zero in the + proposal epoch. +6. Cross the epoch boundary, require three independent relayer checkpoints and + three-validator JWK quorum evidence, then verify the exact Binance index + prices and Polymarket settlement on all four RPC replicas. +7. Process one more bridge event and restart a validator which lagged the + Polymarket fetch, proving it fast-forwards from the committed onchain nonce + and persists the recovered source state. + +Genesis deliberately contains only the historical sourceType `0` task. The +sourceType `3` and `6` registrations come entirely from +`OracleTaskConfig.setTask` governance calls after every binary has been +replaced. + +## Prerequisites + +- An executable old binary built from the intended production baseline. +- An executable new binary built from the Oracle branch under test. +- Both binaries must be consensus-compatible with the fixed-size + `OracleSourceState` used by the pinned genesis contracts. A transition from + the legacy variable-size state requires its own version-gated hardfork test. +- `POLYGON_RPC_URL` or `POLYGON_QUICKNONE_HTTP_URL`. +- Network egress that can access Polygon, Polymarket Gamma, and Binance's + official public-data archive. No Binance API key is required. + +## Run + +```bash +export GRAVITY_OLD_BINARY=/path/to/old/gravity_node +export GRAVITY_NEW_BINARY=/path/to/new/gravity_node +export POLYGON_RPC_URL='https://polygon-rpc.example' +export GRAVITY_E2E_SKIP_GLOBAL_PKILL=1 +export ORACLE_ROLLING_BINANCE_MODE=official-archive + +./gravity_e2e/run_test.sh oracle_rolling_activation_live --force-init +``` + +`GRAVITY_E2E_SKIP_GLOBAL_PKILL=1` prevents the runner from globally killing +unrelated `gravity_node` processes. The suite still stops its own four nodes +through its cluster configuration. + +Optional controls: + +```bash +export BINANCE_PRICE_FEED_ARCHIVE_DATE=2026-07-27 +export BINANCE_PRICE_FEED_ARCHIVE_BASE_URL=https://data.binance.vision +export BINANCE_PRICE_FEED_GRACE_MS=120000 +export POLYMARKET_GAMMA_URL=https://gamma-api.polymarket.com +``` + +`official-archive` downloads Binance's published daily `indexPriceKlines` ZIPs for +both pairs, records each archive SHA-256, selects one common closed minute, +and serves only those exact rows through a localhost protocol adapter. The +four validators still fetch and certify independently. Prices come from +Binance production data; the local adapter is not a generated-price mock. +When no date is pinned, the hook tries the previous seven UTC dates and uses +the newest date available for both pairs. + +To exercise Binance's production REST endpoint directly instead: + +```bash +export ORACLE_ROLLING_BINANCE_MODE=production-rest +export BINANCE_PRICE_FEED_BASE_URL=https://fapi.binance.com +export BINANCE_PRICE_FEED_BUCKET_START_MS=1785200000000 +export BINANCE_PRICE_FEED_GRACE_MS=120000 +``` + +The REST mode never falls back silently. It requires an egress region accepted +by Binance and fails on HTTP 451 otherwise. + +The generated relayer configuration and selected live market metadata are +written under the ignored suite `artifacts/` directory and removed at teardown. +Do not commit RPC URLs, credentials, proxy settings, or generated metadata. diff --git a/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/cluster.toml b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/cluster.toml new file mode 100644 index 000000000..86b9220e7 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/cluster.toml @@ -0,0 +1,73 @@ +# Four-validator rolling Oracle activation proof. +# Fixed listeners stay below Linux's default ephemeral source-port range. + +[cluster] +name = "gravity-devnet-oracle-rolling-activation-live" +base_dir = "/tmp/gravity-cluster-oracle-rolling-activation-live" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26480 +vfn_port = 26490 +rpc_port = 26500 +api_port = 26510 +metrics_port = 26520 +inspection_port = 26530 +https_port = 26540 +authrpc_port = 26550 +reth_p2p_port = 26560 + +[[nodes]] +id = "node2" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26481 +vfn_port = 26491 +rpc_port = 26501 +api_port = 26511 +metrics_port = 26521 +inspection_port = 26531 +https_port = 26541 +authrpc_port = 26551 +reth_p2p_port = 26561 + +[[nodes]] +id = "node3" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26482 +vfn_port = 26492 +rpc_port = 26502 +api_port = 26512 +metrics_port = 26522 +inspection_port = 26532 +https_port = 26542 +authrpc_port = 26552 +reth_p2p_port = 26562 + +[[nodes]] +id = "node4" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26483 +vfn_port = 26493 +rpc_port = 26503 +api_port = 26513 +metrics_port = 26523 +inspection_port = 26533 +https_port = 26543 +authrpc_port = 26553 +reth_p2p_port = 26563 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/genesis.toml b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/genesis.toml new file mode 100644 index 000000000..3f1bbe0d1 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/genesis.toml @@ -0,0 +1,110 @@ +# The historical baseline contains only the bridge task. Price and Polymarket +# providers are deliberately absent until post-upgrade governance activation. + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 26480 +vfn_port = 26490 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node2" +address = "0x7b254Bd44F6CE45e00a912b2460D47F3Be56fAD7" +host = "127.0.0.1" +validator_port = 26481 +vfn_port = 26491 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node3" +address = "0x9B2C25E77a97d3e84DC0Cb7F83fb676ddC4F24b9" +host = "127.0.0.1" +validator_port = 26482 +vfn_port = 26492 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node4" +address = "0x18c23753385ce7A60B15d171302E48b6AFf0BDC5" +host = "127.0.0.1" +validator_port = 26483 +vfn_port = 26493 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 60000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1] +callbacks = ["0x00000000000000000000000000000001625F4001"] + +[genesis.oracle_config.bridge_config] +deploy = true +trusted_bridge = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" +trusted_source_id = 31337 + +[[genesis.oracle_config.tasks]] +source_type = 0 +source_id = 31337 +task_name = "anvil" +config = "gravity://0/31337/events?contract=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512&eventSignature=0x5646e682c7d994bf11f5a2c8addb60d03c83cda3b65025a826346589df43406e&fromBlock=0" + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/hooks.py b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/hooks.py new file mode 100644 index 000000000..fa90613f1 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/hooks.py @@ -0,0 +1,474 @@ +"""Prepare old/new binaries plus live Oracle sources for the rolling proof.""" + +import csv +from datetime import datetime, timedelta, timezone +import hashlib +import importlib.util +from io import BytesIO, TextIOWrapper +import json +import logging +import os +import shutil +import sys +import threading +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from urllib.error import HTTPError +from urllib.parse import parse_qs, urlparse +from urllib.request import Request, urlopen +from zipfile import ZipFile + +try: + import tomllib +except ImportError: + import tomli as tomllib + + +LOG = logging.getLogger(__name__) + +BRIDGE_RPC_PORT = 28646 +BRIDGE_EVENT_COUNT = 6 +BRIDGE_AMOUNT = 1_000_000_000_000_000_000 +BRIDGE_RECIPIENT = "0x6954476eAe13Bd072D9f19406A6B9543514f765C" +BRIDGE_SENDER = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" +BRIDGE_URI = ( + "gravity://0/31337/events?" + "contract=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512&" + "eventSignature=0x5646e682c7d994bf11f5a2c8addb60d03c83cda3b65025a826346589df43406e&" + "fromBlock=0" +) + +BINANCE_REPLAY_PORT = 28647 +INTERVAL_MS = 60_000 +DEFAULT_BINANCE_GRACE_MS = 120_000 +DEFAULT_BINANCE_BASE_URL = "https://fapi.binance.com" +DEFAULT_BINANCE_ARCHIVE_BASE_URL = "https://data.binance.vision" +DEFAULT_BINANCE_MODE = "official-archive" +BINANCE_FEEDS = ((1001, "NVDAUSDT"), (1002, "TSLAUSDT")) + +_METADATA_FILE = "oracle_rolling_activation_metadata.json" +_RELAYER_FILE = "relayer_config.live.json" +_mock = None +_binance_replay = None + + +def _sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def _required_binary(env: dict, name: str) -> Path: + value = env.get(name) or os.environ.get(name) + if not value: + raise RuntimeError(f"{name} must point to an existing gravity_node binary") + path = Path(value).expanduser().resolve() + if not path.is_file(): + raise RuntimeError(f"{name} is not a file: {path}") + if not os.access(path, os.X_OK): + raise RuntimeError(f"{name} is not executable: {path}") + return path + + +def _bucket_start_ms(env: dict) -> int: + configured = env.get("BINANCE_PRICE_FEED_BUCKET_START_MS") + if configured: + return int(configured) + + grace_ms = int( + env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_BINANCE_GRACE_MS)) + ) + minimum_lag = (grace_ms + INTERVAL_MS - 1) // INTERVAL_MS + 1 + lag_minutes = int( + env.get("BINANCE_PRICE_FEED_LAG_MINUTES", str(minimum_lag)) + ) + return ((int(time.time() * 1000) // INTERVAL_MS) - lag_minutes) * INTERVAL_MS + + +def _archive_row(raw: list[str]) -> list: + if len(raw) != 12: + raise RuntimeError(f"unexpected Binance archive row width: {len(raw)}") + row = list(raw) + for index in (0, 6, 8): + row[index] = int(row[index]) + return row + + +def _download_archive( + archive_base_url: str, pair: str, archive_date: str +) -> tuple[dict[int, list], dict]: + filename = f"{pair}-1m-{archive_date}.zip" + source_url = ( + f"{archive_base_url}/data/futures/um/daily/indexPriceKlines/" + f"{pair}/1m/{filename}" + ) + request = Request(source_url, headers={"User-Agent": "gravity-e2e/1"}) + with urlopen(request, timeout=45) as response: + payload = response.read() + + archive_sha256 = hashlib.sha256(payload).hexdigest() + with ZipFile(BytesIO(payload)) as archive: + csv_names = [ + name for name in archive.namelist() if name.lower().endswith(".csv") + ] + if len(csv_names) != 1: + raise RuntimeError( + f"{source_url} contained {len(csv_names)} CSV files" + ) + with archive.open(csv_names[0]) as binary: + reader = csv.reader(TextIOWrapper(binary, encoding="utf-8")) + header = next(reader) + if header[:7] != [ + "open_time", + "open", + "high", + "low", + "close", + "volume", + "close_time", + ]: + raise RuntimeError( + f"unexpected Binance archive header for {pair}: {header}" + ) + rows = { + int(row[0]): _archive_row(row) + for row in reader + if row + } + if not rows: + raise RuntimeError(f"Binance archive contained no rows: {source_url}") + return rows, { + "pair": pair, + "sourceUrl": source_url, + "sha256": archive_sha256, + } + + +def _archive_dates(env: dict) -> list[str]: + configured = env.get("BINANCE_PRICE_FEED_ARCHIVE_DATE") + if configured: + datetime.strptime(configured, "%Y-%m-%d") + return [configured] + + today = datetime.now(timezone.utc).date() + return [ + (today - timedelta(days=offset)).isoformat() + for offset in range(1, 8) + ] + + +def _official_archive_data(env: dict) -> dict: + archive_base_url = env.get( + "BINANCE_PRICE_FEED_ARCHIVE_BASE_URL", + DEFAULT_BINANCE_ARCHIVE_BASE_URL, + ).rstrip("/") + configured_bucket = env.get("BINANCE_PRICE_FEED_BUCKET_START_MS") + last_error = None + + for archive_date in _archive_dates(env): + try: + rows_by_pair = {} + provenance = [] + for _, pair in BINANCE_FEEDS: + rows, source = _download_archive( + archive_base_url, pair, archive_date + ) + rows_by_pair[pair] = rows + provenance.append(source) + except (HTTPError, OSError, RuntimeError) as error: + last_error = error + if env.get("BINANCE_PRICE_FEED_ARCHIVE_DATE"): + raise + continue + + common_buckets = set.intersection( + *(set(rows) for rows in rows_by_pair.values()) + ) + if not common_buckets: + last_error = RuntimeError( + f"no common Binance minute bucket on {archive_date}" + ) + continue + bucket_start_ms = ( + int(configured_bucket) + if configured_bucket + else max(common_buckets) + ) + if bucket_start_ms not in common_buckets: + raise RuntimeError( + f"bucket {bucket_start_ms} is absent from {archive_date}" + ) + return { + "archiveBaseUrl": archive_base_url, + "archiveDate": archive_date, + "bucketStartMs": bucket_start_ms, + "provenance": provenance, + "rows": { + pair: rows_by_pair[pair][bucket_start_ms] + for _, pair in BINANCE_FEEDS + }, + } + + raise RuntimeError( + "could not load a common Binance production archive for all feeds" + ) from last_error + + +def _price_uri( + feed_id: int, pair: str, bucket_start_ms: int, grace_ms: int +) -> str: + return ( + f"gravity://3/{feed_id}/price_feed?" + f"provider=binance_index_kline_v1&pair={pair}&interval=1m&" + f"bucketStartMs={bucket_start_ms}&decimals=8&graceMs={grace_ms}" + ) + + +def _polymarket_hooks(test_dir: Path): + hook_path = test_dir.parent / "polymarket_live_dynamic_mirror" / "hooks.py" + spec = importlib.util.spec_from_file_location( + "gravity_e2e_live_polymarket_hooks", hook_path + ) + if spec is None or spec.loader is None: + raise RuntimeError(f"cannot load live Polymarket helpers from {hook_path}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def _replace_binary(source: Path, destination: Path) -> None: + destination.unlink(missing_ok=True) + try: + os.link(source, destination) + except OSError: + shutil.copy2(source, destination) + destination.chmod(0o755) + if _sha256(destination) != _sha256(source): + raise RuntimeError(f"binary replacement verification failed: {destination}") + + +def _start_binance_replay(binance: dict): + rows = binance["rows"] + + class Handler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def do_GET(self): + parsed = urlparse(self.path) + if parsed.path != "/fapi/v1/indexPriceKlines": + self.send_error(404) + return + + params = parse_qs(parsed.query) + pair = params.get("pair", [""])[0] + try: + start_time = int(params.get("startTime", ["-1"])[0]) + end_time = int(params.get("endTime", ["-1"])[0]) + except ValueError: + self.send_error(400) + return + row = rows.get(pair) + if ( + row is None + or params.get("interval", [""])[0] != "1m" + or params.get("limit", [""])[0] != "1" + or start_time != row[0] + or end_time != row[6] + ): + self.send_error(400) + return + + payload = json.dumps([row]).encode() + self.send_response(200) + self.send_header("content-type", "application/json") + self.send_header("content-length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def log_message(self, fmt: str, *args): + LOG.debug("Binance archive replay: " + fmt, *args) + + server = ThreadingHTTPServer(("127.0.0.1", BINANCE_REPLAY_PORT), Handler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + return server, thread + + +def pre_deploy(test_dir: Path, env: dict, pytest_args: list[str]): + old_binary = _required_binary(env, "GRAVITY_OLD_BINARY") + new_binary = _required_binary(env, "GRAVITY_NEW_BINARY") + old_hash = _sha256(old_binary) + new_hash = _sha256(new_binary) + if old_hash == new_hash: + raise RuntimeError("old and new gravity_node binaries must differ") + + rpc_url = ( + env.get("POLYGON_RPC_URL") + or env.get("POLYGON_QUICKNONE_HTTP_URL") + or os.environ.get("POLYGON_RPC_URL") + or os.environ.get("POLYGON_QUICKNONE_HTTP_URL") + ) + if not rpc_url: + raise RuntimeError("POLYGON_RPC_URL is required for this live suite") + + polymarket = _polymarket_hooks(test_dir) + gamma_url = env.get("POLYMARKET_GAMMA_URL", polymarket.DEFAULT_GAMMA_URL) + market = polymarket._discover_market(rpc_url, gamma_url) + + binance_mode = env.get( + "ORACLE_ROLLING_BINANCE_MODE", DEFAULT_BINANCE_MODE + ) + if binance_mode == "official-archive": + archive_data = _official_archive_data(env) + binance_base_url = f"http://127.0.0.1:{BINANCE_REPLAY_PORT}" + bucket_start_ms = archive_data["bucketStartMs"] + elif binance_mode == "production-rest": + archive_data = None + binance_base_url = env.get( + "BINANCE_PRICE_FEED_BASE_URL", DEFAULT_BINANCE_BASE_URL + ).rstrip("/") + bucket_start_ms = _bucket_start_ms(env) + else: + raise RuntimeError( + "ORACLE_ROLLING_BINANCE_MODE must be " + "'official-archive' or 'production-rest'" + ) + grace_ms = int( + env.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_BINANCE_GRACE_MS)) + ) + price_uris = { + str(feed_id): _price_uri(feed_id, pair, bucket_start_ms, grace_ms) + for feed_id, pair in BINANCE_FEEDS + } + + mappings = {BRIDGE_URI: f"http://127.0.0.1:{BRIDGE_RPC_PORT}"} + mappings.update({uri: binance_base_url for uri in price_uris.values()}) + mappings[market["taskUri"]] = rpc_url + + artifacts = test_dir / "artifacts" + artifacts.mkdir(parents=True, exist_ok=True) + relayer_path = artifacts / _RELAYER_FILE + relayer_path.write_text( + json.dumps({"uri_mappings": mappings}, indent=2) + "\n" + ) + metadata_path = artifacts / _METADATA_FILE + binance_metadata = { + "mode": binance_mode, + "baseUrl": binance_base_url, + "bucketStartMs": bucket_start_ms, + "graceMs": grace_ms, + "feeds": [ + { + "feedId": feed_id, + "pair": pair, + "taskUri": price_uris[str(feed_id)], + } + for feed_id, pair in BINANCE_FEEDS + ], + } + if archive_data is not None: + binance_metadata.update(archive_data) + + metadata_path.write_text( + json.dumps( + { + "oldBinarySha256": old_hash, + "newBinarySha256": new_hash, + "bridge": { + "rpcUrl": f"http://127.0.0.1:{BRIDGE_RPC_PORT}", + "eventCount": BRIDGE_EVENT_COUNT, + "amount": BRIDGE_AMOUNT, + "recipient": BRIDGE_RECIPIENT, + "sender": BRIDGE_SENDER, + "taskUri": BRIDGE_URI, + }, + "binance": binance_metadata, + "polymarket": market, + }, + indent=2, + ensure_ascii=False, + ) + + "\n" + ) + + env["GRAVITY_OLD_BINARY"] = str(old_binary) + env["GRAVITY_NEW_BINARY"] = str(new_binary) + env["BINANCE_PRICE_FEED_MODE"] = "live" + env["BINANCE_PRICE_FEED_BASE_URL"] = binance_base_url + env["BINANCE_PRICE_FEED_BUCKET_START_MS"] = str(bucket_start_ms) + env["BINANCE_PRICE_FEED_GRACE_MS"] = str(grace_ms) + env["RELAYER_CONFIG_TPL"] = str(relayer_path) + LOG.info( + "[hook] Prepared old=%s new=%s Binance mode=%s bucket=%s " + "Polymarket mirror=%s", + old_hash[:12], + new_hash[:12], + binance_mode, + bucket_start_ms, + market["mirrorId"], + ) + + +def pre_start(test_dir: Path, env: dict, pytest_args: list[str]): + global _binance_replay, _mock + + old_binary = _required_binary(env, "GRAVITY_OLD_BINARY") + cluster = tomllib.loads((test_dir / "cluster.toml").read_text()) + base_dir = Path(cluster["cluster"]["base_dir"]) + for node in cluster["nodes"]: + destination = base_dir / node["id"] / "bin" / "gravity_node" + _replace_binary(old_binary, destination) + LOG.info("[hook] Installed old binary for %s", node["id"]) + + e2e_root = str(test_dir.parents[1]) + if e2e_root not in sys.path: + sys.path.insert(0, e2e_root) + from gravity_e2e.utils.mock_anvil import MockAnvil + + _mock = MockAnvil(port=BRIDGE_RPC_PORT) + _mock.start() + _mock.preload_events( + count=BRIDGE_EVENT_COUNT, + amount=BRIDGE_AMOUNT, + recipient=BRIDGE_RECIPIENT, + sender_address=BRIDGE_SENDER, + events_per_block=1, + ) + _mock.set_finalized(0) + LOG.info( + "[hook] Mock bridge source ready on localhost with %s hidden events", + BRIDGE_EVENT_COUNT, + ) + + metadata = json.loads( + (test_dir / "artifacts" / _METADATA_FILE).read_text() + ) + if metadata["binance"]["mode"] == "official-archive": + _binance_replay = _start_binance_replay(metadata["binance"]) + LOG.info( + "[hook] Binance official archive replay ready for %s at bucket %s", + metadata["binance"]["archiveDate"], + metadata["binance"]["bucketStartMs"], + ) + + +def post_stop(test_dir: Path, env: dict): + global _binance_replay, _mock + + if _binance_replay is not None: + server, thread = _binance_replay + server.shutdown() + server.server_close() + thread.join(timeout=5) + _binance_replay = None + + if _mock is not None: + _mock.stop() + _mock = None + + artifacts = test_dir / "artifacts" + for name in (_METADATA_FILE, _RELAYER_FILE): + (artifacts / name).unlink(missing_ok=True) diff --git a/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/test_oracle_rolling_activation_live.py b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/test_oracle_rolling_activation_live.py new file mode 100644 index 000000000..b20740c4f --- /dev/null +++ b/gravity_e2e/cluster_test_cases/oracle_rolling_activation_live/test_oracle_rolling_activation_live.py @@ -0,0 +1,701 @@ +"""Rolling binary upgrade followed by live sourceType 3/6 activation.""" + +import asyncio +from decimal import Decimal +import hashlib +import json +import logging +import os +from pathlib import Path +import shutil +import time +from urllib.parse import urlencode +from urllib.request import Request, urlopen + +import pytest +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support +from gravity_e2e.utils.bridge_utils import poll_all_native_minted + + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_BRIDGE = 0 +SOURCE_TYPE_POLYMARKET = 6 +BRIDGE_SOURCE_ID = 31337 +POLYGON_CHAIN_ID = 137 +CTF_ADDRESS = Web3.to_checksum_address( + "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +) +POLYMARKET_TASK = Web3.keccak(text="polymarket_settlement") +RECONFIGURATION_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F2003" +) +SEL_CURRENT_EPOCH = Web3.keccak(text="currentEpoch()")[:4] +SEL_REMAINING_TIME = Web3.keccak(text="getRemainingTimeSeconds()")[:4] + +QUORUM_VALIDATORS = 3 +MIN_PROPOSAL_WINDOW_SECONDS = 35 +EPOCH_TIMEOUT_SECONDS = 180 +ORACLE_TIMEOUT_SECONDS = 360 + + +def _metadata() -> dict: + return json.loads( + ( + SUITE_DIR + / "artifacts" + / "oracle_rolling_activation_metadata.json" + ).read_text() + ) + + +def _sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def _node_binary(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "bin" / "gravity_node" + + +def _assert_binary_matrix( + cluster: Cluster, upgraded: set[str], old_hash: str, new_hash: str +) -> None: + for node_id in cluster.nodes: + expected = new_hash if node_id in upgraded else old_hash + actual = _sha256(_node_binary(cluster, node_id)) + assert actual == expected, ( + f"{node_id} binary mismatch: expected={expected[:12]} " + f"actual={actual[:12]}" + ) + + +def _replace_binary(source: Path, destination: Path) -> None: + destination.unlink(missing_ok=True) + try: + os.link(source, destination) + except OSError: + shutil.copy2(source, destination) + destination.chmod(0o755) + + +async def _upgrade_node(cluster: Cluster, node_id: str, new_binary: Path): + node = cluster.get_node(node_id) + assert node is not None + before = max( + peer.w3.eth.block_number + for peer_id, peer in cluster.nodes.items() + if peer_id != node_id + ) + assert await node.stop(), f"failed to stop {node_id}" + _replace_binary(new_binary, _node_binary(cluster, node_id)) + assert await node.start(), f"failed to restart {node_id} with new binary" + + deadline = time.monotonic() + 90 + while time.monotonic() < deadline: + try: + if node.w3.eth.block_number >= before: + break + except Exception: + pass + await asyncio.sleep(1) + else: + raise TimeoutError(f"{node_id} did not catch up after binary upgrade") + + assert await cluster.check_block_increasing(timeout=45) + + +def _json_rpc(url: str, method: str, params: list): + payload = json.dumps( + {"jsonrpc": "2.0", "id": 1, "method": method, "params": params} + ).encode() + request = Request( + url, data=payload, headers={"Content-Type": "application/json"} + ) + with urlopen(request, timeout=10) as response: + body = json.loads(response.read()) + if "error" in body: + raise RuntimeError(f"{method} failed: {body['error']}") + return body["result"] + + +async def _release_bridge_round( + cluster: Cluster, bridge: dict, target_nonce: int +) -> None: + assert ( + _json_rpc( + bridge["rpcUrl"], "mock_setFinalized", [target_nonce] + ) + == target_nonce + ) + node1 = cluster.get_node("node1") + result = await poll_all_native_minted( + gravity_w3=node1.w3, + max_nonce=target_nonce, + timeout=ORACLE_TIMEOUT_SECONDS, + poll_interval=2, + ) + assert not result["missing_nonces"], result["missing_nonces"] + + +def _current_epoch(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_CURRENT_EPOCH} + ), + "big", + ) + + +def _remaining_epoch_seconds(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_REMAINING_TIME} + ), + "big", + ) + + +async def _wait_for_epoch_advance( + cluster: Cluster, start_epoch: int +) -> int: + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + node1 = cluster.get_node("node1") + while time.monotonic() < deadline: + epoch = _current_epoch(node1.w3) + if epoch > start_epoch: + for node_id, node in cluster.nodes.items(): + while _current_epoch(node.w3) < epoch: + if time.monotonic() >= deadline: + raise TimeoutError( + f"{node_id} did not reach epoch {epoch}" + ) + await asyncio.sleep(1) + return epoch + await asyncio.sleep(1) + raise TimeoutError(f"chain did not advance past epoch {start_epoch}") + + +async def _wait_for_proposal_window(cluster: Cluster) -> int: + node1 = cluster.get_node("node1") + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + while time.monotonic() < deadline: + remaining = _remaining_epoch_seconds(node1.w3) + if remaining >= MIN_PROPOSAL_WINDOW_SECONDS: + return _current_epoch(node1.w3) + current = _current_epoch(node1.w3) + LOG.info( + "Only %ss remain in epoch %s; waiting for the next proposal window", + remaining, + current, + ) + await _wait_for_epoch_advance(cluster, current) + raise TimeoutError("no epoch had enough time for governance activation") + + +def _fetch_binance_price( + base_url: str, pair: str, bucket_start_ms: int +) -> int: + bucket_end_ms = bucket_start_ms + support.INTERVAL_MS - 1 + query = urlencode( + { + "pair": pair, + "interval": "1m", + "startTime": bucket_start_ms, + "endTime": bucket_end_ms, + "limit": 1, + } + ) + with urlopen( + f"{base_url}/fapi/v1/indexPriceKlines?{query}", timeout=20 + ) as response: + rows = json.loads(response.read()) + assert len(rows) == 1, f"Binance returned {len(rows)} rows for {pair}" + assert rows[0][0] == bucket_start_ms + assert rows[0][6] == bucket_end_ms + scaled = Decimal(rows[0][4]) * (10**support.DECIMALS) + assert scaled == scaled.to_integral_value() + return int(scaled) + + +def _validator_log(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "consensus_log" / "validator.log" + + +def _log_contains(cluster: Cluster, node_id: str, marker: str, issuer: str): + path = _validator_log(cluster, node_id) + content = path.read_text(errors="replace") if path.exists() else "" + return any( + marker in line and issuer in line for line in content.splitlines() + ) + + +async def _wait_for_consensus_evidence( + cluster: Cluster, issuers: list[str] +) -> None: + missing_observers = { + (node_id, issuer) + for node_id in cluster.nodes + for issuer in issuers + } + certifiers = {issuer: set() for issuer in issuers} + missing_quorums = set(issuers) + deadline = time.monotonic() + ORACLE_TIMEOUT_SECONDS + + while time.monotonic() < deadline: + for node_id, issuer in list(missing_observers): + if _log_contains( + cluster, node_id, "JWKObserver spawned.", issuer + ): + missing_observers.remove((node_id, issuer)) + + for issuer in issuers: + for node_id in cluster.nodes: + if _log_contains( + cluster, node_id, "Start certifying update.", issuer + ): + certifiers[issuer].add(node_id) + if _log_contains( + cluster, node_id, "Peer vote aggregated.", issuer + ): + content = _validator_log( + cluster, node_id + ).read_text(errors="replace") + if any( + "Peer vote aggregated." in line + and issuer in line + and ( + "threshold_exceeded=true" in line + or '"threshold_exceeded":true' in line + ) + for line in content.splitlines() + ): + missing_quorums.discard(issuer) + + if ( + not missing_observers + and not missing_quorums + and all( + len(certifiers[issuer]) >= QUORUM_VALIDATORS + for issuer in issuers + ) + ): + return + await asyncio.sleep(2) + + raise AssertionError( + "missing consensus evidence: " + f"observers={sorted(missing_observers)} " + f"certifiers={ {key: sorted(value) for key, value in certifiers.items()} } " + f"quorums={sorted(missing_quorums)}" + ) + + +async def _wait_for_polymarket_settlement( + resolver, mirror_id: int, condition_id: bytes +) -> tuple: + deadline = time.monotonic() + ORACLE_TIMEOUT_SECONDS + while time.monotonic() < deadline: + settlement = tuple( + resolver.functions.getSettlement( + mirror_id, condition_id + ).call() + ) + if settlement[0]: + return settlement + await asyncio.sleep(2) + raise TimeoutError(f"Polymarket mirror {mirror_id} was not settled") + + +def _relayer_sources(cluster: Cluster, node_id: str) -> dict: + path = ( + cluster.base_dir + / node_id + / "data" + / "reth" + / "relayer_state.json" + ) + assert path.exists(), f"{node_id} has no relayer state" + return json.loads(path.read_text())["sources"] + + +def _assert_quorum_relayer_sources( + cluster: Cluster, expected_uris: list[str] +) -> dict[str, set[str]]: + persisted_by_uri = {uri: set() for uri in expected_uris} + for node_id in cluster.nodes: + sources = _relayer_sources(cluster, node_id) + for uri in expected_uris: + if uri in sources: + persisted_by_uri[uri].add(node_id) + for uri, nodes in persisted_by_uri.items(): + assert len(nodes) >= QUORUM_VALIDATORS, ( + f"only {sorted(nodes)} persisted {uri}; " + f"need {QUORUM_VALIDATORS} independent fetchers" + ) + return persisted_by_uri + + +async def _wait_for_relayer_source( + cluster: Cluster, + node_id: str, + uri: str, + minimum_nonce: int, +) -> dict: + deadline = time.monotonic() + 90 + while time.monotonic() < deadline: + try: + source = _relayer_sources(cluster, node_id).get(uri) + except (AssertionError, json.JSONDecodeError): + source = None + if source is not None and int(source["last_nonce"]) >= minimum_nonce: + return source + await asyncio.sleep(1) + raise TimeoutError( + f"{node_id} did not persist {uri} at nonce {minimum_nonce}" + ) + + +@pytest.mark.asyncio +async def test_mixed_binary_bridge_then_governance_activates_live_oracles( + cluster: Cluster, +): + metadata = _metadata() + old_hash = metadata["oldBinarySha256"] + new_hash = metadata["newBinarySha256"] + bridge = metadata["bridge"] + binance = metadata["binance"] + polymarket = metadata["polymarket"] + new_binary = Path(os.environ["GRAVITY_NEW_BINARY"]).resolve() + + assert binance["mode"] in {"official-archive", "production-rest"} + if binance["mode"] == "official-archive": + assert len(binance["provenance"]) == len(binance["feeds"]) + assert {item["pair"] for item in binance["provenance"]} == { + feed["pair"] for feed in binance["feeds"] + } + assert all( + len(item["sha256"]) == 64 for item in binance["provenance"] + ) + + assert len(cluster.nodes) == 4 + assert await cluster.set_full_live(timeout=180) + assert await cluster.check_block_increasing(timeout=60) + active = await cluster.validator_list() + assert {node.id for node in active.active} == set(cluster.nodes) + _assert_binary_matrix(cluster, set(), old_hash, new_hash) + + node1 = cluster.get_node("node1") + w3 = node1.w3 + required = [ + ("PriceFeedResolver.sol", "PriceFeedResolver"), + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("NativeOracle.sol", "NativeOracle"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ] + contracts_out = support.ensure_contracts_out( + SUITE_DIR, required, "rolling Oracle activation" + ) + price_artifact = support.load_artifact( + contracts_out, "PriceFeedResolver.sol", "PriceFeedResolver" + ) + polymarket_artifact = support.load_artifact( + contracts_out, + "PolymarketSettlementResolver.sol", + "PolymarketSettlementResolver", + ) + native_artifact = support.load_artifact( + contracts_out, "NativeOracle.sol", "NativeOracle" + ) + task_artifact = support.load_artifact( + contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig" + ) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + task_config = w3.eth.contract( + address=support.ORACLE_TASK_CONFIG_ADDRESS, + abi=task_artifact["abi"], + ) + + assert task_config.functions.getSourceTypes().call() == [SOURCE_TYPE_BRIDGE] + assert ( + native_oracle.functions.getLatestNonce( + support.SOURCE_TYPE_PRICE_FEED, 1001 + ).call() + == 0 + ) + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET, int(polymarket["mirrorId"]) + ).call() + == 0 + ) + + # Old-only and every mixed-binary composition must continue processing the + # historical sourceType=0 bridge stream. + await _release_bridge_round(cluster, bridge, 1) + upgraded = set() + for target_nonce, node_id in enumerate(cluster.nodes, start=2): + await _upgrade_node(cluster, node_id, new_binary) + upgraded.add(node_id) + _assert_binary_matrix(cluster, upgraded, old_hash, new_hash) + await _release_bridge_round(cluster, bridge, target_nonce) + + assert upgraded == set(cluster.nodes) + assert task_config.functions.getSourceTypes().call() == [SOURCE_TYPE_BRIDGE] + + price_resolver = support.deploy_contract( + w3, price_artifact, support.FAUCET_KEY + ) + polymarket_resolver = support.deploy_contract( + w3, polymarket_artifact, support.FAUCET_KEY + ) + pool_addr = support.pool0_voted_by_faucet(w3) + mirror_id = int(polymarket["mirrorId"]) + condition_id = bytes.fromhex(polymarket["conditionId"][2:]) + price_uris = { + int(feed["feedId"]): feed["taskUri"] + for feed in binance["feeds"] + } + + setup_epoch = await _wait_for_proposal_window(cluster) + targets = [ + support.NATIVE_ORACLE_ADDRESS, + polymarket_resolver.address, + support.NATIVE_ORACLE_ADDRESS, + ] + datas = [ + support.function_calldata( + native_oracle.functions.setDefaultCallback( + support.SOURCE_TYPE_PRICE_FEED, + price_resolver.address, + ) + ), + support.function_calldata( + polymarket_resolver.functions.registerMirror( + mirror_id, + POLYGON_CHAIN_ID, + CTF_ADDRESS, + condition_id, + 2, + ) + ), + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET, + mirror_id, + polymarket_resolver.address, + ) + ), + ] + for feed_id, uri in price_uris.items(): + targets.append(support.ORACLE_TASK_CONFIG_ADDRESS) + datas.append( + support.function_calldata( + task_config.functions.setTask( + support.SOURCE_TYPE_PRICE_FEED, + feed_id, + support.TASK_PRICE_FEED, + uri.encode(), + ) + ) + ) + targets.append(support.ORACLE_TASK_CONFIG_ADDRESS) + datas.append( + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_POLYMARKET, + mirror_id, + POLYMARKET_TASK, + polymarket["taskUri"].encode(), + ) + ) + ) + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + targets, + datas, + "activate-live-source-types-3-and-6-after-rolling-upgrade", + gas=8_000_000, + ) + + assert _current_epoch(w3) == setup_epoch + assert set(task_config.functions.getSourceTypes().call()) == { + SOURCE_TYPE_BRIDGE, + support.SOURCE_TYPE_PRICE_FEED, + SOURCE_TYPE_POLYMARKET, + } + for feed_id in price_uris: + assert ( + native_oracle.functions.getLatestNonce( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call() + == 0 + ) + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET, mirror_id + ).call() + == 0 + ) + issuers = [ + *(f"gravity://3/{feed_id}" for feed_id in price_uris), + f"gravity://6/{mirror_id}", + ] + for node_id in cluster.nodes: + for issuer in issuers: + assert not _log_contains( + cluster, node_id, "JWKObserver spawned.", issuer + ), f"{node_id} started {issuer} before the epoch boundary" + + activation_epoch = await _wait_for_epoch_advance(cluster, setup_epoch) + assert activation_epoch == setup_epoch + 1 + + expected_prices = { + int(feed["feedId"]): await asyncio.to_thread( + _fetch_binance_price, + binance["baseUrl"], + feed["pair"], + int(binance["bucketStartMs"]), + ) + for feed in binance["feeds"] + } + target_round = int(binance["bucketStartMs"]) // support.INTERVAL_MS + target_resolved_at = ( + int(binance["bucketStartMs"]) + support.INTERVAL_MS - 1 + ) + price_rounds = {} + price_progress = {} + for feed_id, expected_price in expected_prices.items(): + progress, stored = await support.wait_for_latest_price( + native_oracle, + price_resolver, + feed_id, + 1, + timeout=ORACLE_TIMEOUT_SECONDS, + ) + progress = tuple(progress) + stored = tuple(stored) + assert progress[0] >= 1 + assert progress[1] == target_resolved_at + assert stored[0] + assert stored[1] == target_round + assert stored[2] == target_resolved_at + assert stored[3] == support.DECIMALS + assert stored[4] == expected_price + price_progress[feed_id] = progress + price_rounds[feed_id] = stored + + settlement = await _wait_for_polymarket_settlement( + polymarket_resolver, mirror_id, condition_id + ) + polymarket_progress = tuple( + await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET, + mirror_id, + 1, + timeout=ORACLE_TIMEOUT_SECONDS, + ) + ) + assert polymarket_progress == (1, int(polymarket["blockNumber"])) + assert settlement[1] == 1 + assert settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_checksum_address(settlement[3]) == CTF_ADDRESS + assert Web3.to_hex(settlement[7]).lower() == polymarket[ + "transactionHash" + ].lower() + assert settlement[8] == int(polymarket["logIndex"]) + assert polymarket_resolver.functions.getPayoutNumerators( + mirror_id, condition_id + ).call() == polymarket["payoutNumerators"] + + await _wait_for_consensus_evidence(cluster, issuers) + expected_uris = [*price_uris.values(), polymarket["taskUri"]] + persisted_by_uri = _assert_quorum_relayer_sources( + cluster, expected_uris + ) + + # sourceType=0 remains live after 3/6 activate. + await _release_bridge_round(cluster, bridge, int(bridge["eventCount"])) + + for node_id, node in cluster.nodes.items(): + price_replica = node.w3.eth.contract( + address=price_resolver.address, abi=price_artifact["abi"] + ) + native_replica = node.w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + for feed_id, expected in price_rounds.items(): + assert tuple( + price_replica.functions.latestPrice(feed_id).call() + ) == expected, f"{node_id} price state diverged" + assert tuple( + native_replica.functions.getSourceProgress( + support.SOURCE_TYPE_PRICE_FEED, feed_id + ).call() + ) == price_progress[feed_id], ( + f"{node_id} price progress diverged" + ) + + polymarket_replica = node.w3.eth.contract( + address=polymarket_resolver.address, + abi=polymarket_artifact["abi"], + ) + assert tuple( + polymarket_replica.functions.getSettlement( + mirror_id, condition_id + ).call() + ) == settlement, f"{node_id} Polymarket state diverged" + assert tuple( + native_replica.functions.getSourceProgress( + SOURCE_TYPE_POLYMARKET, mirror_id + ).call() + ) == polymarket_progress, f"{node_id} Polymarket progress diverged" + + lagging_polymarket_nodes = ( + set(cluster.nodes) - persisted_by_uri[polymarket["taskUri"]] + ) + restart_node_id = ( + sorted(lagging_polymarket_nodes)[0] + if lagging_polymarket_nodes + else "node4" + ) + assert await cluster.get_node(restart_node_id).restart() + assert await cluster.check_block_increasing(timeout=60) + _assert_binary_matrix(cluster, set(cluster.nodes), old_hash, new_hash) + for uri in expected_uris: + await _wait_for_relayer_source( + cluster, restart_node_id, uri, minimum_nonce=1 + ) + + restarted_price = cluster.get_node(restart_node_id).w3.eth.contract( + address=price_resolver.address, abi=price_artifact["abi"] + ) + for feed_id, expected in price_rounds.items(): + assert tuple( + restarted_price.functions.latestPrice(feed_id).call() + ) == expected + + LOG.info( + "Rolling Oracle activation passed: old=%s new=%s epoch=%s " + "BinanceMode=%s Binance=%s PolymarketMirror=%s governanceBlock=%s", + old_hash[:12], + new_hash[:12], + activation_epoch, + binance["mode"], + expected_prices, + mirror_id, + receipt["blockNumber"], + ) diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/README.md b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/README.md new file mode 100644 index 000000000..57d62467d --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/README.md @@ -0,0 +1,29 @@ +# Dynamic Polymarket Mirror E2E + +This suite starts Gravity without any `sourceType=6` task in genesis, then +adds two Polymarket mirrors through governance while the chain remains live. + +It verifies: + +1. a task written during epoch `E` is stored on-chain but is not polled in `E`; +2. the JWK epoch manager creates its observer after the transition to `E+1`; +3. only a finalized Polygon `ConditionResolution` is submitted; +4. the payload reaches JWK consensus, `NativeOracle`, and the settlement resolver; +5. replaying the same Polygon log does not advance the oracle nonce; +6. a second mirror added later follows the same next-epoch lifecycle. + +The two complete Gravity URIs are intentionally present in +`relayer_config.json`. This suite proves dynamic on-chain task discovery, not +dynamic RPC credential discovery. A production watcher should resolve a stable +local alias such as `polygon-mainnet` instead of requiring every condition URI +to be preconfigured. + +Run locally: + +```bash +./gravity_e2e/run_test.sh polymarket_dynamic_mirror --force-init +``` + +The shared runner currently performs a global `pkill -9 gravity_node` before +and after a suite. Run this command only when no unrelated local Gravity node +must remain alive. diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/cluster.toml b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/cluster.toml new file mode 100644 index 000000000..0ec436d7f --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/cluster.toml @@ -0,0 +1,27 @@ +# Gravity Cluster Configuration - dynamic Polymarket mirror E2E + +[cluster] +name = "gravity-devnet-polymarket-dynamic-mirror" +base_dir = "/tmp/gravity-cluster-polymarket-dynamic-mirror" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 45382 +vfn_port = 45392 +rpc_port = 48755 +api_port = 48280 +metrics_port = 49203 +inspection_port = 40102 +https_port = 41124 +authrpc_port = 48775 +reth_p2p_port = 52226 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/genesis.toml b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/genesis.toml new file mode 100644 index 000000000..42ff218f0 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/genesis.toml @@ -0,0 +1,75 @@ +# Gravity Genesis Configuration - dynamic Polymarket mirror E2E + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 45382 +vfn_port = 45392 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 60000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 + +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 6] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", +] + +# No sourceType=6 task is present at genesis. The test adds both mirror tasks +# through governance and verifies that observers appear only after an epoch. + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/hooks.py b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/hooks.py new file mode 100644 index 000000000..000b29c80 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/hooks.py @@ -0,0 +1,43 @@ +"""Lifecycle hooks for the dynamic Polymarket mirror E2E.""" + +import json +import logging +import sys +from pathlib import Path + +LOG = logging.getLogger(__name__) + +_mock = None +_METADATA_FILE = "mock_polymarket_metadata.json" + + +def pre_start(test_dir: Path, env: dict, pytest_args: list = None): + global _mock + + e2e_root = str(Path(__file__).resolve().parent.parent.parent) + if e2e_root not in sys.path: + sys.path.insert(0, e2e_root) + + from gravity_e2e.utils.mock_polymarket_polygon import MockPolymarketPolygon + + LOG.info("[hook] Starting dynamic Polymarket Polygon mock on port 8646") + _mock = MockPolymarketPolygon(port=8646) + _mock.start() + + metadata_path = test_dir / _METADATA_FILE + metadata_path.write_text( + json.dumps({"port": _mock.port, "rpc_url": _mock.rpc_url}, indent=2) + ) + + +def post_stop(test_dir: Path, env: dict): + global _mock + + if _mock is not None: + LOG.info("[hook] Stopping dynamic Polymarket Polygon mock") + _mock.stop() + _mock = None + + metadata_path = test_dir / _METADATA_FILE + if metadata_path.exists(): + metadata_path.unlink() diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/relayer_config.json b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/relayer_config.json new file mode 100644 index 000000000..fda190ab1 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/relayer_config.json @@ -0,0 +1,6 @@ +{ + "uri_mappings": { + "gravity://6/7202626/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20": "http://localhost:8646", + "gravity://6/7202627/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xd1a086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20": "http://localhost:8646" + } +} diff --git a/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/test_polymarket_dynamic_mirror.py b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/test_polymarket_dynamic_mirror.py new file mode 100644 index 000000000..7a0015336 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_dynamic_mirror/test_polymarket_dynamic_mirror.py @@ -0,0 +1,658 @@ +"""Dynamic Polymarket mirror lifecycle E2E.""" + +import asyncio +import json +import logging +import time +import urllib.request +from pathlib import Path + +import pytest +from eth_account import Account +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support +from gravity_e2e.utils.mock_polymarket_polygon import ( + CTF_ADDRESS, + DYNAMIC_BINARY_BLOCK, + DYNAMIC_BINARY_CONDITION_ID, + DYNAMIC_BINARY_LOG_INDEX, + DYNAMIC_BINARY_MARKET_ID, + DYNAMIC_BINARY_QUESTION_ID, + DYNAMIC_BINARY_TX_HASH, + FED_BINARY_BLOCK, + FED_BINARY_CONDITION_ID, + FED_BINARY_LOG_INDEX, + FED_BINARY_MARKET_ID, + FED_BINARY_QUESTION_ID, + FED_BINARY_TX_HASH, +) + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_POLYMARKET_SETTLEMENT = 6 +POLYGON_CHAIN_ID = 137 +TASK_NAME = Web3.keccak(text="polymarket_settlement") +RECONFIGURATION_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F2003" +) +SEL_CURRENT_EPOCH = Web3.keccak(text="currentEpoch()")[:4] +SEL_REMAINING_TIME = Web3.keccak(text="getRemainingTimeSeconds()")[:4] + +EPOCH_INTERVAL_SECONDS = 60 +MIN_PROPOSAL_WINDOW_SECONDS = 40 +EPOCH_TIMEOUT_SECONDS = EPOCH_INTERVAL_SECONDS * 2 + 30 +POLL_TIMEOUT_SECONDS = 90 +USER_STARTING_BALANCE = 1_000 * support.STAKE_UNIT +NO_STAKE = 100 * support.STAKE_UNIT +YES_STAKE = 200 * support.STAKE_UNIT +TOTAL_POOL = NO_STAKE + YES_STAKE + + +def _task_uri(mirror_id: int, condition_id: str) -> str: + return ( + f"gravity://6/{mirror_id}/polymarket_settlement?" + f"ctf={CTF_ADDRESS}&fromBlock=89222200&condition={condition_id}&" + "maxBlocksPerPoll=20" + ) + + +def _mock_rpc(rpc_url: str, method: str, params=None): + payload = json.dumps( + {"jsonrpc": "2.0", "id": 1, "method": method, "params": params or []} + ).encode() + request = urllib.request.Request( + rpc_url, data=payload, headers={"Content-Type": "application/json"} + ) + with urllib.request.urlopen(request, timeout=5) as response: + body = json.loads(response.read()) + if "error" in body: + raise RuntimeError(f"{method} failed: {body['error']}") + return body["result"] + + +def _current_epoch(w3: Web3) -> int: + raw = w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_CURRENT_EPOCH} + ) + return int.from_bytes(raw, "big") + + +def _remaining_epoch_seconds(w3: Web3) -> int: + raw = w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_REMAINING_TIME} + ) + return int.from_bytes(raw, "big") + + +async def _wait_for_epoch_advance(w3: Web3, start_epoch: int) -> int: + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + while time.monotonic() < deadline: + epoch = _current_epoch(w3) + if epoch > start_epoch: + return epoch + await asyncio.sleep(1) + raise TimeoutError(f"chain did not advance past epoch {start_epoch}") + + +async def _wait_for_proposal_window(w3: Web3) -> int: + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + while time.monotonic() < deadline: + remaining = _remaining_epoch_seconds(w3) + if remaining >= MIN_PROPOSAL_WINDOW_SECONDS: + return _current_epoch(w3) + epoch = _current_epoch(w3) + LOG.info( + "Only %ss remain in epoch %s; waiting for a clean proposal window", + remaining, + epoch, + ) + await _wait_for_epoch_advance(w3, epoch) + raise TimeoutError("no epoch window was long enough for governance proposal") + + +def _mock_scanned_condition(requests: list[dict], condition_id: str) -> bool: + expected = condition_id.lower() + for request in requests: + if request.get("method") != "eth_getLogs": + continue + params = request.get("params") or [] + filter_obj = params[0] if params else {} + topics = filter_obj.get("topics") or [] + if any(isinstance(topic, str) and topic.lower() == expected for topic in topics): + return True + return False + + +async def _wait_for_mock_scan(rpc_url: str, condition_id: str) -> list[dict]: + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + while time.monotonic() < deadline: + requests = await asyncio.to_thread(_mock_rpc, rpc_url, "mock_getRequests") + if _mock_scanned_condition(requests, condition_id): + return requests + await asyncio.sleep(1) + raise TimeoutError(f"observer never scanned condition {condition_id}") + + +def _oracle_delivered_logs(w3: Web3, mirror_id: int, from_block: int) -> list: + return w3.eth.get_logs( + { + "fromBlock": from_block, + "toBlock": "latest", + "address": support.NATIVE_ORACLE_ADDRESS, + "topics": [ + support.ORACLE_DELIVERED_TOPIC0, + support.topic(SOURCE_TYPE_POLYMARKET_SETTLEMENT), + support.topic(mirror_id), + ], + } + ) + + +async def _wait_for_oracle_delivered( + w3: Web3, mirror_id: int, from_block: int +) -> list: + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + while time.monotonic() < deadline: + logs = await asyncio.to_thread( + _oracle_delivered_logs, w3, mirror_id, from_block + ) + if logs: + return logs + await asyncio.sleep(1) + raise TimeoutError(f"no OracleDelivered event for mirror {mirror_id}") + + +async def _wait_for_settlement( + resolver, mirror_id: int, condition_id: bytes +) -> tuple: + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + while time.monotonic() < deadline: + settlement = resolver.functions.getSettlement( + mirror_id, condition_id + ).call() + if settlement[0]: + return settlement + await asyncio.sleep(1) + raise TimeoutError(f"resolver did not store settlement for mirror {mirror_id}") + + +def _add_condition( + rpc_url: str, + *, + condition_id: str, + question_id: str, + block_number: int, + log_index: int, + tx_hash: str, + payouts: list[int], + replace_existing: bool = False, +): + return _mock_rpc( + rpc_url, + "mock_addCondition", + [ + { + "conditionId": condition_id, + "questionId": question_id, + "blockNumber": hex(block_number), + "logIndex": hex(log_index), + "txHash": tx_hash, + "payoutNumerators": payouts, + "replaceExisting": replace_existing, + } + ], + ) + + +def _market_params( + w3: Web3, + *, + mirror_id: int, + condition_id: bytes, + resolver: str, + token: str, + spec: str, + lifetime_seconds: int, +) -> tuple: + now_ts = w3.eth.get_block("latest")["timestamp"] + settlement_ref = ( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + condition_id, + resolver, + Web3.to_checksum_address(CTF_ADDRESS), + POLYGON_CHAIN_ID, + 2, + [0, 1], + 0, + ) + return ( + Web3.keccak(text=spec), + now_ts, + now_ts + lifetime_seconds, + token, + settlement_ref, + ) + + +async def _create_dynamic_mirror( + w3: Web3, + *, + pool_addr: str, + task_config, + native_oracle, + resolver, + market, + token, + mirror_id: int, + condition_id: bytes, + condition_hex: str, + description: str, + lifetime_seconds: int, +) -> tuple[dict, int, str]: + uri = _task_uri(mirror_id, condition_hex) + params = _market_params( + w3, + mirror_id=mirror_id, + condition_id=condition_id, + resolver=resolver.address, + token=token.address, + spec=description, + lifetime_seconds=lifetime_seconds, + ) + datas = [ + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + TASK_NAME, + uri.encode(), + ) + ), + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + resolver.address, + ) + ), + support.function_calldata( + resolver.functions.registerMirror( + mirror_id, + POLYGON_CHAIN_ID, + Web3.to_checksum_address(CTF_ADDRESS), + condition_id, + 2, + ) + ), + support.function_calldata(market.functions.createMarket(params)), + ] + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + [ + support.ORACLE_TASK_CONFIG_ADDRESS, + support.NATIVE_ORACLE_ADDRESS, + resolver.address, + market.address, + ], + datas, + description, + gas=8_000_000, + ) + return receipt, support.market_id_from_receipt(receipt), uri + + +@pytest.mark.asyncio +async def test_polymarket_mirrors_activate_on_successive_epochs(cluster: Cluster): + metadata = json.loads((SUITE_DIR / "mock_polymarket_metadata.json").read_text()) + rpc_url = metadata["rpc_url"] + + assert await cluster.set_full_live(timeout=180), "Gravity node failed to become live" + assert await cluster.check_block_increasing(timeout=60), ( + "Gravity chain is not producing blocks" + ) + + node = cluster.get_node("node1") + assert node is not None, "node1 not found" + w3 = node.w3 + assert w3 is not None and w3.is_connected(), "node1 web3 not connected" + + required = [ + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("PolymarketBinaryMarket.sol", "PolymarketBinaryMarket"), + ("MockGToken.sol", "MockGToken"), + ("NativeOracle.sol", "NativeOracle"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ] + contracts_out = support.ensure_contracts_out(SUITE_DIR, required, "Polymarket") + resolver = support.deploy_contract( + w3, + support.load_artifact( + contracts_out, + "PolymarketSettlementResolver.sol", + "PolymarketSettlementResolver", + ), + support.FAUCET_KEY, + ) + market = support.deploy_contract( + w3, + support.load_artifact( + contracts_out, "PolymarketBinaryMarket.sol", "PolymarketBinaryMarket" + ), + support.FAUCET_KEY, + ) + token = support.deploy_contract( + w3, + support.load_artifact(contracts_out, "MockGToken.sol", "MockGToken"), + support.FAUCET_KEY, + ) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=support.load_artifact( + contracts_out, "NativeOracle.sol", "NativeOracle" + )["abi"], + ) + task_config = w3.eth.contract( + address=support.ORACLE_TASK_CONFIG_ADDRESS, + abi=support.load_artifact( + contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig" + )["abi"], + ) + pool_addr = support.pool0_voted_by_faucet(w3) + + first_condition = bytes.fromhex(FED_BINARY_CONDITION_ID[2:]) + second_condition = bytes.fromhex(DYNAMIC_BINARY_CONDITION_ID[2:]) + assert not task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + TASK_NAME, + ).call() + assert not task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + DYNAMIC_BINARY_MARKET_ID, + TASK_NAME, + ).call() + + _mock_rpc(rpc_url, "mock_clearRequests") + first_epoch = await _wait_for_proposal_window(w3) + first_receipt, first_market_id, first_uri = await _create_dynamic_mirror( + w3, + pool_addr=pool_addr, + task_config=task_config, + native_oracle=native_oracle, + resolver=resolver, + market=market, + token=token, + mirror_id=FED_BINARY_MARKET_ID, + condition_id=first_condition, + condition_hex=FED_BINARY_CONDITION_ID, + description="dynamic-polymarket-mirror-one", + lifetime_seconds=55, + ) + + assert _current_epoch(w3) == first_epoch, "governance execution crossed epoch" + assert task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + TASK_NAME, + ).call() + first_task = task_config.functions.getTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + TASK_NAME, + ).call() + assert bytes(first_task[0]).decode() == first_uri + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, FED_BINARY_MARKET_ID + ).call() + == 0 + ) + assert not resolver.functions.getSettlement( + FED_BINARY_MARKET_ID, first_condition + ).call()[0] + requests = _mock_rpc(rpc_url, "mock_getRequests") + assert not _mock_scanned_condition(requests, FED_BINARY_CONDITION_ID), ( + "new task was polled before the next epoch" + ) + + no_account = Account.create("dynamic-polymarket-no") + yes_account = Account.create("dynamic-polymarket-yes") + for account in (no_account, yes_account): + support.send_tx( + w3, + account.address, + b"", + support.FAUCET_KEY, + gas=21_000, + value=support.STAKE_UNIT, + ) + support.send_contract_tx( + w3, + token, + token.functions.mint(account.address, USER_STARTING_BALANCE), + support.FAUCET_KEY, + ) + support.send_contract_tx( + w3, + token, + token.functions.approve(market.address, USER_STARTING_BALANCE), + account.key, + ) + support.send_contract_tx( + w3, + market, + market.functions.placeBet(first_market_id, 0, NO_STAKE), + no_account.key, + gas=1_500_000, + ) + support.send_contract_tx( + w3, + market, + market.functions.placeBet(first_market_id, 1, YES_STAKE), + yes_account.key, + gas=1_500_000, + ) + assert market.functions.getMarket(first_market_id).call()[6] == TOTAL_POOL + + activated_epoch = await _wait_for_epoch_advance(w3, first_epoch) + assert activated_epoch == first_epoch + 1 + await _wait_for_mock_scan(rpc_url, FED_BINARY_CONDITION_ID) + + _add_condition( + rpc_url, + condition_id=FED_BINARY_CONDITION_ID, + question_id=FED_BINARY_QUESTION_ID, + block_number=FED_BINARY_BLOCK, + log_index=FED_BINARY_LOG_INDEX, + tx_hash=FED_BINARY_TX_HASH, + payouts=[0, 1], + ) + _mock_rpc( + rpc_url, + "mock_setHeads", + [hex(FED_BINARY_BLOCK), hex(FED_BINARY_BLOCK - 1)], + ) + await asyncio.sleep(12) + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, FED_BINARY_MARKET_ID + ).call() + == 0 + ), "latest-visible but unfinalized settlement was submitted" + + _mock_rpc( + rpc_url, + "mock_setHeads", + [hex(FED_BINARY_BLOCK), hex(FED_BINARY_BLOCK)], + ) + first_logs = await _wait_for_oracle_delivered( + w3, FED_BINARY_MARKET_ID, first_receipt["blockNumber"] + ) + assert len(first_logs) == 1 + first_progress = await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + 1, + timeout=POLL_TIMEOUT_SECONDS, + ) + assert first_progress == (1, FED_BINARY_BLOCK) + first_settlement = await _wait_for_settlement( + resolver, FED_BINARY_MARKET_ID, first_condition + ) + assert first_settlement[1] == 1 + assert first_settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_hex(first_settlement[7]).lower() == FED_BINARY_TX_HASH.lower() + assert first_settlement[8] == FED_BINARY_LOG_INDEX + assert resolver.functions.getPayoutNumerators( + FED_BINARY_MARKET_ID, first_condition + ).call() == [0, 1] + + _add_condition( + rpc_url, + condition_id=FED_BINARY_CONDITION_ID, + question_id=FED_BINARY_QUESTION_ID, + block_number=FED_BINARY_BLOCK, + log_index=FED_BINARY_LOG_INDEX, + tx_hash=FED_BINARY_TX_HASH, + payouts=[0, 1], + ) + await asyncio.sleep(12) + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, FED_BINARY_MARKET_ID + ).call() + == 1 + ) + assert len( + _oracle_delivered_logs( + w3, FED_BINARY_MARKET_ID, first_receipt["blockNumber"] + ) + ) == 1 + + first_market = market.functions.getMarket(first_market_id).call() + await support.wait_for_chain_time(w3, first_market[2]) + support.send_contract_tx( + w3, + market, + market.functions.lockMarket(first_market_id), + support.FAUCET_KEY, + ) + support.send_contract_tx( + w3, + market, + market.functions.finalizeMarket(first_market_id), + support.FAUCET_KEY, + gas=2_000_000, + ) + finalized_market = market.functions.getMarket(first_market_id).call() + assert finalized_market[4] == 2 + assert finalized_market[5] == 1 + assert market.functions.claimable( + first_market_id, yes_account.address + ).call() == TOTAL_POOL + balance_before = token.functions.balanceOf(yes_account.address).call() + support.send_contract_tx( + w3, + market, + market.functions.claim(first_market_id), + yes_account.key, + gas=1_500_000, + ) + assert ( + token.functions.balanceOf(yes_account.address).call() - balance_before + == TOTAL_POOL + ) + + _mock_rpc(rpc_url, "mock_clearRequests") + second_epoch = await _wait_for_proposal_window(w3) + second_receipt, second_market_id, second_uri = await _create_dynamic_mirror( + w3, + pool_addr=pool_addr, + task_config=task_config, + native_oracle=native_oracle, + resolver=resolver, + market=market, + token=token, + mirror_id=DYNAMIC_BINARY_MARKET_ID, + condition_id=second_condition, + condition_hex=DYNAMIC_BINARY_CONDITION_ID, + description="dynamic-polymarket-mirror-two", + lifetime_seconds=180, + ) + assert second_market_id == first_market_id + 1 + assert _current_epoch(w3) == second_epoch, "second proposal crossed epoch" + second_task = task_config.functions.getTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + DYNAMIC_BINARY_MARKET_ID, + TASK_NAME, + ).call() + assert bytes(second_task[0]).decode() == second_uri + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, DYNAMIC_BINARY_MARKET_ID + ).call() + == 0 + ) + assert not _mock_scanned_condition( + _mock_rpc(rpc_url, "mock_getRequests"), DYNAMIC_BINARY_CONDITION_ID + ), "second task was polled before the next epoch" + + second_activated_epoch = await _wait_for_epoch_advance(w3, second_epoch) + assert second_activated_epoch == second_epoch + 1 + await _wait_for_mock_scan(rpc_url, DYNAMIC_BINARY_CONDITION_ID) + + _add_condition( + rpc_url, + condition_id=DYNAMIC_BINARY_CONDITION_ID, + question_id=DYNAMIC_BINARY_QUESTION_ID, + block_number=DYNAMIC_BINARY_BLOCK, + log_index=DYNAMIC_BINARY_LOG_INDEX, + tx_hash=DYNAMIC_BINARY_TX_HASH, + payouts=[1, 0], + ) + _mock_rpc( + rpc_url, + "mock_setHeads", + [hex(DYNAMIC_BINARY_BLOCK), hex(DYNAMIC_BINARY_BLOCK)], + ) + second_logs = await _wait_for_oracle_delivered( + w3, DYNAMIC_BINARY_MARKET_ID, second_receipt["blockNumber"] + ) + assert len(second_logs) == 1 + second_progress = await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + DYNAMIC_BINARY_MARKET_ID, + 1, + timeout=POLL_TIMEOUT_SECONDS, + ) + assert second_progress == (1, DYNAMIC_BINARY_BLOCK) + second_settlement = await _wait_for_settlement( + resolver, DYNAMIC_BINARY_MARKET_ID, second_condition + ) + assert second_settlement[1] == 1 + assert Web3.to_hex(second_settlement[7]).lower() == DYNAMIC_BINARY_TX_HASH.lower() + assert second_settlement[8] == DYNAMIC_BINARY_LOG_INDEX + assert resolver.functions.getPayoutNumerators( + DYNAMIC_BINARY_MARKET_ID, second_condition + ).call() == [1, 0] + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, FED_BINARY_MARKET_ID + ).call() + == 1 + ), "second mirror changed the first mirror nonce" + + LOG.info( + "Dynamic mirrors settled across epochs: first=%s@%s second=%s@%s", + FED_BINARY_MARKET_ID, + activated_epoch, + DYNAMIC_BINARY_MARKET_ID, + second_activated_epoch, + ) diff --git a/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/README.md b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/README.md new file mode 100644 index 000000000..33ebe7e5c --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/README.md @@ -0,0 +1,35 @@ +# Four-Validator Live Polygon Polymarket E2E + +This public-network suite discovers a recently resolved binary Polymarket from +the Gamma API, verifies its finalized CTF `ConditionResolution` log through a +configured Polygon RPC, and then starts four Gravity validators. + +The test adds the mirror task through governance in epoch `E`. In `E+1`, all +validators start the dynamic observer. At least three equal-power validators +independently certify the same real Polygon log and form a JWK quorum; a slower +validator may instead fast-forward from the committed nonce. The test then +checks all four RPC replicas, the `NativeOracle` write, resolver callback, and +binary-market claim. + +The Polygon RPC URL is written only to the ignored +`artifacts/relayer_config.live.json` file and is removed during normal cleanup. +This suite is excluded from default E2E runs. + +Required environment: + +```bash +export POLYGON_RPC_URL="..." +``` + +Run: + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh \ + polymarket_live_dynamic_mirror \ + --force-init \ + --log-cli-level=INFO +``` + +Set `GRAVITY_E2E_SKIP_GLOBAL_PKILL=1` when an unrelated local Gravity node +must remain alive. The runner will still stop this suite's four-node cluster. diff --git a/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/cluster.toml b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/cluster.toml new file mode 100644 index 000000000..57d5c373c --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/cluster.toml @@ -0,0 +1,72 @@ +# Four-validator live Polygon Polymarket mirror integration test. + +[cluster] +name = "gravity-devnet-polymarket-live-dynamic-mirror" +base_dir = "/tmp/gravity-cluster-polymarket-live-dynamic-mirror" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26280 +vfn_port = 26290 +rpc_port = 26300 +api_port = 26310 +metrics_port = 26320 +inspection_port = 26330 +https_port = 26340 +authrpc_port = 26350 +reth_p2p_port = 26360 + +[[nodes]] +id = "node2" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26281 +vfn_port = 26291 +rpc_port = 26301 +api_port = 26311 +metrics_port = 26321 +inspection_port = 26331 +https_port = 26341 +authrpc_port = 26351 +reth_p2p_port = 26361 + +[[nodes]] +id = "node3" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26282 +vfn_port = 26292 +rpc_port = 26302 +api_port = 26312 +metrics_port = 26322 +inspection_port = 26332 +https_port = 26342 +authrpc_port = 26352 +reth_p2p_port = 26362 + +[[nodes]] +id = "node4" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 26283 +vfn_port = 26293 +rpc_port = 26303 +api_port = 26313 +metrics_port = 26323 +inspection_port = 26333 +https_port = 26343 +authrpc_port = 26353 +reth_p2p_port = 26363 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/genesis.toml b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/genesis.toml new file mode 100644 index 000000000..ee0296902 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/genesis.toml @@ -0,0 +1,103 @@ +# Four-validator live Polygon Polymarket mirror integration test. + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 26280 +vfn_port = 26290 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node2" +address = "0x7b254Bd44F6CE45e00a912b2460D47F3Be56fAD7" +host = "127.0.0.1" +validator_port = 26281 +vfn_port = 26291 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node3" +address = "0x9B2C25E77a97d3e84DC0Cb7F83fb676ddC4F24b9" +host = "127.0.0.1" +validator_port = 26282 +vfn_port = 26292 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[[genesis_validators]] +id = "node4" +address = "0x18c23753385ce7A60B15d171302E48b6AFf0BDC5" +host = "127.0.0.1" +validator_port = 26283 +vfn_port = 26293 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 60000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 6] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", +] + +# The live mirror task is discovered and added by governance after startup. + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/hooks.py b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/hooks.py new file mode 100644 index 000000000..f2ac6bd9d --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/hooks.py @@ -0,0 +1,230 @@ +"""Discover a real finalized Polymarket settlement before cluster deployment.""" + +import json +import logging +import os +import urllib.parse +import urllib.request +from pathlib import Path + +LOG = logging.getLogger(__name__) + +CTF_ADDRESS = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +CONDITION_RESOLUTION_TOPIC0 = ( + "0xb44d84d3289691f71497564b85d4233648d9dbae8cbdbb4329f301c3a0185894" +) +DEFAULT_GAMMA_URL = "https://gamma-api.polymarket.com" +SCAN_CHUNK = 2_000 +MAX_SCAN_BLOCKS = 100_000 +_METADATA_FILE = "polymarket_live_metadata.json" +_RELAYER_FILE = "relayer_config.live.json" + + +def _read_json(request: urllib.request.Request) -> object: + with urllib.request.urlopen(request, timeout=30) as response: + return json.loads(response.read()) + + +def _rpc(rpc_url: str, method: str, params: list): + payload = json.dumps( + {"jsonrpc": "2.0", "id": 1, "method": method, "params": params} + ).encode() + request = urllib.request.Request( + rpc_url, + data=payload, + headers={"Content-Type": "application/json"}, + ) + body = _read_json(request) + if "error" in body: + raise RuntimeError(f"Polygon {method} failed: {body['error']}") + return body["result"] + + +def _gamma_markets(base_url: str) -> list[dict]: + query = urllib.parse.urlencode( + { + "closed": "true", + "limit": 100, + "order": "closedTime", + "ascending": "false", + } + ) + request = urllib.request.Request( + f"{base_url.rstrip('/')}/markets?{query}", + headers={ + "Accept": "application/json", + "User-Agent": "gravity-oracle-e2e/1.0", + }, + ) + markets = _read_json(request) + if not isinstance(markets, list): + raise RuntimeError("Polymarket Gamma response is not a market list") + return markets + + +def _parse_list(value) -> list: + if isinstance(value, str): + value = json.loads(value) + return list(value or []) + + +def _decode_resolution(log: dict) -> tuple[int, list[int]]: + data = bytes.fromhex(log["data"][2:]) + if len(data) < 96: + raise ValueError("ConditionResolution data is too short") + outcome_count = int.from_bytes(data[0:32], "big") + offset = int.from_bytes(data[32:64], "big") + if offset + 32 > len(data): + raise ValueError("ConditionResolution payout offset is invalid") + array_len = int.from_bytes(data[offset : offset + 32], "big") + end = offset + 32 + array_len * 32 + if end > len(data): + raise ValueError("ConditionResolution payouts exceed encoded data") + payouts = [ + int.from_bytes( + data[offset + 32 + index * 32 : offset + 64 + index * 32], + "big", + ) + for index in range(array_len) + ] + if outcome_count != array_len: + raise ValueError("ConditionResolution outcome count does not match payouts") + return outcome_count, payouts + + +def _find_resolution( + rpc_url: str, finalized_block: int, condition_id: str +) -> dict | None: + scanned = 0 + end = finalized_block + while end >= 0 and scanned < MAX_SCAN_BLOCKS: + start = max(0, end - SCAN_CHUNK + 1) + logs = _rpc( + rpc_url, + "eth_getLogs", + [ + { + "fromBlock": hex(start), + "toBlock": hex(end), + "address": CTF_ADDRESS, + "topics": [CONDITION_RESOLUTION_TOPIC0, condition_id], + } + ], + ) + if len(logs) > 1: + raise RuntimeError( + f"condition {condition_id} has multiple finalized resolution logs" + ) + if logs: + return logs[0] + scanned += end - start + 1 + if start == 0: + break + end = start - 1 + return None + + +def _discover_market(rpc_url: str, gamma_url: str) -> dict: + chain_id = int(_rpc(rpc_url, "eth_chainId", []), 16) + if chain_id != 137: + raise RuntimeError(f"Polygon RPC chainId must be 137, got {chain_id}") + finalized = _rpc(rpc_url, "eth_getBlockByNumber", ["finalized", False]) + finalized_block = int(finalized["number"], 16) + + for market in _gamma_markets(gamma_url): + condition_id = market.get("conditionId") + outcomes = _parse_list(market.get("outcomes")) + if ( + not condition_id + or not isinstance(condition_id, str) + or len(condition_id) != 66 + or len(outcomes) != 2 + ): + continue + + log = _find_resolution(rpc_url, finalized_block, condition_id) + if log is None or log.get("removed"): + continue + outcome_count, payouts = _decode_resolution(log) + if outcome_count != 2 or sum(value > 0 for value in payouts) != 1: + continue + + block_number = int(log["blockNumber"], 16) + receipt = _rpc( + rpc_url, "eth_getTransactionReceipt", [log["transactionHash"]] + ) + if int(receipt["status"], 16) != 1: + continue + + mirror_id = int(market["id"]) + task_uri = ( + f"gravity://6/{mirror_id}/polymarket_settlement?" + f"ctf={CTF_ADDRESS}&fromBlock={block_number - 1}&" + f"condition={condition_id}&maxBlocksPerPoll=100" + ) + return { + "mirrorId": mirror_id, + "question": market.get("question"), + "outcomes": outcomes, + "conditionId": condition_id, + "questionId": log["topics"][3], + "oracle": "0x" + log["topics"][2][-40:], + "transactionHash": log["transactionHash"], + "blockNumber": block_number, + "finalizedBlock": finalized_block, + "logIndex": int(log["logIndex"], 16), + "outcomeSlotCount": outcome_count, + "payoutNumerators": payouts, + "winningSlot": next( + index for index, value in enumerate(payouts) if value > 0 + ), + "taskUri": task_uri, + } + + raise RuntimeError( + "no recently closed binary Polymarket had a finalized CTF resolution " + f"within the last {MAX_SCAN_BLOCKS} Polygon blocks" + ) + + +def pre_deploy(test_dir: Path, env: dict, pytest_args: list[str]): + rpc_url = ( + env.get("POLYGON_RPC_URL") + or env.get("POLYGON_QUICKNONE_HTTP_URL") + or os.environ.get("POLYGON_RPC_URL") + or os.environ.get("POLYGON_QUICKNONE_HTTP_URL") + ) + if not rpc_url: + raise RuntimeError("POLYGON_RPC_URL is required for the live Polymarket suite") + + gamma_url = env.get("POLYMARKET_GAMMA_URL", DEFAULT_GAMMA_URL) + metadata = _discover_market(rpc_url, gamma_url) + artifacts = test_dir / "artifacts" + artifacts.mkdir(parents=True, exist_ok=True) + + metadata_path = artifacts / _METADATA_FILE + metadata_path.write_text(json.dumps(metadata, indent=2, ensure_ascii=False) + "\n") + + relayer_path = artifacts / _RELAYER_FILE + relayer_path.write_text( + json.dumps( + {"uri_mappings": {metadata["taskUri"]: rpc_url}}, + indent=2, + ) + + "\n" + ) + env["RELAYER_CONFIG_TPL"] = str(relayer_path) + LOG.info( + "[hook] Selected live Polymarket mirrorId=%s block=%s finalized=%s", + metadata["mirrorId"], + metadata["blockNumber"], + metadata["finalizedBlock"], + ) + + +def post_stop(test_dir: Path, env: dict): + artifacts = test_dir / "artifacts" + for name in (_METADATA_FILE, _RELAYER_FILE): + path = artifacts / name + if path.exists(): + path.unlink() diff --git a/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/test_polymarket_live_dynamic_mirror.py b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/test_polymarket_live_dynamic_mirror.py new file mode 100644 index 000000000..cf0edef65 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_live_dynamic_mirror/test_polymarket_live_dynamic_mirror.py @@ -0,0 +1,453 @@ +"""Four-validator dynamic Polymarket mirror E2E against real Polygon data.""" + +import asyncio +import json +import logging +import time +from pathlib import Path + +import pytest +from eth_account import Account +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_POLYMARKET_SETTLEMENT = 6 +POLYGON_CHAIN_ID = 137 +CTF_ADDRESS = Web3.to_checksum_address( + "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +) +TASK_NAME = Web3.keccak(text="polymarket_settlement") +RECONFIGURATION_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F2003" +) +SEL_CURRENT_EPOCH = Web3.keccak(text="currentEpoch()")[:4] +SEL_REMAINING_TIME = Web3.keccak(text="getRemainingTimeSeconds()")[:4] + +EPOCH_TIMEOUT_SECONDS = 180 +MIN_PROPOSAL_WINDOW_SECONDS = 40 +POLL_TIMEOUT_SECONDS = 300 +USER_STARTING_BALANCE = 1_000 * support.STAKE_UNIT +STAKE_BY_OUTCOME = [100 * support.STAKE_UNIT, 200 * support.STAKE_UNIT] +TOTAL_POOL = sum(STAKE_BY_OUTCOME) +QUORUM_VALIDATORS = 3 + + +def _current_epoch(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_CURRENT_EPOCH} + ), + "big", + ) + + +def _remaining_epoch_seconds(w3: Web3) -> int: + return int.from_bytes( + w3.eth.call( + {"to": RECONFIGURATION_ADDRESS, "data": SEL_REMAINING_TIME} + ), + "big", + ) + + +async def _wait_for_epoch_advance( + cluster: Cluster, start_epoch: int +) -> int: + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + node1 = cluster.get_node("node1") + while time.monotonic() < deadline: + epoch = _current_epoch(node1.w3) + if epoch > start_epoch: + for node in cluster.nodes.values(): + while _current_epoch(node.w3) < epoch: + if time.monotonic() >= deadline: + raise TimeoutError( + f"{node.id} did not reach epoch {epoch}" + ) + await asyncio.sleep(1) + return epoch + await asyncio.sleep(1) + raise TimeoutError(f"chain did not advance past epoch {start_epoch}") + + +async def _wait_for_proposal_window(cluster: Cluster) -> int: + node1 = cluster.get_node("node1") + deadline = time.monotonic() + EPOCH_TIMEOUT_SECONDS + while time.monotonic() < deadline: + remaining = _remaining_epoch_seconds(node1.w3) + if remaining >= MIN_PROPOSAL_WINDOW_SECONDS: + return _current_epoch(node1.w3) + current = _current_epoch(node1.w3) + LOG.info( + "Only %ss remain in epoch %s; waiting for a clean proposal window", + remaining, + current, + ) + await _wait_for_epoch_advance(cluster, current) + raise TimeoutError("no epoch window was long enough for governance proposal") + + +def _oracle_delivered_logs( + w3: Web3, mirror_id: int, from_block: int +) -> list: + return w3.eth.get_logs( + { + "fromBlock": from_block, + "toBlock": "latest", + "address": support.NATIVE_ORACLE_ADDRESS, + "topics": [ + support.ORACLE_DELIVERED_TOPIC0, + support.topic(SOURCE_TYPE_POLYMARKET_SETTLEMENT), + support.topic(mirror_id), + ], + } + ) + + +async def _wait_for_oracle_delivered( + w3: Web3, mirror_id: int, from_block: int +) -> list: + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + while time.monotonic() < deadline: + logs = await asyncio.to_thread( + _oracle_delivered_logs, w3, mirror_id, from_block + ) + if logs: + return logs + await asyncio.sleep(2) + raise TimeoutError(f"no OracleDelivered event for mirror {mirror_id}") + + +async def _wait_for_settlement( + resolver, mirror_id: int, condition_id: bytes +) -> tuple: + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + while time.monotonic() < deadline: + settlement = resolver.functions.getSettlement( + mirror_id, condition_id + ).call() + if settlement[0]: + return tuple(settlement) + await asyncio.sleep(2) + raise TimeoutError(f"resolver did not store settlement for mirror {mirror_id}") + + +def _consensus_log(cluster: Cluster, node_id: str) -> Path: + return cluster.base_dir / node_id / "consensus_log" / "validator.log" + + +async def _wait_for_consensus_evidence( + cluster: Cluster, mirror_id: int +) -> None: + issuer = f"gravity://6/{mirror_id}" + missing_observers = set(cluster.nodes) + certifiers = set() + quorum_seen = False + deadline = time.monotonic() + POLL_TIMEOUT_SECONDS + + while time.monotonic() < deadline: + for node_id in cluster.nodes: + path = _consensus_log(cluster, node_id) + content = path.read_text(errors="replace") if path.exists() else "" + lines = content.splitlines() + if any( + "JWKObserver spawned." in line and issuer in line + for line in lines + ): + missing_observers.discard(node_id) + if any( + "Start certifying update." in line and issuer in line + for line in lines + ): + certifiers.add(node_id) + + if any( + "Peer vote aggregated." in line + and issuer in line + and ( + "threshold_exceeded=true" in line + or '"threshold_exceeded":true' in line + ) + for line in lines + ): + quorum_seen = True + + if ( + not missing_observers + and len(certifiers) >= QUORUM_VALIDATORS + and quorum_seen + ): + return + await asyncio.sleep(2) + + raise AssertionError( + "missing live Polymarket consensus evidence: " + f"observers={sorted(missing_observers)} " + f"certifiers={sorted(certifiers)} quorum={quorum_seen}" + ) + + +@pytest.mark.asyncio +async def test_four_validators_mirror_live_polymarket_settlement( + cluster: Cluster, +): + metadata = json.loads( + (SUITE_DIR / "artifacts" / "polymarket_live_metadata.json").read_text() + ) + mirror_id = int(metadata["mirrorId"]) + condition_id = bytes.fromhex(metadata["conditionId"][2:]) + winning_slot = int(metadata["winningSlot"]) + + assert len(cluster.nodes) == 4 + assert await cluster.set_full_live(timeout=180) + assert await cluster.check_block_increasing(timeout=60) + active = await cluster.validator_list() + assert {node.id for node in active.active} == set(cluster.nodes) + + node1 = cluster.get_node("node1") + w3 = node1.w3 + required = [ + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("PolymarketBinaryMarket.sol", "PolymarketBinaryMarket"), + ("MockGToken.sol", "MockGToken"), + ("NativeOracle.sol", "NativeOracle"), + ("OracleTaskConfig.sol", "OracleTaskConfig"), + ] + contracts_out = support.ensure_contracts_out(SUITE_DIR, required, "Polymarket") + resolver_artifact = support.load_artifact( + contracts_out, + "PolymarketSettlementResolver.sol", + "PolymarketSettlementResolver", + ) + market_artifact = support.load_artifact( + contracts_out, "PolymarketBinaryMarket.sol", "PolymarketBinaryMarket" + ) + token_artifact = support.load_artifact( + contracts_out, "MockGToken.sol", "MockGToken" + ) + native_artifact = support.load_artifact( + contracts_out, "NativeOracle.sol", "NativeOracle" + ) + task_artifact = support.load_artifact( + contracts_out, "OracleTaskConfig.sol", "OracleTaskConfig" + ) + + resolver = support.deploy_contract( + w3, resolver_artifact, support.FAUCET_KEY + ) + market = support.deploy_contract(w3, market_artifact, support.FAUCET_KEY) + token = support.deploy_contract(w3, token_artifact, support.FAUCET_KEY) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, + abi=native_artifact["abi"], + ) + task_config = w3.eth.contract( + address=support.ORACLE_TASK_CONFIG_ADDRESS, + abi=task_artifact["abi"], + ) + pool_addr = support.pool0_voted_by_faucet(w3) + + assert not task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, mirror_id, TASK_NAME + ).call() + setup_epoch = await _wait_for_proposal_window(cluster) + now_ts = w3.eth.get_block("latest")["timestamp"] + closes_at = now_ts + 55 + settlement_ref = ( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + condition_id, + resolver.address, + CTF_ADDRESS, + POLYGON_CHAIN_ID, + 2, + [0, 1], + 0, + ) + create_params = ( + Web3.keccak(text=str(metadata["question"])), + now_ts, + closes_at, + token.address, + settlement_ref, + ) + targets = [ + support.ORACLE_TASK_CONFIG_ADDRESS, + support.NATIVE_ORACLE_ADDRESS, + resolver.address, + market.address, + ] + datas = [ + support.function_calldata( + task_config.functions.setTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + TASK_NAME, + metadata["taskUri"].encode(), + ) + ), + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + resolver.address, + ) + ), + support.function_calldata( + resolver.functions.registerMirror( + mirror_id, + POLYGON_CHAIN_ID, + CTF_ADDRESS, + condition_id, + 2, + ) + ), + support.function_calldata(market.functions.createMarket(create_params)), + ] + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + targets, + datas, + "live-polymarket-dynamic-mirror", + gas=8_000_000, + ) + market_id = support.market_id_from_receipt(receipt) + + assert _current_epoch(w3) == setup_epoch + assert task_config.functions.hasTask( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, mirror_id, TASK_NAME + ).call() + assert ( + native_oracle.functions.getLatestNonce( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, mirror_id + ).call() + == 0 + ) + + bettors = [ + Account.create("live-polymarket-outcome-0"), + Account.create("live-polymarket-outcome-1"), + ] + for outcome, account in enumerate(bettors): + support.send_tx( + w3, + account.address, + b"", + support.FAUCET_KEY, + gas=21_000, + value=support.STAKE_UNIT, + ) + support.send_contract_tx( + w3, + token, + token.functions.mint(account.address, USER_STARTING_BALANCE), + support.FAUCET_KEY, + ) + support.send_contract_tx( + w3, + token, + token.functions.approve(market.address, USER_STARTING_BALANCE), + account.key, + ) + support.send_contract_tx( + w3, + market, + market.functions.placeBet( + market_id, outcome, STAKE_BY_OUTCOME[outcome] + ), + account.key, + gas=1_500_000, + ) + assert market.functions.getMarket(market_id).call()[6] == TOTAL_POOL + + activation_epoch = await _wait_for_epoch_advance(cluster, setup_epoch) + assert activation_epoch == setup_epoch + 1 + logs = await _wait_for_oracle_delivered( + w3, mirror_id, receipt["blockNumber"] + ) + assert len(logs) == 1 + progress = await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + mirror_id, + 1, + timeout=POLL_TIMEOUT_SECONDS, + ) + assert progress == (1, int(metadata["blockNumber"])) + + settlement = await _wait_for_settlement( + resolver, mirror_id, condition_id + ) + assert settlement[1] == 1 + assert settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_checksum_address(settlement[3]) == CTF_ADDRESS + assert Web3.to_checksum_address(settlement[4]) == Web3.to_checksum_address( + metadata["oracle"] + ) + assert Web3.to_hex(settlement[5]).lower() == metadata["questionId"].lower() + assert settlement[6] == 2 + assert ( + Web3.to_hex(settlement[7]).lower() + == metadata["transactionHash"].lower() + ) + assert settlement[8] == metadata["logIndex"] + assert resolver.functions.getPayoutNumerators( + mirror_id, condition_id + ).call() == metadata["payoutNumerators"] + + await _wait_for_consensus_evidence(cluster, mirror_id) + for node_id, node in cluster.nodes.items(): + replica = node.w3.eth.contract( + address=resolver.address, abi=resolver_artifact["abi"] + ) + assert tuple( + replica.functions.getSettlement(mirror_id, condition_id).call() + ) == settlement, f"{node_id} resolver state diverged" + + await support.wait_for_chain_time(w3, closes_at) + support.send_contract_tx( + w3, + market, + market.functions.lockMarket(market_id), + support.FAUCET_KEY, + ) + support.send_contract_tx( + w3, + market, + market.functions.finalizeMarket(market_id), + support.FAUCET_KEY, + gas=2_000_000, + ) + finalized_market = market.functions.getMarket(market_id).call() + assert finalized_market[4] == 2 + assert finalized_market[5] == winning_slot + + winner = bettors[winning_slot] + assert market.functions.claimable(market_id, winner.address).call() == TOTAL_POOL + balance_before = token.functions.balanceOf(winner.address).call() + support.send_contract_tx( + w3, + market, + market.functions.claim(market_id), + winner.key, + gas=1_500_000, + ) + assert ( + token.functions.balanceOf(winner.address).call() - balance_before + == TOTAL_POOL + ) + + LOG.info( + "Live Polymarket mirror settled: mirrorId=%s sourceBlock=%s " + "activationEpoch=%s winningSlot=%s", + mirror_id, + metadata["blockNumber"], + activation_epoch, + winning_slot, + ) diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/README.md b/gravity_e2e/cluster_test_cases/polymarket_mock/README.md new file mode 100644 index 000000000..f7d1bfb54 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/README.md @@ -0,0 +1,17 @@ +# Polymarket Binary Oracle E2E + +The focused local test for a binary market. Unlike the combined demo's fixed +outcome, this suite randomizes the winning slot and checks winner claimability, +loser zero-claimability, and exact source progress. + +Set `POLYMARKET_MOCK_WINNING_SLOT` to `0` or `1` for a reproducible run. + +Run: + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh polymarket_mock --force-init +``` + +See [`../../docs/ORACLE_E2E.md`](../../docs/ORACLE_E2E.md) for the complete +workflow, deterministic debugging option, revisions, and product boundary. diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/cluster.toml b/gravity_e2e/cluster_test_cases/polymarket_mock/cluster.toml new file mode 100644 index 000000000..1f7579476 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/cluster.toml @@ -0,0 +1,27 @@ +# Gravity Cluster Configuration - Polymarket mirror integration test + +[cluster] +name = "gravity-devnet-polymarket-mock" +base_dir = "/tmp/gravity-cluster-polymarket-mock" + +[genesis_source] +genesis_path = "./artifacts/genesis.json" +waypoint_path = "./artifacts/waypoint.txt" + +[[nodes]] +id = "node1" +role = "genesis" +source = { project_path = "../" } +host = "127.0.0.1" +validator_port = 45282 +vfn_port = 45292 +rpc_port = 48655 +api_port = 48180 +metrics_port = 49103 +inspection_port = 40002 +https_port = 41024 +authrpc_port = 48675 +reth_p2p_port = 52126 + +[faucet_init] +num_accounts = 0 diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/genesis.toml b/gravity_e2e/cluster_test_cases/polymarket_mock/genesis.toml new file mode 100644 index 000000000..b3b9dbe2e --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/genesis.toml @@ -0,0 +1,78 @@ +# Gravity Genesis Configuration - Polymarket mirror integration test + +[dependencies.genesis_contracts] +path = "../../../../gravity_chain_core_contracts" +ref = "631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d" + +[[genesis_validators]] +id = "node1" +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +host = "127.0.0.1" +validator_port = 45282 +vfn_port = 45292 +stake_amount = "2000000000000000000" +voting_power = "2000000000000000000" +consensus_pop = "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +[genesis] +chain_id = 1337 +epoch_interval_micros = 7200000000 +major_version = 1 +consensus_config = "0x0301010a00000000000000280000000000000001010000000a000000000000000100010200000000000000000020000000000000" +execution_config = "0x00" +initial_locked_until_micros = 1798848000000000 + +governance_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + +[genesis.faucet] +address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" +balance = "0x2000000000000000000000000000000000000000000000000000000000000000" + +[genesis.validator_config] +minimum_bond = "1000000000000000000" +maximum_bond = "1000000000000000000000000" +unbonding_delay_micros = 604800000000 +allow_validator_set_change = true +voting_power_increase_limit_pct = 20 +max_validator_set_size = "100" +auto_evict_enabled = false +auto_evict_threshold_pct = 0 + +[genesis.staking_config] +minimum_stake = "1000000000000000000" +lockup_duration_micros = 86400000000 +unbonding_delay_micros = 86400000000 + +[genesis.governance_config] +min_voting_threshold = "1000000000000000000" +required_proposer_stake = "1000000000000000000" +voting_duration_micros = 5000000 + +[genesis.randomness_config] +variant = 1 +secrecy_threshold = 9223372036854775808 +reconstruction_threshold = 12297829382473033728 +fast_path_secrecy_threshold = 12297829382473033728 + +[genesis.oracle_config] +source_types = [1, 6] +callbacks = [ + "0x00000000000000000000000000000001625F4001", + "0x0000000000000000000000000000000000000000", +] + +[[genesis.oracle_config.tasks]] +source_type = 6 +source_id = 7202626 +task_name = "polymarket_settlement" +config = "gravity://6/7202626/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20" + +[genesis.jwk_config] +issuers = ["0x68747470733a2f2f6163636f756e74732e676f6f676c652e636f6d"] + +[[genesis.jwk_config.jwks]] +kid = "f5f4c0ae6e6090a65ab0a694d6ba6f19d5d0b4e6" +kty = "RSA" +alg = "RS256" +e = "AQAB" +n = "2K7epoJWl_aBoYGpXmDBBiEnwQ0QdVRU1gsbGXNrEbrZEQdY5KjH5P5gZMq3d3KvT1j5KsD2tF_9jFMDLqV4VWDNJRLgSNJxhJuO_oLO2BXUSL9a7fLHxnZCUfJvT2K-O8AXjT3_ZM8UuL8d4jBn_fZLzdEI4MHrZLVSaHDvvKqL_mExQo6cFD-qyLZ-T6aHv2x8R7L_3X7E1nGMjKVVZMveQ_HMeXvnGxKf5yfEP0hIQlC_kFm4L_1kV1S0UPmMptZL2qI4VnXqmqI6TZJyE-3VXHgNn1Z1O_9QZlPC0fF0spLHf2S3nNqI0v3k2E7q3DkqxVf5xvn7q_X-gPqzVE9Jw" diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/hooks.py b/gravity_e2e/cluster_test_cases/polymarket_mock/hooks.py new file mode 100644 index 000000000..541c27d3b --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/hooks.py @@ -0,0 +1,65 @@ +"""Hooks for the Polymarket mirror integration suite.""" + +import json +import logging +import sys +from pathlib import Path + +LOG = logging.getLogger(__name__) + +_mock = None +_METADATA_FILE = "mock_polymarket_metadata.json" + + +def pre_start(test_dir: Path, env: dict, pytest_args: list = None): + global _mock + + e2e_root = str(Path(__file__).resolve().parent.parent.parent) + if e2e_root not in sys.path: + sys.path.insert(0, e2e_root) + + from gravity_e2e.utils.mock_polymarket_polygon import ( + CTF_ADDRESS, + FED_BINARY_BLOCK, + FED_BINARY_CONDITION_ID, + FED_BINARY_LOG_INDEX, + FED_BINARY_MARKET_ID, + FED_BINARY_QUESTION_ID, + FED_BINARY_TX_HASH, + MockPolymarketPolygon, + ) + + LOG.info("[hook] Starting MockPolymarketPolygon on port 8546 with hidden settlement") + _mock = MockPolymarketPolygon(port=8546) + _mock.start() + + metadata = { + "port": 8546, + "rpc_url": _mock.rpc_url, + "ctf": CTF_ADDRESS, + "market_id": FED_BINARY_MARKET_ID, + "condition_id": FED_BINARY_CONDITION_ID, + "question_id": FED_BINARY_QUESTION_ID, + "tx_hash": FED_BINARY_TX_HASH, + "block": FED_BINARY_BLOCK, + "log_index": FED_BINARY_LOG_INDEX, + "winning_slot": None, + "payout_numerators": None, + "source_log": None, + } + metadata_path = test_dir / _METADATA_FILE + metadata_path.write_text(json.dumps(metadata, indent=2)) + LOG.info("[hook] Wrote Polymarket mock metadata to %s", metadata_path) + + +def post_stop(test_dir: Path, env: dict): + global _mock + + if _mock is not None: + LOG.info("[hook] Stopping MockPolymarketPolygon") + _mock.stop() + _mock = None + + metadata_path = test_dir / _METADATA_FILE + if metadata_path.exists(): + metadata_path.unlink() diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/relayer_config.json b/gravity_e2e/cluster_test_cases/polymarket_mock/relayer_config.json new file mode 100644 index 000000000..909ffa168 --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/relayer_config.json @@ -0,0 +1,5 @@ +{ + "uri_mappings": { + "gravity://6/7202626/polymarket_settlement?ctf=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045&fromBlock=89222200&condition=0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23&maxBlocksPerPoll=20": "http://localhost:8546" + } +} diff --git a/gravity_e2e/cluster_test_cases/polymarket_mock/test_polymarket_mock.py b/gravity_e2e/cluster_test_cases/polymarket_mock/test_polymarket_mock.py new file mode 100644 index 000000000..76ae6839e --- /dev/null +++ b/gravity_e2e/cluster_test_cases/polymarket_mock/test_polymarket_mock.py @@ -0,0 +1,257 @@ +"""Polymarket binary market mirror E2E test.""" + +import asyncio +import json +import logging +import os +import secrets +import time +import urllib.request +from pathlib import Path + +import pytest +from eth_account import Account +from web3 import Web3 + +from gravity_e2e.cluster.manager import Cluster +from gravity_e2e.utils import oracle_test_support as support +from gravity_e2e.utils.mock_polymarket_polygon import FED_BINARY_MARKET_ID + +LOG = logging.getLogger(__name__) +SUITE_DIR = Path(__file__).resolve().parent + +SOURCE_TYPE_POLYMARKET_SETTLEMENT = 6 +POLYGON_CHAIN_ID = 137 +BINARY_OUTCOME_COUNT = 2 +SETTLEMENT_KIND_CTF_CONDITION_RESOLUTION = 1 +USER_STARTING_BALANCE = 1_000 * support.STAKE_UNIT +BET_AMOUNTS = [100 * support.STAKE_UNIT, 300 * support.STAKE_UNIT] +TOTAL_POOL = sum(BET_AMOUNTS) + + +def _mock_set_winning_slot(rpc_url: str, winning_slot: int) -> dict: + payload = json.dumps( + { + "jsonrpc": "2.0", + "method": "mock_setBinaryWinningSlot", + "params": [winning_slot], + "id": 1, + } + ).encode() + request = urllib.request.Request( + rpc_url, data=payload, headers={"Content-Type": "application/json"} + ) + with urllib.request.urlopen(request, timeout=5) as response: + body = json.loads(response.read()) + if "error" in body: + raise RuntimeError(f"mock_setBinaryWinningSlot failed: {body['error']}") + return body["result"] + + +async def _wait_for_resolver_settlement( + resolver, mirror_id: int, condition_id: bytes, timeout: int = 120 +): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + settlement = resolver.functions.getSettlement(mirror_id, condition_id).call() + if settlement[0]: + return settlement + await asyncio.sleep(2) + raise TimeoutError("resolver settlement was not stored") + + +@pytest.mark.asyncio +async def test_polymarket_binary_market_mock_resolves_random_outcome(cluster: Cluster): + metadata_path = SUITE_DIR / "mock_polymarket_metadata.json" + metadata = json.loads(metadata_path.read_text()) + + assert await cluster.set_full_live(timeout=120), "Gravity node failed to become live" + assert await cluster.check_block_increasing(timeout=60), "Gravity chain is not producing blocks" + + node = cluster.get_node("node1") + assert node is not None, "node1 not found in cluster" + w3 = node.w3 + assert w3 is not None and w3.is_connected(), "node1 web3 not connected" + + required = [ + ("PolymarketSettlementResolver.sol", "PolymarketSettlementResolver"), + ("PolymarketBinaryMarket.sol", "PolymarketBinaryMarket"), + ("MockGToken.sol", "MockGToken"), + ("NativeOracle.sol", "NativeOracle"), + ] + contracts_out = support.ensure_contracts_out(SUITE_DIR, required, "Polymarket") + resolver_artifact = support.load_artifact( + contracts_out, "PolymarketSettlementResolver.sol", "PolymarketSettlementResolver" + ) + market_artifact = support.load_artifact( + contracts_out, "PolymarketBinaryMarket.sol", "PolymarketBinaryMarket" + ) + token_artifact = support.load_artifact(contracts_out, "MockGToken.sol", "MockGToken") + native_artifact = support.load_artifact(contracts_out, "NativeOracle.sol", "NativeOracle") + + resolver = support.deploy_contract(w3, resolver_artifact, support.FAUCET_KEY) + market = support.deploy_contract(w3, market_artifact, support.FAUCET_KEY) + token = support.deploy_contract(w3, token_artifact, support.FAUCET_KEY) + native_oracle = w3.eth.contract( + address=support.NATIVE_ORACLE_ADDRESS, abi=native_artifact["abi"] + ) + + condition_id = bytes.fromhex(metadata["condition_id"][2:]) + ctf = Web3.to_checksum_address(metadata["ctf"]) + pool_addr = support.pool0_voted_by_faucet(w3) + + now_ts = w3.eth.get_block("latest")["timestamp"] + closes_at = now_ts + 20 + settlement_ref = ( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + condition_id, + resolver.address, + ctf, + POLYGON_CHAIN_ID, + BINARY_OUTCOME_COUNT, + [1, 0], + 0, + ) + create_params = ( + Web3.keccak(text="Fed binary random e2e market"), + now_ts, + closes_at, + token.address, + settlement_ref, + ) + + setup_data = [ + support.function_calldata( + native_oracle.functions.setCallback( + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + resolver.address, + ) + ), + support.function_calldata( + resolver.functions.registerMirror( + FED_BINARY_MARKET_ID, + POLYGON_CHAIN_ID, + ctf, + condition_id, + BINARY_OUTCOME_COUNT, + ) + ), + support.function_calldata(market.functions.createMarket(create_params)), + ] + receipt = await support.execute_governance_proposal( + w3, + pool_addr, + [support.NATIVE_ORACLE_ADDRESS, resolver.address, market.address], + setup_data, + "polymarket-binary-market-e2e-setup", + ) + market_id = support.market_id_from_receipt(receipt) + + bettors = [Account.create(f"polymarket-bettor-{i}") for i in range(BINARY_OUTCOME_COUNT)] + for account in bettors: + support.send_tx( + w3, account.address, b"", support.FAUCET_KEY, gas=21_000, value=support.STAKE_UNIT + ) + support.send_contract_tx( + w3, + token, + token.functions.mint(account.address, USER_STARTING_BALANCE), + support.FAUCET_KEY, + ) + support.send_contract_tx( + w3, + token, + token.functions.approve(market.address, USER_STARTING_BALANCE), + account.key, + ) + + for outcome, (account, amount) in enumerate(zip(bettors, BET_AMOUNTS)): + support.send_contract_tx( + w3, + market, + market.functions.placeBet(market_id, outcome, amount), + account.key, + gas=1_500_000, + ) + assert market.functions.getMarket(market_id).call()[6] == TOTAL_POOL + + await support.wait_for_chain_time(w3, closes_at) + support.send_contract_tx( + w3, market, market.functions.lockMarket(market_id), support.FAUCET_KEY + ) + + forced_slot = os.environ.get("POLYMARKET_MOCK_WINNING_SLOT") + winning_slot = ( + int(forced_slot) if forced_slot is not None else secrets.randbelow(BINARY_OUTCOME_COUNT) + ) + assert 0 <= winning_slot < BINARY_OUTCOME_COUNT + release = _mock_set_winning_slot(metadata["rpc_url"], winning_slot) + metadata.update(release) + metadata_path.write_text(json.dumps(metadata, indent=2)) + + logs = await support.poll_oracle_delivered( + w3, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + timeout=180, + ) + assert logs, "No Polymarket sourceType=6 OracleDelivered event observed" + assert support.topic_hex(logs[0]["topics"][1]) == support.topic( + SOURCE_TYPE_POLYMARKET_SETTLEMENT + ) + assert support.topic_hex(logs[0]["topics"][2]) == support.topic(FED_BINARY_MARKET_ID) + progress = await support.wait_for_source_progress( + native_oracle, + SOURCE_TYPE_POLYMARKET_SETTLEMENT, + FED_BINARY_MARKET_ID, + 1, + timeout=60, + ) + assert progress == (1, int(metadata["block"])) + + settlement = await _wait_for_resolver_settlement( + resolver, FED_BINARY_MARKET_ID, condition_id, timeout=60 + ) + assert settlement[0] is True + assert settlement[2] == POLYGON_CHAIN_ID + assert Web3.to_checksum_address(settlement[3]) == ctf + assert settlement[6] == BINARY_OUTCOME_COUNT + assert settlement[9] == SETTLEMENT_KIND_CTF_CONDITION_RESOLUTION + assert resolver.functions.getPayoutNumerators( + FED_BINARY_MARKET_ID, condition_id + ).call() == release["payout_numerators"] + + support.send_contract_tx( + w3, + market, + market.functions.finalizeMarket(market_id), + support.FAUCET_KEY, + gas=2_000_000, + ) + final_market = market.functions.getMarket(market_id).call() + winning_outcome = 1 - winning_slot + assert final_market[4] == 2 + assert final_market[5] == winning_outcome + + winner = bettors[winning_outcome] + assert market.functions.claimable(market_id, winner.address).call() == TOTAL_POOL + balance_before = token.functions.balanceOf(winner.address).call() + support.send_contract_tx( + w3, market, market.functions.claim(market_id), winner.key, gas=1_500_000 + ) + assert token.functions.balanceOf(winner.address).call() - balance_before == TOTAL_POOL + assert market.functions.claimable(market_id, winner.address).call() == 0 + + for outcome, account in enumerate(bettors): + if outcome != winning_outcome: + assert market.functions.claimable(market_id, account.address).call() == 0 + + LOG.info( + "Polymarket binary market resolved: marketId=%s winningSlot=%s winningOutcome=%s totalPool=%s", + market_id, + winning_slot, + winning_outcome, + TOTAL_POOL, + ) diff --git a/gravity_e2e/docs/MANUAL.md b/gravity_e2e/docs/MANUAL.md index 8971df391..39a1d78f3 100644 --- a/gravity_e2e/docs/MANUAL.md +++ b/gravity_e2e/docs/MANUAL.md @@ -79,7 +79,25 @@ You can control the Python logging level by passing standard pytest flags to the ./gravity_e2e/run_test.sh --log-cli-level=DEBUG ``` -### 5. Docker Runner (CI) +### 5. Oracle E2E Suites + +Oracle testing is split into deterministic, dynamic, and public-network gates: + +| Suite | Coverage | +| --- | --- | +| `oracle_demo` | Deterministic Binance plus binary Polymarket integration | +| `polymarket_mock` | Randomized binary settlement and payout claims | +| `polymarket_dynamic_mirror` | Successive governance-created mirrors and replay protection | +| `binance_price_feed_multivalidator` | Approved live Binance and four-validator quorum | +| `polymarket_live_dynamic_mirror` | Real finalized Polygon settlement and four-validator quorum | +| `oracle_live_soak` | Governance-activated NVDA and Polymarket 24-hour soak | + +The canonical commands, latest-only storage checks, frontend mode, revisions, +and scope are documented in +[`ORACLE_E2E.md`](ORACLE_E2E.md). Live suites are excluded from default runs +because they send public network requests. + +### 6. Docker Runner (CI) The `run_docker.sh` script runs the full pipeline inside Docker. It accepts the same arguments as `run_test.sh`: ```bash # Run all suites in Docker diff --git a/gravity_e2e/docs/ORACLE_E2E.md b/gravity_e2e/docs/ORACLE_E2E.md new file mode 100644 index 000000000..e7d2f471f --- /dev/null +++ b/gravity_e2e/docs/ORACLE_E2E.md @@ -0,0 +1,280 @@ +# Gravity Oracle E2E + +This is the canonical runbook for the Oracle suites added by PR #758. + +## Suite Matrix + +| Suite | Network | Purpose | Default run | +| --- | --- | --- | --- | +| `oracle_demo` | Local mocks | Deterministic Binance plus binary Polymarket integration and frontend config | Yes | +| `polymarket_mock` | Local mock | Binary market, random winner, settlement, and payout claims | Yes | +| `polymarket_dynamic_mirror` | Local Polygon fixtures | Successive governance-created mirrors and replay protection | Yes | +| `binance_price_feed_multivalidator` | Binance public API | Four-validator independent fetch, voting-power QC, execution, and RPC replication | No | +| `polymarket_live_dynamic_mirror` | Gamma API and Polygon RPC | Four-validator dynamic mirror of a real finalized settlement | No | +| `oracle_live_soak` | Binance, Gamma, and Polygon RPC | Governance activation followed by a four-validator 24-hour liveness and consistency soak | No | + +The old standalone `binance_price_feed` suite was removed because its +deterministic assertions are covered by `oracle_demo`, while its live source +and consensus assertions are covered more strongly by the four-validator +suite. Live frontend config generation moved to that suite. + +`polymarket_mock` remains separate because the combined demo uses a fixed +binary outcome. The focused suite randomizes the winning slot and checks both +winner claimability and loser zero-claimability. + +```mermaid +flowchart LR + S["Binance index kline or Polygon CTF log"] + R["gravity-reth source adapter"] + J["JWK observer and voting-power quorum"] + N["NativeOracle"] + P["PriceFeedResolver"] + M["PolymarketSettlementResolver and market"] + + S --> R --> J --> N + N --> P + N --> M +``` + +## Build + +From the repository root: + +```bash +RUSTFLAGS="--cfg tokio_unstable" \ + cargo build --profile quick-release -p gravity_node -p gravity_cli --locked +``` + +When using an E2E virtualenv, activate it before running a suite. Put Foundry +and the quick-release binaries on `PATH`: + +```bash +export PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" +``` + +## Deterministic Combined Gate + +`oracle_demo` sends no public network traffic. It starts local Binance and +Polygon fixtures, records `sourceType=3` and `sourceType=6` through the same +Oracle consensus path, verifies two exact price rounds, and permissionlessly +finalizes one binary Gravity market from the canonical Polymarket resolver +classification. The binary market has no Gravity-local settlement deadline or +governance timeout path. + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh oracle_demo --force-init +``` + +For the frontend: + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh oracle_demo \ + --force-init \ + --keep-running \ + --demo-config-out ../gravity_price_feed_demo_web/public/demo-config.json \ + --log-cli-level=INFO +``` + +Stop the retained backend with: + +```bash +bash cluster/stop.sh \ + --config gravity_e2e/cluster_test_cases/oracle_demo/cluster.toml +kill "$(cat gravity_e2e/cluster_test_cases/oracle_demo/artifacts/mock_binance.pid)" +``` + +## Focused Binary Polymarket Gate + +`polymarket_mock` uses a local Polygon JSON-RPC fixture. It verifies a reviewed +CTF reference, a two-slot binary market, randomized winner mapping, market +lock and settlement, winner payout, and zero claimability for losers. + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh polymarket_mock --force-init +``` + +Set `POLYMARKET_MOCK_WINNING_SLOT` to `0` or `1` for a reproducible +debug run. Without it, the test chooses a random valid slot. + +## Dynamic Polymarket Gates + +`polymarket_dynamic_mirror` proves that governance can add mirror tasks in +successive epochs. Each task activates in the next epoch, resolves through the +same JWK path, and advances only its own `(sourceType, sourceId)` progress. +Replaying an already delivered settlement emits no second `OracleDelivered` +event and does not advance the nonce. + +```bash +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh polymarket_dynamic_mirror --force-init +``` + +`polymarket_live_dynamic_mirror` queries the Gamma API for a recently closed +binary market, verifies a unique finalized Polygon CTF +`ConditionResolution`, and starts four validators. The test creates the task +through Gravity governance, waits for next-epoch activation, requires +voting-power JWK quorum evidence, compares resolver state across all four RPC +replicas, and settles and claims the Gravity binary market. + +```bash +export POLYGON_RPC_URL="..." +GRAVITY_E2E_SKIP_GLOBAL_PKILL=1 \ +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh \ + polymarket_live_dynamic_mirror \ + --force-init \ + --log-cli-level=INFO +``` + +## Live Four-Validator Binance Gate + +This suite is excluded from the default all-suite run because it sends public +requests. Run it only after outbound access has been approved. + +Four equal-power validators observe the same closed one-minute +`indexPriceKlines` bucket. The test requires: + +- all four validators active and advancing; +- all four observers to start and persist independent relayer state; +- at least three validators to certify each feed and cross the JWK threshold; +- a slower validator to safely fast-forward from the committed nonce; +- onchain prices to equal Binance close values at 8 decimals; +- all four RPC endpoints to return identical source progress and latest price. + +`NativeOracle` and `PriceFeedResolver` keep fixed-size latest-only state. The +test does not depend on historical payload records or per-round price storage. + +```bash +BINANCE_PRICE_FEED_MODE=live \ +BINANCE_PRICE_FEED_BASE_URL=https://testnet.binancefuture.com \ +BINANCE_PRICE_FEED_LAG_MINUTES=4 \ +GRAVITY_E2E_SKIP_GLOBAL_PKILL=1 \ +PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" \ + ./gravity_e2e/run_test.sh \ + binance_price_feed_multivalidator \ + --force-init \ + --log-cli-level=INFO +``` + +To retain the cluster and write frontend discovery metadata, add: + +```text +--keep-running +--demo-config-out ../gravity_price_feed_demo_web/public/demo-config.json +``` + +Stop the retained four-validator cluster with: + +```bash +bash cluster/stop.sh \ + --config gravity_e2e/cluster_test_cases/binance_price_feed_multivalidator/cluster.toml +``` + +The public `indexPriceKlines` method does not require `BINANCE_API_KEY` or +`BINANCE_SECRET_KEY`. Testnet uses the production response shape but returns +test-market prices. The suite does not silently switch endpoints. + +Set `BINANCE_PRICE_FEED_BASE_URL=https://fapi.binance.com` for production +index prices. An HTTP 451 response means the process egress is not eligible +for Binance production under its regional policy; it does not mean that the +endpoint or pair is missing. Use an approved eligible egress or the futures +testnet. A process-level proxy must bypass loopback and private networks so +validator consensus and local RPC traffic remain local. + +For an immutable replay, set: + +```bash +BINANCE_PRICE_FEED_BUCKET_START_MS= +``` + +The bucket must already be closed and older than `graceMs`. + +## Live Oracle Soak + +`oracle_live_soak` is the long-running operational gate. Genesis declares the +`sourceType=3` and `sourceType=6` capabilities but contains neither task. A +single governance proposal registers the continuous NVDA feed, its resolver, +and a discovered finalized Polymarket mirror. The +observers activate only after the next epoch begins. + +The default 24-hour monitor requires continuous Gravity block production, +monotonic NVDA minute delivery, at least three persisted relayer cursors, exact +four-RPC state replication, immutable one-shot Polymarket settlement, and one +mid-run validator restart with catch-up. It writes an ignored JSONL heartbeat +and a final JSON summary. + +```bash +export POLYGON_RPC_URL="..." +export BINANCE_PRICE_FEED_BASE_URL=https://fapi.binance.com +export ORACLE_SOAK_DURATION_SECONDS=86400 +export GRAVITY_E2E_SKIP_GLOBAL_PKILL=1 +export PATH="$HOME/.foundry/bin:$PWD/target/quick-release:$PATH" + +./gravity_e2e/run_test.sh \ + oracle_live_soak \ + --force-init \ + --log-cli-level=INFO +``` + +Use `ORACLE_SOAK_DURATION_SECONDS=180`, +`ORACLE_SOAK_MIN_ADVANCES=1`, and +`ORACLE_SOAK_RESTART_AFTER_SECONDS=0` for a short validation. Full controls, +failure criteria, and evidence files are documented in the suite README. + +## Pinned Revisions + +| Repository | Revision | +| --- | --- | +| `gravity_chain_core_contracts` | `631b3bde8e2d6a98377e62a9b9e54ccdf0896e9d` | +| `gravity-reth` | `a5cf019429d772cd2f4964fc0705676d84464953` | +| `gravity-aptos` | `d163fa649970c7c8446dbc41a367c2d0b960cca6` | +| `gravity-sdk` | `codex/sports-score-oracle-poc` (this branch) | + +Each suite's genesis file pins the contracts revision it requires. +`Cargo.lock` pins the reth and Aptos revisions. + +## Last Live Verification + +The following live suites were verified on 2026-07-30: + +| Evidence | Value | +| --- | --- | +| Active validators | 4 | +| Total voting power | `8000000000000000000` | +| JWK quorum power | `5333333333333333334` | +| Binance testnet stored round | `29756744` | +| Binance testnet NVDAUSDT / TSLAUSDT | `19199999338` / `30046300000` | +| Binance testnet pytest | `1 passed in 44.81s` | +| Live Polymarket mirror ID | `3029713` | +| Live Polymarket source block | `91132830` | +| Live Polymarket activation epoch | `3` | +| Live Polymarket pytest | `1 passed in 70.79s` | + +The same Binance suite against `https://fapi.binance.com` could not observe a +round from this environment because the API returned HTTP 451 under Binance's +regional eligibility policy. All four Gravity validators remained active and +continued producing blocks; this is an egress limitation, not a consensus or +contract failure. + +## Scope + +These suites prove configured task execution and contract consumption. They do +not implement generic intra-epoch request discovery or automatic mirroring of +arbitrary Polymarket UI markets. + +Production Polymarket mirrors need a reviewed manifest containing the rules, +condition and question IDs, CTF address, outcome labels, slot mapping, source +block range, and metadata hashes. Dynamic discovery additionally needs +finality gates, watermarks, request-expiry policies, and typed pending or +expired states. Request expiry is a watcher lifecycle concern; it must not +create a Gravity-local fallback result for a strict Polymarket mirror. + +Use `--force-init` after changing genesis configuration or a pinned contracts +revision. Otherwise cached artifacts may be reused. + +The runner normally performs a global `gravity_node` cleanup. Set +`GRAVITY_E2E_SKIP_GLOBAL_PKILL=1` when an unrelated local Gravity node must +remain running; the suite still stops its own configured cluster. diff --git a/gravity_e2e/gravity_e2e/utils/mock_binance_index.py b/gravity_e2e/gravity_e2e/utils/mock_binance_index.py new file mode 100644 index 000000000..62805508f --- /dev/null +++ b/gravity_e2e/gravity_e2e/utils/mock_binance_index.py @@ -0,0 +1,136 @@ +"""Deterministic local Binance index-kline fixture shared by oracle E2E suites.""" + +import argparse +from contextlib import contextmanager +import json +import logging +import os +import threading +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from urllib.parse import parse_qs, urlparse + +LOG = logging.getLogger(__name__) + +BUCKET_START_MS = 1_783_252_500_000 +INTERVAL_MS = 60_000 +DECIMALS = 8 +MOCK_BINANCE_PORT = 18547 +SUPPORTED_PAIRS = {"NVDAUSDT", "TSLAUSDT"} + + +def format_price(scaled_price: int) -> str: + whole = scaled_price // 10**DECIMALS + fraction = scaled_price % 10**DECIMALS + return f"{whole}.{fraction:0{DECIMALS}d}" + + +def mock_close_price(pair: str, bucket_index: int) -> str: + base_prices = {"NVDAUSDT": 19_592_645_000, "TSLAUSDT": 40_067_545_000} + increments = {"NVDAUSDT": 10_000_000, "TSLAUSDT": 25_000_000} + return format_price(base_prices[pair] + bucket_index * increments[pair]) + + +class MockBinanceIndexKlineHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def do_GET(self): + parsed = urlparse(self.path) + if parsed.path != "/fapi/v1/indexPriceKlines": + self.send_error(404) + return + + params = parse_qs(parsed.query) + pair = params.get("pair", [""])[0] + try: + start_time = int(params.get("startTime", ["-1"])[0]) + end_time = int(params.get("endTime", ["-1"])[0]) + except ValueError: + self.send_error(400) + return + if ( + params.get("interval", [""])[0] != "1m" + or params.get("limit", [""])[0] != "1" + or start_time < BUCKET_START_MS + or (start_time - BUCKET_START_MS) % INTERVAL_MS != 0 + or end_time != start_time + INTERVAL_MS - 1 + or pair not in SUPPORTED_PAIRS + ): + self.send_error(400) + return + + bucket_index = (start_time - BUCKET_START_MS) // INTERVAL_MS + close_px = mock_close_price(pair, bucket_index) + response = [ + [ + start_time, + close_px, + close_px, + close_px, + close_px, + "0", + end_time, + "0", + 60, + "0", + "0", + "0", + ] + ] + payload = json.dumps(response).encode() + self.send_response(200) + self.send_header("content-type", "application/json") + self.send_header("content-length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def log_message(self, fmt: str, *args): + LOG.debug("mock Binance index kline: " + fmt, *args) + + +class ReusableThreadingHTTPServer(ThreadingHTTPServer): + allow_reuse_address = True + + +@contextmanager +def mock_binance_index_kline_server(port: int = MOCK_BINANCE_PORT): + server = ReusableThreadingHTTPServer(("127.0.0.1", port), MockBinanceIndexKlineHandler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + yield f"http://127.0.0.1:{port}" + finally: + server.shutdown() + server.server_close() + thread.join(timeout=5) + + +def serve_forever(port: int, pid_file: Path | None = None): + if pid_file is not None: + pid_file.parent.mkdir(parents=True, exist_ok=True) + pid_file.write_text(f"{os.getpid()}\n") + server = ReusableThreadingHTTPServer(("127.0.0.1", port), MockBinanceIndexKlineHandler) + LOG.info("Mock Binance index kline server listening on 127.0.0.1:%s", port) + try: + server.serve_forever() + finally: + server.server_close() + if pid_file is not None: + pid_file.unlink(missing_ok=True) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--port", type=int, default=MOCK_BINANCE_PORT) + parser.add_argument("--pid-file", type=Path) + args = parser.parse_args() + + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)s %(message)s", + ) + serve_forever(args.port, args.pid_file) + + +if __name__ == "__main__": + main() diff --git a/gravity_e2e/gravity_e2e/utils/mock_polymarket_polygon.py b/gravity_e2e/gravity_e2e/utils/mock_polymarket_polygon.py new file mode 100644 index 000000000..9a2a8c66f --- /dev/null +++ b/gravity_e2e/gravity_e2e/utils/mock_polymarket_polygon.py @@ -0,0 +1,530 @@ +""" +MockPolymarketPolygon - deterministic local Polygon JSON-RPC fixture for oracle E2E tests. + +The mock only implements the Polygon methods used by the gravity-reth +Polymarket settlement source: + - eth_chainId / net_version + - eth_blockNumber + - eth_getBlockByNumber("finalized" | "latest" | hex) + - eth_getLogs + +It preloads CTF ConditionResolution logs so the e2e cluster can exercise the +relayer + UnsupportedJWK consensus + NativeOracle path without a real Polygon +RPC endpoint or secrets. +""" + +import json +import logging +import threading +import time +from http.server import BaseHTTPRequestHandler, HTTPServer +from typing import Any, Dict, List, Optional + +LOG = logging.getLogger(__name__) + +POLYGON_CHAIN_ID = 137 +CTF_ADDRESS = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +UMA_ORACLE = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296" +MATCH_MARKET_ID = 1_897_398 +MATCH_CONDITION_ID = "0x2afe86f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23" +MATCH_QUESTION_ID = "0x49a5e94a4b5a400dcd720ca1875fcd49ba55c303e43bf091bc175df72f74f501" +MATCH_TX_HASH = "0x97828bf9110f78c07f1ad5cff5415875b67b3fe032e19ee6aa2317355861aab2" +MATCH_BLOCK = 89_222_209 +MATCH_LOG_INDEX = 2_077 + +FED_BINARY_MARKET_ID = 7_202_626 +FED_BINARY_CONDITION_ID = "0xfed086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23" +FED_BINARY_QUESTION_ID = "0xfed5e94a4b5a400dcd720ca1875fcd49ba55c303e43bf091bc175df72f74f501" +FED_BINARY_TX_HASH = "0xfed28bf9110f78c07f1ad5cff5415875b67b3fe032e19ee6aa2317355861aab2" +FED_BINARY_BLOCK = 89_222_209 +FED_BINARY_LOG_INDEX = 2_078 + +DYNAMIC_BINARY_MARKET_ID = 7_202_627 +DYNAMIC_BINARY_CONDITION_ID = ( + "0xd1a086f96be81a0d89ed776bedbd52d1c75bc47b49e6f0f791ddd009f52faf23" +) +DYNAMIC_BINARY_QUESTION_ID = ( + "0xd1a5e94a4b5a400dcd720ca1875fcd49ba55c303e43bf091bc175df72f74f501" +) +DYNAMIC_BINARY_TX_HASH = ( + "0xd1a28bf9110f78c07f1ad5cff5415875b67b3fe032e19ee6aa2317355861aab2" +) +DYNAMIC_BINARY_BLOCK = 89_222_215 +DYNAMIC_BINARY_LOG_INDEX = 2_079 + +# Backward-compatible aliases used by the original match-market test. +DRAW_MARKET_ID = MATCH_MARKET_ID +DRAW_CONDITION_ID = MATCH_CONDITION_ID +DRAW_QUESTION_ID = MATCH_QUESTION_ID +DRAW_TX_HASH = MATCH_TX_HASH +DRAW_BLOCK = MATCH_BLOCK +DRAW_LOG_INDEX = MATCH_LOG_INDEX + +CONDITION_RESOLUTION_TOPIC0 = "0xb44d84d3289691f71497564b85d4233648d9dbae8cbdbb4329f301c3a0185894" + + +def _to_hex(value: int) -> str: + return hex(value) + + +def _pad_topic(value: int) -> str: + return "0x" + value.to_bytes(32, "big").hex() + + +def _uint256(value: int) -> bytes: + return value.to_bytes(32, "big") + + +def _address_topic(address: str) -> str: + return "0x" + bytes.fromhex(address.replace("0x", "")).rjust(32, b"\x00").hex() + + +def _fake_hash(seed: int) -> str: + return "0x" + seed.to_bytes(32, "big").hex() + + +def generate_condition_resolution_log( + block_number: int = MATCH_BLOCK, + log_index: int = MATCH_LOG_INDEX, + payout_numerators: Optional[List[int]] = None, + condition_id: str = MATCH_CONDITION_ID, + question_id: str = MATCH_QUESTION_ID, + tx_hash: str = MATCH_TX_HASH, +) -> Dict[str, Any]: + """Generate a CTF ConditionResolution log for a configured mock market.""" + payouts = payout_numerators or [0, 1, 0] + data = _uint256(len(payouts)) + _uint256(64) + _uint256(len(payouts)) + data += b"".join(_uint256(payout) for payout in payouts) + return { + "address": CTF_ADDRESS.lower(), + "topics": [ + CONDITION_RESOLUTION_TOPIC0, + condition_id.lower(), + _address_topic(UMA_ORACLE).lower(), + question_id.lower(), + ], + "data": "0x" + data.hex(), + "blockNumber": _to_hex(block_number), + "blockHash": _fake_hash(block_number + 0x100), + "transactionHash": tx_hash, + "transactionIndex": "0x0", + "logIndex": _to_hex(log_index), + "removed": False, + } + + +class MockPolymarketPolygon: + def __init__(self, port: int = 8546, chain_id: int = POLYGON_CHAIN_ID): + self.port = port + self.chain_id = chain_id + self.latest_block = MATCH_BLOCK - 1 + self.finalized_block = MATCH_BLOCK - 1 + self._logs: Dict[int, List[Dict[str, Any]]] = {} + self._requests: List[Dict[str, Any]] = [] + self._lock = threading.RLock() + self._server: Optional[HTTPServer] = None + self._thread: Optional[threading.Thread] = None + + @property + def current_block(self) -> int: + """Backward-compatible alias for mocks that expose one chain head.""" + return self.latest_block + + @current_block.setter + def current_block(self, block_number: int) -> None: + self.set_heads(block_number, block_number) + + @property + def rpc_url(self) -> str: + return f"http://localhost:{self.port}" + + @property + def is_running(self) -> bool: + return self._thread is not None and self._thread.is_alive() + + @property + def requests(self) -> List[Dict[str, Any]]: + with self._lock: + return list(self._requests) + + def clear_requests(self) -> None: + with self._lock: + self._requests.clear() + + def set_heads(self, latest_block: int, finalized_block: Optional[int] = None) -> dict: + finalized = latest_block if finalized_block is None else finalized_block + if finalized > latest_block: + raise ValueError( + f"finalized block {finalized} cannot exceed latest block {latest_block}" + ) + with self._lock: + self.latest_block = latest_block + self.finalized_block = finalized + return { + "latestBlock": latest_block, + "finalizedBlock": finalized, + } + + def add_condition( + self, + *, + condition_id: str, + question_id: str, + block_number: int, + log_index: int, + payout_numerators: List[int], + tx_hash: Optional[str] = None, + removed: bool = False, + replace_existing: bool = False, + ) -> Dict[str, Any]: + if not payout_numerators: + raise ValueError("payout_numerators must not be empty") + if tx_hash is None: + tx_hash = _fake_hash(block_number * 1_000_000 + log_index) + + log = generate_condition_resolution_log( + block_number=block_number, + log_index=log_index, + payout_numerators=payout_numerators, + condition_id=condition_id, + question_id=question_id, + tx_hash=tx_hash, + ) + log["removed"] = removed + + with self._lock: + block_logs = self._logs.setdefault(block_number, []) + if replace_existing: + block_logs[:] = [ + existing + for existing in block_logs + if not ( + existing["topics"][1].lower() == condition_id.lower() + and existing["logIndex"] == _to_hex(log_index) + ) + ] + block_logs.append(log) + + return { + "condition_id": condition_id, + "question_id": question_id, + "ctf": CTF_ADDRESS, + "oracle": UMA_ORACLE, + "tx_hash": tx_hash, + "block": block_number, + "log_index": log_index, + "payout_numerators": payout_numerators, + "source_log": log, + } + + def preload_draw_resolution(self) -> Dict[str, Any]: + log = self.preload_match_resolution(1, visible=True) + LOG.info( + "MockPolymarketPolygon: preloaded Draw settlement at block=%s logIndex=%s", + MATCH_BLOCK, + MATCH_LOG_INDEX, + ) + return log + + def preload_match_resolution(self, winning_slot: int, visible: bool = False) -> Dict[str, Any]: + if winning_slot < 0 or winning_slot > 2: + raise ValueError(f"winning_slot must be 0, 1, or 2; got {winning_slot}") + payouts = [0, 0, 0] + payouts[winning_slot] = 1 + result = self.add_condition( + condition_id=MATCH_CONDITION_ID, + question_id=MATCH_QUESTION_ID, + block_number=MATCH_BLOCK, + log_index=MATCH_LOG_INDEX, + payout_numerators=payouts, + tx_hash=MATCH_TX_HASH, + replace_existing=True, + ) + head = MATCH_BLOCK if visible else MATCH_BLOCK - 1 + self.set_heads(head, head) + LOG.info( + "MockPolymarketPolygon: prepared winning_slot=%s payout=%s visible=%s", + winning_slot, + payouts, + visible, + ) + return result["source_log"] + + def release_match_resolution(self, winning_slot: int) -> Dict[str, Any]: + if winning_slot < 0 or winning_slot > 2: + raise ValueError(f"winning_slot must be 0, 1, or 2; got {winning_slot}") + payouts = [0, 0, 0] + payouts[winning_slot] = 1 + log = self.preload_match_resolution(winning_slot, visible=True) + return { + "market_id": MATCH_MARKET_ID, + "condition_id": MATCH_CONDITION_ID, + "question_id": MATCH_QUESTION_ID, + "ctf": CTF_ADDRESS, + "oracle": UMA_ORACLE, + "tx_hash": MATCH_TX_HASH, + "block": MATCH_BLOCK, + "log_index": MATCH_LOG_INDEX, + "winning_slot": winning_slot, + "payout_numerators": payouts, + "source_log": log, + } + + def preload_binary_resolution(self, winning_slot: int, visible: bool = False) -> Dict[str, Any]: + if winning_slot < 0 or winning_slot > 1: + raise ValueError(f"winning_slot must be 0 or 1; got {winning_slot}") + payouts = [0, 0] + payouts[winning_slot] = 1 + result = self.add_condition( + condition_id=FED_BINARY_CONDITION_ID, + question_id=FED_BINARY_QUESTION_ID, + block_number=FED_BINARY_BLOCK, + log_index=FED_BINARY_LOG_INDEX, + tx_hash=FED_BINARY_TX_HASH, + payout_numerators=payouts, + replace_existing=True, + ) + head = FED_BINARY_BLOCK if visible else FED_BINARY_BLOCK - 1 + self.set_heads(head, head) + LOG.info( + "MockPolymarketPolygon: prepared binary winning_slot=%s payout=%s visible=%s", + winning_slot, + payouts, + visible, + ) + return result["source_log"] + + def release_binary_resolution(self, winning_slot: int) -> Dict[str, Any]: + if winning_slot < 0 or winning_slot > 1: + raise ValueError(f"winning_slot must be 0 or 1; got {winning_slot}") + payouts = [0, 0] + payouts[winning_slot] = 1 + log = self.preload_binary_resolution(winning_slot, visible=True) + return { + "market_id": FED_BINARY_MARKET_ID, + "condition_id": FED_BINARY_CONDITION_ID, + "question_id": FED_BINARY_QUESTION_ID, + "ctf": CTF_ADDRESS, + "oracle": UMA_ORACLE, + "tx_hash": FED_BINARY_TX_HASH, + "block": FED_BINARY_BLOCK, + "log_index": FED_BINARY_LOG_INDEX, + "winning_slot": winning_slot, + "payout_numerators": payouts, + "source_log": log, + } + + def handle_request(self, body: dict) -> dict: + method = body.get("method", "") + params = body.get("params", []) + req_id = body.get("id", 1) + + try: + if method not in ("mock_getRequests", "mock_clearRequests"): + with self._lock: + self._requests.append({"method": method, "params": params}) + + if method == "eth_getBlockByNumber": + result = self._handle_get_block_by_number(params) + elif method == "eth_getLogs": + result = self._handle_get_logs(params) + elif method == "eth_chainId": + result = _to_hex(self.chain_id) + elif method == "net_version": + result = str(self.chain_id) + elif method == "eth_blockNumber": + result = _to_hex(self.latest_block) + elif method == "mock_addCondition": + config = params[0] if params else {} + result = self.add_condition( + condition_id=config["conditionId"], + question_id=config["questionId"], + block_number=self._parse_block_tag(config["blockNumber"]), + log_index=self._parse_block_tag(config["logIndex"]), + payout_numerators=[int(value) for value in config["payoutNumerators"]], + tx_hash=config.get("txHash"), + removed=bool(config.get("removed", False)), + replace_existing=bool(config.get("replaceExisting", False)), + ) + elif method == "mock_setHeads": + latest = self._parse_block_tag(params[0]) + finalized = self._parse_block_tag(params[1]) if len(params) > 1 else latest + result = self.set_heads(latest, finalized) + elif method == "mock_getRequests": + result = self.requests + elif method == "mock_clearRequests": + self.clear_requests() + result = True + elif method == "mock_setWinningSlot": + winning_slot = params[0] if params else 1 + if isinstance(winning_slot, str): + winning_slot = int(winning_slot, 16) if winning_slot.startswith("0x") else int(winning_slot) + result = self.release_match_resolution(int(winning_slot)) + elif method == "mock_setBinaryWinningSlot": + winning_slot = params[0] if params else 0 + if isinstance(winning_slot, str): + winning_slot = int(winning_slot, 16) if winning_slot.startswith("0x") else int(winning_slot) + result = self.release_binary_resolution(int(winning_slot)) + else: + LOG.debug("MockPolymarketPolygon: unsupported method '%s'", method) + result = None + return {"jsonrpc": "2.0", "id": req_id, "result": result} + except Exception as exc: + LOG.error("MockPolymarketPolygon: error handling %s: %s", method, exc) + return { + "jsonrpc": "2.0", + "id": req_id, + "error": {"code": -32603, "message": str(exc)}, + } + + def _handle_get_block_by_number(self, params: list) -> Optional[dict]: + if not params: + return None + + block_tag = params[0] + if block_tag == "finalized": + block_num = self.finalized_block + elif block_tag in ("latest", "safe", "pending"): + block_num = self.latest_block + elif block_tag == "earliest": + block_num = 0 + elif isinstance(block_tag, str) and block_tag.startswith("0x"): + block_num = int(block_tag, 16) + else: + block_num = int(block_tag) + + if block_num > self.latest_block: + return None + + return { + "number": _to_hex(block_num), + "hash": _fake_hash(block_num + 0x100), + "parentHash": _fake_hash(block_num + 0x0FF), + "timestamp": _to_hex(1_700_000_000 + block_num), + "gasLimit": _to_hex(100_000_000), + "gasUsed": "0x0", + "miner": "0x" + "00" * 20, + "difficulty": "0x0", + "totalDifficulty": "0x0", + "size": "0x100", + "nonce": "0x0000000000000000", + "extraData": "0x", + "logsBloom": "0x" + "00" * 256, + "transactionsRoot": "0x" + "00" * 32, + "stateRoot": "0x" + "00" * 32, + "receiptsRoot": "0x" + "00" * 32, + "sha3Uncles": "0x" + "00" * 32, + "uncles": [], + "transactions": [], + "baseFeePerGas": "0x0", + "mixHash": "0x" + "00" * 32, + } + + def _handle_get_logs(self, params: list) -> list: + if not params: + return [] + filter_obj = params[0] + from_block = self._parse_block_tag(filter_obj.get("fromBlock", "0x0")) + to_block = min( + self._parse_block_tag(filter_obj.get("toBlock", _to_hex(self.latest_block))), + self.latest_block, + ) + filter_address = filter_obj.get("address", "").lower() + filter_topics = filter_obj.get("topics", []) + + results = [] + with self._lock: + for block_num in range(from_block, to_block + 1): + for log in self._logs.get(block_num, []): + if filter_address and log["address"] != filter_address: + continue + if not self._topics_match(log["topics"], filter_topics): + continue + results.append(log) + return results + + def _parse_block_tag(self, tag) -> int: + if isinstance(tag, int): + return tag + if tag == "finalized": + return self.finalized_block + if tag in ("latest", "safe", "pending"): + return self.latest_block + if tag == "earliest": + return 0 + if isinstance(tag, str) and tag.startswith("0x"): + return int(tag, 16) + return int(tag) + + @staticmethod + def _topics_match(log_topics: list, filter_topics: list) -> bool: + for idx, filter_topic in enumerate(filter_topics): + if filter_topic is None: + continue + if idx >= len(log_topics): + return False + if isinstance(filter_topic, list): + allowed = [topic.lower() for topic in filter_topic] + if log_topics[idx].lower() not in allowed: + return False + elif log_topics[idx].lower() != filter_topic.lower(): + return False + return True + + def start(self) -> None: + if self.is_running: + self.stop() + + mock = self + + class Handler(BaseHTTPRequestHandler): + def do_POST(self): + content_len = int(self.headers.get("Content-Length", 0)) + body_bytes = self.rfile.read(content_len) + try: + body = json.loads(body_bytes) + except json.JSONDecodeError: + self.send_error(400, "Invalid JSON") + return + + if isinstance(body, list): + response_body = json.dumps([mock.handle_request(req) for req in body]) + else: + response_body = json.dumps(mock.handle_request(body)) + + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(response_body.encode()) + + def log_message(self, fmt, *args): + pass + + self._server = HTTPServer(("127.0.0.1", self.port), Handler) + self.port = self._server.server_port + self._thread = threading.Thread(target=self._server.serve_forever, daemon=True) + self._thread.start() + + import socket + + deadline = time.time() + 5 + while time.time() < deadline: + try: + with socket.create_connection(("127.0.0.1", self.port), timeout=1): + break + except (ConnectionRefusedError, OSError): + time.sleep(0.1) + + LOG.info("MockPolymarketPolygon running at %s", self.rpc_url) + + def stop(self) -> None: + server = self._server + thread = self._thread + if server is not None: + LOG.info("MockPolymarketPolygon: shutting down") + self._server = None + self._thread = None + server.shutdown() + server.server_close() + if thread is not None: + thread.join(timeout=1) diff --git a/gravity_e2e/gravity_e2e/utils/oracle_test_support.py b/gravity_e2e/gravity_e2e/utils/oracle_test_support.py new file mode 100644 index 000000000..aa6bfe02f --- /dev/null +++ b/gravity_e2e/gravity_e2e/utils/oracle_test_support.py @@ -0,0 +1,504 @@ +"""Shared contract, governance, and price-feed helpers for oracle E2E suites.""" + +import asyncio +from contextlib import nullcontext +import json +import os +import shutil +import subprocess +import time +from pathlib import Path +from typing import Optional + +import pytest +from eth_abi import encode +from eth_account import Account +from web3 import Web3 + +from gravity_e2e.utils.mock_binance_index import ( + BUCKET_START_MS, + DECIMALS, + INTERVAL_MS, + MOCK_BINANCE_PORT, + format_price, + mock_binance_index_kline_server, +) + +try: + import tomllib +except ImportError: + import tomli as tomllib + + +NATIVE_ORACLE_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F4000" +) +ORACLE_TASK_CONFIG_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F1009" +) +GOVERNANCE_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F3000" +) +STAKING_ADDRESS = Web3.to_checksum_address( + "0x00000000000000000000000000000001625F2000" +) + +FAUCET_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +FAUCET_ADDR = Web3.to_checksum_address("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") + +SOURCE_TYPE_PRICE_FEED = 3 +TASK_PRICE_FEED = Web3.keccak(text="price_feed") +NVDA_FEED_ID = 1001 +TSLA_FEED_ID = 1002 +TARGET_DELIVERY_NONCE = 3 +EXPECTED_NVDA_PRICE = 19_612_645_000 +EXPECTED_TSLA_PRICE = 40_117_545_000 +DEFAULT_LIVE_BINANCE_BASE_URL = "https://fapi.binance.com" +DEFAULT_BINANCE_GRACE_MS = 120_000 +MODE_MOCK = "mock" +MODE_LIVE = "live" + +ORACLE_DELIVERED_TOPIC0 = Web3.keccak( + text="OracleDelivered(uint32,uint256,uint128,uint128,bytes32)" +).hex() +MARKET_CREATED_TOPIC0 = Web3.keccak(text="MarketCreated(uint256,bytes32,uint256)") +PROPOSAL_CREATED_TOPIC0 = Web3.keccak( + text="ProposalCreated(uint64,address,address,bytes32,string)" +) + +SEL_OWNER = Web3.keccak(text="owner()")[:4] +SEL_ADD_EXECUTOR = Web3.keccak(text="addExecutor(address)")[:4] +SEL_IS_EXECUTOR = Web3.keccak(text="isExecutor(address)")[:4] +SEL_GET_POOL = Web3.keccak(text="getPool(uint256)")[:4] +SEL_GET_POOL_VOTER = Web3.keccak(text="getPoolVoter(address)")[:4] +SEL_GET_POOL_VOTING_POWER_NOW = Web3.keccak(text="getPoolVotingPowerNow(address)")[:4] +SEL_CREATE_PROPOSAL = Web3.keccak(text="createProposal(address,address[],bytes[],string)")[:4] +SEL_VOTE = Web3.keccak(text="vote(address,uint64,uint128,bool)")[:4] +SEL_RESOLVE = Web3.keccak(text="resolve(uint64)")[:4] +SEL_EXECUTE = Web3.keccak(text="execute(uint64,address[],bytes[])")[:4] +SEL_GET_PROPOSAL_STATE = Web3.keccak(text="getProposalState(uint64)")[:4] + +MAX_UINT128 = (1 << 128) - 1 +PROPOSAL_STATE_SUCCEEDED = 1 +VOTING_DURATION_SECS = 5 +STAKE_UNIT = 10**18 + + +def topic(value: int) -> str: + return "0x" + value.to_bytes(32, "big").hex() + + +def topic_hex(value) -> str: + result = value.hex() + return result if result.startswith("0x") else f"0x{result}" + + +def as_bytes(data) -> bytes: + if isinstance(data, bytes): + return data + if isinstance(data, str): + return bytes.fromhex(data[2:] if data.startswith("0x") else data) + return bytes(data) + + +def function_calldata(fn) -> bytes: + return as_bytes(fn._encode_transaction_data()) + + +def send_tx( + w3: Web3, + to: Optional[str], + data, + sender_key: str, + gas: int = 1_000_000, + value: int = 0, +) -> dict: + sender = Account.from_key(sender_key) + tx = { + "data": data, + "gas": gas, + "gasPrice": w3.eth.gas_price, + "nonce": w3.eth.get_transaction_count(sender.address), + "chainId": w3.eth.chain_id, + "value": value, + } + if to is not None: + tx["to"] = to + signed = sender.sign_transaction(tx) + tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction) + receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=90) + assert receipt["status"] == 1, f"transaction failed: {receipt}" + return receipt + + +def send_contract_tx(w3: Web3, contract, fn, sender_key: str, gas: int = 1_000_000) -> dict: + return send_tx(w3, contract.address, function_calldata(fn), sender_key, gas=gas) + + +def artifact_file(out_dir: Path, source_name: str, contract_name: str) -> Path: + direct = out_dir / source_name / f"{contract_name}.json" + if direct.exists(): + return direct + raise FileNotFoundError( + f"missing {source_name}/{contract_name}.json under contracts out dir" + ) + + +def contracts_repo_from_genesis(suite_dir: Path) -> Path | None: + data = tomllib.loads((suite_dir / "genesis.toml").read_text()) + rel = data.get("dependencies", {}).get("genesis_contracts", {}).get("path") + sdk_root = suite_dir.parents[2] + checkout_name = ( + "gravity_chain_core_contracts_local" + if rel + else "gravity_chain_core_contracts" + ) + generated_checkout = sdk_root / "external" / checkout_name + if generated_checkout.is_dir(): + return generated_checkout + return (suite_dir / rel).resolve() if rel else None + + +def required_contract_sources( + contracts_repo: Path, required: list[tuple[str, str]] +) -> list[Path]: + source_names = dict.fromkeys(source for source, _ in required) + source_roots = [contracts_repo / name for name in ("src", "test", "script")] + paths = [] + + for source_name in source_names: + matches = [ + path + for root in source_roots + if root.is_dir() + for path in root.rglob(source_name) + ] + if len(matches) != 1: + relative_matches = [str(path.relative_to(contracts_repo)) for path in matches] + raise FileNotFoundError( + f"expected exactly one source file named {source_name}; " + f"found {relative_matches}" + ) + paths.append(matches[0].relative_to(contracts_repo)) + + return paths + + +def ensure_contracts_out( + suite_dir: Path, + required: list[tuple[str, str]], + error_label: str = "Oracle", +) -> Path: + sdk_root = suite_dir.parents[2] + contracts_repo = contracts_repo_from_genesis(suite_dir) + if contracts_repo is not None and shutil.which("forge"): + sources = required_contract_sources(contracts_repo, required) + subprocess.run( + ["forge", "build", *(str(source) for source in sources)], + cwd=contracts_repo, + check=True, + ) + out_dir = contracts_repo / "out" + for source, name in required: + artifact_file(out_dir, source, name) + return out_dir + + candidates = [] + candidates.extend( + [ + sdk_root / "external" / "gravity_chain_core_contracts_local" / "out", + sdk_root / "external" / "gravity_chain_core_contracts" / "out", + ] + ) + + for out_dir in candidates: + if not out_dir.exists(): + continue + try: + for source, name in required: + artifact_file(out_dir, source, name) + return out_dir + except FileNotFoundError: + pass + + raise FileNotFoundError( + f"{error_label} contract artifacts not found; run forge build in contracts repo" + ) + + +def load_artifact(out_dir: Path, source_name: str, contract_name: str) -> dict: + return json.loads(artifact_file(out_dir, source_name, contract_name).read_text()) + + +def deploy_contract( + w3: Web3, + artifact: dict, + sender_key: str, + args=None, + gas: int = 8_000_000, +): + sender = Account.from_key(sender_key) + factory = w3.eth.contract(abi=artifact["abi"], bytecode=_bytecode(artifact)) + tx = factory.constructor(*(args or [])).build_transaction( + { + "from": sender.address, + "gas": gas, + "gasPrice": w3.eth.gas_price, + "nonce": w3.eth.get_transaction_count(sender.address), + "chainId": w3.eth.chain_id, + } + ) + signed = sender.sign_transaction(tx) + tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction) + receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120) + assert receipt["status"] == 1, f"deploy failed: {receipt}" + return w3.eth.contract(address=receipt["contractAddress"], abi=artifact["abi"]) + + +def _bytecode(artifact: dict) -> str: + bytecode = artifact["bytecode"] + if isinstance(bytecode, dict): + bytecode = bytecode["object"] + return bytecode if bytecode.startswith("0x") else f"0x{bytecode}" + + +def _call(w3: Web3, to: str, data: bytes) -> bytes: + return w3.eth.call({"to": to, "data": data}) + + +def _decode_address(raw: bytes) -> str: + return Web3.to_checksum_address("0x" + raw[-20:].hex()) + + +def _ensure_faucet_executor(w3: Web3): + owner = _decode_address(_call(w3, GOVERNANCE_ADDRESS, SEL_OWNER)) + assert owner == FAUCET_ADDR, f"Governance.owner expected faucet, got {owner}" + is_executor = bool( + int.from_bytes( + _call(w3, GOVERNANCE_ADDRESS, SEL_IS_EXECUTOR + encode(["address"], [FAUCET_ADDR])), + "big", + ) + ) + if not is_executor: + send_tx( + w3, + GOVERNANCE_ADDRESS, + SEL_ADD_EXECUTOR + encode(["address"], [FAUCET_ADDR]), + FAUCET_KEY, + ) + + +async def execute_governance_proposal( + w3: Web3, + pool_addr: str, + targets: list[str], + datas: list[bytes], + description: str, + gas: int = 5_000_000, +) -> dict: + _ensure_faucet_executor(w3) + create_data = SEL_CREATE_PROPOSAL + encode( + ["address", "address[]", "bytes[]", "string"], + [pool_addr, targets, datas, description], + ) + try: + w3.eth.call({"from": FAUCET_ADDR, "to": GOVERNANCE_ADDRESS, "data": create_data, "gas": gas}) + except Exception as exc: + pytest.fail(f"createProposal would revert: {exc!r}") + receipt = send_tx(w3, GOVERNANCE_ADDRESS, create_data, FAUCET_KEY, gas=gas) + + proposal_id = next( + ( + int.from_bytes(log["topics"][1], "big") + for log in receipt["logs"] + if log["topics"] and bytes(log["topics"][0]) == bytes(PROPOSAL_CREATED_TOPIC0) + ), + None, + ) + assert proposal_id is not None, "ProposalCreated event not found" + + vote_data = SEL_VOTE + encode( + ["address", "uint64", "uint128", "bool"], + [pool_addr, proposal_id, MAX_UINT128, True], + ) + send_tx(w3, GOVERNANCE_ADDRESS, vote_data, FAUCET_KEY) + vote_block = w3.eth.block_number + + await asyncio.sleep(VOTING_DURATION_SECS + 2) + deadline = time.monotonic() + 30 + while time.monotonic() < deadline and w3.eth.block_number < vote_block + 3: + await asyncio.sleep(1) + assert w3.eth.block_number >= vote_block + 3, "chain did not advance past vote block" + + resolve_data = SEL_RESOLVE + encode(["uint64"], [proposal_id]) + send_tx(w3, GOVERNANCE_ADDRESS, resolve_data, FAUCET_KEY) + state = int.from_bytes( + _call(w3, GOVERNANCE_ADDRESS, SEL_GET_PROPOSAL_STATE + encode(["uint64"], [proposal_id])), + "big", + ) + assert state == PROPOSAL_STATE_SUCCEEDED, f"proposal state is not SUCCEEDED: {state}" + + execute_data = SEL_EXECUTE + encode( + ["uint64", "address[]", "bytes[]"], [proposal_id, targets, datas] + ) + return send_tx(w3, GOVERNANCE_ADDRESS, execute_data, FAUCET_KEY, gas=gas) + + +def pool0_voted_by_faucet(w3: Web3) -> str: + pool_addr = _decode_address(_call(w3, STAKING_ADDRESS, SEL_GET_POOL + encode(["uint256"], [0]))) + voter_addr = _decode_address( + _call(w3, STAKING_ADDRESS, SEL_GET_POOL_VOTER + encode(["address"], [pool_addr])) + ) + assert voter_addr == FAUCET_ADDR, f"pool[0].voter expected faucet, got {voter_addr}" + voting_power = int.from_bytes( + _call( + w3, + STAKING_ADDRESS, + SEL_GET_POOL_VOTING_POWER_NOW + encode(["address"], [pool_addr]), + ), + "big", + ) + assert voting_power >= STAKE_UNIT, f"pool[0] voting power too low: {voting_power}" + return pool_addr + + +def market_id_from_receipt(receipt: dict) -> int: + for log in receipt["logs"]: + if log["topics"] and bytes(log["topics"][0]) == bytes(MARKET_CREATED_TOPIC0): + return int.from_bytes(log["topics"][1], "big") + raise AssertionError("MarketCreated event not found") + + +async def wait_for_chain_time(w3: Web3, target_ts: int, timeout: Optional[int] = None): + latest = w3.eth.get_block("latest") + if timeout is None: + timeout = max(30, target_ts - latest["timestamp"] + 30) + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + latest = w3.eth.get_block("latest") + if latest["timestamp"] >= target_ts: + return latest + await asyncio.sleep(1) + raise TimeoutError(f"chain timestamp did not reach {target_ts}") + + +async def poll_oracle_delivered( + w3: Web3, + source_type: int, + source_id: int, + timeout: int = 180, +): + deadline = time.monotonic() + timeout + filter_params = { + "fromBlock": 0, + "toBlock": "latest", + "address": NATIVE_ORACLE_ADDRESS, + "topics": [ORACLE_DELIVERED_TOPIC0, topic(source_type), topic(source_id)], + } + while time.monotonic() < deadline: + logs = await asyncio.to_thread(w3.eth.get_logs, filter_params) + if logs: + return logs + await asyncio.sleep(2) + return [] + + +async def wait_for_source_progress( + native_oracle, + source_type: int, + source_id: int, + target_nonce: int, + timeout: int = 240, +): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + progress = tuple( + native_oracle.functions.getSourceProgress(source_type, source_id).call() + ) + if progress[0] >= target_nonce: + return progress + await asyncio.sleep(2) + raise TimeoutError( + f"source progress for {source_type}:{source_id} did not reach nonce {target_nonce}" + ) + + +async def wait_for_latest_price( + native_oracle, + resolver, + feed_id: int, + target_nonce: int, + timeout: int = 240, +): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + progress = tuple( + native_oracle.functions.getSourceProgress( + SOURCE_TYPE_PRICE_FEED, feed_id + ).call() + ) + latest = tuple(resolver.functions.latestPrice(feed_id).call()) + if ( + progress[0] >= target_nonce + and latest[0] + and latest[2] == progress[1] + ): + return progress, latest + await asyncio.sleep(2) + raise TimeoutError( + f"latestPrice({feed_id}) did not match source progress at nonce {target_nonce}" + ) + + +def assert_price_round(latest, expected_price: int, round_id: int, resolved_at: int): + assert latest[0] is True + assert latest[1] == round_id + assert latest[2] == resolved_at + assert latest[3] == DECIMALS + assert latest[4] == expected_price + + +def price_feed_mode() -> str: + return os.environ.get("BINANCE_PRICE_FEED_MODE", MODE_MOCK).strip().lower() + + +def is_live_mode() -> bool: + return price_feed_mode() == MODE_LIVE + + +def binance_base_url() -> str: + if is_live_mode(): + return os.environ.get("BINANCE_PRICE_FEED_BASE_URL", DEFAULT_LIVE_BINANCE_BASE_URL) + return f"http://127.0.0.1:{MOCK_BINANCE_PORT}" + + +def binance_grace_ms() -> int: + return int(os.environ.get("BINANCE_PRICE_FEED_GRACE_MS", str(DEFAULT_BINANCE_GRACE_MS))) + + +def round_start_ms(first_bucket_start_ms: int, delivery_nonce: int) -> int: + return first_bucket_start_ms + (delivery_nonce - 1) * INTERVAL_MS + + +def round_id(first_bucket_start_ms: int, delivery_nonce: int) -> int: + return round_start_ms(first_bucket_start_ms, delivery_nonce) // INTERVAL_MS + + +def round_end_ms(first_bucket_start_ms: int, delivery_nonce: int) -> int: + return round_start_ms(first_bucket_start_ms, delivery_nonce) + INTERVAL_MS - 1 + + +def price_feed_uri(feed_id: int, pair: str, bucket_start_ms: int) -> str: + return ( + f"gravity://3/{feed_id}/price_feed?" + f"provider=binance_index_kline_v1&pair={pair}&interval=1m&" + f"bucketStartMs={bucket_start_ms}&decimals=8&graceMs={binance_grace_ms()}" + ) + + +def server_context(): + if is_live_mode(): + return nullcontext(binance_base_url()) + if os.environ.get("BINANCE_PRICE_FEED_EXTERNAL_MOCK") == "1": + return nullcontext(f"http://127.0.0.1:{MOCK_BINANCE_PORT}") + return mock_binance_index_kline_server(MOCK_BINANCE_PORT) diff --git a/gravity_e2e/gravity_e2e/utils/test_mock_polymarket_polygon.py b/gravity_e2e/gravity_e2e/utils/test_mock_polymarket_polygon.py new file mode 100644 index 000000000..297f94bb4 --- /dev/null +++ b/gravity_e2e/gravity_e2e/utils/test_mock_polymarket_polygon.py @@ -0,0 +1,141 @@ +from gravity_e2e.utils.mock_polymarket_polygon import ( + CONDITION_RESOLUTION_TOPIC0, + CTF_ADDRESS, + DYNAMIC_BINARY_BLOCK, + DYNAMIC_BINARY_CONDITION_ID, + DYNAMIC_BINARY_LOG_INDEX, + DYNAMIC_BINARY_QUESTION_ID, + FED_BINARY_BLOCK, + FED_BINARY_CONDITION_ID, + FED_BINARY_LOG_INDEX, + FED_BINARY_QUESTION_ID, + MockPolymarketPolygon, +) + + +def _condition_filter(condition_id: str, to_block: str = "latest") -> dict: + return { + "fromBlock": hex(FED_BINARY_BLOCK - 10), + "toBlock": to_block, + "address": CTF_ADDRESS, + "topics": [CONDITION_RESOLUTION_TOPIC0, condition_id], + } + + +def test_latest_and_finalized_heads_are_independent(): + mock = MockPolymarketPolygon(port=0) + mock.set_heads(FED_BINARY_BLOCK, FED_BINARY_BLOCK - 1) + + latest = mock.handle_request( + {"jsonrpc": "2.0", "id": 1, "method": "eth_getBlockByNumber", "params": ["latest", False]} + ) + finalized = mock.handle_request( + { + "jsonrpc": "2.0", + "id": 2, + "method": "eth_getBlockByNumber", + "params": ["finalized", False], + } + ) + + assert latest["result"]["number"] == hex(FED_BINARY_BLOCK) + assert finalized["result"]["number"] == hex(FED_BINARY_BLOCK - 1) + + +def test_conditions_in_the_same_block_are_appended_and_filtered(): + mock = MockPolymarketPolygon(port=0) + mock.add_condition( + condition_id=FED_BINARY_CONDITION_ID, + question_id=FED_BINARY_QUESTION_ID, + block_number=FED_BINARY_BLOCK, + log_index=FED_BINARY_LOG_INDEX, + payout_numerators=[1, 0], + ) + mock.add_condition( + condition_id=DYNAMIC_BINARY_CONDITION_ID, + question_id=DYNAMIC_BINARY_QUESTION_ID, + block_number=FED_BINARY_BLOCK, + log_index=DYNAMIC_BINARY_LOG_INDEX, + payout_numerators=[0, 1], + ) + mock.set_heads(FED_BINARY_BLOCK) + + first = mock.handle_request( + { + "jsonrpc": "2.0", + "id": 1, + "method": "eth_getLogs", + "params": [_condition_filter(FED_BINARY_CONDITION_ID)], + } + ) + second = mock.handle_request( + { + "jsonrpc": "2.0", + "id": 2, + "method": "eth_getLogs", + "params": [_condition_filter(DYNAMIC_BINARY_CONDITION_ID)], + } + ) + + assert [log["topics"][1] for log in first["result"]] == [ + FED_BINARY_CONDITION_ID + ] + assert [log["topics"][1] for log in second["result"]] == [ + DYNAMIC_BINARY_CONDITION_ID + ] + + +def test_generic_control_rpc_adds_condition_and_records_scan_range(): + mock = MockPolymarketPolygon(port=0) + added = mock.handle_request( + { + "jsonrpc": "2.0", + "id": 1, + "method": "mock_addCondition", + "params": [ + { + "conditionId": DYNAMIC_BINARY_CONDITION_ID, + "questionId": DYNAMIC_BINARY_QUESTION_ID, + "blockNumber": hex(DYNAMIC_BINARY_BLOCK), + "logIndex": hex(DYNAMIC_BINARY_LOG_INDEX), + "payoutNumerators": [0, 1], + } + ], + } + ) + mock.handle_request( + { + "jsonrpc": "2.0", + "id": 2, + "method": "mock_setHeads", + "params": [hex(DYNAMIC_BINARY_BLOCK), hex(DYNAMIC_BINARY_BLOCK)], + } + ) + filter_params = _condition_filter( + DYNAMIC_BINARY_CONDITION_ID, hex(DYNAMIC_BINARY_BLOCK) + ) + logs = mock.handle_request( + { + "jsonrpc": "2.0", + "id": 3, + "method": "eth_getLogs", + "params": [filter_params], + } + ) + + assert added["result"]["condition_id"] == DYNAMIC_BINARY_CONDITION_ID + assert len(logs["result"]) == 1 + assert any( + request["method"] == "eth_getLogs" and request["params"] == [filter_params] + for request in mock.requests + ) + + +def test_releasing_existing_binary_fixture_remains_backward_compatible(): + mock = MockPolymarketPolygon(port=0) + release = mock.release_binary_resolution(1) + + assert mock.latest_block == FED_BINARY_BLOCK + assert mock.finalized_block == FED_BINARY_BLOCK + assert release["payout_numerators"] == [0, 1] + assert len(mock._logs[FED_BINARY_BLOCK]) == 1 diff --git a/gravity_e2e/gravity_e2e/utils/test_oracle_test_support.py b/gravity_e2e/gravity_e2e/utils/test_oracle_test_support.py new file mode 100644 index 000000000..44cf2f52c --- /dev/null +++ b/gravity_e2e/gravity_e2e/utils/test_oracle_test_support.py @@ -0,0 +1,37 @@ +from gravity_e2e.utils import oracle_test_support as support + + +def _suite_dir(tmp_path): + suite_dir = tmp_path / "gravity_e2e" / "cluster_test_cases" / "oracle_demo" + suite_dir.mkdir(parents=True) + return suite_dir + + +def test_contracts_repo_prefers_generated_local_checkout(tmp_path): + suite_dir = _suite_dir(tmp_path) + source_repo = tmp_path / "contracts_source" + source_repo.mkdir() + (suite_dir / "genesis.toml").write_text( + "[dependencies.genesis_contracts]\n" + f'path = "{source_repo}"\n' + 'ref = "deadbeef"\n' + ) + generated_checkout = ( + tmp_path / "external" / "gravity_chain_core_contracts_local" + ) + generated_checkout.mkdir(parents=True) + + assert support.contracts_repo_from_genesis(suite_dir) == generated_checkout + + +def test_contracts_repo_falls_back_to_configured_source(tmp_path): + suite_dir = _suite_dir(tmp_path) + source_repo = tmp_path / "contracts_source" + source_repo.mkdir() + (suite_dir / "genesis.toml").write_text( + "[dependencies.genesis_contracts]\n" + f'path = "{source_repo}"\n' + 'ref = "deadbeef"\n' + ) + + assert support.contracts_repo_from_genesis(suite_dir) == source_repo diff --git a/gravity_e2e/runner.py b/gravity_e2e/runner.py index a20dbeb5d..d876a6270 100644 --- a/gravity_e2e/runner.py +++ b/gravity_e2e/runner.py @@ -109,6 +109,12 @@ def init_faucet_if_needed(test_dir: Path, cluster_config_path: Path, env: dict): def cleanup_cluster(): """Kill any running gravity_node processes.""" + if os.environ.get("GRAVITY_E2E_SKIP_GLOBAL_PKILL") == "1": + logger.warning( + "Skipping global gravity_node cleanup because " + "GRAVITY_E2E_SKIP_GLOBAL_PKILL=1" + ) + return logger.info("Cleaning up running nodes...") # This is a bit aggressive but necessary for clean slate in docker subprocess.run(["pkill", "-9", "gravity_node"], check=False) @@ -195,9 +201,11 @@ def verify_nodes_alive(cluster_config: Path, env: dict): def run_test_suite( test_dir: Path, no_cleanup: bool = False, + keep_running: bool = False, pytest_args: list = None, force_init: bool = False, resume: bool = False, + demo_config_out: Path | None = None, ): """ Run tests in a specific directory. @@ -216,6 +224,10 @@ def run_test_suite( env = os.environ.copy() ensure_local_no_proxy(env) env["GRAVITY_ARTIFACTS_DIR"] = str(suite_artifacts_dir) + if keep_running: + env["GRAVITY_DEMO_KEEP_RUNNING"] = "1" + if demo_config_out is not None: + env["GRAVITY_DEMO_CONFIG_OUT"] = str(demo_config_out.resolve()) # Set genesis config path if it exists if genesis_config.exists(): @@ -328,6 +340,10 @@ def run_test_suite( env[env_var] = str(tpl_path) logger.info(f"Using custom reth config template: {env_var}={tpl_path}") + if hooks and hasattr(hooks, "pre_deploy"): + logger.info(f"Running pre_deploy hook from {hooks_path}") + hooks.pre_deploy(test_dir, env, pytest_args or []) + run_command( ["bash", str(deploy_script), str(cluster_config)], cwd=CLUSTER_SCRIPTS_DIR, @@ -390,6 +406,13 @@ def run_test_suite( # 5. Teardown if resume: logger.info("♻️ Reuse-cluster mode: skipping teardown") + elif keep_running and success: + logger.warning("Demo keep-running mode enabled; cluster left running.") + logger.warning(f"Cluster config: {cluster_config}") + logger.warning( + "Stop it with: " + f"bash {CLUSTER_SCRIPTS_DIR / 'stop.sh'} --config {cluster_config}" + ) elif no_cleanup and not success: logger.warning( f"Test failed and --no-cleanup set. Cluster left running using config: {cluster_config}" @@ -411,7 +434,13 @@ def run_test_suite( # MockAnvil runs as a daemon thread in this process — it dies # when we exit anyway, but explicit cleanup is cleaner and # prevents the relayer from crashing on connection loss. - if not resume and hooks and hasattr(hooks, "post_stop"): + should_run_post_stop = ( + not resume + and not (keep_running and success) + and hooks + and hasattr(hooks, "post_stop") + ) + if should_run_post_stop: logger.info("Running post_stop hook...") try: hooks.post_stop(test_dir, env) @@ -426,6 +455,17 @@ def main(): action="store_true", help="Leave cluster running if tests fail (for debugging)", ) + parser.add_argument( + "--keep-running", + action="store_true", + help="Leave the cluster and demo helper processes running after a successful suite.", + ) + parser.add_argument( + "--demo-config-out", + type=Path, + default=None, + help="Path where a suite may write frontend-readable demo runtime config.", + ) parser.add_argument( "--force-init", action="store_true", @@ -437,9 +477,16 @@ def main(): help="Resume with existing cluster: skip cleanup/init/deploy/start/stop, " "only run pytest. Useful for re-running tests against an already deployed cluster.", ) - # Long-running suites excluded from CI by default. - # Run them explicitly: runner.py long_test - DEFAULT_EXCLUDES = ["long_test", "rolling_upgrade"] + # Long-running or public-network suites excluded from CI by default. + # Run them explicitly by suite name. + DEFAULT_EXCLUDES = [ + "long_test", + "rolling_upgrade", + "binance_price_feed_multivalidator", + "polymarket_live_dynamic_mirror", + "oracle_rolling_activation_live", + "oracle_live_soak", + ] parser.add_argument( "--exclude", @@ -519,9 +566,11 @@ def main(): run_test_suite( test_dir, no_cleanup=args.no_cleanup, + keep_running=args.keep_running, pytest_args=pytest_args, force_init=args.force_init, resume=args.resume, + demo_config_out=args.demo_config_out, ) except Exception: logger.exception(f"Suite {test_dir.name} failed with exception:")