diff --git a/.github/workflows/gnd-binary-build.yml b/.github/workflows/gnd-binary-build.yml index fd642606e69..237de3342b5 100644 --- a/.github/workflows/gnd-binary-build.yml +++ b/.github/workflows/gnd-binary-build.yml @@ -1,8 +1,14 @@ name: Build gnd Binaries on: + release: + types: [published] workflow_dispatch: inputs: + release_tag: + description: 'Existing release tag to upload binaries to and publish as on npm (e.g. v0.44.0). Leave empty to only build artifacts.' + type: string + default: '' dry_run: description: 'Dry-run npm publish (no actual publish)' type: boolean @@ -130,7 +136,7 @@ jobs: release: name: Create Release needs: build - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') || inputs.release_tag != '' runs-on: ubuntu-latest steps: - name: Checkout code @@ -153,10 +159,8 @@ jobs: - name: Upload Assets to Release run: | - # Extract version from ref (remove refs/tags/ prefix) - VERSION=${GITHUB_REF#refs/tags/} - - # Upload Linux x86_64 asset + VERSION="${{ inputs.release_tag != '' && inputs.release_tag || github.ref_name }}" + gh release upload $VERSION --clobber --repo $GITHUB_REPOSITORY \ artifacts/gnd-linux-x86_64/gnd-linux-x86_64.gz \ artifacts/gnd-linux-aarch64/gnd-linux-aarch64.gz \ @@ -169,7 +173,7 @@ jobs: publish-npm: name: Publish npm package for ${{ matrix.platform }} needs: release - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') || inputs.release_tag != '' runs-on: ubuntu-latest permissions: id-token: write @@ -212,7 +216,7 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - gh release download "${{ github.ref_name }}" \ + gh release download "${{ inputs.release_tag != '' && inputs.release_tag || github.ref_name }}" \ --repo "${{ github.repository }}" \ --pattern "${{ matrix.asset }}" \ --output ./binary-archive @@ -232,7 +236,7 @@ jobs: id: version shell: bash run: | - VERSION="${{ github.ref_name }}" + VERSION="${{ inputs.release_tag != '' && inputs.release_tag || github.ref_name }}" VERSION="${VERSION#v}" echo "version=${VERSION}" >> $GITHUB_OUTPUT # Prerelease versions (e.g. 0.42.2-dev.1) need an explicit --tag @@ -283,7 +287,7 @@ jobs: publish-npm-wrapper: name: Publish @graphprotocol/gnd wrapper needs: publish-npm - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') || inputs.release_tag != '' runs-on: ubuntu-latest permissions: id-token: write @@ -299,7 +303,7 @@ jobs: id: version shell: bash run: | - VERSION="${{ github.ref_name }}" + VERSION="${{ inputs.release_tag != '' && inputs.release_tag || github.ref_name }}" VERSION="${VERSION#v}" echo "version=${VERSION}" >> $GITHUB_OUTPUT if [[ "$VERSION" == *-* ]]; then diff --git a/CLAUDE.md b/CLAUDE.md index 4432890bfd8..b8ec983428b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -98,6 +98,9 @@ TEST_CASE=grafted just test-integration # (Optional) Use graph-cli instead of gnd for compatibility testing GRAPH_CLI=node_modules/.bin/graph just test-integration + +# Override ports if using different service ports (e.g., for local development) +POSTGRES_TEST_PORT=5432 ETHEREUM_TEST_PORT=8545 IPFS_TEST_PORT=5001 just test-integration ``` **⚠️ Test Verification Requirements:** @@ -111,6 +114,8 @@ GRAPH_CLI=node_modules/.bin/graph just test-integration - Integration tests take significant time (several minutes) - Tests automatically reset the database between runs - Logs are written to `tests/integration-tests/graph-node.log` +- **If a test hangs for >10 minutes**, it's likely stuck - kill with `pkill -9 integration_tests` and check logs +- CI uses the default ports (3011, 3021, 3001) - local development can override with environment variables ### Code Quality diff --git a/Cargo.lock b/Cargo.lock index 7b6822ecc95..5e204e6ad4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.25.1" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +checksum = "59317f77929f0e679d39364702289274de2f0f0b22cbf50b2b8cff2169a0b27a" dependencies = [ "gimli", ] @@ -33,7 +33,7 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "const-random", "getrandom 0.3.1", "once_cell", @@ -73,9 +73,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4973038846323e4e69a433916522195dce2947770076c03078fc21c80ea0f1c4" +checksum = "5e1e915a830ea2ee123c9d3886bfec3302a7ddcd73a973ab165ed45aca2e42c3" dependencies = [ "alloy-consensus", "alloy-contract", @@ -111,9 +111,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728" +checksum = "83447eeb17816e172f1dfc0db1f9dc0b7c5d069bd1f7cecbecceb382bf931015" dependencies = [ "alloy-eips", "alloy-primitives", @@ -129,8 +129,8 @@ dependencies = [ "either", "k256", "once_cell", - "rand 0.8.5", - "secp256k1", + "rand 0.8.6", + "secp256k1 0.30.0", "serde", "serde_json", "serde_with", @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434" +checksum = "5406343e306856dc2be762700e98a16904de45dee14a07f233e742ce68daff2f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca63b7125a981415898ffe2a2a696c83696c9c6bdb1671c8a912946bbd8e49e7" +checksum = "3ae8b60d71b92824e095b4003ff01fd2bc923017b7568997c5f459240e83499c" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -173,13 +173,14 @@ dependencies = [ "futures-util", "serde_json", "thiserror 2.0.18", + "tracing", ] [[package]] name = "alloy-core" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a651e1d9e50e6d0a78bd23cd08facb70459a94501c4036c7799a093e569a310" +checksum = "62ddde5968de6044d67af107ad835bc0069a7ca245870b94c5958a7d8712b184" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -190,9 +191,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d48a9101f4a67c22fae57489f1ddf3057b8ab4a368d8eac3be088b6e9d9c9d9" +checksum = "a475bb02d9cef2dbb99065c1664ab3fe1f9352e21d6d5ed3f02cdbfc06ed1abc" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -203,7 +204,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] @@ -216,7 +217,7 @@ dependencies = [ "alloy-rlp", "arbitrary", "crc", - "rand 0.8.5", + "rand 0.8.6", "serde", "thiserror 2.0.18", ] @@ -231,7 +232,7 @@ dependencies = [ "alloy-rlp", "arbitrary", "borsh", - "rand 0.8.5", + "rand 0.8.6", "serde", ] @@ -246,7 +247,7 @@ dependencies = [ "arbitrary", "borsh", "k256", - "rand 0.8.5", + "rand 0.8.6", "serde", "thiserror 2.0.18", ] @@ -266,9 +267,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8" +checksum = "0dca4c89ace90684b4b77366d00631ed498c9af962079af2a5dbc593a0618a77" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -286,14 +287,13 @@ dependencies = [ "serde", "serde_with", "sha2 0.10.9", - "thiserror 2.0.18", ] [[package]] name = "alloy-genesis" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9cf3b99f46615fbf7dc1add0c96553abb7bf88fc9ec70dfbe7ad0b47ba7fe8" +checksum = "ab0e0fe9e6d1120ad7bb9254c3fc2b9bc80a8df42a033fb626be6559c13d5153" dependencies = [ "alloy-eips", "alloy-primitives", @@ -306,9 +306,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9914c147bb9b25f440eca68a31dc29f5c22298bfa7754aa802965695384122b0" +checksum = "7c36c9d7f9021601b04bfef14a4b64849f6d73116a4e91e071d7fbfe10247901" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -318,13 +318,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff42cd777eea61f370c0b10f2648a1c81e0b783066cd7269228aa993afd487f7" +checksum = "ec0a82e56b1843bce483942d54fcadea92e676f1bde162e93c7d3b621fabc4e1" dependencies = [ "alloy-primitives", "alloy-sol-types", - "http 1.4.0", + "http 1.4.2", "serde", "serde_json", "thiserror 2.0.18", @@ -333,9 +333,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbca04f9b410fdc51aaaf88433cbac761213905a65fe832058bcf6690585762" +checksum = "a7db7b095b0b1db1d18ce7e91dcd2e82007f2d52bfb8125e6b64633a74a06bc3" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -359,9 +359,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04" +checksum = "cd28d9bfd11729037d194f2b1d43db8642eb3f342032691f4ca96bb745479c3c" dependencies = [ "alloy-consensus", "alloy-eips", @@ -372,39 +372,39 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db950a29746be9e2f2c6288c8bd7a6202a81f999ce109a2933d2379970ec0fa" +checksum = "4885c1409b6936c4898e646ef58baf6ec54edaf6d8179f79df805a7b85b7cf3e" dependencies = [ "alloy-rlp", "arbitrary", "bytes", - "cfg-if 1.0.0", + "cfg-if", "const-hex", "derive_more", "foldhash 0.2.0", - "hashbrown 0.16.1", - "indexmap 2.11.4", + "hashbrown 0.17.0", + "indexmap 2.14.0", "itoa", "k256", "keccak-asm", "paste", "proptest", - "proptest-derive 0.6.0", - "rand 0.9.2", + "proptest-derive 0.8.0", + "rand 0.9.3", "rapidhash", "ruint", - "rustc-hash 2.1.1", + "rustc-hash", + "secp256k1 0.31.1", "serde", "sha3", - "tiny-keccak 2.0.2", ] [[package]] name = "alloy-provider" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d181c8cc7cf4805d7e589bf4074d56d55064fa1a979f005a45a62b047616d870" +checksum = "8955ab30418343de57b356de2ea60200f9fb8016a7ea3bc7f5c6176f01a8b1cf" dependencies = [ "alloy-chains", "alloy-consensus", @@ -436,7 +436,7 @@ dependencies = [ "lru", "parking_lot", "pin-project", - "reqwest", + "reqwest 0.13.2", "serde", "serde_json", "thiserror 2.0.18", @@ -448,9 +448,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8bd82953194dec221aa4cbbbb0b1e2df46066fe9d0333ac25b43a311e122d13" +checksum = "7cd85cfea1fa8ebd20d3475e961fe3a3624c0eb4659ea137715c0c83c8aeaff0" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -475,7 +475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ "alloy-rlp-derive", - "arrayvec 0.7.4", + "arrayvec", "bytes", ] @@ -487,14 +487,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "alloy-rpc-client" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2792758a93ae32a32e9047c843d536e1448044f78422d71bf7d7c05149e103f" +checksum = "24f461f091dc8f657e73b5dea18fd63d5c7049720cd252f1eade4a7ebed6a7e1" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -505,7 +505,7 @@ dependencies = [ "alloy-transport-ws", "futures 0.3.31", "pin-project", - "reqwest", + "reqwest 0.13.2", "serde", "serde_json", "tokio", @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bdcbf9dfd5eea8bfeb078b1d906da8cd3a39c4d4dbe7a628025648e323611f6" +checksum = "052c031d1f7c5611997056bbcb8814e5cbf20f7efeee8c3de690555172038cf2" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -535,9 +535,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a3100b76987c1b1dc81f3abe592b7edc29e92b1242067a69d65e0030b35cf9" +checksum = "2ff111a54268dc0bbd3b17f98571a7e27cc661dc081ad2999d91888647eb2e11" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -547,22 +547,27 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd720b63f82b457610f2eaaf1f32edf44efffe03ae25d537632e7d23e7929e1a" +checksum = "0a6561ed4759c974d9c144500a59e3fb8c1d87327a12900d5ce455c0cae6dcb6" dependencies = [ "alloy-consensus-any", + "alloy-network-primitives", + "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", + "serde", + "serde_json", ] [[package]] name = "alloy-rpc-types-debug" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b21e1ad18ff1b31ff1030e046462ab8168cf8894e6778cd805c8bdfe2bd649" +checksum = "48b9ad6eee93dd35a9ec0a6c1c6b180892a900ee17a6ed6500921552dd71e846" dependencies = [ "alloy-primitives", + "alloy-rlp", "derive_more", "serde", "serde_with", @@ -570,9 +575,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ac61f03f1edabccde1c687b5b25fff28f183afee64eaa2e767def3929e4457" +checksum = "7eba59e1c069f168a01982f42a57797736923b76aa854194df4930be17867e1c" dependencies = [ "alloy-consensus", "alloy-eips", @@ -581,16 +586,16 @@ dependencies = [ "alloy-serde", "arbitrary", "derive_more", - "rand 0.8.5", + "rand 0.8.6", "serde", "strum 0.27.2", ] [[package]] name = "alloy-rpc-types-eth" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9" +checksum = "175a2a5b6017d7f61b5e4b800d21215fe8e94fe729d00828e13bb6d93dcf3492" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -601,7 +606,7 @@ dependencies = [ "alloy-serde", "alloy-sol-types", "arbitrary", - "itertools 0.14.0", + "itertools 0.13.0", "serde", "serde_json", "serde_with", @@ -610,9 +615,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad79f1e27e161943b5a4f99fe5534ef0849876214be411e0032c12f38e94daa" +checksum = "514b4b1ce3354f65067b4fc7eb75358e0f2ec8be3340c96dea65d6894f9ca435" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -624,9 +629,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d459f902a2313737bc66d18ed094c25d2aeb268b74d98c26bbbda2aa44182ab0" +checksum = "76e34a42ebb4a71ab0bfdebc6d2f3c7bf809f01edf154d08fed159d10d1ef1d4" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -636,9 +641,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37" +checksum = "cc21a8772af7d78bba286726aa245bd2ff81cd9abe230afea2e91578996831c9" dependencies = [ "alloy-primitives", "arbitrary", @@ -648,9 +653,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2425c6f314522c78e8198979c8cbf6769362be4da381d4152ea8eefce383535d" +checksum = "8ffbce94c50dd9d4d1f83e044c5595bbd3ada981bd3057ce28b3a5470e77385d" dependencies = [ "alloy-primitives", "async-trait", @@ -663,9 +668,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ecb71ee53d8d9c3fa7bac17542c8116ebc7a9726c91b1bf333ec3d04f5a789" +checksum = "e48366d2c42b8d95ef951101bafa28486590f21b7a1e68b6b2d069746557bbe3" dependencies = [ "alloy-consensus", "alloy-network", @@ -673,48 +678,48 @@ dependencies = [ "alloy-signer", "async-trait", "k256", - "rand 0.8.5", + "rand 0.8.6", "thiserror 2.0.18", ] [[package]] name = "alloy-sol-macro" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b96d5f5890605ba9907ce1e2158e2701587631dc005bfa582cf92dd6f21147" +checksum = "840128ed2b2971d6d4668a553fe403a82683d3acc646c73e75887e7157408033" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8247b7cca5cde556e93f8b3882b01dbd272f527836049083d240c57bf7b4c15" +checksum = "63ec265e5d65d725175f6ca7711c970824c90ef9c0d1f1973711d4150ee612dd" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.11.4", + "indexmap 2.14.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "sha3", + "syn 2.0.118", "syn-solidity", - "tiny-keccak 2.0.2", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd54f38512ac7bae10bbc38480eefb1b9b398ca2ce25db9cc0c048c6411c4f1" +checksum = "89bf01077f18650876cfa682eb1f949967b5cde03f1a51c955c469d2c9b4aa67" dependencies = [ "alloy-json-abi", "const-hex", @@ -724,25 +729,25 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.117", + "syn 2.0.118", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af67a0b0dcebe14244fc92002cd8d96ecbf65db4639d479f5fcd5805755a4c27" +checksum = "857b470ecdd2ed38beaf82ad1a38c516a8ff75266750f38b9eeed001d575241b" dependencies = [ "serde", - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] name = "alloy-sol-types" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1038284171df8bfd48befc0c7b78f667a7e2be162f45f07bd1c378078ebe58" +checksum = "384cf252de0db2dec52821eac037a7f57e2aa33fe5b900ce6fe39973402341f1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -752,13 +757,13 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa186e560d523d196580c48bf00f1bf62e63041f28ecf276acc22f8b27bb9f53" +checksum = "86052fdcec72d37ca4aa4b66254601e7453c45a6e1c70aa4561033d002fb80cc" dependencies = [ "alloy-json-rpc", "auto_impl", - "base64 0.22.1", + "base64", "derive_more", "futures 0.3.31", "futures-utils-wasm", @@ -775,14 +780,14 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa501ad58dd20acddbfebc65b52e60f05ebf97c52fa40d1b35e91f5e2da0ad0e" +checksum = "b273587487921274f4f5d0ef2c7ef36944dcbb75a4e2318e69eae822bd263f91" dependencies = [ "alloy-json-rpc", "alloy-transport", - "itertools 0.14.0", - "reqwest", + "itertools 0.13.0", + "reqwest 0.13.2", "serde_json", "tower 0.5.2", "tracing", @@ -791,9 +796,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ef85688e5ac2da72afc804e0a1f153a1f309f05a864b1998bbbed7804dbaab" +checksum = "bfb89df168b24773ef603af14f2449c05a7d3f27d05d3eceaea6bf96cccae168" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -811,18 +816,20 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f00445db69d63298e2b00a0ea1d859f00e6424a3144ffc5eba9c31da995e16" +checksum = "33e32e0b47d3b3bf5770b7c132090c614b008d307c5e1544f1925f5b7e9e9af6" dependencies = [ "alloy-pubsub", "alloy-transport", "futures 0.3.31", - "http 1.4.0", + "http 1.4.2", + "rustls", "serde_json", "tokio", - "tokio-tungstenite 0.26.2", + "tokio-tungstenite 0.28.0", "tracing", + "url", "ws_stream_wasm", ] @@ -835,7 +842,7 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "arbitrary", - "arrayvec 0.7.4", + "arrayvec", "derive_arbitrary", "derive_more", "nybbles", @@ -848,14 +855,14 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.7.3" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc" +checksum = "01a0035943b75fe1e249f52e688492d7a1b1826bc2d19b8e1d5d3c24a2ad8f50" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -867,6 +874,21 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse 0.2.4", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstream" version = "1.0.0" @@ -874,7 +896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", - "anstyle-parse", + "anstyle-parse 1.0.0", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -888,6 +910,15 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + [[package]] name = "anstyle-parse" version = "1.0.0" @@ -914,14 +945,14 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.1", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arbitrary" @@ -934,9 +965,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ "rustversion", ] @@ -995,7 +1026,7 @@ dependencies = [ "ark-ff-macros 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", - "arrayvec 0.7.4", + "arrayvec", "digest 0.10.7", "educe", "itertools 0.13.0", @@ -1032,7 +1063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1070,7 +1101,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1101,7 +1132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-std 0.5.0", - "arrayvec 0.7.4", + "arrayvec", "digest 0.10.7", "num-bigint 0.4.6", ] @@ -1113,7 +1144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1123,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -1133,21 +1164,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", ] -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.4" @@ -1159,9 +1178,9 @@ dependencies = [ [[package]] name = "arrow" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d441fdda254b65f3e9025910eb2c2066b6295d9c8ed409522b8d2ace1ff8574c" +checksum = "ffaaa3e009861fd829d0a24dd6f115aa8e4634324bb092147d43baafe69ca4a7" dependencies = [ "arrow-arith", "arrow-array", @@ -1180,9 +1199,9 @@ dependencies = [ [[package]] name = "arrow-arith" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced5406f8b720cc0bc3aa9cf5758f93e8593cda5490677aa194e4b4b383f9a59" +checksum = "3ac95125e1d71c4a252b5a9c729aef111e80418f08aaa6dbabd1ba66918247fc" dependencies = [ "arrow-array", "arrow-buffer", @@ -1194,9 +1213,9 @@ dependencies = [ [[package]] name = "arrow-array" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772bd34cacdda8baec9418d80d23d0fb4d50ef0735685bd45158b83dfeb6e62d" +checksum = "0c60c79628e9a97cb90d7a0dc3e944f216a902f837d4ecabc14d524bddbbc137" dependencies = [ "ahash", "arrow-buffer", @@ -1204,7 +1223,7 @@ dependencies = [ "arrow-schema", "chrono", "half", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "num-complex", "num-integer", "num-traits", @@ -1212,9 +1231,9 @@ dependencies = [ [[package]] name = "arrow-buffer" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898f4cf1e9598fdb77f356fdf2134feedfd0ee8d5a4e0a5f573e7d0aec16baa4" +checksum = "6026f638c400e9878c1b1cc05c3cfd46fbf381285916ab408678701c1df46c1a" dependencies = [ "bytes", "half", @@ -1224,9 +1243,9 @@ dependencies = [ [[package]] name = "arrow-cast" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0127816c96533d20fc938729f48c52d3e48f99717e7a0b5ade77d742510736d" +checksum = "c82c236c3caf8df5664284f3f1fbe89938852163998c3fdbf37e84ac220445e9" dependencies = [ "arrow-array", "arrow-buffer", @@ -1235,7 +1254,7 @@ dependencies = [ "arrow-schema", "arrow-select", "atoi", - "base64 0.22.1", + "base64", "chrono", "half", "lexical-core", @@ -1245,9 +1264,9 @@ dependencies = [ [[package]] name = "arrow-csv" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca025bd0f38eeecb57c2153c0123b960494138e6a957bbda10da2b25415209fe" +checksum = "12714e5fb7954159af1e26d4e0d37108bcf1a2ad5ee5c5bf02a944d564d588b7" dependencies = [ "arrow-array", "arrow-cast", @@ -1260,9 +1279,9 @@ dependencies = [ [[package]] name = "arrow-data" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d10beeab2b1c3bb0b53a00f7c944a178b622173a5c7bcabc3cb45d90238df4" +checksum = "7bd568aa70c4ec5947027b0d5caee94877433b661a0bb9e8ddceeeb5f0c9b1ab" dependencies = [ "arrow-buffer", "arrow-schema", @@ -1273,9 +1292,9 @@ dependencies = [ [[package]] name = "arrow-flight" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302b2e036335f3f04d65dad3f74ff1f2aae6dc671d6aa04dc6b61193761e16fb" +checksum = "68365401e834743d708094927e2ca727a32d639fe900df04b936e07a36701b74" dependencies = [ "arrow-arith", "arrow-array", @@ -1288,7 +1307,7 @@ dependencies = [ "arrow-schema", "arrow-select", "arrow-string", - "base64 0.22.1", + "base64", "bytes", "futures 0.3.31", "once_cell", @@ -1301,9 +1320,9 @@ dependencies = [ [[package]] name = "arrow-ipc" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609a441080e338147a84e8e6904b6da482cefb957c5cdc0f3398872f69a315d0" +checksum = "e57ee4d470eab1a021bc4b63fa2b2c15d572892bf227b0a982d3b755a6c662b5" dependencies = [ "arrow-array", "arrow-buffer", @@ -1315,18 +1334,19 @@ dependencies = [ [[package]] name = "arrow-json" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ead0914e4861a531be48fe05858265cf854a4880b9ed12618b1d08cba9bebc8" +checksum = "38f47e0e7a284e1f3707a780dc8cd5451b1614e9e398ea2d9ca03c7a2fe9a9ed" dependencies = [ "arrow-array", "arrow-buffer", "arrow-cast", - "arrow-data", + "arrow-ord", "arrow-schema", + "arrow-select", "chrono", "half", - "indexmap 2.11.4", + "indexmap 2.14.0", "itoa", "lexical-core", "memchr", @@ -1339,9 +1359,9 @@ dependencies = [ [[package]] name = "arrow-ord" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a7ba279b20b52dad300e68cfc37c17efa65e68623169076855b3a9e941ca5" +checksum = "a79cf73ad2eba8686ec2aa9bbf8671208e509025f166afc040cedbd94ffe4983" dependencies = [ "arrow-array", "arrow-buffer", @@ -1352,9 +1372,9 @@ dependencies = [ [[package]] name = "arrow-row" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14fe367802f16d7668163ff647830258e6e0aeea9a4d79aaedf273af3bdcd3e" +checksum = "cea0f7d8ed6182f14952761e2c0f989852d5aa334fcbc49f73a9f2247c25b879" dependencies = [ "arrow-array", "arrow-buffer", @@ -1365,15 +1385,15 @@ dependencies = [ [[package]] name = "arrow-schema" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30a1365d7a7dc50cc847e54154e6af49e4c4b0fddc9f607b687f29212082743" +checksum = "80b3e786a0dd9103acd583a6fb486dbf2f3268466cc0bd571dcf34cef231c1f1" [[package]] name = "arrow-select" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78694888660a9e8ac949853db393af2a8b8fc82c19ce333132dfa2e72cc1a7fe" +checksum = "067a67e0361f6c31f4a7248759f36ca4ca71b187a941ed4d49da1c7d3d4db624" dependencies = [ "ahash", "arrow-array", @@ -1385,9 +1405,9 @@ dependencies = [ [[package]] name = "arrow-string" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e04a01f8bb73ce54437514c5fd3ee2aa3e8abe4c777ee5cc55853b1652f79e" +checksum = "99bc95847f3ff62a2b03d6f8ce2e3e78f01362060549a2a311898dd442f6256d" dependencies = [ "arrow-array", "arrow-buffer", @@ -1442,15 +1462,15 @@ dependencies = [ "async-io", "async-trait", "asynk-strim", - "base64 0.22.1", + "base64", "bytes", "chrono", "fast_chemail", "fnv", "futures-util", "handlebars", - "http 1.4.0", - "indexmap 2.11.4", + "http 1.4.2", + "indexmap 2.14.0", "mime", "multer", "num-traits", @@ -1494,7 +1514,7 @@ dependencies = [ "proc-macro2", "quote", "strum 0.27.2", - "syn 2.0.117", + "syn 2.0.118", "thiserror 2.0.18", ] @@ -1517,7 +1537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e3ef112905abea9dea592fc868a6873b10ebd3f983e83308f995d6284e9ba41" dependencies = [ "bytes", - "indexmap 2.11.4", + "indexmap 2.14.0", "serde", "serde_json", ] @@ -1529,15 +1549,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix 1.0.7", + "rustix 1.1.4", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -1559,7 +1579,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1581,18 +1601,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1633,9 +1653,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atomic_refcell" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" +checksum = "21e4227379beff4205943696e6c3e0cd809bacdf3f0edd6e3dd153e2269571a4" [[package]] name = "auto_impl" @@ -1645,7 +1665,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1654,18 +1674,40 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "aws-lc-rs" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "axum" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", - "base64 0.22.1", + "base64", "bytes", "form_urlencoded", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -1683,7 +1725,7 @@ dependencies = [ "sha1 0.10.6", "sync_wrapper", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite 0.29.0", "tower 0.5.2", "tower-layer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1698,7 +1740,7 @@ checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.2", "http-body", "http-body-util", "mime", @@ -1730,12 +1772,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -1760,17 +1796,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", -] - [[package]] name = "bimap" version = "0.6.3" @@ -1816,9 +1841,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "bitvec" @@ -1834,30 +1859,14 @@ dependencies = [ [[package]] name = "blake3" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "cc", - "cfg-if 0.1.10", - "constant_time_eq 0.1.5", - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "blake3" -version = "1.8.4" +version = "1.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" dependencies = [ - "arrayref", - "arrayvec 0.7.4", + "arrayvec", "cc", - "cfg-if 1.0.0", - "constant_time_eq 0.4.2", + "cfg-if", + "constant_time_eq", "cpufeatures 0.3.0", ] @@ -1911,7 +1920,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1962,9 +1971,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" dependencies = [ "allocator-api2", ] @@ -1983,9 +1992,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] @@ -2008,9 +2017,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.43" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -2019,10 +2028,10 @@ dependencies = [ ] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" @@ -2042,42 +2051,41 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.3.0", "rand_core 0.10.0", ] [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] name = "cid" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" +checksum = "21a304f95f84d169a6f31c4d0a30d784643aaa0bbc9c1e449a2c23e963ec4971" dependencies = [ - "core2", "multibase", "multihash", - "unsigned-varint 0.8.0", + "unsigned-varint", ] [[package]] name = "clap" -version = "4.6.0" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" dependencies = [ "clap_builder", "clap_derive", @@ -2085,11 +2093,11 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" dependencies = [ - "anstream", + "anstream 0.6.21", "anstyle", "clap_lex", "strsim", @@ -2107,27 +2115,39 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "clap_lex" -version = "1.1.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] [[package]] name = "cobs" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] [[package]] name = "colorchoice" @@ -2173,14 +2193,14 @@ dependencies = [ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", "unicode-width", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -2189,7 +2209,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.2.12", "proptest", "serde_core", @@ -2224,15 +2244,9 @@ checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ "getrandom 0.2.15", "once_cell", - "tiny-keccak 2.0.2", + "tiny-keccak", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.4.2" @@ -2274,22 +2288,13 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - [[package]] name = "cpp_demangle" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -2312,46 +2317,48 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c088d3406f0c0252efa7445adfd2d05736bfb5218838f64eaf79d567077aed14" +checksum = "e06aeba2c965fc446d13c56a6ccb2631b78445d7544543dd9a25289977630914" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c03f887a763abb9c1dc08f722aa82b69067fda623b6f0273050f45f8b1a6776" +checksum = "ee2d2dde4ec1352715595b5cfa6fe2e5b8ebb9da3457b3ee8db0aa2808c069aa" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206887a11a43f507fee320a218dc365980bfc42ec2696792079a9f8c9369e90" +checksum = "03b4982ef9fa54ec9eee841e891e7ddc5434be1250e88de31572e000c888f30b" dependencies = [ "cranelift-entity", + "wasmtime-internal-core", ] [[package]] name = "cranelift-bitset" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0790c83cfdab95709c5d0105fd888221e3af9049a7d7ec376ec901ab4e4dba" +checksum = "529143118c4eeb58c39ecb02319557d512be6c61348486422974ab8e3906b8a8" dependencies = [ "serde", "serde_derive", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a98aed2d262eda69310e84bae8e053ee4f17dbdd3347b8d9156aa618ba2de0a" +checksum = "b7780677247ad3577e3a6a3ebf43f39b325a11d6393db72b2c9968a910d4d13d" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -2363,22 +2370,26 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.15.2", + "hashbrown 0.17.0", + "libm", "log", + "postcard", "pulley-interpreter", "regalloc2", - "rustc-hash 2.1.1", + "rustc-hash", "serde", + "serde_derive", + "sha2 0.10.9", "smallvec", "target-lexicon", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen-meta" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6906852826988563e9b0a9232ad951f53a47aa41ffd02f8ac852d3f41aae836a" +checksum = "ac9645250416cbf92454fe61160e17e026e0ce405906a54500b114f923ddffc9" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -2389,37 +2400,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a50105aab667b5cc845f2be37c78475d7cc127cd8ec0a31f7b2b71d526099a7" +checksum = "20ee8d222ff0fd3681791979afbf88586ac9f49010d3db96b3cbe4c96759aee3" [[package]] name = "cranelift-control" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6adcc7aa7c0bc1727176a6f2d99c28a9e79a541ccd5ca911a0cb352da8befa36" +checksum = "591abe6f5312bd2c4220f1b3bead56c2ad00257c52668015ba013b85dcf2a17a" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981b56af777f9a34ea6dcce93255125776d391410c2a68b75bed5941b714fa15" +checksum = "a5300c49cf940526fe771517b3b3eabd5d0ff164ee61698579cf403fe8d3af3c" dependencies = [ "cranelift-bitset", "serde", "serde_derive", + "wasmtime-internal-core", ] [[package]] name = "cranelift-frontend" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea982589684dfb71afecb9fc09555c3a266300a1162a60d7fa39d41a5705b1c" +checksum = "da4adbf760207fdbbe130f1191cce01cdef66831a9f648b1f39ff2800d126d45" dependencies = [ "cranelift-codegen", + "hashbrown 0.17.0", "log", "smallvec", "target-lexicon", @@ -2427,15 +2440,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0422686b22ed6a1f33cc40e3c43eb84b67155788568d1a5cac8439d3dca1783" +checksum = "8315b21ff018226a42a60a4702c2dd75f6447cac26e9bca622e14c22088c2ff5" [[package]] name = "cranelift-native" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f697bbbe135c655ea1deb7af0bae4a5c4fae2c88fdfc0fa57b34ae58c91040" +checksum = "d506ef23a60715bde451b06620b14402166ded3b648454fccbf04f3e46a4aa70" dependencies = [ "cranelift-codegen", "libc", @@ -2444,9 +2457,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.125.4" +version = "0.133.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718efe674f3df645462677e22a3128e890d88ba55821bb091083d257707be76c" +checksum = "48ed47e602652e3410f9387fc0db70fefadcee4d78a78881421aabcab4e26b89" [[package]] name = "crc" @@ -2469,7 +2482,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -2534,13 +2547,13 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "crossterm_winapi", "derive_more", "document-features", "mio", "parking_lot", - "rustix 1.0.7", + "rustix 1.1.4", "signal-hook", "signal-hook-mio", "winapi", @@ -2592,16 +2605,6 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "csv" version = "1.4.0" @@ -2664,7 +2667,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2677,9 +2680,8 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "serde", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2691,8 +2693,9 @@ dependencies = [ "ident_case", "proc-macro2", "quote", + "serde", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2703,7 +2706,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2714,7 +2717,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2725,7 +2728,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2734,7 +2737,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", @@ -2860,7 +2863,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2881,7 +2884,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2891,7 +2894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2913,24 +2916,24 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.117", + "syn 2.0.118", "unicode-xid", ] [[package]] name = "diesel" -version = "2.3.2" +version = "2.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8496eeb328dce26ee9d9b73275d396d9bddb433fa30106cf6056dd8c3c2764c" +checksum = "9940fb8467a0a06312218ed384185cb8536aa10d8ec017d0ce7fad2c1bd882d5" dependencies = [ - "bigdecimal 0.3.1", - "bitflags 2.9.0", + "bigdecimal", + "bitflags 2.11.1", "byteorder", "chrono", "diesel_derives", "downcast-rs", "itoa", - "num-bigint 0.4.6", + "num-bigint 0.2.6", "num-integer", "num-traits", "pq-sys", @@ -2940,16 +2943,15 @@ dependencies = [ [[package]] name = "diesel-async" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95864e58597509106f1fddfe0600de7e589e1fddddd87f54eee0a49fd111bbc" +checksum = "dd39af30158d444884f166fe4c58f35dc40ad71ad017bb59408a3448526ff4bd" dependencies = [ "deadpool 0.13.0", "diesel", "futures-core", "futures-util", "pin-project-lite", - "scoped-futures", "tokio", "tokio-postgres", ] @@ -2963,7 +2965,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2977,22 +2979,22 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.3.7" +version = "2.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47618bf0fac06bb670c036e48404c26a865e6a71af4114dfd97dfe89936e404e" +checksum = "d1817b7f4279b947fc4cafddec12b0e5f8727141706561ce3ac94a60bddd1cf5" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "diesel_migrations" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745fd255645f0f1135f9ec55c7b00e0882192af9683ab4731e4bba3da82b8f9c" +checksum = "28d0f4a98124ba6d4ca75da535f65984badec16a003b6e2f94a01e31a79490b8" dependencies = [ "diesel", "migrations_internals", @@ -3005,7 +3007,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c" dependencies = [ - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3058,7 +3060,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -3077,7 +3079,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -3112,7 +3114,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3147,7 +3149,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3186,7 +3188,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3242,7 +3244,7 @@ version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -3262,14 +3264,14 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "env_filter" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" dependencies = [ "log", "regex", @@ -3277,11 +3279,11 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ - "anstream", + "anstream 1.0.0", "anstyle", "env_filter", "jiff", @@ -3305,7 +3307,7 @@ checksum = "452c458dfb890a2fea64e4c894f83daad61689fb9bbe84c382e1ce6d7536710b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3377,9 +3379,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fastrlp" @@ -3387,7 +3389,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "auto_impl", "bytes", ] @@ -3398,7 +3400,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "auto_impl", "bytes", ] @@ -3415,9 +3417,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "firestorm" @@ -3438,11 +3440,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.5", + "rand 0.8.6", "rustc-hex", "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -3455,7 +3463,7 @@ version = "25.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "rustc_version 0.4.0", ] @@ -3512,6 +3520,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -3599,7 +3613,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3654,9 +3668,9 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25234f20a3ec0a962a61770cfe39ecf03cb529a6e474ad8cff025ed497eda557" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "debugid", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_derive", "serde_json", @@ -3679,7 +3693,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -3692,7 +3706,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.13.3+wasi-0.2.2", @@ -3706,7 +3720,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "r-efi", "rand_core 0.10.0", @@ -3716,12 +3730,13 @@ dependencies = [ [[package]] name = "gimli" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ - "fallible-iterator 0.3.0", - "indexmap 2.11.4", + "fnv", + "hashbrown 0.16.1", + "indexmap 2.14.0", "stable_deref_trait", ] @@ -3743,7 +3758,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "time", ] @@ -3768,14 +3783,14 @@ dependencies = [ [[package]] name = "gnd" -version = "0.42.1" +version = "0.45.0" dependencies = [ "Inflector", "anyhow", "async-trait", "clap", "clap_complete", - "console 0.16.3", + "console 0.16.4", "env_logger", "git-testament", "globset", @@ -3795,7 +3810,7 @@ dependencies = [ "pgtemp", "pq-sys", "regex", - "reqwest", + "reqwest 0.12.23", "semver 1.0.28", "serde", "serde_json", @@ -3814,7 +3829,7 @@ dependencies = [ [[package]] name = "graph" -version = "0.42.1" +version = "0.45.0" dependencies = [ "Inflector", "ahash", @@ -3825,8 +3840,8 @@ dependencies = [ "async-stream", "async-trait", "atomic_refcell", - "base64 0.21.7", - "bigdecimal 0.1.2", + "base64", + "bigdecimal", "bs58 0.5.1", "bytes", "chrono", @@ -3846,12 +3861,12 @@ dependencies = [ "hex", "hex-literal", "http 0.2.12", - "http 1.4.0", + "http 1.4.2", "http-body-util", "hyper", "hyper-util", "indoc", - "itertools 0.14.0", + "itertools 0.15.0", "lazy-regex", "lazy_static", "lru_time_cache", @@ -3861,16 +3876,17 @@ dependencies = [ "num-traits", "object_store", "parking_lot", - "petgraph", + "petgraph 0.8.3", "portable-atomic", "priority-queue", "prometheus", "prost", "prost-types", - "rand 0.9.2", + "rand 0.9.3", "redis", "regex", - "reqwest", + "reqwest 0.12.23", + "rustls", "semver 1.0.28", "serde", "serde_derive", @@ -3884,17 +3900,17 @@ dependencies = [ "slog-envlogger", "slog-term", "sqlparser 0.57.0", - "sqlparser 0.61.0", + "sqlparser 0.62.0", "stable-hash 0.3.4", "stable-hash 0.4.4", "strum_macros 0.28.0", + "tempfile", "thiserror 2.0.18", - "tiny-keccak 1.5.0", "tokio", "tokio-retry", "tokio-stream", "tokio-util", - "toml 1.1.0+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", "tonic", "tonic-prost", "tonic-prost-build", @@ -3905,7 +3921,7 @@ dependencies = [ [[package]] name = "graph-chain-common" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "heck 0.5.0", @@ -3915,25 +3931,24 @@ dependencies = [ [[package]] name = "graph-chain-ethereum" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-trait", - "base64 0.22.1", + "base64", "envconfig", "futures 0.3.31", "graph", "graph-runtime-derive", "graph-runtime-wasm", "hex", - "itertools 0.14.0", + "itertools 0.15.0", "jsonrpc-core", "prost", "prost-types", "semver 1.0.28", "serde", "thiserror 2.0.18", - "tiny-keccak 1.5.0", "tokio", "tokio-stream", "tonic-prost-build", @@ -3942,7 +3957,7 @@ dependencies = [ [[package]] name = "graph-chain-near" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-trait", @@ -3959,7 +3974,7 @@ dependencies = [ [[package]] name = "graph-core" -version = "0.42.1" +version = "0.45.0" dependencies = [ "alloy", "anyhow", @@ -3973,7 +3988,7 @@ dependencies = [ "graph-chain-near", "graph-runtime-wasm", "indoc", - "itertools 0.14.0", + "itertools 0.15.0", "parking_lot", "prometheus", "serde_yaml", @@ -3990,7 +4005,7 @@ dependencies = [ [[package]] name = "graph-graphql" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-recursion", @@ -4006,11 +4021,11 @@ dependencies = [ [[package]] name = "graph-node" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "clap", - "console 0.16.3", + "console 0.16.4", "diesel", "diesel-async", "env_logger", @@ -4028,7 +4043,7 @@ dependencies = [ "graphman", "graphman-server", "indicatif", - "itertools 0.14.0", + "itertools 0.15.0", "json-structural-diff", "lazy_static", "prometheus", @@ -4042,21 +4057,21 @@ dependencies = [ [[package]] name = "graph-runtime-derive" -version = "0.42.1" +version = "0.45.0" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "graph-runtime-test" -version = "0.42.1" +version = "0.45.0" dependencies = [ "async-trait", "graph", "graph-chain-ethereum", "graph-runtime-wasm", - "rand 0.9.2", + "rand 0.9.3", "semver 1.0.28", "test-store", "wasmtime", @@ -4064,7 +4079,7 @@ dependencies = [ [[package]] name = "graph-runtime-wasm" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-trait", @@ -4082,7 +4097,7 @@ dependencies = [ [[package]] name = "graph-server-http" -version = "0.42.1" +version = "0.45.0" dependencies = [ "async-trait", "graph", @@ -4093,10 +4108,10 @@ dependencies = [ [[package]] name = "graph-server-index-node" -version = "0.42.1" +version = "0.45.0" dependencies = [ "async-trait", - "blake3 1.8.4", + "blake3", "git-testament", "graph", "graph-chain-ethereum", @@ -4106,7 +4121,7 @@ dependencies = [ [[package]] name = "graph-server-json-rpc" -version = "0.42.1" +version = "0.45.0" dependencies = [ "axum", "graph", @@ -4119,20 +4134,20 @@ dependencies = [ [[package]] name = "graph-server-metrics" -version = "0.42.1" +version = "0.45.0" dependencies = [ "graph", ] [[package]] name = "graph-store-postgres" -version = "0.42.1" +version = "0.45.0" dependencies = [ "Inflector", "anyhow", "arrow", "async-trait", - "blake3 1.8.4", + "blake3", "chrono", "clap", "deadpool 0.13.0", @@ -4148,7 +4163,7 @@ dependencies = [ "graph", "graphman-store", "hex", - "itertools 0.14.0", + "itertools 0.15.0", "lazy_static", "lru_time_cache", "openssl", @@ -4156,11 +4171,11 @@ dependencies = [ "postgres", "postgres-openssl", "pretty_assertions", - "rand 0.9.2", + "rand 0.9.3", "serde", "serde_json", "serde_yaml", - "sqlparser 0.61.0", + "sqlparser 0.62.0", "stable-hash 0.3.4", "thiserror 2.0.18", "tokio", @@ -4169,7 +4184,7 @@ dependencies = [ [[package]] name = "graph-tests" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "assert-json-diff", @@ -4195,17 +4210,17 @@ dependencies = [ [[package]] name = "graph_derive" -version = "0.42.1" +version = "0.45.0" dependencies = [ "proc-macro-utils", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "graphman" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "diesel", @@ -4213,14 +4228,14 @@ dependencies = [ "graph", "graph-store-postgres", "graphman-store", - "itertools 0.14.0", + "itertools 0.15.0", "thiserror 2.0.18", "tokio", ] [[package]] name = "graphman-server" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-graphql", @@ -4234,19 +4249,19 @@ dependencies = [ "graphman", "graphman-store", "lazy_static", - "reqwest", + "reqwest 0.12.23", "serde", "serde_json", "slog", "test-store", "thiserror 2.0.18", "tokio", - "tower-http", + "tower-http 0.7.0", ] [[package]] name = "graphman-store" -version = "0.42.1" +version = "0.45.0" dependencies = [ "anyhow", "async-trait", @@ -4284,17 +4299,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.4.0", - "indexmap 2.11.4", + "http 1.4.2", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -4307,7 +4322,7 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crunchy", "num-traits", "zerocopy", @@ -4348,7 +4363,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash 0.1.5", - "serde", ] [[package]] @@ -4360,6 +4374,15 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +dependencies = [ + "foldhash 0.2.0", "serde", "serde_core", ] @@ -4410,7 +4433,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", ] [[package]] @@ -4450,9 +4473,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -4465,7 +4488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 1.4.0", + "http 1.4.2", ] [[package]] @@ -4476,7 +4499,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.2", "http-body", "pin-project-lite", ] @@ -4510,16 +4533,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http 1.4.2", "http-body", "httparse", "httpdate", @@ -4537,16 +4560,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 1.4.0", + "http 1.4.2", "hyper", "hyper-util", "rustls", - "rustls-native-certs 0.7.1", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.26.11", ] [[package]] @@ -4584,18 +4605,18 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2", "system-configuration", "tokio", "tower-layer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4633,9 +4654,9 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1fcc7f316b2c079dde77564a1360639c1a956a23fa96122732e416cb10717bb" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "static_assertions", ] @@ -4754,14 +4775,14 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "id-arena" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "ident_case" @@ -4823,24 +4844,24 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "arbitrary", "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] [[package]] name = "indicatif" -version = "0.18.4" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +checksum = "993f007684f2e9727160da8b960ec161264703bfd1af084fd2e34d040c9a0dd4" dependencies = [ - "console 0.16.3", + "console 0.16.4", "portable-atomic", "unicode-width", "unit-prefix", @@ -4862,7 +4883,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -4882,7 +4903,7 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6654738b8024300cf062d04a1c13c10c8e2cea598ec1c47dc9b6641159429756" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "crossterm", "dyn-clone", "fuzzy-matcher", @@ -4890,12 +4911,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - [[package]] name = "interprocess" version = "2.2.3" @@ -4917,16 +4932,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "is-docker" version = "0.2.0" @@ -4990,6 +4995,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.17" @@ -5037,7 +5051,51 @@ checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.61", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[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.118", ] [[package]] @@ -5051,11 +5109,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -5092,7 +5151,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "once_cell", @@ -5102,18 +5161,19 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" dependencies = [ - "cpufeatures 0.2.12", + "cfg-if", + "cpufeatures 0.3.0", ] [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "1766b89733097006f3a1388a02849865d6bc98c89273cb622e29fdd209922183" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -5159,7 +5219,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5239,15 +5299,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" @@ -5255,7 +5315,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "libc", ] @@ -5267,9 +5327,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -5330,22 +5390,19 @@ dependencies = [ [[package]] name = "mach2" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] +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", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5366,7 +5423,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "digest 0.10.7", ] @@ -5378,11 +5435,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 0.38.34", + "rustix 1.1.4", ] [[package]] @@ -5453,7 +5510,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.4.0", + "http 1.4.2", "httparse", "memchr", "mime", @@ -5474,12 +5531,11 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "577c63b00ad74d57e8c9aa870b5fccebf2fd64a308a5aee9f1bb88e4aea19447" dependencies = [ - "core2", - "unsigned-varint 0.7.2", + "unsigned-varint", ] [[package]] @@ -5511,13 +5567,25 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.11.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "notify" version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -5634,7 +5702,7 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5645,7 +5713,7 @@ checksum = "7b5676b5c379cf5b03da1df2b3061c4a4e2aa691086a56ac923e08c143f53f59" dependencies = [ "alloy-rlp", "arbitrary", - "cfg-if 1.0.0", + "cfg-if", "proptest", "ruint", "serde", @@ -5654,41 +5722,42 @@ dependencies = [ [[package]] name = "object" -version = "0.37.3" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" dependencies = [ "crc32fast", - "hashbrown 0.15.2", - "indexmap 2.11.4", + "hashbrown 0.17.0", + "indexmap 2.14.0", "memchr", ] [[package]] name = "object_store" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622acbc9100d3c10e2ee15804b0caa40e55c933d5aa53814cd520805b7958a49" +checksum = "765784b4390c6bcf80316e5a22f4e3661b639c9d8c83246856643c27d8ce9dbe" dependencies = [ "async-trait", - "base64 0.22.1", + "aws-lc-rs", + "base64", "bytes", "chrono", "form_urlencoded", "futures-channel", "futures-core", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body-util", "humantime", "hyper", - "itertools 0.14.0", + "itertools 0.15.0", + "nix", "parking_lot", "percent-encoding", "quick-xml", - "rand 0.10.0", - "reqwest", - "ring", + "rand 0.10.1", + "reqwest 0.13.2", "rustls-pki-types", "serde", "serde_json", @@ -5700,6 +5769,7 @@ dependencies = [ "walkdir", "wasm-bindgen-futures", "web-time", + "windows-sys 0.61.2", ] [[package]] @@ -5716,26 +5786,24 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" -version = "5.3.3" +version = "5.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" dependencies = [ "is-wsl", "libc", - "pathdiff", ] [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.9.0", - "cfg-if 1.0.0", + "bitflags 2.11.1", + "cfg-if", "foreign-types", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -5748,7 +5816,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5768,9 +5836,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -5785,22 +5853,13 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - [[package]] name = "parity-scale-codec" version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", @@ -5848,18 +5907,18 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.5.2", "smallvec", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] name = "parquet" -version = "58.1.0" +version = "59.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3f9f2205199603564127932b89695f52b62322f541d0fc7179d57c2e1c9877" +checksum = "970dff83e97d953c827ae8176f6bf4e9f77bf62daacc01ec5df348ec5eacd913" dependencies = [ "ahash", "arrow-array", @@ -5868,13 +5927,13 @@ dependencies = [ "arrow-ipc", "arrow-schema", "arrow-select", - "base64 0.22.1", + "base64", "brotli", "bytes", "chrono", "flate2", "half", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "lz4_flex", "num-bigint 0.4.6", "num-integer", @@ -5883,7 +5942,6 @@ dependencies = [ "seq-macro", "simdutf8", "snap", - "thrift", "twox-hash", "zstd", ] @@ -5894,12 +5952,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -5937,7 +5989,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5951,15 +6003,25 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.14.0", +] + [[package]] name = "petgraph" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ - "fixedbitset", + "fixedbitset 0.5.7", "hashbrown 0.15.2", - "indexmap 2.11.4", + "indexmap 2.14.0", "serde", ] @@ -6020,7 +6082,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6057,12 +6119,12 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "hermit-abi 0.5.2", "pin-project-lite", - "rustix 1.0.7", - "windows-sys 0.61.1", + "rustix 1.1.4", + "windows-sys 0.61.2", ] [[package]] @@ -6082,9 +6144,9 @@ dependencies = [ [[package]] name = "postcard" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", "embedded-io 0.4.0", @@ -6108,9 +6170,9 @@ dependencies = [ [[package]] name = "postgres-openssl" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f86f073ad570f76e9e278ce6f05775fc723eed7daa6b4f9c2aa078080a564a0" +checksum = "06743eefaa1a5c0ef2ccb6d9abf6528790a229eabd62ddcabf9b2a3aeff09fa4" dependencies = [ "openssl", "tokio", @@ -6124,14 +6186,14 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ - "base64 0.22.1", + "base64", "byteorder", "bytes", "fallible-iterator 0.2.0", "hmac", "md-5", "memchr", - "rand 0.9.2", + "rand 0.9.3", "sha2 0.10.9", "stringprep", ] @@ -6198,7 +6260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6219,7 +6281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93980406f12d9f8140ed5abe7155acb10bb1e69ea55c88960b9c2f117445ef96" dependencies = [ "equivalent", - "indexmap 2.11.4", + "indexmap 2.14.0", "serde", ] @@ -6229,7 +6291,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -6251,7 +6313,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6280,14 +6342,14 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fnv", "lazy_static", "libc", "memchr", "parking_lot", "protobuf", - "reqwest", + "reqwest 0.12.23", "thiserror 2.0.18", ] @@ -6299,9 +6361,9 @@ checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.0", + "bitflags 2.11.1", "num-traits", - "rand 0.9.2", + "rand 0.9.3", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -6318,25 +6380,25 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "proptest-derive" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "095a99f75c69734802359b682be8daaf8980296731f6470434ea2c652af1dd30" +checksum = "c57924a81864dddafba92e1bf92f9bf82f97096c44489548a60e888e1547549b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "prost" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", "prost-derive", @@ -6349,38 +6411,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ "heck 0.5.0", - "itertools 0.14.0", + "itertools 0.13.0", "log", "multimap", - "petgraph", + "petgraph 0.8.3", "prettyplease", "prost", "prost-types", "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn 2.0.117", + "syn 2.0.118", "tempfile", ] [[package]] name = "prost-derive" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "prost-types" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ "prost", ] @@ -6403,7 +6465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973" dependencies = [ "anyhow", - "indexmap 2.11.4", + "indexmap 2.14.0", "log", "protobuf", "protobuf-support", @@ -6436,7 +6498,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "memchr", "unicase", ] @@ -6452,25 +6514,25 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beafc309a2d35e16cc390644d88d14dfa45e45e15075ec6a9e37f6dfb43e926f" +checksum = "38b92604caae1a1899b6a5b54967289dd538177c626004c91accf9d0ec7e4a12" dependencies = [ "cranelift-bitset", "log", "pulley-macros", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "pulley-macros" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885fbb6c07454cfc8725a18a1da3cfc328ee8c53fb8d0671ea313edc8567947" +checksum = "5a7ac85c0bb3fb351f10d531230aaa5e366b46d7c4e5328e5f02801d6dac1165" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6481,9 +6543,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" dependencies = [ "memchr", "serde", @@ -6491,19 +6553,22 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", + "rustc-hash", "rustls", - "thiserror 1.0.61", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", + "web-time", ] [[package]] @@ -6512,12 +6577,13 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ + "aws-lc-rs", "bytes", "getrandom 0.3.1", "lru-slab", - "rand 0.9.2", + "rand 0.9.3", "ring", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -6529,22 +6595,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.7", + "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -6574,9 +6641,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -6586,9 +6653,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -6597,9 +6664,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom 0.4.2", @@ -6706,7 +6773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6717,16 +6784,16 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redis" -version = "1.1.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e41a79ae5cbb41257d84cf4cf0db0bb5a95b11bf05c62c351de4fe748620d" +checksum = "a12e6b5f4d8ef33944e833e2b1859ad478deab6e431d7337b30ee2efe21f7543" dependencies = [ "arc-swap", "arcstr", "async-lock", "backon", "bytes", - "cfg-if 1.0.0", + "cfg-if", "combine", "futures-channel", "futures-util", @@ -6736,7 +6803,7 @@ dependencies = [ "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.6.0", + "socket2", "tokio", "tokio-util", "url", @@ -6758,7 +6825,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", ] [[package]] @@ -6772,25 +6839,46 @@ dependencies = [ "thiserror 1.0.61", ] +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "regalloc2" -version = "0.13.5" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" +checksum = "de2c52737737f8609e94f975dee22854a2d5c125772d4b1cf292120f4d45c186" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.2", + "hashbrown 0.17.0", "log", - "rustc-hash 2.1.1", + "rustc-hash", + "serde", "smallvec", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -6811,9 +6899,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" @@ -6822,14 +6910,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "async-compression", - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-channel", "futures-core", "futures-util", "h2", - "http 1.4.0", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -6843,9 +6931,6 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", - "rustls-native-certs 0.8.1", "rustls-pki-types", "serde", "serde_json", @@ -6853,17 +6938,56 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-util", + "tower 0.5.2", + "tower-http 0.6.11", + "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.0", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http 1.4.2", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", "tokio-rustls", "tokio-util", "tower 0.5.2", - "tower-http", + "tower-http 0.6.11", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", - "webpki-roots 1.0.5", ] [[package]] @@ -6883,7 +7007,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", "getrandom 0.2.15", "libc", "untrusted", @@ -6920,8 +7044,8 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.5", - "rand 0.9.2", + "rand 0.8.6", + "rand 0.9.3", "rlp", "ruint-macro", "serde_core", @@ -6941,12 +7065,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -6983,7 +7101,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys 0.4.14", @@ -6992,26 +7110,26 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys 0.12.1", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ + "aws-lc-rs", "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -7020,54 +7138,60 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile", "rustls-pki-types", "schannel", - "security-framework 2.11.0", + "security-framework 3.7.0", ] [[package]] -name = "rustls-native-certs" -version = "0.8.1" +name = "rustls-pki-types" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework 3.2.0", + "web-time", + "zeroize", ] [[package]] -name = "rustls-pemfile" -version = "2.1.2" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "base64 0.22.1", - "rustls-pki-types", + "core-foundation 0.10.0", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework 3.7.0", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", ] [[package]] -name = "rustls-pki-types" -version = "1.11.0" +name = "rustls-platform-verifier-android" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" -dependencies = [ - "web-time", -] +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -7125,12 +7249,27 @@ dependencies = [ ] [[package]] -name = "scoped-futures" -version = "0.1.4" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" dependencies = [ - "pin-project-lite", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] @@ -7161,11 +7300,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", + "rand 0.8.6", + "secp256k1-sys 0.10.1", "serde", ] +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.3", + "secp256k1-sys 0.11.0", +] + [[package]] name = "secp256k1-sys" version = "0.10.1" @@ -7175,13 +7325,22 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -7190,11 +7349,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -7203,9 +7362,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -7253,9 +7412,9 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -7263,33 +7422,35 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -7313,9 +7474,9 @@ dependencies = [ [[package]] name = "serde_regex" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" +checksum = "bafc8d0c5330cecff10f16b459b479fd9acaa5b4acd7167301414e21b0057012" dependencies = [ "regex", "serde", @@ -7323,18 +7484,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -7353,17 +7505,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", + "bs58 0.5.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", - "serde", - "serde_derive", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -7371,14 +7525,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ - "darling 0.20.10", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7387,7 +7541,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.14.0", "itoa", "ryu", "serde", @@ -7410,7 +7564,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.2.12", "digest 0.10.7", ] @@ -7421,7 +7575,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.3.0", "digest 0.11.2", ] @@ -7438,7 +7592,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.2.12", "digest 0.10.7", ] @@ -7449,29 +7603,29 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures 0.3.0", "digest 0.11.2", ] [[package]] name = "sha3" -version = "0.10.8" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" dependencies = [ - "digest 0.10.7", + "digest 0.11.2", "keccak", ] [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "9f3f15d4e239ebe08413eed880e0f9b5af4b40ee0472543320efa91d488e96a7" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -7543,9 +7697,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "3.0.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d0b06eba54f0ca0770f970a3e89823e766ca638dd940f8469fa0fa50c75396" +checksum = "e6505efef05804732ed8a3f2d4f279429eb485bd69d5b0cc6b19cc02005cda16" dependencies = [ "bstr", ] @@ -7641,9 +7795,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "arbitrary", "serde", @@ -7655,16 +7809,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.0" @@ -7704,9 +7848,9 @@ dependencies = [ [[package]] name = "sqlparser" -version = "0.61.0" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf5ea8d4d7c808e1af1cbabebca9a2abe603bcefc22294c5b95018d53200cb7" +checksum = "13c6d1b651dc4edf07eead2a0c6c78016ce971bc2c10da5266861b13f25e7cec" dependencies = [ "log", "recursive", @@ -7721,7 +7865,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7732,15 +7876,15 @@ checksum = "a6dd45d8fc1c79299bfbb7190e42ccbbdf6a5f52e4a6ad98d92357ea965bd289" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "stable-hash" version = "0.3.4" -source = "git+https://github.com/graphprotocol/stable-hash?branch=old#7af76261e8098c58bfadd5b7c31810e1c0fdeccb" +source = "git+https://github.com/graphprotocol/stable-hash?rev=42b85d936c6b9f1b7a4b8385d2f081d5564daa69#42b85d936c6b9f1b7a4b8385d2f081d5564daa69" dependencies = [ - "blake3 0.3.8", + "blake3", "firestorm 0.4.6", "ibig", "lazy_static", @@ -7751,15 +7895,15 @@ dependencies = [ [[package]] name = "stable-hash" version = "0.4.4" -source = "git+https://github.com/graphprotocol/stable-hash?branch=main#e50aabef55b8c4de581ca5c4ffa7ed8beed7e998" +source = "git+https://github.com/graphprotocol/stable-hash?rev=70300f974e61529675aef3f20803f26a23f0e0ea#70300f974e61529675aef3f20803f26a23f0e0ea" dependencies = [ - "blake3 0.3.8", + "blake3", "firestorm 0.5.1", "ibig", "lazy_static", "leb128", "num-traits", - "uint 0.8.5", + "uint 0.10.1", "xxhash-rust", ] @@ -7776,7 +7920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "psm", "windows-sys 0.59.0", @@ -7838,7 +7982,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7850,7 +7994,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7872,9 +8016,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -7883,14 +8027,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f92d01b5de07eaf324f7fca61cc6bd3d82bbc1de5b6c963e6fe79e86f36580d" +checksum = "ec005042c7d952febc1a3ef5b0f6674e9054aa836877a31c90b20e25b3d31744" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7910,7 +8054,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7919,7 +8063,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -7948,21 +8092,21 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if 1.0.0", "fastrand", + "getrandom 0.4.2", "once_cell", - "rustix 0.38.34", - "windows-sys 0.59.0", + "rustix 1.1.4", + "windows-sys 0.52.0", ] [[package]] @@ -7987,17 +8131,17 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 1.0.7", - "windows-sys 0.61.1", + "rustix 0.38.34", + "windows-sys 0.48.0", ] [[package]] name = "test-store" -version = "0.42.1" +version = "0.45.0" dependencies = [ "async-trait", "diesel", @@ -8042,7 +8186,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8053,7 +8197,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8062,7 +8206,7 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -8075,17 +8219,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "thrift" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" -dependencies = [ - "byteorder", - "integer-encoding", - "ordered-float", -] - [[package]] name = "time" version = "0.3.47" @@ -8117,15 +8250,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-keccak" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" -dependencies = [ - "crunchy", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -8172,9 +8296,9 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.0", + "socket2", "tokio-macros", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -8185,7 +8309,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8229,8 +8353,8 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.9.2", - "socket2 0.6.0", + "rand 0.9.3", + "socket2", "tokio", "tokio-util", "whoami", @@ -8238,12 +8362,12 @@ dependencies = [ [[package]] name = "tokio-retry" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +checksum = "4a129d95275ebf4c493ec53bf0f8cd95f5ac161bc4f381700809a54f595d4470" dependencies = [ - "pin-project", - "rand 0.8.5", + "pin-project-lite", + "rand 0.10.1", "tokio", ] @@ -8284,9 +8408,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", @@ -8294,20 +8418,20 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.26.2", + "tungstenite 0.28.0", "webpki-roots 0.26.11", ] [[package]] name = "tokio-tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite 0.29.0", ] [[package]] @@ -8324,41 +8448,31 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" -dependencies = [ - "serde", - "serde_spanned 0.6.6", - "toml_datetime 0.6.6", - "toml_edit 0.22.16", -] - [[package]] name = "toml" version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ + "indexmap 2.14.0", "serde_core", - "serde_spanned 1.1.0", + "serde_spanned", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", + "toml_writer", "winnow 0.7.13", ] [[package]] name = "toml" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.14.0", "serde_core", - "serde_spanned 1.1.0", - "toml_datetime 1.1.0+spec-1.1.0", + "serde_spanned", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", "winnow 1.0.0", @@ -8369,9 +8483,6 @@ name = "toml_datetime" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" -dependencies = [ - "serde", -] [[package]] name = "toml_datetime" @@ -8384,9 +8495,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -8397,52 +8508,39 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.14.0", "toml_datetime 0.6.6", "winnow 0.5.40", ] -[[package]] -name = "toml_edit" -version = "0.22.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" -dependencies = [ - "indexmap 2.11.4", - "serde", - "serde_spanned 0.6.6", - "toml_datetime 0.6.6", - "winnow 0.6.13", -] - [[package]] name = "toml_parser" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow 1.0.0", ] [[package]] name = "toml_writer" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tonic" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64 0.22.1", + "base64", "bytes", "flate2", "h2", - "http 1.4.0", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -8450,8 +8548,8 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "rustls-native-certs 0.8.1", - "socket2 0.6.0", + "rustls-native-certs", + "socket2", "sync_wrapper", "tokio", "tokio-rustls", @@ -8464,21 +8562,21 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.14.3" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27aac809edf60b741e2d7db6367214d078856b8a5bff0087e94ff330fb97b6fc" +checksum = "c68f61875ac5293cf72e6c8cf0158086428c82c37229e98c840878f1706b0322" dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "tonic-prost" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" dependencies = [ "bytes", "prost", @@ -8487,16 +8585,16 @@ dependencies = [ [[package]] name = "tonic-prost-build" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3144df636917574672e93d0f56d7edec49f90305749c668df5101751bb8f95a" +checksum = "654e5643eff75d7f8c99197ce1440ed19a3474eada74c12bbac488b2cafdae27" dependencies = [ "prettyplease", "proc-macro2", "prost-build", "prost-types", "quote", - "syn 2.0.117", + "syn 2.0.118", "tempfile", "tonic-build", ] @@ -8510,7 +8608,7 @@ dependencies = [ "futures-core", "futures-util", "hdrhistogram", - "indexmap 2.11.4", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -8524,12 +8622,12 @@ dependencies = [ [[package]] name = "tower" version = "0.5.3" -source = "git+https://github.com/tower-rs/tower.git#251296dc54a044383dffd16d2179b443e2615672" +source = "git+https://github.com/tower-rs/tower.git#df06d70dbea345facbffb5881fe8647f53bf424d" dependencies = [ "futures-core", "futures-util", "hdrhistogram", - "indexmap 2.11.4", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -8542,20 +8640,35 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "bytes", "futures-util", - "http 1.4.0", + "http 1.4.2", "http-body", - "iri-string", "pin-project-lite", "tower 0.5.2", "tower-layer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url", +] + +[[package]] +name = "tower-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +dependencies = [ + "bitflags 2.11.1", + "bytes", + "http 1.4.2", + "percent-encoding", + "pin-project-lite", + "tower-layer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -8567,7 +8680,7 @@ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-layer" version = "0.3.3" -source = "git+https://github.com/tower-rs/tower.git#251296dc54a044383dffd16d2179b443e2615672" +source = "git+https://github.com/tower-rs/tower.git#df06d70dbea345facbffb5881fe8647f53bf424d" [[package]] name = "tower-service" @@ -8578,12 +8691,12 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tower-service" version = "0.3.3" -source = "git+https://github.com/tower-rs/tower.git#251296dc54a044383dffd16d2179b443e2615672" +source = "git+https://github.com/tower-rs/tower.git#df06d70dbea345facbffb5881fe8647f53bf424d" [[package]] name = "tower-test" version = "0.4.1" -source = "git+https://github.com/tower-rs/tower.git#251296dc54a044383dffd16d2179b443e2615672" +source = "git+https://github.com/tower-rs/tower.git#df06d70dbea345facbffb5881fe8647f53bf424d" dependencies = [ "pin-project-lite", "tokio", @@ -8612,7 +8725,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8632,16 +8745,16 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[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", - "http 1.4.0", + "http 1.4.2", "httparse", "log", - "rand 0.9.2", + "rand 0.9.3", "rustls", "rustls-pki-types", "sha1 0.10.6", @@ -8651,19 +8764,18 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http 1.4.2", "httparse", "log", - "rand 0.9.2", + "rand 0.9.3", "sha1 0.10.6", "thiserror 2.0.18", - "utf-8", ] [[package]] @@ -8686,21 +8798,21 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" -version = "0.8.5" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", - "rustc-hex", + "hex", "static_assertions", ] [[package]] name = "uint" -version = "0.9.5" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +checksum = "6f9227a75a5a540a464c832ad4a4195dbdbecd8787610a56262721fde6f04f90" dependencies = [ "byteorder", "crunchy", @@ -8780,12 +8892,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" -[[package]] -name = "unsigned-varint" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" - [[package]] name = "unsigned-varint" version = "0.8.0" @@ -8928,47 +9034,32 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" dependencies = [ - "cfg-if 1.0.0", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8976,34 +9067,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", - "wasm-bindgen-backend", + "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" dependencies = [ "unicode-ident", ] [[package]] -name = "wasm-encoder" -version = "0.239.0" +name = "wasm-compose" +version = "0.251.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" +checksum = "b089037d7eb453ed57b560fe7833de0707411c8b9fdc429745ced77e2a1bacb9" dependencies = [ - "leb128fmt", - "wasmparser 0.239.0", + "anyhow", + "heck 0.5.0", + "indexmap 2.14.0", + "log", + "petgraph 0.6.5", + "smallvec", + "wasm-encoder 0.251.0", + "wasmparser 0.251.0", + "wat", ] [[package]] @@ -9016,11 +9114,31 @@ dependencies = [ "wasmparser 0.244.0", ] +[[package]] +name = "wasm-encoder" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a879a421bd17c528b74721b2abf4c62e8f1d1889c2ba8c3c50d02deaf2ce395" +dependencies = [ + "leb128fmt", + "wasmparser 0.251.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f" +dependencies = [ + "leb128fmt", + "wasmparser 0.252.0", +] + [[package]] name = "wasm-instrument" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bca81f5279342b38b17d9acbf007a46ddeb73144e2bd5f0a21bfa9fc5d4ab3e" +checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" dependencies = [ "parity-wasm", ] @@ -9032,7 +9150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.11.4", + "indexmap 2.14.0", "wasm-encoder 0.244.0", "wasmparser 0.244.0", ] @@ -9050,70 +9168,92 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.14.0", "semver 1.0.28", ] [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", "hashbrown 0.15.2", - "indexmap 2.11.4", + "indexmap 2.14.0", + "semver 1.0.28", +] + +[[package]] +name = "wasmparser" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437970b35b1a85cfde9c74b2398352d8d653f3bd8e3a3db0c063ea8f5b4b36ff" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.17.0", + "indexmap 2.14.0", "semver 1.0.28", "serde", ] [[package]] name = "wasmparser" -version = "0.244.0" +version = "0.252.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c" dependencies = [ - "bitflags 2.9.0", - "hashbrown 0.15.2", - "indexmap 2.11.4", + "bitflags 2.11.1", + "indexmap 2.14.0", "semver 1.0.28", ] [[package]] name = "wasmprinter" -version = "0.239.0" +version = "0.251.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3981f3d51f39f24f5fc90f93049a90f08dbbca8deba602cd46bb8ca67a94718" +checksum = "8798c1a699bd25648b6708eefe94d97c6f9891febb94b42cca1f7a4b086ea64e" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.239.0", + "wasmparser 0.251.0", ] [[package]] name = "wasmtime" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81eafc07c867be94c47e0dc66355d9785e09107a18901f76a20701ba0663ad7" +checksum = "c4213d2f019a5e44aa8a61d8826dd33a505bff79f749b14a8bafd67321cb9351" dependencies = [ "addr2line", - "anyhow", "async-trait", - "bitflags 2.9.0", + "bitflags 2.11.1", "bumpalo", "cc", - "cfg-if 1.0.0", + "cfg-if", "encoding_rs", + "futures 0.3.31", "fxprof-processed-profile", "gimli", - "hashbrown 0.15.2", - "indexmap 2.11.4", "ittapi", "libc", "log", @@ -9124,44 +9264,47 @@ dependencies = [ "postcard", "pulley-interpreter", "rayon", - "rustix 1.0.7", + "rustix 1.1.4", "semver 1.0.28", "serde", "serde_derive", "serde_json", "smallvec", "target-lexicon", - "wasm-encoder 0.239.0", - "wasmparser 0.239.0", + "tempfile", + "wasm-compose", + "wasm-encoder 0.251.0", + "wasmparser 0.251.0", "wasmtime-environ", "wasmtime-internal-cache", "wasmtime-internal-component-macro", "wasmtime-internal-component-util", + "wasmtime-internal-core", "wasmtime-internal-cranelift", "wasmtime-internal-fiber", "wasmtime-internal-jit-debug", "wasmtime-internal-jit-icache-coherence", - "wasmtime-internal-math", - "wasmtime-internal-slab", "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", - "wasmtime-internal-winch", "wat", - "windows-sys 0.60.2", + "windows-sys 0.61.2", + "wit-parser 0.251.0", ] [[package]] name = "wasmtime-environ" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78587abe085a44a13c90fa16fea6db014e9883e627a7044d7f0cb397ad08d1da" +checksum = "d45863de41977ec6453e859cf843d456fa3fcb45a659b66d16e794f90ec4f5b7" dependencies = [ "anyhow", "cpp_demangle", + "cranelift-bforest", "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.4", + "hashbrown 0.17.0", + "indexmap 2.14.0", "log", "object", "postcard", @@ -9169,63 +9312,76 @@ dependencies = [ "semver 1.0.28", "serde", "serde_derive", + "sha2 0.10.9", "smallvec", "target-lexicon", - "wasm-encoder 0.239.0", - "wasmparser 0.239.0", + "wasm-encoder 0.251.0", + "wasmparser 0.251.0", "wasmprinter", "wasmtime-internal-component-util", + "wasmtime-internal-core", ] [[package]] name = "wasmtime-internal-cache" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78fb9299e318b0af3efb75d88321515a20a5ccb040bcde1f0f7d46d656fa8fef" +checksum = "438bc7dc45fb75297d75f79a9a0ce852345d13ebc6a6863f6f688f013836a9dd" dependencies = [ - "anyhow", - "base64 0.22.1", + "base64", "directories-next", "log", "postcard", - "rustix 1.0.7", + "rustix 1.1.4", "serde", "serde_derive", "sha2 0.10.9", - "toml 0.8.15", - "windows-sys 0.60.2", + "toml 0.9.12+spec-1.1.0", + "wasmtime-environ", + "windows-sys 0.61.2", "zstd", ] [[package]] name = "wasmtime-internal-component-macro" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d843bb444f2d1509ea9304ad749242d1fa5de95cde67665bfcdcafa0f360925c" +checksum = "f1e48f8d4966d62a10b6d70722bc432c1e163890be2801d3b5784589ad36ffc3" dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "wasmtime-internal-component-util", "wasmtime-internal-wit-bindgen", - "wit-parser 0.239.0", + "wit-parser 0.251.0", ] [[package]] name = "wasmtime-internal-component-util" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801ee1a80ab66f065a88c6a62f2d495d5540d027b366757c6a53e9c42f153aef" +checksum = "819ad5abd5822a22dbf4014475cdfd1fe790707761cd732d74aaa3ba4d5ba489" [[package]] -name = "wasmtime-internal-cranelift" -version = "38.0.4" +name = "wasmtime-internal-core" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb50f1c50365c32e557266ca85acdf77696c44a3f98797ba6af58cebc6d6d1e" +checksum = "3fc28372e36eaf8cf70faa83b5779137f7e99c8d18569a125d1580e735cc9e4d" dependencies = [ "anyhow", - "cfg-if 1.0.0", + "hashbrown 0.17.0", + "libm", + "serde", +] + +[[package]] +name = "wasmtime-internal-cranelift" +version = "46.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a433efc6e35112a5457e1dc8bc4d8d39820ac7722267e89bc04e5df641f32124" +dependencies = [ + "cfg-if", "cranelift-codegen", "cranelift-control", "cranelift-entity", @@ -9239,120 +9395,87 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 2.0.18", - "wasmparser 0.239.0", + "wasmparser 0.251.0", "wasmtime-environ", - "wasmtime-internal-math", + "wasmtime-internal-core", "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-fiber" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9308cdb17f8d51e3164185616d809e28c29a6515c03b9dd95c89436b71f6d154" +checksum = "18a1d3a39d0d210f6b8574ee96a4315e0a14c67f3a1fc3cd5372cb10d2fb4422" dependencies = [ - "anyhow", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", - "rustix 1.0.7", + "rustix 1.1.4", + "wasmtime-environ", "wasmtime-internal-versioned-export-macros", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "wasmtime-internal-jit-debug" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c9b63a22bf2a8b6a149a41c6768bc17a8b2e3288a249cb8216987fbd7128e81" +checksum = "9f667288cb4dfa68a4639ffac4d5628535dda64ebdc2b990526efb12b30ba803" dependencies = [ "cc", "object", - "rustix 1.0.7", + "rustix 1.1.4", "wasmtime-internal-versioned-export-macros", ] [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb8e042b6e3de2f3d708279f89f50b4b9aa1b9bab177300cdffb0ffcd2816df5" +checksum = "eba651d44ab0faad4c58106b3adb45068189fb65ef50f0c404b6d9e3bf81a357" dependencies = [ - "anyhow", - "cfg-if 1.0.0", + "cfg-if", "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "wasmtime-internal-math" -version = "38.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1f0674f38cd7d014eb1a49ea1d1766cca1a64459e8856ee118a10005302e16" -dependencies = [ - "libm", + "wasmtime-internal-core", + "windows-sys 0.61.2", ] -[[package]] -name = "wasmtime-internal-slab" -version = "38.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb24b7535306713e7a250f8b71e35f05b6a5031bf9c3ed7330c308e899cbe7d3" - [[package]] name = "wasmtime-internal-unwinder" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21d5a80e2623a49cb8e8c419542337b8fe0260b162c40dcc201080a84cbe9b7c" +checksum = "2ecc52563b0558af2a7487eb710de07cc4532564b55528876129238e83118cb1" dependencies = [ - "anyhow", - "cfg-if 1.0.0", + "cfg-if", "cranelift-codegen", "log", "object", + "wasmtime-environ", ] [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e277f734b9256359b21517c3b0c26a2a9de6c53a51b670ae55cdcde548bf4e" +checksum = "e747f4a074699ba1b4e4d841fb263f9b7df5bd1555181c4752bf5990d21ba676" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "wasmtime-internal-winch" -version = "38.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4dc9333737142f6ece4369c8bcdda03a11edbd43d8fbd3e15004c194b9b743" -dependencies = [ - "anyhow", - "cranelift-codegen", - "gimli", - "log", - "object", - "target-lexicon", - "wasmparser 0.239.0", - "wasmtime-environ", - "wasmtime-internal-cranelift", - "winch-codegen", + "syn 2.0.118", ] [[package]] name = "wasmtime-internal-wit-bindgen" -version = "38.0.4" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f758625553fe33fdce0713f63bb7784c4f5fecb7f7cd4813414519ec24b6a4c" +checksum = "80009f46991622814196d96fac6fc0a938f46b5cba737a8f4e21e24e5a03856f" dependencies = [ "anyhow", - "bitflags 2.9.0", + "bitflags 2.11.1", "heck 0.5.0", - "indexmap 2.11.4", - "wit-parser 0.239.0", + "indexmap 2.14.0", + "wit-parser 0.251.0", ] [[package]] @@ -9371,31 +9494,31 @@ dependencies = [ [[package]] name = "wast" -version = "244.0.0" +version = "252.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e7b9f9e23311275920e3d6b56d64137c160cf8af4f84a7283b36cfecbf4acb" +checksum = "942a3449d6a593fccc111a6241c8df52bda168af30e40bf9580d4394d7374c65" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.244.0", + "wasm-encoder 0.252.0", ] [[package]] name = "wat" -version = "1.244.0" +version = "1.252.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf35b87ed352f9ab6cd0732abde5a67dd6153dfd02c493e61459218b19456fa" +checksum = "c72a4ba7088f7bac94cf516e49882bdf97068904a563768cf249efc839ec42cb" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" dependencies = [ "js-sys", "wasm-bindgen", @@ -9411,6 +9534,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.11" @@ -9489,26 +9621,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "winch-codegen" -version = "38.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c0bb17ae9bf89ebc74512150e6ee0a27b1eac5ff3b54d8cec264f4b4255022d" -dependencies = [ - "anyhow", - "cranelift-assembler-x64", - "cranelift-codegen", - "gimli", - "regalloc2", - "smallvec", - "target-lexicon", - "thiserror 2.0.18", - "wasmparser 0.239.0", - "wasmtime-environ", - "wasmtime-internal-cranelift", - "wasmtime-internal-math", -] - [[package]] name = "windows-core" version = "0.52.0" @@ -9526,9 +9638,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" @@ -9559,6 +9671,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -9597,11 +9718,26 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows-link 0.2.0", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -9652,6 +9788,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -9670,6 +9812,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -9688,6 +9836,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -9718,6 +9872,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -9736,6 +9896,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -9754,6 +9920,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -9772,6 +9944,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -9799,29 +9977,20 @@ dependencies = [ "memchr", ] -[[package]] -name = "winnow" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] [[package]] name = "winnow" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +dependencies = [ + "memchr", +] [[package]] name = "wiremock" @@ -9830,10 +9999,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" dependencies = [ "assert-json-diff", - "base64 0.22.1", + "base64", "deadpool 0.12.3", "futures 0.3.31", - "http 1.4.0", + "http 1.4.2", "http-body-util", "hyper", "hyper-util", @@ -9872,7 +10041,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.11.1", ] [[package]] @@ -9883,9 +10052,9 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.4", + "indexmap 2.14.0", "prettyplease", - "syn 2.0.117", + "syn 2.0.118", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -9901,7 +10070,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -9913,8 +10082,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.9.0", - "indexmap 2.11.4", + "bitflags 2.11.1", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -9927,38 +10096,39 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.239.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.4", + "indexmap 2.14.0", "log", "semver 1.0.28", "serde", "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.239.0", + "wasmparser 0.244.0", ] [[package]] name = "wit-parser" -version = "0.244.0" +version = "0.251.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +checksum = "e960732e824fab95099971a09e638979347c94ca48568d3c854c945729196947" dependencies = [ "anyhow", + "hashbrown 0.17.0", "id-arena", - "indexmap 2.11.4", + "indexmap 2.14.0", "log", "semver 1.0.28", "serde", "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.244.0", + "wasmparser 0.251.0", ] [[package]] @@ -10033,7 +10203,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] @@ -10054,7 +10224,7 @@ checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10074,7 +10244,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] @@ -10095,7 +10265,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10117,7 +10287,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10126,6 +10296,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c745c48e1007337ed136dc99df34128b9faa6ed542d80a1c673cf55a6d7236c8" +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index cfe09925a4a..a956a514a95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,8 @@ members = [ ] [workspace.package] -version = "0.42.1" -edition = "2021" +version = "0.45.0" +edition = "2024" authors = ["The Graph core developers & contributors"] readme = "README.md" homepage = "https://thegraph.com" @@ -35,13 +35,18 @@ repository = "https://github.com/graphprotocol/graph-node" license = "MIT OR Apache-2.0" [workspace.dependencies] -alloy = { version = "1.7.3", features = ["dyn-abi", "json-abi", "full", "arbitrary", "json-rpc", "serde"] } -alloy-rpc-types = "1.0.33" +alloy = { version = "2.0.5", features = ["dyn-abi", "json-abi", "full", "arbitrary", "json-rpc", "serde"] } +alloy-rpc-types = "2.0.0" +# rustls is pulled in transitively by alloy (aws_lc_rs) and object_store via +# reqwest (ring). With both providers linked, rustls 0.23 requires an explicit +# default provider to be installed before any TLS use. We install aws_lc_rs +# explicitly in each binary/test entry point. +rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs"] } anyhow = "1.0" async-graphql = { version = "7.2.1", features = ["chrono"] } async-graphql-axum = "7.2.1" async-trait = "0.1.74" -axum = "0.8.8" +axum = "0.8.9" chrono = "0.4.44" bs58 = "0.5.1" clap = { version = "4.5.4", features = ["derive", "env", "wrap_help"] } @@ -56,11 +61,11 @@ diesel = { version = "2.2.7", features = [ "chrono", "i-implement-a-third-party-backend-and-opt-into-breaking-changes", ] } -diesel-async = { version = "0.8.0", features = ["deadpool", "async-connection-wrapper", "tokio", "postgres"] } +diesel-async = { version = "0.9.0", features = ["deadpool", "async-connection-wrapper", "tokio", "postgres"] } diesel-derive-enum = { version = "2.1.0", features = ["postgres"] } diesel-dynamic-schema = { version = "0.2.3", features = ["postgres"] } -diesel_derives = "2.3.7" -diesel_migrations = "2.3.1" +diesel_derives = "2.3.9" +diesel_migrations = "2.3.2" env_logger = "0.11.10" envconfig = "0.11.1" git-testament = "0.2" @@ -73,11 +78,11 @@ graphman-store = { path = "./core/graphman_store" } graphql-tools = "0.5.1" indicatif = "0.18" Inflector = "0.11.3" -itertools = "0.14.0" +itertools = "0.15.0" lazy_static = "1.5.0" prost = "0.14" prost-types = "0.14" -redis = { version = "1.1.0", features = [ +redis = { version = "1.2.2", features = [ "aio", "connection-manager", "tokio-comp", @@ -93,7 +98,7 @@ serde_yaml = "0.9.21" slog = { version = "2.8.2", features = ["release_max_level_trace", "max_level_trace"] } slog-async = "2.5.0" slog-term = "2.7.0" -sqlparser = { version = "0.61.0", features = ["visitor"] } +sqlparser = { version = "0.62.0", features = ["visitor"] } strum = { version = "0.28", features = ["derive"] } syn = { version = "2.0.117", features = ["full"] } test-store = { path = "./store/test-store" } @@ -106,19 +111,19 @@ tokio-retry = "0.3.0" tonic = { version = "0.14", features = ["tls-native-roots", "gzip"] } tonic-prost = "0.14" tonic-prost-build = "0.14" -tower-http = { version = "0.6.8", features = ["cors"] } +tower-http = { version = "0.7.0", features = ["cors"] } tower = { version = "0.5.1", features = ["full"] } wasmparser = "0.118.1" -wasmtime = { version = "38.0.4", features = ["async"] } +wasmtime = { version = "46.0.0", features = ["async"] } rand = { version = "0.9.2", features = ["os_rng"] } prometheus = "0.14.0" url = "2.5.8" # Dependencies related to Amp subgraphs ahash = "0.8.11" -arrow = { version = "=58.1.0" } -arrow-flight = { version = "=58.1.0", features = ["flight-sql-experimental"] } -parquet = { version = "=58.1.0" } +arrow = { version = "=59.0.0" } +arrow-flight = { version = "=59.0.0", features = ["flight-sql-experimental"] } +parquet = { version = "=59.0.0" } futures = "0.3.31" half = "2.7.1" indoc = "2.0.7" diff --git a/NEWS.md b/NEWS.md index 1c8682503af..8068ecbc9fa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,148 @@ # NEWS +## v0.45.0 + +``` +$ docker pull graphprotocol/graph-node:v0.45.0 +``` + +### Breaking Changes + +- **`GRAPH_GETH_ETH_CALL_ERRORS` renamed to `GRAPH_RPC_ETH_CALL_ERRORS`.** The env var (and internal config field) controlling which `eth_call` error messages are treated as reverts is renamed for provider-neutral naming. Update it before upgrading, or the setting is silently ignored and defaults apply. ([#6487](https://github.com/graphprotocol/graph-node/pull/6487)) + +### What's New + +- **Postponed attribute index creation re-enabled, now built in the background.** `GRAPH_POSTPONE_ATTRIBUTE_INDEX_CREATION` (introduced in v0.44.0 but inert — hardcoded off) now actually defers non-critical attribute indexes until a new deployment nears chain head (`GRAPH_POSTPONE_INDEXES_CREATION_THRESHOLD`, default 10000 blocks from head). Index creation now runs in a background task instead of blocking block processing, and interrupted `CREATE INDEX CONCURRENTLY` runs are detected and rebuilt on retry instead of being silently skipped. ([#6608](https://github.com/graphprotocol/graph-node/pull/6608)) +- **`ethereum.decodeParams` host function.** Decodes calldata/event data whose top-level type is a dynamic tuple (e.g. Gnosis Safe's `execTransaction`), which `ethereum.decode` cannot handle since it expects a single ABI value with a leading offset word. Gated behind apiVersion 0.0.10; `ethereum.decode` itself is unchanged. ([#6649](https://github.com/graphprotocol/graph-node/pull/6649)) + +### Bug Fixes + +- Fixed `EthereumLogFilter` merging per-handler `receipt` flags with overwrite instead of OR semantics, so a handler declaring `receipt: true` could silently run with `event.receipt == null` if another handler on the same filter key declared `receipt: false`. ([#6558](https://github.com/graphprotocol/graph-node/pull/6558)) +- Fixed grafts silently succeeding when the graft block was below the base deployment's earliest available block, leaving the destination missing pre-graft entity versions and producing `unexpected null in handler` errors on every event; `Graft::validate` now rejects these upfront. ([#6610](https://github.com/graphprotocol/graph-node/pull/6610)) +- Fixed `_logs` queries returning an empty result (indistinguishable from a subgraph producing no logs) when no log store is configured; now returns a `NotSupported` error. ([#6637](https://github.com/graphprotocol/graph-node/pull/6637)) +- Fixed startup panicking when a shard is configured with `pool_size = 0`; such shards' chains are now skipped instead of erroring. ([#6648](https://github.com/graphprotocol/graph-node/pull/6648)) +- Fixed the Firehose extended-blocks check matching on `optimism-mainnet` instead of the `optimism` chain ID used by Firehose endpoints, so Optimism's extended block data went undetected. ([#6662](https://github.com/graphprotocol/graph-node/pull/6662)) +- Fixed fulltext (`tsvector`) search columns being silently dropped when copying or grafting a subgraph, leaving the destination's fulltext index empty. ([#6687](https://github.com/graphprotocol/graph-node/pull/6687)) +- Fixed Reth `StackUnderflow`/`StackOverflow`/`OpcodeNotFound` EVM halts being misclassified as non-deterministic — Reth surfaces them via its `Debug` format (e.g. `EVM error: StackUnderflow`), which didn't match graph-node's space-separated deterministic-error patterns, so subgraphs indexing via Reth-backed RPC providers stalled and retried instead of recording a deterministic revert. ([#6645](https://github.com/graphprotocol/graph-node/pull/6645)) + +### Graphman + +- Fixed `graphman dump` panicking on tables with more than ~2 GiB in a single string/binary column; batches are now split into byte-bounded slices before conversion to Arrow. ([#6646](https://github.com/graphprotocol/graph-node/pull/6646)) + +### gnd (Graph Node Dev) + +- Fixed `gnd add` producing a subgraph that failed `codegen`/`build` because it never wrote new event entities to `schema.graphql`; unified `add` and `init` onto one scaffolding path, which also fixes event-name collisions across data sources, overloaded-event disambiguation, small-integer type mapping, and reserved-word parameter names. ([#6660](https://github.com/graphprotocol/graph-node/pull/6660)) + +### Upgrade Notes + +- If you set `GRAPH_GETH_ETH_CALL_ERRORS`, rename it to `GRAPH_RPC_ETH_CALL_ERRORS` before upgrading. ([#6487](https://github.com/graphprotocol/graph-node/pull/6487)) +- `GRAPH_POSTPONE_ATTRIBUTE_INDEX_CREATION` now actually takes effect (it was a no-op in v0.44.0). If you already set it expecting no behavior change, be aware new deployments will now defer some attribute indexes until near chain head. ([#6608](https://github.com/graphprotocol/graph-node/pull/6608)) +- If a subgraph was grafted from a base block below the base deployment's earliest available block before this release, it may be missing pre-graft entity versions; re-create the graft from a valid earliest block. ([#6610](https://github.com/graphprotocol/graph-node/pull/6610)) + +### Contributors + +Thanks to all contributors for this release: @cargopete, @dimitrovmaksim, @fordN, @incrypto32, @lutter, @YaroShkvorets + +**Full Changelog**: https://github.com/graphprotocol/graph-node/compare/v0.44.0...v0.45.0 + +## v0.44.0 + +``` +$ docker pull graphprotocol/graph-node:v0.44.0 +``` + +### Critical Fix + +- **`EntityCache::load_related` returned wrong derived-collection membership on same-block parent reassignment.** Membership was decided against intermediate cache layers rather than the entity's final state, so entities reassigned to a new parent within the same block could be left in the old collection, omitted from the new one, or wrongly retained after a cross-handler revert. See Upgrade Notes. ([#6548](https://github.com/graphprotocol/graph-node/pull/6548)) + +### Breaking Changes + +- **Elasticsearch CLI flags removed.** `--elasticsearch-url`, `--elasticsearch-user`, `--elasticsearch-password` (and the matching `ELASTICSEARCH_*` env vars) are gone. Configure Elasticsearch under the new `[log_store]` section in `graph-node.toml`. See Upgrade Notes. ([#6278](https://github.com/graphprotocol/graph-node/pull/6278)) + +### What's New + +- **Query subgraph logs over GraphQL.** A new `_logs` field exposes subgraph-emitted logs (mapping `log.*` calls, runtime, system) with filters for level, timestamp range, and text search, plus pagination and `orderDirection`. The old Elasticsearch sink for subgraph logs is replaced by a unified `LogStore` abstraction with three backends configured under a new `[log_store]` section in `graph-node.toml`: File (JSON Lines), Loki, or Elasticsearch. Omit `[log_store]` to disable; logs still go to stdout/stderr. ([#6278](https://github.com/graphprotocol/graph-node/pull/6278)) + + + + +### Improvements + +- Revert entity versions during copy instead of in a separate post-copy pass, speeding up subgraph copy and graft. ([#6472](https://github.com/graphprotocol/graph-node/pull/6472)) + +### Bug Fixes + +- Fixed `trace_filter` deserialization failing on providers that omit `result.output` (notably Sonic), which caused repeated trace ingestion retries. Fixed upstream in alloy 2.0.5 ([alloy#3931](https://github.com/alloy-rs/alloy/pull/3931)) and picked up via the bump in this release. ([#6576](https://github.com/graphprotocol/graph-node/pull/6576)) +- Fixed runner panics on out-of-range `BigInt` values: `to_signed_u256` replaced by fallible `to_i256`, and `to_unsigned_u256` now errors on values `>= 2^256` instead of panicking. ([#6560](https://github.com/graphprotocol/graph-node/pull/6560)) +- Fixed `graphman chain change-shard` failing with a duplicate-key error on revert to the original shard. Backups now use unique names and revert reuses the existing `-old`. ([#6199](https://github.com/graphprotocol/graph-node/pull/6199)) + +### Upgrade Notes + +- v0.44.0 changes `EntityCache::load_related` results for same-block parent-reassignment edge cases ([#6548](https://github.com/graphprotocol/graph-node/pull/6548)). Subgraphs that read derived fields within handlers may diverge in POI from v0.43.0 on blocks exhibiting this pattern; resync from before the affected blocks if affected. The v0.44.0 result is canonical. +- If you set `--elasticsearch-*` flags or `ELASTICSEARCH_*` env vars, migrate to a `[log_store]` section in `graph-node.toml` before upgrading. See `docs/log-store.md`. ([#6278](https://github.com/graphprotocol/graph-node/pull/6278)) + +### Contributors + +Thanks to all contributors for this release: @erayack, @fordN, @incrypto32, @lutter + +**Full Changelog**: https://github.com/graphprotocol/graph-node/compare/v0.43.0...v0.44.0 + +## v0.43.0 + +### What's New + +- **`skipDuplicates` for immutable entities.** A new `skipDuplicates` parameter on the `@entity` directive (`@entity(immutable: true, skipDuplicates: true)`) silently skips duplicate inserts instead of failing the subgraph. This unblocks subgraph composition on Amp-powered subgraphs where SQL queries can produce the same entities across block ranges. ([#6458](https://github.com/graphprotocol/graph-node/pull/6458)) +- **Per-chain RPC settings via TOML config.** Chain-specific tuning parameters (`json_rpc_timeout`, `request_retries`, `max_block_range_size`, `polling_interval`, `block_batch_size`, etc.) can now be set per chain in `config.toml` instead of relying on global environment variables. Fully backwards compatible — env vars remain the fallback. ([#6459](https://github.com/graphprotocol/graph-node/pull/6459)) +- **RPC provider failover for block ingestor.** When the current RPC provider becomes unreachable during block ingestion polling, graph-node now automatically switches to a healthy alternative provider. ([#6430](https://github.com/graphprotocol/graph-node/pull/6430)) +- Warn on startup when running a debug build, with `[DEBUG-BUILD]` prefix on all log lines. ([#6488](https://github.com/graphprotocol/graph-node/pull/6488)) + +### Improvements + +- **Call cache eviction rewrite.** Replaced the old per-contract iteration approach with ctid-based join deletes against the `call_meta` table, significantly faster on large `call_cache` tables. The old `--ttl-max-contracts` flag has been replaced by `--max-contracts`, which computes an effective TTL cutoff instead of limiting per-invocation iteration. Eviction now also returns stats on the number of contracts and entries removed. ([#6476](https://github.com/graphprotocol/graph-node/pull/6476)) ([#6477](https://github.com/graphprotocol/graph-node/pull/6477)) +- Reduced unnecessary `eth_getBlockByHash` and `eth_getBlockByNumber` RPC calls by checking the block cache first in `block_pointer_from_number` and `fetch_full_block_with_rpc`. ([#6491](https://github.com/graphprotocol/graph-node/pull/6491), partially reverted by [#6537](https://github.com/graphprotocol/graph-node/pull/6537)) +- Header-only `ChainStore` query methods (`ancestor_block_ptr`, `block_parent_ptr`) skip deserializing the full block `data` JSONB column when only hash/number/parent are needed. ([#6456](https://github.com/graphprotocol/graph-node/pull/6456)) +- Batch checking for update attempts on immutable entities, reducing per-entity overhead. +- Node name is now used as the PostgreSQL `application_name` when `PGAPPNAME` is not set, making it easier to identify graph-node connections in `pg_stat_activity`. + +### Bug Fixes + +- Fixed dropped block trigger when `once` and `polling` filters match the same block — only one trigger type was firing. ([#6530](https://github.com/graphprotocol/graph-node/pull/6530)) +- Fixed block stream ignoring configured `endBlock` in two cases: the block-skip optimization bypassing the `max_end_block` check, and `max_end_block` being set to `None` when multiple data sources share the same `endBlock`. ([#6474](https://github.com/graphprotocol/graph-node/pull/6474)) +- Fixed GraphQL introspection not returning `isDeprecated: false` for `__InputValue`, which caused some client libraries to fail. ([#6475](https://github.com/graphprotocol/graph-node/pull/6475)) +- Fixed IPC provider connections failing when configured with `ipc://` or `file://` URLs — the URL was passed directly to the transport instead of extracting the file path. ([#6443](https://github.com/graphprotocol/graph-node/pull/6443)) +- Fixed `graphman config pools` not working due to hardcoded pool size override. ([#6444](https://github.com/graphprotocol/graph-node/pull/6444)) +- Fixed unfail retry mechanism stopping after the first attempt when the deployment head was still behind the error block. ([#6529](https://github.com/graphprotocol/graph-node/pull/6529)) + +### Note on `ethereum.decode()` whitespace handling + +The migration from `ethabi` to `alloy` in v0.42.0 ([#6063](https://github.com/graphprotocol/graph-node/pull/6063)) incidentally fixed a long-standing parsing bug in `ethabi` where type strings containing whitespace before a type name (e.g. `" address"` with a leading space) were silently decoded as `Uint(8)` instead of the intended type. `alloy` parses these correctly. + +Subgraphs that relied on the incorrect `Uint(8)` decoding to subsequently call `.toBigInt()` on what is actually an `Address` value will abort on v0.42.0+ with: + +``` +Mapping aborted ... Ethereum value is not an int or uint. +``` + +This is not a graph-node regression. Recompile the subgraph with the correct accessor (`.toAddress()` for addresses) to fix. See [#6461](https://github.com/graphprotocol/graph-node/issues/6461) for details. + +### gnd (Graph Node Dev) + +- `gnd indexer` command that delegates to `graph-indexer`, allowing indexer management (allocations, rules, cost models, status) directly through gnd. ([#6492](https://github.com/graphprotocol/graph-node/pull/6492)) +- `gnd deploy` now prompts for `--version-label` in interactive mode and requires it in non-interactive mode. ([#6532](https://github.com/graphprotocol/graph-node/pull/6532)) +- Test framework improvements: partial receipt.logs support, mock IPFS/Arweave clients for file data source testing. ([#6442](https://github.com/graphprotocol/graph-node/pull/6442)) + +### Contributors + +Thanks to all contributors for this release: @aayushbaluni, @dimitrovmaksim, @incrypto32, @isum, @lutter, @suntzu + +**Full Changelog**: https://github.com/graphprotocol/graph-node/compare/v0.42.1...v0.43.0 + ## v0.42.1 ### Bug Fixes diff --git a/README.md b/README.md index f5c3416ce29..667c606a045 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,44 @@ Very large `graph-node` instances can also be configured using a the `graph-node` needs to connect to multiple chains or if the work of indexing and querying needs to be split across [multiple databases](./docs/config.md). +#### Log Storage + +`graph-node` supports storing and querying subgraph logs through multiple backends: + +- **File**: Local JSON Lines files (recommended for local development) +- **Elasticsearch**: Enterprise-grade search and analytics (for production) +- **Loki**: Grafana's log aggregation system (for production) +- **Disabled**: No log storage (default) + +**Quick example (file-based logs for local development):** +```bash +mkdir -p ./graph-logs + +cargo run -p graph-node --release -- \ + --postgres-url $POSTGRES_URL \ + --ethereum-rpc mainnet:archive:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend file \ + --log-store-file-dir ./graph-logs +``` + +Logs are queried via GraphQL at `http://localhost:8000/graphql`: +```graphql +query { + _logs(subgraphId: "QmYourSubgraphHash", level: ERROR, first: 10) { + timestamp + level + text + } +} +``` + +**For complete documentation**, see the **[Log Store Guide](./docs/log-store.md)**, which covers: +- How to configure each backend (Elasticsearch, Loki, File) +- Complete GraphQL query examples +- Choosing the right backend for your use case +- Performance considerations and best practices + ## Contributing Please check [CONTRIBUTING.md](CONTRIBUTING.md) for development flow and conventions we use. diff --git a/chain/common/src/lib.rs b/chain/common/src/lib.rs index b8f2ae47eb4..395dd440c84 100644 --- a/chain/common/src/lib.rs +++ b/chain/common/src/lib.rs @@ -2,13 +2,13 @@ use std::collections::HashMap; use std::fmt::Debug; use anyhow::Error; -use protobuf::descriptor::field_descriptor_proto::Label; -use protobuf::descriptor::field_descriptor_proto::Type; +use protobuf::Message; +use protobuf::UnknownValueRef; use protobuf::descriptor::DescriptorProto; use protobuf::descriptor::FieldDescriptorProto; use protobuf::descriptor::OneofDescriptorProto; -use protobuf::Message; -use protobuf::UnknownValueRef; +use protobuf::descriptor::field_descriptor_proto::Label; +use protobuf::descriptor::field_descriptor_proto::Type; use std::convert::From; use std::path::Path; diff --git a/chain/common/tests/test-acme.rs b/chain/common/tests/test-acme.rs index cd0b32b8582..2945fea337e 100644 --- a/chain/common/tests/test-acme.rs +++ b/chain/common/tests/test-acme.rs @@ -7,8 +7,8 @@ fn check_repeated_type_ok() { let types = parse_proto_file(PROTO_FILE).expect("Unable to read proto file!"); let array_types = types - .iter() - .flat_map(|(_, t)| t.fields.iter()) + .values() + .flat_map(|t| t.fields.iter()) .filter(|t| t.is_array) .map(|t| t.type_name.clone()) .collect::>(); diff --git a/chain/ethereum/Cargo.toml b/chain/ethereum/Cargo.toml index c9a125136bf..a9c9d42a124 100644 --- a/chain/ethereum/Cargo.toml +++ b/chain/ethereum/Cargo.toml @@ -12,7 +12,6 @@ serde = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } anyhow = "1.0" -tiny-keccak = "1.5.0" hex = "0.4.3" semver = { workspace = true } thiserror = { workspace = true } @@ -21,7 +20,7 @@ tokio = { workspace = true } tokio-stream = { workspace = true } tower = { workspace = true } -itertools = "0.14.0" +itertools = "0.15.0" graph-runtime-wasm = { path = "../../runtime/wasm" } graph-runtime-derive = { path = "../../runtime/derive" } diff --git a/chain/ethereum/examples/firehose.rs b/chain/ethereum/examples/firehose.rs index 45199a0ec89..3dd21859653 100644 --- a/chain/ethereum/examples/firehose.rs +++ b/chain/ethereum/examples/firehose.rs @@ -4,7 +4,7 @@ use graph::{ env::env_var, firehose::{self, FirehoseEndpoint, SubgraphLimit}, log::logger, - prelude::{prost, tokio, tonic, MetricsRegistry}, + prelude::{MetricsRegistry, prost, tokio, tonic}, }; use graph_chain_ethereum::codec; use hex::ToHex; diff --git a/chain/ethereum/src/adapter.rs b/chain/ethereum/src/adapter.rs index 5f7fb7d84c0..d37d5ba81f7 100644 --- a/chain/ethereum/src/adapter.rs +++ b/chain/ethereum/src/adapter.rs @@ -9,6 +9,7 @@ use graph::data_source::common::ContractCall; use graph::firehose::CallToFilter; use graph::firehose::CombinedFilter; use graph::firehose::LogFilter; +use graph::prelude::alloy::primitives::keccak256; use graph::prelude::alloy::primitives::{Address, B256}; use graph::prelude::alloy::rpc::types::Log; use graph::prelude::alloy::transports::{RpcError, TransportErrorKind}; @@ -18,8 +19,8 @@ use prost_types::Any; use std::cmp; use std::collections::{HashMap, HashSet}; use std::fmt; +use std::hash::Hash; use thiserror::Error; -use tiny_keccak::keccak256; use graph::prelude::*; use graph::{ @@ -35,7 +36,7 @@ const COMBINED_FILTER_TYPE_URL: &str = use crate::capabilities::NodeCapabilities; use crate::data_source::{BlockHandlerFilter, DataSource}; -use crate::{Chain, Mapping, ENV_VARS}; +use crate::{Chain, ENV_VARS, Mapping}; pub type EventSignature = B256; pub type FunctionSelector = [u8; 4]; @@ -351,15 +352,113 @@ pub struct EthereumLogFilter { /// Log filters can be represented as a bipartite graph between contracts and events. An edge /// exists between a contract and an event if a data source for the contract has a trigger for /// the event. - /// Edges are of `bool` type and indicates when a trigger requires a transaction receipt. - contracts_and_events_graph: GraphMap, + /// Edge weights are booleans indicating whether the trigger requires a transaction receipt. + contracts_and_events_graph: MergeGraph, /// Event sigs with no associated address, matching on all addresses. - /// Maps to a boolean representing if a trigger requires a transaction receipt. - wildcard_events: HashMap, - /// Events with any of the topic filters set - /// Maps to a boolean representing if a trigger requires a transaction receipt. - events_with_topic_filters: HashMap, + /// Values are booleans indicating whether the trigger requires a transaction receipt. + wildcard_events: MergeMap, + /// Events with any of the topic filters set. + /// Values are booleans indicating whether the trigger requires a transaction receipt. + events_with_topic_filters: MergeMap, +} + +/// `HashMap` wrapper whose values are OR-merged on every write. +/// +/// The only mutator that writes values is [`MergeMap::or_insert`] — the inner +/// `HashMap` is private so callers cannot bypass the merge via +/// `HashMap::insert`. Used by `EthereumLogFilter` to track per-key receipt +/// requirements where any handler asking for a receipt at a given key forces +/// receipt fetching. +#[derive(Clone, Debug)] +struct MergeMap(HashMap); + +impl Default for MergeMap { + fn default() -> Self { + Self(HashMap::new()) + } +} + +impl MergeMap { + fn or_insert(&mut self, k: K, v: bool) { + self.0.entry(k).and_modify(|e| *e |= v).or_insert(v); + } + + fn get(&self, k: &K) -> Option<&bool> { + self.0.get(k) + } + + fn contains_key(&self, k: &K) -> bool { + self.0.contains_key(k) + } + + fn iter(&self) -> impl Iterator + '_ { + self.0.iter() + } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl IntoIterator for MergeMap { + type Item = (K, bool); + type IntoIter = std::collections::hash_map::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +/// `GraphMap` wrapper that OR-merges edge weights on +/// every write. +/// +/// The only mutator that writes edge weights is [`MergeGraph::or_add_edge`] — +/// the inner `GraphMap` is private so callers cannot bypass the merge via +/// `GraphMap::add_edge`. +#[derive(Clone, Debug)] +struct MergeGraph(GraphMap); + +impl Default for MergeGraph { + fn default() -> Self { + Self(GraphMap::new()) + } +} + +impl MergeGraph { + fn or_add_edge(&mut self, a: LogFilterNode, b: LogFilterNode, v: bool) { + // Short-circuit on `v == true`: a `true` weight always wins over any + // prior weight, so we can skip the edge_weight lookup entirely. + let merged = v || self.0.edge_weight(a, b).copied().unwrap_or(false); + self.0.add_edge(a, b, merged); + } + + fn edge_weight(&self, a: LogFilterNode, b: LogFilterNode) -> Option<&bool> { + self.0.edge_weight(a, b) + } + + fn contains_edge(&self, a: LogFilterNode, b: LogFilterNode) -> bool { + self.0.contains_edge(a, b) + } + + fn edge_count(&self) -> usize { + self.0.edge_count() + } + + fn nodes(&self) -> impl Iterator + '_ { + self.0.nodes() + } + + fn neighbors(&self, n: LogFilterNode) -> impl Iterator + '_ { + self.0.neighbors(n) + } + + fn remove_node(&mut self, n: LogFilterNode) -> bool { + self.0.remove_node(n) + } + + fn all_edges(&self) -> impl Iterator { + self.0.all_edges() + } } impl From for Vec { @@ -458,14 +557,14 @@ impl EthereumLogFilter { let event_sig = event_handler.topic0(); match ds.address { Some(contract) if !event_handler.has_additional_topics() => { - this.contracts_and_events_graph.add_edge( + this.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(contract), LogFilterNode::Event(event_sig), event_handler.receipt, ); } Some(contract) => { - this.events_with_topic_filters.insert( + this.events_with_topic_filters.or_insert( EventSignatureWithTopics::new( Some(contract), event_sig, @@ -479,11 +578,11 @@ impl EthereumLogFilter { None if (!event_handler.has_additional_topics()) => { this.wildcard_events - .insert(event_sig, event_handler.receipt); + .or_insert(event_sig, event_handler.receipt); } None => { - this.events_with_topic_filters.insert( + this.events_with_topic_filters.or_insert( EventSignatureWithTopics::new( ds.address, event_sig, @@ -505,12 +604,18 @@ impl EthereumLogFilter { for event_handler in &mapping.event_handlers { let signature = event_handler.topic0(); this.wildcard_events - .insert(signature, event_handler.receipt); + .or_insert(signature, event_handler.receipt); } this } /// Extends this log filter with another one. + /// + /// The `receipt` flag stored at each filter key is OR-combined across the + /// two filters: a key whose receipt requirement is `true` in either filter + /// stays `true` in the merged result. Overwriting with the incoming value + /// would drop a prior `true` and silently downgrade receipt fetching for + /// any handler that declared `receipt: true` at that key. pub fn extend(&mut self, other: EthereumLogFilter) { if other.is_empty() { return; @@ -523,11 +628,14 @@ impl EthereumLogFilter { events_with_topic_filters, } = other; for (s, t, e) in contracts_and_events_graph.all_edges() { - self.contracts_and_events_graph.add_edge(s, t, *e); + self.contracts_and_events_graph.or_add_edge(s, t, *e); + } + for (k, v) in wildcard_events { + self.wildcard_events.or_insert(k, v); + } + for (k, v) in events_with_topic_filters { + self.events_with_topic_filters.or_insert(k, v); } - self.wildcard_events.extend(wildcard_events); - self.events_with_topic_filters - .extend(events_with_topic_filters); } /// An empty filter is one that never matches. @@ -555,15 +663,15 @@ impl EthereumLogFilter { // Start with the wildcard event filters. filters.extend( self.wildcard_events - .into_keys() - .map(EthGetLogsFilter::from_event), + .into_iter() + .map(|(k, _)| EthGetLogsFilter::from_event(k)), ); // Handle events with topic filters. filters.extend( self.events_with_topic_filters - .into_keys() - .map(EthGetLogsFilter::from_event_with_topics), + .into_iter() + .map(|(k, _)| EthGetLogsFilter::from_event_with_topics(k)), ); // The current algorithm is to repeatedly find the maximum cardinality vertex and turn all @@ -1186,7 +1294,7 @@ pub trait EthereumAdapter: Send + Sync + 'static { #[cfg(test)] mod tests { - use crate::adapter::{FunctionSelector, COMBINED_FILTER_TYPE_URL}; + use crate::adapter::{COMBINED_FILTER_TYPE_URL, FunctionSelector}; use super::{EthereumBlockFilter, LogFilterNode}; use super::{EthereumCallFilter, EthereumLogFilter, TriggerFilter}; @@ -1194,9 +1302,8 @@ mod tests { use base64::prelude::*; use graph::blockchain::TriggerFilter as _; use graph::firehose::{CallToFilter, CombinedFilter, LogFilter, MultiLogFilter}; - use graph::petgraph::graphmap::GraphMap; - use graph::prelude::alloy::primitives::{Address, Bytes, B256, U256}; use graph::prelude::EthereumCall; + use graph::prelude::alloy::primitives::{Address, B256, Bytes, U256}; use hex::ToHex; use itertools::Itertools; use prost::Message; @@ -1264,9 +1371,11 @@ mod tests { assert_eq!(sig, actual_sig); let filter = LogFilter { - addresses: vec![Address::from_str(hex_addr) - .expect("failed to parse address") - .to_vec()], + addresses: vec![ + Address::from_str(hex_addr) + .expect("failed to parse address") + .to_vec(), + ], event_signatures: vec![fs.to_vec()], }; @@ -1282,11 +1391,7 @@ mod tests { fn ethereum_trigger_filter_to_firehose() { let sig = |value: u64| B256::from(U256::from(value)); let mut filter = TriggerFilter { - log: EthereumLogFilter { - contracts_and_events_graph: GraphMap::new(), - wildcard_events: HashMap::new(), - events_with_topic_filters: HashMap::new(), - }, + log: EthereumLogFilter::default(), call: EthereumCallFilter { contract_addresses_function_signatures: HashMap::from_iter(vec![ (address(0), (0, HashSet::from_iter(vec![[0u8; 4]]))), @@ -1335,17 +1440,17 @@ mod tests { }, ]; - filter.log.contracts_and_events_graph.add_edge( + filter.log.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(address(10)), LogFilterNode::Event(sig(100)), false, ); - filter.log.contracts_and_events_graph.add_edge( + filter.log.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(address(10)), LogFilterNode::Event(sig(101)), false, ); - filter.log.contracts_and_events_graph.add_edge( + filter.log.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(address(20)), LogFilterNode::Event(sig(100)), false, @@ -1405,11 +1510,7 @@ mod tests { let address = |value: u64| Address::left_padding_from(&value.to_le_bytes()); let sig = |value: u64| B256::left_padding_from(&value.to_le_bytes()); let mut filter = TriggerFilter { - log: EthereumLogFilter { - contracts_and_events_graph: GraphMap::new(), - wildcard_events: HashMap::new(), - events_with_topic_filters: HashMap::new(), - }, + log: EthereumLogFilter::default(), call: EthereumCallFilter { contract_addresses_function_signatures: HashMap::new(), wildcard_signatures: HashSet::new(), @@ -1421,7 +1522,7 @@ mod tests { }, }; - filter.log.contracts_and_events_graph.add_edge( + filter.log.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(address(10)), LogFilterNode::Event(sig(101)), false, @@ -1651,8 +1752,8 @@ mod tests { } #[test] - fn extending_ethereum_block_filter_every_block_in_base_and_merge_contract_addresses_and_polling_intervals( - ) { + fn extending_ethereum_block_filter_every_block_in_base_and_merge_contract_addresses_and_polling_intervals() + { let mut base = EthereumBlockFilter { polling_intervals: HashSet::from_iter(vec![(10, 3)]), contract_addresses: HashSet::from_iter(vec![(10, address(2))]), @@ -1757,10 +1858,10 @@ fn complete_log_filter() { let contracts: BTreeSet<_> = (0..j).map(|n| Address::from([n as u8; 20])).collect(); // Construct the complete bipartite graph with i events and j contracts. - let mut contracts_and_events_graph = GraphMap::new(); + let mut filter = EthereumLogFilter::default(); for &contract in &contracts { for &event in &events { - contracts_and_events_graph.add_edge( + filter.contracts_and_events_graph.or_add_edge( LogFilterNode::Contract(contract), LogFilterNode::Event(event), false, @@ -1769,13 +1870,9 @@ fn complete_log_filter() { } // Run `eth_get_logs_filters`, which is what we want to test. - let logs_filters: Vec<_> = EthereumLogFilter { - contracts_and_events_graph, - wildcard_events: HashMap::new(), - events_with_topic_filters: HashMap::new(), - } - .eth_get_logs_filters(ENV_VARS.get_logs_max_contracts) - .collect(); + let logs_filters: Vec<_> = filter + .eth_get_logs_filters(ENV_VARS.get_logs_max_contracts) + .collect(); // Assert that a contract or event is filtered on iff it was present in the graph. assert_eq!( @@ -1840,14 +1937,6 @@ fn log_filter_require_transacion_receipt_method() { let wildcard_event_with_receipt = b256(6); let wildcard_event_without_receipt = b256(7); - let wildcard_events = [ - (wildcard_event_with_receipt, true), - (wildcard_event_without_receipt, false), - ] - .into_iter() - .collect(); - - let events_with_topic_filters = HashMap::new(); // TODO(krishna): Test events with topic filters let alien_event_signature = b256(8); // those will not be inserted in the graph let alien_contract_address = address(9); @@ -1875,25 +1964,28 @@ fn log_filter_require_transacion_receipt_method() { // event_b -- contract_a [ receipt=false ] // } // ``` - let mut contracts_and_events_graph = GraphMap::new(); - - let event_a_id = contracts_and_events_graph.add_node(event_a_node); - let event_b_id = contracts_and_events_graph.add_node(event_b_node); - let event_c_id = contracts_and_events_graph.add_node(event_c_node); - let contract_a_id = contracts_and_events_graph.add_node(contract_a_node); - let contract_b_id = contracts_and_events_graph.add_node(contract_b_node); - let contract_c_id = contracts_and_events_graph.add_node(contract_c_node); - contracts_and_events_graph.add_edge(event_a_id, contract_a_id, true); - contracts_and_events_graph.add_edge(event_b_id, contract_b_id, true); - contracts_and_events_graph.add_edge(event_a_id, contract_b_id, false); - contracts_and_events_graph.add_edge(event_b_id, contract_a_id, false); - contracts_and_events_graph.add_edge(event_c_id, contract_c_id, true); - - let filter = EthereumLogFilter { - contracts_and_events_graph, - wildcard_events, - events_with_topic_filters, - }; + let mut filter = EthereumLogFilter::default(); + filter + .contracts_and_events_graph + .or_add_edge(event_a_node, contract_a_node, true); + filter + .contracts_and_events_graph + .or_add_edge(event_b_node, contract_b_node, true); + filter + .contracts_and_events_graph + .or_add_edge(event_a_node, contract_b_node, false); + filter + .contracts_and_events_graph + .or_add_edge(event_b_node, contract_a_node, false); + filter + .contracts_and_events_graph + .or_add_edge(event_c_node, contract_c_node, true); + filter + .wildcard_events + .or_insert(wildcard_event_with_receipt, true); + filter + .wildcard_events + .or_insert(wildcard_event_without_receipt, false); let empty_vec: Vec = vec![]; @@ -1980,3 +2072,268 @@ fn log_filter_require_transacion_receipt_method() { &empty_vec )); } + +// Tests that `EthereumLogFilter` OR-merges per-handler `receipt` flags across +// every insertion site (`from_data_sources`, `from_mapping`, `extend`). + +#[cfg(test)] +fn receipt_merge_test_addr(n: u64) -> Address { + Address::left_padding_from(&n.to_be_bytes()) +} + +#[cfg(test)] +fn receipt_merge_test_sig(n: u64) -> B256 { + B256::left_padding_from(&n.to_be_bytes()) +} + +#[cfg(test)] +fn receipt_merge_test_mock_abi() -> std::sync::Arc { + std::sync::Arc::new(graph::data_source::common::MappingABI { + name: "mock_abi".to_string(), + contract: abi::JsonAbi::new(), + }) +} + +#[cfg(test)] +fn receipt_merge_test_event_handler( + sig: B256, + topic1: Option>, + topic2: Option>, + topic3: Option>, + receipt: bool, +) -> crate::data_source::MappingEventHandler { + crate::data_source::MappingEventHandler { + event: "Event()".to_string(), + topic0: Some(sig), + topic1, + topic2, + topic3, + handler: "handleEvent".to_string(), + receipt, + calls: graph::data_source::common::CallDecls::default(), + } +} + +#[cfg(test)] +fn receipt_merge_test_mapping( + handlers: Vec, +) -> crate::Mapping { + crate::Mapping { + kind: "ethereum/events".to_string(), + api_version: semver::Version::new(0, 0, 7), + language: "wasm/assemblyscript".to_string(), + entities: vec![], + abis: vec![receipt_merge_test_mock_abi()], + block_handlers: vec![], + call_handlers: vec![], + event_handlers: handlers, + runtime: std::sync::Arc::new(vec![]), + link: graph::prelude::Link { + link: "test".to_string(), + }, + } +} + +#[cfg(test)] +fn receipt_merge_test_data_source( + address: Option
, + handlers: Vec, +) -> crate::data_source::DataSource { + crate::data_source::DataSource { + kind: "ethereum/contract".to_string(), + network: Some("test".to_string()), + name: "Test".to_string(), + manifest_idx: 0, + address, + start_block: 0, + end_block: None, + mapping: receipt_merge_test_mapping(handlers), + context: std::sync::Arc::new(None), + creation_block: None, + contract_abi: receipt_merge_test_mock_abi(), + } +} + +/// Run two data sources with `receipt: true` and `receipt: false` at the +/// same effective filter key through `from_data_sources` and assert the +/// merged filter still requires a transaction receipt. Runs both +/// declaration orders so order-independence is verified per variant. +#[cfg(test)] +fn assert_from_data_sources_or_merges( + label: &str, + address: Option
, + topic1: Option>, + log_topics: &[B256], +) { + let event_sig = receipt_merge_test_sig(100); + let ds_yes = receipt_merge_test_data_source( + address, + vec![receipt_merge_test_event_handler( + event_sig, + topic1.clone(), + None, + None, + true, + )], + ); + let ds_no = receipt_merge_test_data_source( + address, + vec![receipt_merge_test_event_handler( + event_sig, + topic1.clone(), + None, + None, + false, + )], + ); + + for (order, dss) in [("yes,no", [&ds_yes, &ds_no]), ("no,yes", [&ds_no, &ds_yes])] { + let filter = EthereumLogFilter::from_data_sources(dss); + assert!( + filter.requires_transaction_receipt(&event_sig, address.as_ref(), log_topics), + "{label} ({order}): receipt:true must survive a later receipt:false", + ); + } +} + +/// Build two filters via `from_data_sources`, each with one handler at the +/// same effective key but with opposite receipt flags, then merge them via +/// `extend` and assert the merged filter still requires a transaction +/// receipt. Runs both extend directions so order-independence is verified +/// per variant. +#[cfg(test)] +fn assert_extend_or_merges( + label: &str, + address: Option
, + topic1: Option>, + log_topics: &[B256], +) { + let event_sig = receipt_merge_test_sig(105); + let ds_yes = receipt_merge_test_data_source( + address, + vec![receipt_merge_test_event_handler( + event_sig, + topic1.clone(), + None, + None, + true, + )], + ); + let ds_no = receipt_merge_test_data_source( + address, + vec![receipt_merge_test_event_handler( + event_sig, + topic1.clone(), + None, + None, + false, + )], + ); + + for (order, base, ext) in [ + ("yes.extend(no)", &ds_yes, &ds_no), + ("no.extend(yes)", &ds_no, &ds_yes), + ] { + let mut filter = EthereumLogFilter::from_data_sources([base]); + filter.extend(EthereumLogFilter::from_data_sources([ext])); + assert!( + filter.requires_transaction_receipt(&event_sig, address.as_ref(), log_topics), + "{label} ({order}): extend must OR-merge", + ); + } +} + +#[test] +fn from_data_sources_or_merges_at_every_insertion_site() { + let contract = receipt_merge_test_addr(1); + let event_sig = receipt_merge_test_sig(100); + let topic = receipt_merge_test_sig(200); + let with_topic = vec![event_sig, topic]; + + // Each case maps to one arm of the `match ds.address` in `from_data_sources`. + assert_from_data_sources_or_merges("graph edge", Some(contract), None, &[]); + assert_from_data_sources_or_merges( + "addressed topics", + Some(contract), + Some(vec![topic]), + &with_topic, + ); + assert_from_data_sources_or_merges("wildcard", None, None, &[]); + assert_from_data_sources_or_merges("wildcard topics", None, Some(vec![topic]), &with_topic); +} + +#[test] +fn from_mapping_or_merges_via_extend() { + // Two templates handling the same event signature with different receipt + // flags merged via `from_mapping` + `extend`. + let event_sig = receipt_merge_test_sig(104); + + let mapping_yes = receipt_merge_test_mapping(vec![receipt_merge_test_event_handler( + event_sig, None, None, None, true, + )]); + let mapping_no = receipt_merge_test_mapping(vec![receipt_merge_test_event_handler( + event_sig, None, None, None, false, + )]); + + let mut filter = EthereumLogFilter::from_mapping(&mapping_yes); + filter.extend(EthereumLogFilter::from_mapping(&mapping_no)); + + assert!(filter.requires_transaction_receipt(&event_sig, None, &[])); +} + +#[test] +fn extend_or_merges_at_every_collection() { + let contract = receipt_merge_test_addr(5); + let event_sig = receipt_merge_test_sig(105); + let topic = receipt_merge_test_sig(203); + let with_topic = vec![event_sig, topic]; + + assert_extend_or_merges("graph edge", Some(contract), None, &[]); + assert_extend_or_merges( + "addressed topics", + Some(contract), + Some(vec![topic]), + &with_topic, + ); + assert_extend_or_merges("wildcard", None, None, &[]); + assert_extend_or_merges("wildcard topics", None, Some(vec![topic]), &with_topic); +} + +#[test] +fn requires_transaction_receipt_has_or_semantics_across_handlers() { + // `requires_transaction_receipt` must return true iff at least one handler + // at the key declared `receipt: true`, regardless of declaration order. + let event_sig = receipt_merge_test_sig(108); + + for flags in [ + vec![false], + vec![true], + vec![true, false], + vec![false, true], + vec![false, false, true], + vec![true, false, false], + vec![false, true, false], + vec![true, true, false], + vec![false, false, false], + ] { + let dss: Vec<_> = flags + .iter() + .map(|&r| { + receipt_merge_test_data_source( + None, + vec![receipt_merge_test_event_handler( + event_sig, None, None, None, r, + )], + ) + }) + .collect(); + let filter = EthereumLogFilter::from_data_sources(dss.iter()); + + let any_requires_receipt = flags.iter().any(|&r| r); + assert_eq!( + filter.requires_transaction_receipt(&event_sig, None, &[]), + any_requires_receipt, + "flag sequence {flags:?}", + ); + } +} diff --git a/chain/ethereum/src/buffered_call_cache.rs b/chain/ethereum/src/buffered_call_cache.rs index 2ec0bfa40e7..29aa84e90ab 100644 --- a/chain/ethereum/src/buffered_call_cache.rs +++ b/chain/ethereum/src/buffered_call_cache.rs @@ -9,7 +9,7 @@ use graph::{ components::store::EthereumCallCache, data::store::ethereum::call, prelude::{BlockPtr, CachedEthereumCall}, - slog::{error, Logger}, + slog::{Logger, error}, }; /// A wrapper around an Ethereum call cache that buffers call results in diff --git a/chain/ethereum/src/call_helper.rs b/chain/ethereum/src/call_helper.rs index ef0b85fc293..8a1216b58c5 100644 --- a/chain/ethereum/src/call_helper.rs +++ b/chain/ethereum/src/call_helper.rs @@ -3,8 +3,9 @@ use graph::{ abi, data::store::ethereum::call, prelude::{ + Logger, alloy::transports::{RpcError, TransportErrorKind}, - serde_json, Logger, + serde_json, }, slog::info, }; @@ -57,21 +58,32 @@ const RPC_EXECUTION_ERRORS: &[&str] = &[ "invalidjump", "notactivated", "invalidfeopcode", + // Reth surfaces EVM halts via `EvmHalt(HaltReason)`, formatted with the + // reason's `Debug` repr (`"EVM error: {0:?}"`). revm's `HaltReason` + // variants are CamelCase with no spaces, so e.g. a stack underflow arrives + // as "EVM error: StackUnderflow", which the space-separated "stack + // underflow" above does not match. "invalidjump"/"invalidfeopcode" already + // cover the matching variants; these add the rest. Reth's OutOfGas is + // handled before EvmHalt and rendered as "out of gas: ...", so it is + // already covered above. See https://github.com/streamingfast/eth-go/pull/10. + "stackunderflow", + "stackoverflow", + "opcodenotfound", ]; -/// Helper that checks if a geth style RPC error message corresponds to a revert. +/// Helper that checks if a RPC error message corresponds to a revert. fn is_rpc_revert_message(message: &str) -> bool { - let env_geth_call_errors = ENV_VARS.geth_eth_call_errors.iter(); + let env_rpc_call_errors = ENV_VARS.rpc_eth_call_errors.iter(); let mut execution_errors = RPC_EXECUTION_ERRORS .iter() .copied() - .chain(env_geth_call_errors.map(|s| s.as_str())); + .chain(env_rpc_call_errors.map(|s| s.as_str())); execution_errors.any(|e| message.to_lowercase().contains(e)) } /// Decode a Solidity revert(reason) payload, returning the reason string when possible. fn as_solidity_revert_reason(bytes: &[u8]) -> Option { - let selector = &tiny_keccak::keccak256(b"Error(string)")[..4]; + let selector = &graph::prelude::alloy::primitives::keccak256(b"Error(string)")[..4]; if bytes.len() >= 4 && &bytes[..4] == selector { abi::DynSolType::String .abi_decode(&bytes[4..]) @@ -93,10 +105,10 @@ pub fn interpret_eth_call_error( Ok(call::Retval::Null) } - if let RpcError::ErrorResp(rpc_error) = &err { - if is_rpc_revert_message(&rpc_error.message) { - return reverted(logger, &rpc_error.message); - } + if let RpcError::ErrorResp(rpc_error) = &err + && is_rpc_revert_message(&rpc_error.message) + { + return reverted(logger, &rpc_error.message); } if let RpcError::ErrorResp(rpc_error) = &err { @@ -106,12 +118,11 @@ pub fn interpret_eth_call_error( .as_ref() .and_then(|d| serde_json::from_str(d.get()).ok()); - if code == PARITY_VM_EXECUTION_ERROR { - if let Some(data) = data { - if is_parity_revert(&data) { - return reverted(logger, &parity_revert_reason(&data)); - } - } + if code == PARITY_VM_EXECUTION_ERROR + && let Some(data) = data + && is_parity_revert(&data) + { + return reverted(logger, &parity_revert_reason(&data)); } } diff --git a/chain/ethereum/src/chain.rs b/chain/ethereum/src/chain.rs index ee7d45ca2a6..405c3123bdc 100644 --- a/chain/ethereum/src/chain.rs +++ b/chain/ethereum/src/chain.rs @@ -1,5 +1,5 @@ -use anyhow::{anyhow, bail, Result}; use anyhow::{Context, Error}; +use anyhow::{Result, anyhow, bail}; use async_trait::async_trait; use graph::blockchain::client::ChainClient; use graph::blockchain::firehose_block_ingestor::{FirehoseBlockIngestor, Transforms}; @@ -13,26 +13,27 @@ use graph::data::subgraph::UnifiedMappingApiVersion; use graph::firehose::{FirehoseEndpoint, FirehoseEndpoints, ForkStep}; use graph::futures03::TryStreamExt; use graph::prelude::{ - retry, BlockHash, ComponentLoggerConfig, ElasticComponentLoggerConfig, EthereumBlock, + BlockHash, ComponentLoggerConfig, ElasticComponentLoggerConfig, EthereumBlock, EthereumCallCache, LightEthereumBlock, LightEthereumBlockExt, MetricsRegistry, StoreError, + retry, }; use graph::slog::{debug, error, trace, warn}; use graph::{ blockchain::{ + Block, BlockPtr, Blockchain, ChainHeadUpdateListener, IngestorError, + RuntimeAdapter as RuntimeAdapterTrait, TriggerFilter as _, block_stream::{ BlockRefetcher, BlockStreamEvent, BlockWithTriggers, FirehoseError, FirehoseMapper as FirehoseMapperTrait, TriggersAdapter as TriggersAdapterTrait, }, firehose_block_stream::FirehoseBlockStream, - Block, BlockPtr, Blockchain, ChainHeadUpdateListener, IngestorError, - RuntimeAdapter as RuntimeAdapterTrait, TriggerFilter as _, }, cheap_clone::CheapClone, components::store::DeploymentLocator, firehose, prelude::{ - o, serde_json as json, BlockNumber, ChainStore, EthereumBlockWithCalls, Logger, - LoggerFactory, + BlockNumber, ChainStore, EthereumBlockWithCalls, Logger, LoggerFactory, o, + serde_json as json, }, }; use prost::Message; @@ -49,7 +50,9 @@ use crate::ingestor::PollingBlockIngestor; use crate::network::EthereumNetworkAdapters; use crate::polling_block_stream::PollingBlockStream; use crate::runtime::runtime_adapter::eth_call_gas; +use crate::{BufferedCallCache, NodeCapabilities}; use crate::{ + ENV_VARS, SubgraphEthRpcMetrics, TriggerFilter, adapter::EthereumAdapter as _, codec, data_source::{DataSource, UnresolvedDataSource}, @@ -57,9 +60,7 @@ use crate::{ blocks_with_triggers, get_calls, parse_block_triggers, parse_call_triggers, parse_log_triggers, }, - SubgraphEthRpcMetrics, TriggerFilter, ENV_VARS, }; -use crate::{BufferedCallCache, NodeCapabilities}; use crate::{EthereumAdapter, RuntimeAdapter}; use graph::blockchain::block_stream::{ BlockStream, BlockStreamBuilder, BlockStreamError, BlockStreamMapper, FirehoseCursor, @@ -396,10 +397,10 @@ where for _ in 0..offset { match parent_getter(current_ptr.clone()).await? { Some(parent) => { - if let Some(root_hash) = &root { - if parent.hash == *root_hash { - break; - } + if let Some(root_hash) = &root + && parent.hash == *root_hash + { + break; } current_ptr = parent; } @@ -581,6 +582,18 @@ impl Blockchain for Chain { .await .map_err(IngestorError::Unknown), ChainClient::Rpc(adapters) => { + let cached = self + .chain_store + .cheap_clone() + .block_ptrs_by_numbers(vec![number]) + .await + .unwrap_or_default(); + if let Some(ptrs) = cached.get(&number) + && ptrs.len() == 1 + { + return Ok(BlockPtr::new(ptrs[0].hash.clone(), ptrs[0].number)); + } + let adapter = adapters .cheapest() .await @@ -815,8 +828,8 @@ async fn fetch_unique_blocks_from_cache( // Collect blocks and filter out ones with multiple entries let blocks: Vec> = blocks_map - .into_iter() - .filter_map(|(_, values)| { + .into_values() + .filter_map(|values| { if values.len() == 1 { Some(Arc::new(values[0].clone())) } else { @@ -1062,6 +1075,12 @@ impl TriggersAdapterTrait for TriggersAdapter { } async fn is_on_main_chain(&self, ptr: BlockPtr) -> Result { + // It is tempting to use the block cache here; but that can go wrong + // when graph-node gets shut down and some of its nonfinal blocks + // then are reorged; when graph-node gets started again when those + // block numbers have become final, it might consider a reorged + // block as canonical; allowing the use of the block cache here + // would require us to also track the finality of blocks. match &*self.chain_client { ChainClient::Firehose(endpoints) => { let endpoint = endpoints.endpoint().await?; @@ -1260,16 +1279,14 @@ impl TriggersAdapter { adapters: &EthereumNetworkAdapters, block_ptr: &BlockPtr, ) -> Result, Error> { - let adapter = adapters.cheapest_with(&self.capabilities).await?; - - let block = adapter - .block_by_hash(&self.logger, block_ptr.hash.as_b256()) - .await?; - - match block { - Some(block) => { + // Use the cache-aware light block fetch first; it checks recent_blocks_cache + // and the DB before falling back to eth_getBlockByHash. + let light_block = self.fetch_light_block_with_rpc(adapters, block_ptr).await?; + match light_block { + Some(light_block) => { + let adapter = adapters.cheapest_with(&self.capabilities).await?; let ethereum_block = adapter - .load_full_block(&self.logger, block) + .load_full_block(&self.logger, light_block.inner().clone()) .await .map_err(|e| anyhow!("Failed to load full block: {}", e))?; Ok(Some(ethereum_block)) @@ -1372,7 +1389,9 @@ impl FirehoseMapperTrait for FirehoseMapper { } StepFinal => { - unreachable!("irreversible step is not handled and should not be requested in the Firehose request") + unreachable!( + "irreversible step is not handled and should not be requested in the Firehose request" + ) } StepUnset => { diff --git a/chain/ethereum/src/codec.rs b/chain/ethereum/src/codec.rs index 8a73ce83136..b40bcd11910 100644 --- a/chain/ethereum/src/codec.rs +++ b/chain/ethereum/src/codec.rs @@ -12,15 +12,15 @@ use graph::{ AnyBlock, AnyHeader, AnyRpcHeader, AnyTransactionReceiptBare, AnyTxEnvelope, }, prelude::{ + BlockNumber, Error, EthereumBlock, EthereumBlockWithCalls, EthereumCall, + LightEthereumBlock, alloy::{ self, consensus::{ReceiptWithBloom, TxEnvelope, TxType}, network::AnyReceiptEnvelope, - primitives::{aliases::B2048, Address, Bloom, Bytes, LogData, B256, U256}, + primitives::{Address, B256, Bloom, Bytes, LogData, U256, aliases::B2048}, rpc::types::{self as alloy_rpc_types, AccessList, AccessListItem, Transaction}, }, - BlockNumber, Error, EthereumBlock, EthereumBlockWithCalls, EthereumCall, - LightEthereumBlock, }, }; use std::sync::Arc; @@ -162,6 +162,11 @@ impl<'a> TryInto> for TransactionTraceAt<'a> { // Extract data from trace and block let block_hash = self.block.hash.try_decode_proto("transaction block hash")?; let block_number = self.block.number; + let block_timestamp = self + .block + .header + .as_ref() + .and_then(|h| h.timestamp.as_ref().map(|t| t.seconds as u64)); let transaction_index = Some(self.trace.index as u64); let from_address = self .trace @@ -241,6 +246,7 @@ impl<'a> TryInto> for TransactionTraceAt<'a> { inner: recovered, block_hash: Some(block_hash), block_number: Some(block_number), + block_timestamp, transaction_index, effective_gas_price: if gas_price > 0 { Some(gas_price) } else { None }, }); @@ -451,6 +457,7 @@ impl<'a> TryInto> for TransactionTraceAt<'a> { inner: recovered, block_hash: Some(block_hash), block_number: Some(block_number), + block_timestamp, transaction_index, effective_gas_price: if gas_price > 0 { Some(gas_price) } else { None }, // gas_price already contains effective gas price per protobuf spec }) @@ -528,6 +535,8 @@ impl TryInto for &Block { } else { Some(header.requests_hash.try_decode_proto("requests hash")?) }, + block_access_list_hash: None, + slot_number: None, }; let rpc_header = alloy::rpc::types::Header { @@ -650,7 +659,7 @@ fn transaction_trace_to_alloy_txn_reciept( TransactionTraceStatus::Unknown => { return Err(format_err!( "Transaction trace has UNKNOWN status; datasource is broken" - )) + )); } TransactionTraceStatus::Succeeded => true, TransactionTraceStatus::Failed | TransactionTraceStatus::Reverted => false, diff --git a/chain/ethereum/src/data_source.rs b/chain/ethereum/src/data_source.rs index b2303b6d053..709884496e8 100644 --- a/chain/ethereum/src/data_source.rs +++ b/chain/ethereum/src/data_source.rs @@ -1,5 +1,5 @@ -use anyhow::{anyhow, Error}; -use anyhow::{ensure, Context}; +use anyhow::{Context, ensure}; +use anyhow::{Error, anyhow}; use async_trait::async_trait; use graph::abi; use graph::abi::EventExt; @@ -18,16 +18,17 @@ use graph::data_source::common::{ }; use graph::data_source::{CausalityRegion, MappingTrigger as MappingTriggerType}; use graph::env::ENV_VARS; +use graph::futures03::TryStreamExt; use graph::futures03::future::try_join; use graph::futures03::stream::FuturesOrdered; -use graph::futures03::TryStreamExt; +use graph::prelude::alloy::primitives::keccak256; use graph::prelude::alloy::{ consensus::{TxEnvelope, TxLegacy}, network::TransactionResponse, primitives::{Address, B256, U256}, rpc::types::Log, }; -use graph::prelude::{alloy, Link, SubgraphManifestValidationError}; +use graph::prelude::{Link, SubgraphManifestValidationError, alloy}; use graph::slog::{debug, error, o, trace}; use itertools::Itertools; use serde::de::Error as ErrorD; @@ -37,26 +38,25 @@ use std::num::NonZeroU32; use std::str::FromStr; use std::sync::Arc; use std::time::{Duration, Instant}; -use tiny_keccak::{keccak256, Keccak}; use graph::{ blockchain::{self, Blockchain}, prelude::{ - serde_json, warn, BlockNumber, CheapClone, EthereumCall, LightEthereumBlock, - LightEthereumBlockExt, LinkResolver, Logger, + BlockNumber, CheapClone, EthereumCall, LightEthereumBlock, LightEthereumBlockExt, + LinkResolver, Logger, serde_json, warn, }, }; use graph::data::subgraph::{ - calls_host_fn, DataSourceContext, Source, MIN_SPEC_VERSION, SPEC_VERSION_0_0_8, - SPEC_VERSION_1_2_0, + DataSourceContext, MIN_SPEC_VERSION, SPEC_VERSION_0_0_8, SPEC_VERSION_1_2_0, Source, + calls_host_fn, }; +use crate::NodeCapabilities; use crate::adapter::EthereumAdapter as _; use crate::chain::Chain; use crate::network::EthereumNetworkAdapters; use crate::trigger::{EthereumBlockTriggerType, EthereumTrigger, MappingTrigger}; -use crate::NodeCapabilities; // The recommended kind is `ethereum`, `ethereum/contract` is accepted for backwards compatibility. const ETHEREUM_KINDS: &[&str] = &["ethereum/contract", "ethereum"]; @@ -446,7 +446,7 @@ fn create_dummy_transaction( ) -> Result { use graph::components::ethereum::AnyTxEnvelope; use graph::prelude::alloy::{ - consensus::transaction::Recovered, consensus::Signed, primitives::Signature, + consensus::Signed, consensus::transaction::Recovered, primitives::Signature, rpc::types::Transaction, }; @@ -468,6 +468,7 @@ fn create_dummy_transaction( inner: recovered, block_hash: Some(block_hash), block_number: Some(block_number), + block_timestamp: None, transaction_index, effective_gas_price: None, }) @@ -1589,13 +1590,7 @@ impl MappingEventHandler { /// Hashes a string to a B256 hash. fn string_to_b256(s: &str) -> B256 { - let mut result = [0u8; 32]; - let data = s.replace(' ', "").into_bytes(); - let mut sponge = Keccak::new_keccak256(); - sponge.update(&data); - sponge.finalize(&mut result); - - B256::from_slice(&result) + keccak256(s.replace(' ', "").as_bytes()) } #[derive(Clone, Debug, Default, Hash, Eq, PartialEq, Deserialize)] diff --git a/chain/ethereum/src/env.rs b/chain/ethereum/src/env.rs index 027a26b623f..b15ee0ee018 100644 --- a/chain/ethereum/src/env.rs +++ b/chain/ethereum/src/env.rs @@ -1,6 +1,6 @@ use envconfig::Envconfig; use graph::env::EnvVarBoolean; -use graph::prelude::{envconfig, lazy_static, BlockNumber}; +use graph::prelude::{BlockNumber, envconfig, lazy_static}; use std::fmt; use std::time::Duration; @@ -13,9 +13,9 @@ lazy_static! { pub struct EnvVars { /// Additional deterministic errors that have not yet been hardcoded. /// - /// Set by the environment variable `GRAPH_GETH_ETH_CALL_ERRORS`, separated + /// Set by the environment variable `GRAPH_RPC_ETH_CALL_ERRORS`, separated /// by `;`. - pub geth_eth_call_errors: Vec, + pub rpc_eth_call_errors: Vec, /// Set by the environment variable `GRAPH_ETH_GET_LOGS_MAX_CONTRACTS`. The /// default value is 2000. pub get_logs_max_contracts: usize, @@ -114,8 +114,8 @@ impl From for EnvVars { fn from(x: Inner) -> Self { Self { get_logs_max_contracts: x.get_logs_max_contracts, - geth_eth_call_errors: x - .geth_eth_call_errors + rpc_eth_call_errors: x + .rpc_eth_call_errors .split(';') .filter(|s| !s.is_empty()) .map(str::to_string) @@ -158,8 +158,8 @@ impl Default for EnvVars { #[derive(Clone, Debug, Envconfig)] struct Inner { - #[envconfig(from = "GRAPH_GETH_ETH_CALL_ERRORS", default = "")] - geth_eth_call_errors: String, + #[envconfig(from = "GRAPH_RPC_ETH_CALL_ERRORS", default = "")] + rpc_eth_call_errors: String, #[envconfig(from = "GRAPH_ETH_GET_LOGS_MAX_CONTRACTS", default = "2000")] get_logs_max_contracts: usize, diff --git a/chain/ethereum/src/ethereum_adapter.rs b/chain/ethereum/src/ethereum_adapter.rs index e58055a97a7..9c85f0ac551 100644 --- a/chain/ethereum/src/ethereum_adapter.rs +++ b/chain/ethereum/src/ethereum_adapter.rs @@ -3,24 +3,24 @@ use futures03::{future::BoxFuture, stream::FuturesUnordered}; use graph::abi; use graph::abi::DynSolValueExt; use graph::abi::FunctionExt; -use graph::blockchain::client::ChainClient; use graph::blockchain::BlockHash; use graph::blockchain::ChainIdentifier; use graph::blockchain::ExtendedBlockPtr; +use graph::blockchain::client::ChainClient; use graph::components::ethereum::*; use graph::components::transaction_receipt::LightTransactionReceipt; use graph::data::store::ethereum::call; use graph::data::store::scalar; -use graph::data::subgraph::UnifiedMappingApiVersion; use graph::data::subgraph::API_VERSION_0_0_7; +use graph::data::subgraph::UnifiedMappingApiVersion; use graph::data_source::common::ContractCall; use graph::derive::CheapClone; -use graph::futures01::stream; use graph::futures01::Future; use graph::futures01::Stream; +use graph::futures01::stream; use graph::futures03::future::try_join_all; use graph::futures03::{ - self, compat::Future01CompatExt, FutureExt, StreamExt, TryFutureExt, TryStreamExt, + self, FutureExt, StreamExt, TryFutureExt, TryStreamExt, compat::Future01CompatExt, }; use graph::prelude::{ alloy::{ @@ -28,15 +28,15 @@ use graph::prelude::{ network::TransactionResponse, primitives::{Address, B256}, providers::{ + Identity, Provider, RootProvider, ext::TraceApi, fillers::{ BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, }, - Identity, Provider, RootProvider, }, rpc::types::{ - trace::{filter::TraceFilter as AlloyTraceFilter, parity::LocalizedTransactionTrace}, TransactionInput, TransactionRequest, + trace::{filter::TraceFilter as AlloyTraceFilter, parity::LocalizedTransactionTrace}, }, transports::{RpcError, TransportErrorKind}, }, @@ -44,11 +44,12 @@ use graph::prelude::{ }; use graph::slog::o; use graph::{ - blockchain::{block_stream::BlockWithTriggers, BlockPtr, IngestorError}, + blockchain::{BlockPtr, IngestorError, block_stream::BlockWithTriggers}, prelude::{ - anyhow::{self, anyhow, bail, ensure, Context}, - debug, error, hex, info, retry, trace, warn, BlockNumber, ChainStore, CheapClone, - DynTryFuture, Error, EthereumCallCache, Logger, TimeoutError, + BlockNumber, ChainStore, CheapClone, DynTryFuture, Error, EthereumCallCache, Logger, + TimeoutError, + anyhow::{self, Context, anyhow, bail, ensure}, + debug, error, hex, info, retry, trace, warn, }, }; use itertools::Itertools; @@ -61,6 +62,9 @@ use std::time::{Duration, Instant}; use tokio::sync::RwLock; use tokio::time::timeout; +use crate::Chain; +use crate::NodeCapabilities; +use crate::TriggerFilter; use crate::adapter::EthGetLogsFilter; use crate::adapter::EthereumRpcError; use crate::adapter::ProviderStatus; @@ -68,17 +72,14 @@ use crate::call_helper::interpret_eth_call_error; use crate::chain::BlockFinality; use crate::chain::ChainSettings; use crate::trigger::{LogPosition, LogRef}; -use crate::Chain; -use crate::NodeCapabilities; -use crate::TriggerFilter; use crate::{ + ENV_VARS, adapter::{ ContractCallError, EthereumAdapter as EthereumAdapterTrait, EthereumBlockFilter, EthereumCallFilter, EthereumLogFilter, ProviderEthRpcMetrics, SubgraphEthRpcMetrics, }, transport::Transport, trigger::{EthereumBlockTriggerType, EthereumTrigger}, - ENV_VARS, }; type AlloyProvider = FillProvider< @@ -173,13 +174,11 @@ impl EthereumAdapter { Transport::RPC(client) => Arc::new( alloy::providers::ProviderBuilder::<_, _, AnyNetworkBare>::default() .network::() - .with_recommended_fillers() .connect_client(client.clone()), ), Transport::IPC(ipc_connect) => Arc::new( alloy::providers::ProviderBuilder::<_, _, AnyNetworkBare>::default() .network::() - .with_recommended_fillers() .connect_ipc(ipc_connect.clone()) .await .expect("Failed to connect to Ethereum IPC"), @@ -187,7 +186,6 @@ impl EthereumAdapter { Transport::WS(ws_connect) => Arc::new( alloy::providers::ProviderBuilder::<_, _, AnyNetworkBare>::default() .network::() - .with_recommended_fillers() .connect_ws(ws_connect.clone()) .await .expect("Failed to connect to Ethereum WS"), @@ -1014,34 +1012,20 @@ impl EthereumAdapter { ) -> Pin< Box< dyn std::future::Future, anyhow::Error>> - + std::marker::Send, + + std::marker::Send + + '_, >, > { - // Create a HashMap of block numbers to Vec + // Create a HashMap of block numbers to Vec. let matching_blocks = (from..=to) .filter_map(|block_number| { - filter - .polling_intervals - .iter() - .find_map(|(start_block, interval)| { - let has_once_trigger = (*interval == 0) && (block_number == *start_block); - let has_polling_trigger = block_number >= *start_block - && *interval > 0 - && ((block_number - start_block) % *interval) == 0; - - if has_once_trigger || has_polling_trigger { - let mut triggers = Vec::new(); - if has_once_trigger { - triggers.push(EthereumBlockTriggerType::Start); - } - if has_polling_trigger { - triggers.push(EthereumBlockTriggerType::End); - } - Some((block_number, triggers)) - } else { - None - } - }) + let triggers = + block_trigger_types_from_intervals(block_number, &filter.polling_intervals); + if triggers.is_empty() { + None + } else { + Some((block_number, triggers)) + } }) .collect::>(); @@ -1053,15 +1037,13 @@ impl EthereumAdapter { let block_futures = blocks_matching_polling_filter.map(move |ptrs| { ptrs.into_iter() .flat_map(|ptr| { - let triggers = matching_blocks + matching_blocks .get(&ptr.number) // Safe to unwrap since we are iterating over ptrs which was created from // the keys of matching_blocks .unwrap() .iter() - .map(move |trigger| EthereumTrigger::Block(ptr.clone(), trigger.clone())); - - triggers + .map(move |trigger| EthereumTrigger::Block(ptr.clone(), trigger.clone())) }) .collect::>() }); @@ -1126,7 +1108,7 @@ impl EthereumAdapter { logger: Logger, from: BlockNumber, to: BlockNumber, - ) -> Box, Error = Error> + Send> { + ) -> Box, Error = Error> + Send + '_> { // Currently we can't go to the DB for this because there might be duplicate entries for // the same block number. debug!(&logger, "Requesting hashes for blocks [{}, {}]", from, to); @@ -1140,7 +1122,7 @@ impl EthereumAdapter { &self, logger: Logger, blocks: Vec, - ) -> Box, Error = Error> + Send> { + ) -> Box, Error = Error> + Send + '_> { // Currently we can't go to the DB for this because there might be duplicate entries for // the same block number. debug!(&logger, "Requesting hashes for blocks {:?}", blocks); @@ -1587,15 +1569,26 @@ impl EthereumAdapterTrait for EthereumAdapter { fn log_call_error(logger: &ProviderLogger, e: &ContractCallError, call: &ContractCall) { match e { - ContractCallError::AlloyError(e) => error!(logger, + ContractCallError::AlloyError(e) => error!( + logger, "Ethereum node returned an error when calling function \"{}\" of contract \"{}\": {}", - call.function.name, call.contract_name, e), - ContractCallError::Timeout => error!(logger, + call.function.name, + call.contract_name, + e + ), + ContractCallError::Timeout => error!( + logger, "Ethereum node did not respond when calling function \"{}\" of contract \"{}\"", - call.function.name, call.contract_name), - _ => error!(logger, + call.function.name, + call.contract_name + ), + _ => error!( + logger, "Failed to call function \"{}\" of contract \"{}\": {}", - call.function.name, call.contract_name, e), + call.function.name, + call.contract_name, + e + ), } } @@ -2001,6 +1994,36 @@ pub(crate) fn parse_call_triggers( } } +/// For a given `block_number`, return the block trigger types that fire +/// based on the rules in `polling_intervals`. Each entry is `(start_block, +/// interval)` where `interval == 0` encodes a `once` rule and `interval > 0` +/// encodes a `polling every interval` rule. Both rule kinds can fire at the +/// same block (e.g. a once and polling rule sharing a `start_block`), so the +/// returned Vec may contain `Start`, `End`, both, or neither. +pub(crate) fn block_trigger_types_from_intervals( + block_number: i32, + polling_intervals: &HashSet<(i32, i32)>, +) -> Vec { + let has_once_trigger = polling_intervals + .iter() + .any(|(start_block, interval)| *interval == 0 && block_number == *start_block); + + let has_polling_trigger = polling_intervals.iter().any(|(start_block, interval)| { + *interval > 0 + && block_number >= *start_block + && (block_number - start_block) % *interval == 0 + }); + + let mut triggers = Vec::new(); + if has_once_trigger { + triggers.push(EthereumBlockTriggerType::Start); + } + if has_polling_trigger { + triggers.push(EthereumBlockTriggerType::End); + } + triggers +} + /// This method does not parse block triggers with `once` filters. /// This is because it is to be run before any other triggers are run. /// So we have `parse_initialization_triggers` for that. @@ -2042,38 +2065,12 @@ pub(crate) fn parse_block_triggers( EthereumBlockTriggerType::End, )); } else if !block_filter.polling_intervals.is_empty() { - let has_polling_trigger = - &block_filter - .polling_intervals - .iter() - .any(|(start_block, interval)| match interval { - 0 => false, - _ => { - block_number >= *start_block - && (block_number - *start_block) % *interval == 0 - } - }); - - let has_once_trigger = - &block_filter - .polling_intervals - .iter() - .any(|(start_block, interval)| match interval { - 0 => block_number == *start_block, - _ => false, - }); - - if *has_once_trigger { - triggers.push(EthereumTrigger::Block( - block_ptr3.clone(), - EthereumBlockTriggerType::Start, - )); - } - - if *has_polling_trigger { + for trigger_type in + block_trigger_types_from_intervals(block_number, &block_filter.polling_intervals) + { triggers.push(EthereumTrigger::Block( - block_ptr3, - EthereumBlockTriggerType::End, + block_ptr3.cheap_clone(), + trigger_type, )); } } @@ -2125,7 +2122,7 @@ async fn filter_call_triggers_from_unsuccessful_transactions( // And obtain all Transaction values for the calls in this block. let transactions: Vec<&AnyTransaction> = { match &block.block { - BlockFinality::Final(ref block) => block + BlockFinality::Final(block) => block .transactions() .ok_or_else(|| anyhow!("Block transactions not available"))? .iter() @@ -2696,15 +2693,15 @@ mod tests { use crate::trigger::{EthereumBlockTriggerType, EthereumTrigger}; use super::{ - check_block_receipt_support, parse_block_triggers, EthereumBlock, EthereumBlockFilter, - EthereumBlockWithCalls, + EthereumBlock, EthereumBlockFilter, EthereumBlockWithCalls, + block_trigger_types_from_intervals, check_block_receipt_support, parse_block_triggers, }; use graph::blockchain::BlockPtr; use graph::components::ethereum::AnyNetworkBare; - use graph::prelude::alloy::primitives::{Address, Bytes, B256}; - use graph::prelude::alloy::providers::mock::Asserter; + use graph::prelude::alloy::primitives::{Address, B256, Bytes}; use graph::prelude::alloy::providers::ProviderBuilder; - use graph::prelude::{create_minimal_block_for_test, EthereumCall, LightEthereumBlock}; + use graph::prelude::alloy::providers::mock::Asserter; + use graph::prelude::{EthereumCall, LightEthereumBlock, create_minimal_block_for_test}; use jsonrpc_core::serde_json::{self, Value}; use std::collections::HashSet; use std::iter::FromIterator; @@ -2779,7 +2776,6 @@ mod tests { let asserter = Asserter::new(); let provider = ProviderBuilder::<_, _, AnyNetworkBare>::default() .network::() - .with_recommended_fillers() .connect_mocked_client(asserter.clone()); asserter.push_success(&json_value); @@ -2919,6 +2915,115 @@ mod tests { ); } + #[test] + fn block_trigger_types_once_only() { + let intervals = HashSet::from_iter(vec![(100, 0)]); + + assert_eq!( + vec![EthereumBlockTriggerType::Start], + block_trigger_types_from_intervals(100, &intervals), + "once rule fires Start at start_block" + ); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(99, &intervals), + "once rule does not fire before start_block" + ); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(101, &intervals), + "once rule does not fire after start_block" + ); + } + + #[test] + fn block_trigger_types_polling_only() { + let intervals = HashSet::from_iter(vec![(100, 10)]); + + assert_eq!( + vec![EthereumBlockTriggerType::End], + block_trigger_types_from_intervals(100, &intervals), + "polling rule fires End at start_block" + ); + assert_eq!( + vec![EthereumBlockTriggerType::End], + block_trigger_types_from_intervals(110, &intervals), + "polling rule fires End at start_block + interval" + ); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(105, &intervals), + "polling rule does not fire off-interval" + ); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(90, &intervals), + "polling rule does not fire before start_block" + ); + } + + #[test] + fn block_trigger_types_once_and_polling_same_start_block() { + // A single data source with both a `once` handler and a `polling` handler + // contributes both entries at its start_block. Both must fire at start_block. + let intervals = HashSet::from_iter(vec![(100, 0), (100, 10)]); + + assert_eq!( + vec![ + EthereumBlockTriggerType::Start, + EthereumBlockTriggerType::End, + ], + block_trigger_types_from_intervals(100, &intervals), + "both Start and End should fire when once and polling rules share start_block" + ); + assert_eq!( + vec![EthereumBlockTriggerType::End], + block_trigger_types_from_intervals(110, &intervals), + "only polling fires at later interval matches" + ); + } + + #[test] + fn block_trigger_types_cross_datasource_collision() { + // Two data sources: DS-A with once at 100, DS-B with polling every 10 from 50. + // Block 100 satisfies DS-A's once rule and also (100-50) % 10 == 0, so both fire. + let intervals = HashSet::from_iter(vec![(100, 0), (50, 10)]); + + assert_eq!( + vec![ + EthereumBlockTriggerType::Start, + EthereumBlockTriggerType::End, + ], + block_trigger_types_from_intervals(100, &intervals), + "both triggers fire when a once rule and an unrelated polling rule collide" + ); + assert_eq!( + vec![EthereumBlockTriggerType::End], + block_trigger_types_from_intervals(60, &intervals), + "only polling fires at a block where only the polling rule matches" + ); + } + + #[test] + fn block_trigger_types_no_match() { + let intervals = HashSet::from_iter(vec![(100, 0), (100, 10)]); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(99, &intervals), + "no triggers when block matches neither rule" + ); + } + + #[test] + fn block_trigger_types_empty_intervals() { + let intervals: HashSet<(i32, i32)> = HashSet::new(); + assert_eq!( + Vec::::new(), + block_trigger_types_from_intervals(100, &intervals), + "empty intervals yields no triggers" + ); + } + fn address(id: u64) -> Address { Address::left_padding_from(&id.to_be_bytes()) } diff --git a/chain/ethereum/src/ingestor.rs b/chain/ethereum/src/ingestor.rs index e2d469a3954..dcbcc42c6f8 100644 --- a/chain/ethereum/src/ingestor.rs +++ b/chain/ethereum/src/ingestor.rs @@ -1,9 +1,9 @@ -use crate::{chain::BlockFinality, ENV_VARS}; +use crate::{ENV_VARS, chain::BlockFinality}; use crate::{EthereumAdapter, EthereumAdapterTrait as _}; use async_trait::async_trait; use futures::future::select_ok; -use graph::blockchain::client::ChainClient; use graph::blockchain::BlockchainKind; +use graph::blockchain::client::ChainClient; use graph::components::network_provider::ChainName; use graph::prelude::alloy::primitives::B256; use graph::slog::o; @@ -12,8 +12,8 @@ use graph::{ blockchain::{BlockHash, BlockIngestor, BlockPtr, IngestorError}, cheap_clone::CheapClone, prelude::{ - debug, error, info, tokio, trace, warn, ChainStore, Error, EthereumBlockWithCalls, LogCode, - Logger, + ChainStore, Error, EthereumBlockWithCalls, LogCode, Logger, debug, error, info, tokio, + trace, warn, }, }; use std::{sync::Arc, time::Duration}; @@ -281,10 +281,10 @@ async fn on_poll_failure( // at the match level. If the current provider responds to eth_blockNumber, the // failure was not caused by provider unavailability — switching cannot help. let current = providers.iter().find(|p| p.provider() == current_name); - if let Some(current) = current { - if current.is_reachable().await { - return; - } + if let Some(current) = current + && current.is_reachable().await + { + return; } // Probe all alternatives in parallel; switch to the first that responds. @@ -378,7 +378,7 @@ mod tests { use graph::components::ethereum::LightEthereumBlock; use graph::data::store::ethereum::call; use graph::data_source::common::ContractCall; - use graph::prelude::alloy::primitives::{Address, Bytes, B256, U256}; + use graph::prelude::alloy::primitives::{Address, B256, Bytes, U256}; use graph::prelude::{BlockNumber, Error, EthereumCallCache, Logger}; use graph::slog::Discard; use std::collections::HashSet; diff --git a/chain/ethereum/src/network.rs b/chain/ethereum/src/network.rs index efd6bc6d317..ad9cd0a83c0 100644 --- a/chain/ethereum/src/network.rs +++ b/chain/ethereum/src/network.rs @@ -15,9 +15,9 @@ use std::sync::Arc; pub use graph::impl_slog_value; use graph::prelude::Error; +use crate::EthereumAdapter; use crate::adapter::EthereumAdapter as _; use crate::capabilities::NodeCapabilities; -use crate::EthereumAdapter; pub const DEFAULT_ADAPTER_ERROR_RETEST_PERCENT: f64 = 0.2; @@ -107,7 +107,7 @@ impl EthereumNetworkAdapters { use std::cmp::Ordering; use graph::components::network_provider::ProviderCheckStrategy; - use graph::slog::{o, Discard, Logger}; + use graph::slog::{Discard, Logger, o}; let chain_id: ChainName = "testing".into(); adapters.sort_by(|a, b| { @@ -118,7 +118,7 @@ impl EthereumNetworkAdapters { let provider = ProviderManager::new( Logger::root(Discard, o!()), - vec![(chain_id.clone(), adapters)].into_iter(), + vec![(chain_id.clone(), adapters)], ProviderCheckStrategy::MarkAsValid, ); @@ -329,14 +329,14 @@ mod tests { endpoint::EndpointMetrics, firehose::SubgraphLimit, prelude::MetricsRegistry, - slog::{o, Discard, Logger}, + slog::{Discard, Logger, o}, url::Url, }; use std::sync::Arc; use crate::{ - chain::ChainSettings, Compression, EthereumAdapter, EthereumAdapterTrait, - ProviderEthRpcMetrics, Transport, + Compression, EthereumAdapter, EthereumAdapterTrait, ProviderEthRpcMetrics, Transport, + chain::ChainSettings, }; use super::{EthereumNetworkAdapter, EthereumNetworkAdapters, NodeCapabilities}; @@ -465,13 +465,15 @@ mod tests { { // Not Found - assert!(adapters - .cheapest_with(&NodeCapabilities { - archive: false, - traces: true, - }) - .await - .is_err()); + assert!( + adapters + .cheapest_with(&NodeCapabilities { + archive: false, + traces: true, + }) + .await + .is_err() + ); // Check cheapest is not call only let adapter = adapters diff --git a/chain/ethereum/src/polling_block_stream.rs b/chain/ethereum/src/polling_block_stream.rs index 55d2aed3df8..339386207f1 100644 --- a/chain/ethereum/src/polling_block_stream.rs +++ b/chain/ethereum/src/polling_block_stream.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Error}; +use anyhow::{Error, anyhow}; use std::cmp; use std::collections::VecDeque; use std::pin::Pin; @@ -7,13 +7,13 @@ use std::task::{Context, Poll}; use std::time::Duration; use graph::blockchain::block_stream::{ - BlockStream, BlockStreamError, BlockStreamEvent, BlockWithTriggers, ChainHeadUpdateStream, - FirehoseCursor, TriggersAdapterWrapper, BUFFERED_BLOCK_STREAM_SIZE, + BUFFERED_BLOCK_STREAM_SIZE, BlockStream, BlockStreamError, BlockStreamEvent, BlockWithTriggers, + ChainHeadUpdateStream, FirehoseCursor, TriggersAdapterWrapper, }; use graph::blockchain::{Block, BlockPtr, TriggerFilterWrapper}; -use graph::futures03::{stream::Stream, Future, FutureExt}; -use graph::prelude::{DeploymentHash, BLOCK_NUMBER_MAX}; -use graph::slog::{info, trace, warn, Logger}; +use graph::futures03::{Future, FutureExt, stream::Stream}; +use graph::prelude::{BLOCK_NUMBER_MAX, DeploymentHash}; +use graph::slog::{Logger, info, trace, warn}; use graph::components::store::BlockNumber; use graph::data::subgraph::UnifiedMappingApiVersion; @@ -182,7 +182,7 @@ impl PollingBlockStreamContext { return Ok(NextBlocks::Done); } ReconciliationStep::Revert(parent_ptr) => { - return Ok(NextBlocks::Revert(parent_ptr)) + return Ok(NextBlocks::Revert(parent_ptr)); } } } @@ -224,10 +224,10 @@ impl PollingBlockStreamContext { // Only continue if the subgraph block ptr is behind the head block ptr. // subgraph_ptr > head_ptr shouldn't happen, but if it does, it's safest to just stop. - if let Some(ptr) = &subgraph_ptr { - if ptr.number >= head_ptr.number { - return Ok(ReconciliationStep::Done); - } + if let Some(ptr) = &subgraph_ptr + && ptr.number >= head_ptr.number + { + return Ok(ReconciliationStep::Done); } // Subgraph ptr is behind head ptr. @@ -569,7 +569,7 @@ impl Stream for PollingBlockStream { } // Yielding blocks from reconciliation process - BlockStreamState::YieldingBlocks(ref mut next_blocks) => { + BlockStreamState::YieldingBlocks(next_blocks) => { match next_blocks.pop_front() { // Yield one block Some(next_block) => { @@ -589,7 +589,7 @@ impl Stream for PollingBlockStream { } // Pausing after an error, before looking for more blocks - BlockStreamState::RetryAfterDelay(ref mut delay) => match delay.as_mut().poll(cx) { + BlockStreamState::RetryAfterDelay(delay) => match delay.as_mut().poll(cx) { Poll::Ready(Ok(..)) | Poll::Ready(Err(_)) => { self.state = BlockStreamState::BeginReconciliation; } diff --git a/chain/ethereum/src/runtime/abi.rs b/chain/ethereum/src/runtime/abi.rs index 8f85866b3d4..4311fed3c48 100644 --- a/chain/ethereum/src/runtime/abi.rs +++ b/chain/ethereum/src/runtime/abi.rs @@ -12,8 +12,8 @@ use graph::prelude::alloy::rpc::types::{Log, TransactionReceipt}; use graph::{ prelude::BigInt, runtime::{ - asc_get, asc_new, asc_new_or_null, gas::GasCounter, AscHeap, AscIndexId, AscPtr, AscType, - DeterministicHostError, FromAscObj, HostExportError, IndexForAscTypeId, ToAscObj, + AscHeap, AscIndexId, AscPtr, AscType, DeterministicHostError, FromAscObj, HostExportError, + IndexForAscTypeId, ToAscObj, asc_get, asc_new, asc_new_or_null, gas::GasCounter, }, }; use graph_runtime_derive::AscType; diff --git a/chain/ethereum/src/runtime/runtime_adapter.rs b/chain/ethereum/src/runtime/runtime_adapter.rs index a5597efcd4d..a5d68a761a7 100644 --- a/chain/ethereum/src/runtime/runtime_adapter.rs +++ b/chain/ethereum/src/runtime/runtime_adapter.rs @@ -2,10 +2,10 @@ use std::{sync::Arc, time::Instant}; use crate::adapter::EthereumRpcError; use crate::{ - capabilities::NodeCapabilities, network::EthereumNetworkAdapters, Chain, ContractCallError, - EthereumAdapter, EthereumAdapterTrait, ENV_VARS, + Chain, ContractCallError, ENV_VARS, EthereumAdapter, EthereumAdapterTrait, + capabilities::NodeCapabilities, network::EthereumNetworkAdapters, }; -use anyhow::{anyhow, Context, Error}; +use anyhow::{Context, Error, anyhow}; use blockchain::HostFn; use graph::abi; use graph::abi::DynSolValueExt; @@ -23,8 +23,8 @@ use graph::{ blockchain::{self, BlockPtr, HostFnCtx}, cheap_clone::CheapClone, futures03::FutureExt, - prelude::{alloy::primitives::Address, EthereumCallCache}, - runtime::{asc_get, asc_new, AscPtr, HostExportError}, + prelude::{EthereumCallCache, alloy::primitives::Address}, + runtime::{AscPtr, HostExportError, asc_get, asc_new}, slog::Logger, }; use graph_runtime_wasm::asc_abi::class::{AscBigInt, AscEnumArray, AscWrapped, EthereumValueKind}; @@ -346,32 +346,34 @@ async fn eth_call( Err(e) => (Err(e), call::Source::Rpc), }; let result = match result { - Ok(res) => Ok(res), + Ok(res) => Ok(res), - // Any error reported by the Ethereum node could be due to the block no longer being on - // the main chain. This is very unespecific but we don't want to risk failing a - // subgraph due to a transient error such as a reorg. - Err(ContractCallError::AlloyError(e)) => Err(HostExportError::PossibleReorg(anyhow::anyhow!( + // Any error reported by the Ethereum node could be due to the block no longer being on + // the main chain. This is very unespecific but we don't want to risk failing a + // subgraph due to a transient error such as a reorg. + Err(ContractCallError::AlloyError(e)) => { + Err(HostExportError::PossibleReorg(anyhow::anyhow!( "Ethereum node returned an error when calling function \"{}\" of contract \"{}\": {}", unresolved_call.function_name, unresolved_call.contract_name, e - ))), - - // Also retry on timeouts. - Err(ContractCallError::Timeout) => Err(HostExportError::PossibleReorg(anyhow::anyhow!( - "Ethereum node did not respond when calling function \"{}\" of contract \"{}\"", - unresolved_call.function_name, - unresolved_call.contract_name, - ))), + ))) + } - Err(e) => Err(HostExportError::Unknown(anyhow::anyhow!( - "Failed to call function \"{}\" of contract \"{}\": {}", - unresolved_call.function_name, - unresolved_call.contract_name, - e - ))), - }; + // Also retry on timeouts. + Err(ContractCallError::Timeout) => Err(HostExportError::PossibleReorg(anyhow::anyhow!( + "Ethereum node did not respond when calling function \"{}\" of contract \"{}\"", + unresolved_call.function_name, + unresolved_call.contract_name, + ))), + + Err(e) => Err(HostExportError::Unknown(anyhow::anyhow!( + "Failed to call function \"{}\" of contract \"{}\": {}", + unresolved_call.function_name, + unresolved_call.contract_name, + e + ))), + }; let elapsed = start_time.elapsed(); diff --git a/chain/ethereum/src/tests.rs b/chain/ethereum/src/tests.rs index 5fa236323a4..a5f0a17bff0 100644 --- a/chain/ethereum/src/tests.rs +++ b/chain/ethereum/src/tests.rs @@ -1,17 +1,17 @@ use std::sync::Arc; use graph::{ - blockchain::{block_stream::BlockWithTriggers, BlockPtr, Trigger}, + blockchain::{BlockPtr, Trigger, block_stream::BlockWithTriggers}, prelude::{ + EthereumCall, LightEthereumBlock, alloy::{ self, - primitives::{Address, Bytes, LogData, B256}, + primitives::{Address, B256, Bytes, LogData}, rpc::types::{Block, Log}, }, rand::{self, Rng}, - EthereumCall, LightEthereumBlock, }, - slog::{self, o, Logger}, + slog::{self, Logger, o}, }; use crate::{ diff --git a/chain/ethereum/src/transport.rs b/chain/ethereum/src/transport.rs index ea5d63bc83b..5b5414c4a5d 100644 --- a/chain/ethereum/src/transport.rs +++ b/chain/ethereum/src/transport.rs @@ -265,12 +265,10 @@ impl Service for PatchingHttp { )); } - if should_patch { - if let Some(patched) = Self::patch_response(&body) { - return serde_json::from_slice(&patched).map_err(|err| { - TransportError::deser_err(err, String::from_utf8_lossy(&patched)) - }); - } + if should_patch && let Some(patched) = Self::patch_response(&body) { + return serde_json::from_slice(&patched).map_err(|err| { + TransportError::deser_err(err, String::from_utf8_lossy(&patched)) + }); } serde_json::from_slice(&body) .map_err(|err| TransportError::deser_err(err, String::from_utf8_lossy(&body))) diff --git a/chain/ethereum/src/trigger.rs b/chain/ethereum/src/trigger.rs index 6a5e1503073..b5d51d9a379 100644 --- a/chain/ethereum/src/trigger.rs +++ b/chain/ethereum/src/trigger.rs @@ -8,19 +8,19 @@ use graph::data::subgraph::API_VERSION_0_0_2; use graph::data::subgraph::API_VERSION_0_0_6; use graph::data::subgraph::API_VERSION_0_0_7; use graph::data_source::common::DeclaredCall; +use graph::prelude::BlockNumber; +use graph::prelude::BlockPtr; +use graph::prelude::LightEthereumBlock; use graph::prelude::alloy::consensus::Transaction as TransactionTrait; use graph::prelude::alloy::network::TransactionResponse; use graph::prelude::alloy::primitives::{Address, B256, U256}; use graph::prelude::alloy::rpc::types::Log; -use graph::prelude::BlockNumber; -use graph::prelude::BlockPtr; -use graph::prelude::LightEthereumBlock; use graph::prelude::{CheapClone, EthereumCall}; -use graph::runtime::asc_new; -use graph::runtime::gas::GasCounter; use graph::runtime::AscHeap; use graph::runtime::AscPtr; use graph::runtime::HostExportError; +use graph::runtime::asc_new; +use graph::runtime::gas::GasCounter; use graph::semver::Version; use graph_runtime_wasm::module::ToAscPtr; use std::{cmp::Ordering, sync::Arc}; diff --git a/chain/near/src/adapter.rs b/chain/near/src/adapter.rs index 8a9de408bad..31c7dca7c97 100644 --- a/chain/near/src/adapter.rs +++ b/chain/near/src/adapter.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use crate::data_source::PartialAccounts; -use crate::{data_source::DataSource, Chain}; +use crate::{Chain, data_source::DataSource}; use graph::blockchain as bc; use graph::firehose::{BasicReceiptFilter, PrefixSuffixPair}; use graph::itertools::Itertools; @@ -251,7 +251,7 @@ mod test { use std::collections::HashSet; use super::NearBlockFilter; - use crate::adapter::{TriggerFilter, BASIC_RECEIPT_FILTER_TYPE_URL}; + use crate::adapter::{BASIC_RECEIPT_FILTER_TYPE_URL, TriggerFilter}; use graph::{ blockchain::TriggerFilter as _, firehose::{BasicReceiptFilter, PrefixSuffixPair}, diff --git a/chain/near/src/chain.rs b/chain/near/src/chain.rs index 6dae3c3a1f0..5698301b5e8 100644 --- a/chain/near/src/chain.rs +++ b/chain/near/src/chain.rs @@ -14,17 +14,17 @@ use graph::prelude::MetricsRegistry; use graph::{ anyhow::Result, blockchain::{ + BlockHash, BlockPtr, Blockchain, EmptyNodeCapabilities, IngestorError, + RuntimeAdapter as RuntimeAdapterTrait, block_stream::{ BlockStreamEvent, BlockWithTriggers, FirehoseError, FirehoseMapper as FirehoseMapperTrait, TriggersAdapter as TriggersAdapterTrait, }, firehose_block_stream::FirehoseBlockStream, - BlockHash, BlockPtr, Blockchain, EmptyNodeCapabilities, IngestorError, - RuntimeAdapter as RuntimeAdapterTrait, }, components::store::DeploymentLocator, firehose::{self as firehose, ForkStep}, - prelude::{o, BlockNumber, Error, Logger, LoggerFactory}, + prelude::{BlockNumber, Error, Logger, LoggerFactory, o}, }; use prost::Message; use std::collections::BTreeSet; @@ -197,7 +197,9 @@ impl Blockchain for Chain { _logger: &Logger, _cursor: FirehoseCursor, ) -> Result { - unimplemented!("This chain does not support Dynamic Data Sources. is_refetch_block_required always returns false, this shouldn't be called.") + unimplemented!( + "This chain does not support Dynamic Data Sources. is_refetch_block_required always returns false, this shouldn't be called." + ) } async fn chain_head_ptr(&self) -> Result, Error> { @@ -367,7 +369,7 @@ impl BlockStreamMapper for FirehoseMapper { return Err(anyhow::anyhow!( "near mapper is expected to always have a block" )) - .map_err(BlockStreamError::from) + .map_err(BlockStreamError::from); } }; @@ -439,7 +441,9 @@ impl FirehoseMapperTrait for FirehoseMapper { } StepFinal => { - panic!("irreversible step is not handled and should not be requested in the Firehose request") + panic!( + "irreversible step is not handled and should not be requested in the Firehose request" + ) } StepUnset => { @@ -477,23 +481,23 @@ mod test { use std::{collections::HashSet, sync::Arc, vec}; use graph::{ - blockchain::{block_stream::BlockWithTriggers, DataSource as _, TriggersAdapter as _}, + blockchain::{DataSource as _, TriggersAdapter as _, block_stream::BlockWithTriggers}, data::subgraph::LATEST_VERSION, prelude::Link, semver::Version, - slog::{self, o, Logger}, + slog::{self, Logger, o}, }; use crate::{ + Chain, adapter::{NearReceiptFilter, TriggerFilter}, codec::{ - self, execution_outcome, receipt, Block, BlockHeader, DataReceiver, ExecutionOutcome, - ExecutionOutcomeWithId, IndexerExecutionOutcomeWithReceipt, IndexerShard, - ReceiptAction, SuccessValueExecutionStatus, + self, Block, BlockHeader, DataReceiver, ExecutionOutcome, ExecutionOutcomeWithId, + IndexerExecutionOutcomeWithReceipt, IndexerShard, ReceiptAction, + SuccessValueExecutionStatus, execution_outcome, receipt, }, - data_source::{DataSource, Mapping, PartialAccounts, ReceiptHandler, NEAR_KIND}, + data_source::{DataSource, Mapping, NEAR_KIND, PartialAccounts, ReceiptHandler}, trigger::{NearTrigger, ReceiptWithOutcome}, - Chain, }; use super::TriggersAdapter; diff --git a/chain/near/src/codec.rs b/chain/near/src/codec.rs index fca0a4f4c9e..569e8cf5243 100644 --- a/chain/near/src/codec.rs +++ b/chain/near/src/codec.rs @@ -4,7 +4,7 @@ pub mod pbcodec; use graph::{ blockchain::{Block as BlockchainBlock, BlockPtr, BlockTime}, - prelude::{alloy::primitives::B256, hex, BlockNumber}, + prelude::{BlockNumber, alloy::primitives::B256, hex}, }; use std::convert::TryFrom; use std::fmt::LowerHex; diff --git a/chain/near/src/data_source.rs b/chain/near/src/data_source.rs index e64197eeb0d..01484905a58 100644 --- a/chain/near/src/data_source.rs +++ b/chain/near/src/data_source.rs @@ -7,7 +7,7 @@ use graph::components::subgraph::InstanceDSTemplateInfo; use graph::data::subgraph::{DataSourceContext, DeploymentHash}; use graph::prelude::SubgraphManifestValidationError; use graph::{ - anyhow::{anyhow, Error}, + anyhow::{Error, anyhow}, blockchain::{self, Blockchain}, prelude::{BlockNumber, CheapClone, Deserialize, Link, LinkResolver, Logger}, semver, diff --git a/chain/near/src/runtime/abi.rs b/chain/near/src/runtime/abi.rs index 87e224dc4d0..b74d8f5f7ff 100644 --- a/chain/near/src/runtime/abi.rs +++ b/chain/near/src/runtime/abi.rs @@ -3,7 +3,7 @@ use crate::trigger::ReceiptWithOutcome; use async_trait::async_trait; use graph::anyhow::anyhow; use graph::runtime::gas::GasCounter; -use graph::runtime::{asc_new, AscHeap, AscPtr, DeterministicHostError, HostExportError, ToAscObj}; +use graph::runtime::{AscHeap, AscPtr, DeterministicHostError, HostExportError, ToAscObj, asc_new}; use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, EnumPayload, Uint8Array}; pub(crate) use super::generated::*; @@ -517,7 +517,7 @@ impl ToAscObj for codec::MerklePathItem { "Invalid direction value {}", x )) - .into()) + .into()); } }, }) @@ -557,7 +557,7 @@ impl ToAscObj for codec::Signature { "Invalid signature type {}", value, )) - .into()) + .into()); } }, bytes: asc_new(heap, self.bytes.as_slice(), gas).await?, @@ -596,7 +596,7 @@ impl ToAscObj for codec::PublicKey { "Invalid public key type {}", value, )) - .into()) + .into()); } }, bytes: asc_new(heap, self.bytes.as_slice(), gas).await?, diff --git a/chain/near/src/trigger.rs b/chain/near/src/trigger.rs index ab68ab71beb..bf9794d2b20 100644 --- a/chain/near/src/trigger.rs +++ b/chain/near/src/trigger.rs @@ -3,11 +3,11 @@ use graph::blockchain::Block; use graph::blockchain::MappingTriggerTrait; use graph::blockchain::TriggerData; use graph::derive::CheapClone; +use graph::prelude::BlockNumber; use graph::prelude::alloy::primitives::B256; use graph::prelude::hex; -use graph::prelude::BlockNumber; use graph::runtime::HostExportError; -use graph::runtime::{asc_new, gas::GasCounter, AscHeap, AscPtr}; +use graph::runtime::{AscHeap, AscPtr, asc_new, gas::GasCounter}; use graph_runtime_wasm::module::ToAscPtr; use std::{cmp::Ordering, sync::Arc}; @@ -158,8 +158,8 @@ mod tests { anyhow::anyhow, components::metrics::gas::GasMetrics, data::subgraph::API_VERSION_0_0_5, - prelude::{hex, BigInt}, - runtime::{gas::GasCounter, DeterministicHostError, HostExportError}, + prelude::{BigInt, hex}, + runtime::{DeterministicHostError, HostExportError, gas::GasCounter}, util::mem::init_slice, }; diff --git a/core/graphman/src/commands/deployment/info.rs b/core/graphman/src/commands/deployment/info.rs index 55e00e917ca..155a821d715 100644 --- a/core/graphman/src/commands/deployment/info.rs +++ b/core/graphman/src/commands/deployment/info.rs @@ -11,10 +11,10 @@ use graph_store_postgres::ConnectionPool; use graph_store_postgres::Store; use itertools::Itertools; +use crate::GraphmanError; use crate::deployment::Deployment; use crate::deployment::DeploymentSelector; use crate::deployment::DeploymentVersionSelector; -use crate::GraphmanError; #[derive(Clone, Debug)] pub struct DeploymentStatus { diff --git a/core/graphman/src/commands/deployment/pause.rs b/core/graphman/src/commands/deployment/pause.rs index 0257768a03b..e2405b5f68b 100644 --- a/core/graphman/src/commands/deployment/pause.rs +++ b/core/graphman/src/commands/deployment/pause.rs @@ -3,15 +3,15 @@ use std::sync::Arc; use anyhow::anyhow; use graph::components::store::DeploymentLocator; use graph::components::store::StoreEvent; -use graph_store_postgres::command_support::catalog; -use graph_store_postgres::command_support::catalog::Site; use graph_store_postgres::ConnectionPool; use graph_store_postgres::NotificationSender; +use graph_store_postgres::command_support::catalog; +use graph_store_postgres::command_support::catalog::Site; use thiserror::Error; +use crate::GraphmanError; use crate::deployment::DeploymentSelector; use crate::deployment::DeploymentVersionSelector; -use crate::GraphmanError; pub struct ActiveDeployment { locator: DeploymentLocator, diff --git a/core/graphman/src/commands/deployment/reassign.rs b/core/graphman/src/commands/deployment/reassign.rs index b1ead37cd12..f4279946917 100644 --- a/core/graphman/src/commands/deployment/reassign.rs +++ b/core/graphman/src/commands/deployment/reassign.rs @@ -5,15 +5,15 @@ use graph::components::store::DeploymentLocator; use graph::components::store::StoreEvent; use graph::prelude::AssignmentChange; use graph::prelude::NodeId; -use graph_store_postgres::command_support::catalog; -use graph_store_postgres::command_support::catalog::Site; use graph_store_postgres::ConnectionPool; use graph_store_postgres::NotificationSender; +use graph_store_postgres::command_support::catalog; +use graph_store_postgres::command_support::catalog::Site; use thiserror::Error; +use crate::GraphmanError; use crate::deployment::DeploymentSelector; use crate::deployment::DeploymentVersionSelector; -use crate::GraphmanError; pub struct Deployment { locator: DeploymentLocator, @@ -134,7 +134,10 @@ pub async fn reassign_deployment( .map_err(GraphmanError::from)? .len(); if count == 1 { - let warning_msg = format!("This is the only deployment assigned to '{}'. Please make sure that the node ID is spelled correctly.",node.as_str()); + let warning_msg = format!( + "This is the only deployment assigned to '{}'. Please make sure that the node ID is spelled correctly.", + node.as_str() + ); Ok(ReassignResult::CompletedWithWarnings(vec![warning_msg])) } else { Ok(ReassignResult::Ok) diff --git a/core/graphman/src/commands/deployment/resume.rs b/core/graphman/src/commands/deployment/resume.rs index a8f9f4769e7..4fa0162f83e 100644 --- a/core/graphman/src/commands/deployment/resume.rs +++ b/core/graphman/src/commands/deployment/resume.rs @@ -3,15 +3,15 @@ use std::sync::Arc; use anyhow::anyhow; use graph::components::store::DeploymentLocator; use graph::prelude::StoreEvent; -use graph_store_postgres::command_support::catalog; -use graph_store_postgres::command_support::catalog::Site; use graph_store_postgres::ConnectionPool; use graph_store_postgres::NotificationSender; +use graph_store_postgres::command_support::catalog; +use graph_store_postgres::command_support::catalog::Site; use thiserror::Error; +use crate::GraphmanError; use crate::deployment::DeploymentSelector; use crate::deployment::DeploymentVersionSelector; -use crate::GraphmanError; pub struct PausedDeployment { locator: DeploymentLocator, diff --git a/core/graphman/src/commands/deployment/unassign.rs b/core/graphman/src/commands/deployment/unassign.rs index 474358c297e..cef72e947f1 100644 --- a/core/graphman/src/commands/deployment/unassign.rs +++ b/core/graphman/src/commands/deployment/unassign.rs @@ -3,15 +3,15 @@ use std::sync::Arc; use anyhow::anyhow; use graph::components::store::DeploymentLocator; use graph::components::store::StoreEvent; -use graph_store_postgres::command_support::catalog; -use graph_store_postgres::command_support::catalog::Site; use graph_store_postgres::ConnectionPool; use graph_store_postgres::NotificationSender; +use graph_store_postgres::command_support::catalog; +use graph_store_postgres::command_support::catalog::Site; use thiserror::Error; +use crate::GraphmanError; use crate::deployment::DeploymentSelector; use crate::deployment::DeploymentVersionSelector; -use crate::GraphmanError; pub struct AssignedDeployment { locator: DeploymentLocator, diff --git a/core/graphman/src/deployment.rs b/core/graphman/src/deployment.rs index 0a38f175586..6538017edaa 100644 --- a/core/graphman/src/deployment.rs +++ b/core/graphman/src/deployment.rs @@ -1,6 +1,4 @@ use anyhow::anyhow; -use diesel::dsl::sql; -use diesel::sql_types::Text; use diesel::BoolExpressionMethods; use diesel::ExpressionMethods; use diesel::JoinOnDsl; @@ -8,12 +6,14 @@ use diesel::NullableExpressionMethods; use diesel::PgTextExpressionMethods; use diesel::QueryDsl; use diesel::Queryable; +use diesel::dsl::sql; +use diesel::sql_types::Text; use diesel_async::RunQueryDsl; use graph::components::store::DeploymentId; use graph::components::store::DeploymentLocator; use graph::data::subgraph::DeploymentHash; -use graph_store_postgres::command_support::catalog; use graph_store_postgres::AsyncPgConnection; +use graph_store_postgres::command_support::catalog; use itertools::Itertools; use crate::GraphmanError; diff --git a/core/graphman_store/src/lib.rs b/core/graphman_store/src/lib.rs index f986d6484c0..8b1965df7cd 100644 --- a/core/graphman_store/src/lib.rs +++ b/core/graphman_store/src/lib.rs @@ -7,6 +7,9 @@ use anyhow::Result; use async_trait::async_trait; use chrono::DateTime; use chrono::Utc; +use diesel::AsExpression; +use diesel::FromSqlRow; +use diesel::Queryable; use diesel::deserialize::FromSql; use diesel::pg::Pg; use diesel::pg::PgValue; @@ -14,9 +17,6 @@ use diesel::serialize::Output; use diesel::serialize::ToSql; use diesel::sql_types::BigSerial; use diesel::sql_types::Varchar; -use diesel::AsExpression; -use diesel::FromSqlRow; -use diesel::Queryable; use strum::Display; use strum::EnumString; use strum::IntoStaticStr; diff --git a/core/src/amp_subgraph/manager.rs b/core/src/amp_subgraph/manager.rs index ae272830880..61ec421ca17 100644 --- a/core/src/amp_subgraph/manager.rs +++ b/core/src/amp_subgraph/manager.rs @@ -18,7 +18,7 @@ use graph::{ use slog::{debug, error}; use tokio_util::sync::CancellationToken; -use super::{runner, Metrics, Monitor}; +use super::{Metrics, Monitor, runner}; /// Manages Amp subgraph runner futures. /// diff --git a/core/src/amp_subgraph/metrics.rs b/core/src/amp_subgraph/metrics.rs index e54b07c1a6a..7088cf9a48f 100644 --- a/core/src/amp_subgraph/metrics.rs +++ b/core/src/amp_subgraph/metrics.rs @@ -4,7 +4,7 @@ use alloy::primitives::BlockNumber; use graph::{ cheap_clone::CheapClone, components::{ - metrics::{stopwatch::StopwatchMetrics, MetricsRegistry}, + metrics::{MetricsRegistry, stopwatch::StopwatchMetrics}, store::WritableStore, }, prelude::DeploymentHash, diff --git a/core/src/amp_subgraph/monitor.rs b/core/src/amp_subgraph/monitor.rs index 93cf30252a6..314f464c0d1 100644 --- a/core/src/amp_subgraph/monitor.rs +++ b/core/src/amp_subgraph/monitor.rs @@ -7,11 +7,11 @@ //! `subgraph instance` - A background task that executes the subgraph runner future. use std::{ - collections::{hash_map::Entry, HashMap}, + collections::{HashMap, hash_map::Entry}, fmt, sync::{ - atomic::{AtomicU32, Ordering::SeqCst}, Arc, + atomic::{AtomicU32, Ordering::SeqCst}, }, time::Duration, }; @@ -21,7 +21,7 @@ use futures::future::BoxFuture; use graph::{ cheap_clone::CheapClone, components::store::DeploymentLocator, log::factory::LoggerFactory, }; -use slog::{debug, error, info, warn, Logger}; +use slog::{Logger, debug, error, info, warn}; use tokio::{ sync::mpsc::{self, error::SendError}, task::JoinHandle, diff --git a/core/src/amp_subgraph/runner/context.rs b/core/src/amp_subgraph/runner/context.rs index 8ea0bb9e1f1..d8b5b7b638e 100644 --- a/core/src/amp_subgraph/runner/context.rs +++ b/core/src/amp_subgraph/runner/context.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use alloy::primitives::{BlockHash, BlockNumber}; use graph::{ - amp::{log::Logger as _, Codec, Manifest}, + amp::{Codec, Manifest, log::Logger as _}, cheap_clone::CheapClone, components::store::WritableStore, data::subgraph::DeploymentHash, diff --git a/core/src/amp_subgraph/runner/data_processing.rs b/core/src/amp_subgraph/runner/data_processing.rs index b9b2f20aba1..d5bf991d505 100644 --- a/core/src/amp_subgraph/runner/data_processing.rs +++ b/core/src/amp_subgraph/runner/data_processing.rs @@ -6,7 +6,7 @@ use arrow::array::RecordBatch; use chrono::{DateTime, Utc}; use graph::{ amp::{ - codec::{utils::auto_block_timestamp_decoder, DecodeOutput, DecodedEntity, Decoder}, + codec::{DecodeOutput, DecodedEntity, Decoder, utils::auto_block_timestamp_decoder}, stream_aggregator::{RecordBatchGroup, RecordBatchGroups, StreamRecordBatch}, }, blockchain::block_stream::FirehoseCursor, @@ -15,7 +15,7 @@ use graph::{ }; use slog::{debug, trace}; -use super::{data_stream::TablePtr, Compat, Context, Error}; +use super::{Compat, Context, Error, data_stream::TablePtr}; pub(super) async fn process_record_batch_groups( cx: &mut Context, diff --git a/core/src/amp_subgraph/runner/data_stream.rs b/core/src/amp_subgraph/runner/data_stream.rs index 1d7d9a11c4e..693ae9384a7 100644 --- a/core/src/amp_subgraph/runner/data_stream.rs +++ b/core/src/amp_subgraph/runner/data_stream.rs @@ -3,16 +3,16 @@ use std::{collections::HashMap, ops::RangeInclusive, sync::Arc}; use alloy::primitives::BlockNumber; use anyhow::anyhow; use futures::{ - stream::{self, BoxStream}, StreamExt, TryStreamExt, + stream::{self, BoxStream}, }; use graph::{ amp::{ + Client, client::ResponseBatch, error::IsDeterministic, manifest::DataSource, stream_aggregator::{RecordBatchGroups, StreamAggregator}, - Client, }, cheap_clone::CheapClone, prelude::StopwatchMetrics, @@ -152,10 +152,10 @@ where match result { Ok(response) => { if !start_block_checked { - if let Some(((first_block, _), _)) = response.0.first_key_value() { - if *first_block < start_block { - return Err(Error::NonDeterministic(anyhow!("chain reorg"))); - } + if let Some(((first_block, _), _)) = response.0.first_key_value() + && *first_block < start_block + { + return Err(Error::NonDeterministic(anyhow!("chain reorg"))); } start_block_checked = true; diff --git a/core/src/amp_subgraph/runner/latest_blocks.rs b/core/src/amp_subgraph/runner/latest_blocks.rs index cb62f2e3a42..17bdc23dd29 100644 --- a/core/src/amp_subgraph/runner/latest_blocks.rs +++ b/core/src/amp_subgraph/runner/latest_blocks.rs @@ -1,13 +1,13 @@ use alloy::primitives::BlockNumber; use anyhow::anyhow; use arrow::array::RecordBatch; -use futures::{future::try_join_all, stream::BoxStream, StreamExt, TryFutureExt}; +use futures::{StreamExt, TryFutureExt, future::try_join_all, stream::BoxStream}; use graph::amp::{ + Client, client::ResponseBatch, - codec::{utils::block_number_decoder, Decoder}, + codec::{Decoder, utils::block_number_decoder}, error::IsDeterministic, manifest::DataSource, - Client, }; use itertools::Itertools; use slog::debug; @@ -152,7 +152,9 @@ async fn latest_block_changed( where AC: Client, { - let query = format!("SELECT _block_num FROM {dataset}.{table} WHERE _block_num > {latest_block} SETTINGS stream = true"); + let query = format!( + "SELECT _block_num FROM {dataset}.{table} WHERE _block_num > {latest_block} SETTINGS stream = true" + ); let stream = cx.client.query(&cx.logger, query, None); let _record_batch = read_once(stream).await?; diff --git a/core/src/amp_subgraph/runner/mod.rs b/core/src/amp_subgraph/runner/mod.rs index e90b5c257c2..4e0e85294b6 100644 --- a/core/src/amp_subgraph/runner/mod.rs +++ b/core/src/amp_subgraph/runner/mod.rs @@ -119,11 +119,9 @@ where ) .await?; - if deployment_is_failed { - if let Some(block_ptr) = cx.store.block_ptr() { - cx.store.unfail_non_deterministic_error(&block_ptr).await?; - deployment_is_failed = false; - } + if deployment_is_failed && let Some(block_ptr) = cx.store.block_ptr() { + cx.store.unfail_non_deterministic_error(&block_ptr).await?; + deployment_is_failed = false; } } diff --git a/core/src/amp_subgraph/runner/reorg_handler.rs b/core/src/amp_subgraph/runner/reorg_handler.rs index 03130b19625..8f59169304b 100644 --- a/core/src/amp_subgraph/runner/reorg_handler.rs +++ b/core/src/amp_subgraph/runner/reorg_handler.rs @@ -1,10 +1,10 @@ use alloy::primitives::{BlockHash, BlockNumber}; use anyhow::anyhow; -use futures::{future::try_join_all, StreamExt, TryFutureExt}; +use futures::{StreamExt, TryFutureExt, future::try_join_all}; use graph::{ amp::{ - client::{LatestBlockBeforeReorg, RequestMetadata, ResponseBatch, ResumeStreamingQuery}, Client, + client::{LatestBlockBeforeReorg, RequestMetadata, ResponseBatch, ResumeStreamingQuery}, }, blockchain::block_stream::FirehoseCursor, }; diff --git a/core/src/polling_monitor/arweave_service.rs b/core/src/polling_monitor/arweave_service.rs index d0e557905f6..cc42f7af5ea 100644 --- a/core/src/polling_monitor/arweave_service.rs +++ b/core/src/polling_monitor/arweave_service.rs @@ -8,7 +8,7 @@ use graph::{ prelude::CheapClone, }; use std::{sync::Arc, time::Duration}; -use tower::{buffer::Buffer, ServiceBuilder, ServiceExt}; +use tower::{ServiceBuilder, ServiceExt, buffer::Buffer}; pub type ArweaveService = Buffer, Error>>>; diff --git a/core/src/polling_monitor/ipfs_service.rs b/core/src/polling_monitor/ipfs_service.rs index ef061530fd3..6847bb82acd 100644 --- a/core/src/polling_monitor/ipfs_service.rs +++ b/core/src/polling_monitor/ipfs_service.rs @@ -1,13 +1,13 @@ use std::sync::Arc; use std::time::Duration; -use anyhow::anyhow; use anyhow::Error; +use anyhow::anyhow; use bytes::Bytes; use graph::futures03::future::BoxFuture; use graph::ipfs::{ContentPath, IpfsClient, IpfsContext, RetryPolicy}; use graph::{derive::CheapClone, prelude::CheapClone}; -use tower::{buffer::Buffer, ServiceBuilder, ServiceExt}; +use tower::{ServiceBuilder, ServiceExt, buffer::Buffer}; pub type IpfsService = Buffer, Error>>>; @@ -109,10 +109,10 @@ mod test { use graph::ipfs::{IpfsContext, IpfsMetrics, IpfsRpcClient, ServerAddress}; use graph::log::discard; use tower::ServiceExt; - use wiremock::matchers as m; use wiremock::Mock; use wiremock::MockServer; use wiremock::ResponseTemplate; + use wiremock::matchers as m; use super::*; diff --git a/core/src/polling_monitor/mod.rs b/core/src/polling_monitor/mod.rs index fa0b433f4de..f8a24db97d7 100644 --- a/core/src/polling_monitor/mod.rs +++ b/core/src/polling_monitor/mod.rs @@ -14,11 +14,11 @@ use graph::cheap_clone::CheapClone; use graph::env::ENV_VARS; use graph::futures03::future::BoxFuture; use graph::futures03::stream::StreamExt; -use graph::futures03::{stream, Future, FutureExt, TryFutureExt}; +use graph::futures03::{Future, FutureExt, TryFutureExt, stream}; use graph::parking_lot::Mutex; use graph::prelude::tokio; use graph::prometheus::{Counter, Gauge}; -use graph::slog::{debug, Logger}; +use graph::slog::{Logger, debug}; use graph::util::monitored::MonitoredVecDeque as VecDeque; use tokio::sync::{mpsc, watch}; use tower::retry::backoff::{Backoff, ExponentialBackoff, ExponentialBackoffMaker, MakeBackoff}; @@ -28,8 +28,8 @@ use tower::{Service, ServiceExt}; use self::request::RequestId; pub use self::metrics::PollingMonitorMetrics; -pub use arweave_service::{arweave_service, ArweaveService}; -pub use ipfs_service::{ipfs_service, IpfsRequest, IpfsService}; +pub use arweave_service::{ArweaveService, arweave_service}; +pub use ipfs_service::{IpfsRequest, IpfsService, ipfs_service}; const MIN_BACKOFF: Duration = Duration::from_secs(5); @@ -53,7 +53,7 @@ impl Backoffs { } } - fn next_backoff(&mut self, id: ID) -> impl Future { + fn next_backoff(&mut self, id: ID) -> impl Future + Send + use { self.backoffs .entry(id) .or_insert_with(|| self.backoff_maker.make_backoff()) diff --git a/core/src/subgraph/context/instance/mod.rs b/core/src/subgraph/context/instance/mod.rs index e9c311420e6..494ae227e97 100644 --- a/core/src/subgraph/context/instance/mod.rs +++ b/core/src/subgraph/context/instance/mod.rs @@ -5,8 +5,8 @@ use graph::futures01::sync::mpsc::Sender; use graph::{ blockchain::{Blockchain, TriggerData as _}, data_source::{ - causality_region::CausalityRegionSeq, offchain, CausalityRegion, DataSource, - DataSourceTemplate, TriggerData, + CausalityRegion, DataSource, DataSourceTemplate, TriggerData, + causality_region::CausalityRegionSeq, offchain, }, prelude::*, }; @@ -100,11 +100,11 @@ where ) -> Result>, Error> { let module_bytes = match &data_source.runtime() { None => return Ok(None), - Some(ref module_bytes) => module_bytes.cheap_clone(), + Some(module_bytes) => module_bytes.cheap_clone(), }; let mapping_request_sender = { - let module_hash = tiny_keccak::keccak256(module_bytes.as_ref()); + let module_hash = alloy::primitives::keccak256(module_bytes.as_ref()).0; if let Some(sender) = self.module_cache.get(&module_hash) { sender.clone() } else { diff --git a/core/src/subgraph/context/mod.rs b/core/src/subgraph/context/mod.rs index 07af703d7d7..affbc09aa0f 100644 --- a/core/src/subgraph/context/mod.rs +++ b/core/src/subgraph/context/mod.rs @@ -1,7 +1,7 @@ mod instance; use crate::polling_monitor::{ - spawn_monitor, ArweaveService, IpfsRequest, IpfsService, PollingMonitor, PollingMonitorMetrics, + ArweaveService, IpfsRequest, IpfsService, PollingMonitor, PollingMonitorMetrics, spawn_monitor, }; use anyhow::{self, Error}; use bytes::Bytes; @@ -10,9 +10,9 @@ use graph::{ components::{store::DeploymentId, subgraph::HostMetrics}, data::subgraph::SubgraphManifest, data_source::{ + CausalityRegion, DataSource, DataSourceTemplate, causality_region::CausalityRegionSeq, offchain::{self, Base64}, - CausalityRegion, DataSource, DataSourceTemplate, }, derive::CheapClone, ipfs::IpfsContext, @@ -132,12 +132,12 @@ impl> IndexingContext { .map(|ds| (ds.source.clone(), ds.is_processed())); let host = self.instance.add_dynamic_data_source(logger, data_source)?; - if host.is_some() { - if let Some((source, is_processed)) = offchain_fields { - // monitor data source only if it has not yet been processed. - if !is_processed { - self.offchain_monitor.add_source(source); - } + if host.is_some() + && let Some((source, is_processed)) = offchain_fields + { + // monitor data source only if it has not yet been processed. + if !is_processed { + self.offchain_monitor.add_source(source); } } diff --git a/core/src/subgraph/error.rs b/core/src/subgraph/error.rs index 6aad9f7cb3e..00413acb258 100644 --- a/core/src/subgraph/error.rs +++ b/core/src/subgraph/error.rs @@ -1,6 +1,6 @@ use graph::data::subgraph::schema::SubgraphError; use graph::env::ENV_VARS; -use graph::prelude::{anyhow, thiserror, Error, StoreError}; +use graph::prelude::{Error, StoreError, anyhow, thiserror}; pub trait DeterministicError: std::fmt::Debug + std::fmt::Display + Send + Sync + 'static {} diff --git a/core/src/subgraph/inputs.rs b/core/src/subgraph/inputs.rs index 88e89de4ff4..03a8cec29bc 100644 --- a/core/src/subgraph/inputs.rs +++ b/core/src/subgraph/inputs.rs @@ -1,5 +1,5 @@ use graph::{ - blockchain::{block_stream::TriggersAdapterWrapper, Blockchain}, + blockchain::{Blockchain, block_stream::TriggersAdapterWrapper}, components::{ store::{DeploymentLocator, SourceableStore, SubgraphFork, WritableStore}, subgraph::ProofOfIndexingVersion, diff --git a/core/src/subgraph/instance_manager.rs b/core/src/subgraph/instance_manager.rs index 8273b0045cf..ea301ffc723 100644 --- a/core/src/subgraph/instance_manager.rs +++ b/core/src/subgraph/instance_manager.rs @@ -2,10 +2,10 @@ use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; use crate::polling_monitor::{ArweaveService, IpfsService}; +use crate::subgraph::Decoder; use crate::subgraph::context::{IndexingContext, SubgraphKeepAlive}; use crate::subgraph::inputs::IndexingInputs; use crate::subgraph::loader::load_dynamic_data_sources; -use crate::subgraph::Decoder; use std::collections::BTreeSet; use crate::subgraph::runner::SubgraphRunner; @@ -17,18 +17,18 @@ use graph::components::metrics::gas::GasMetrics; use graph::components::metrics::subgraph::DeploymentStatusMetric; use graph::components::store::SourceableStore; use graph::components::subgraph::ProofOfIndexingVersion; -use graph::data::subgraph::{UnresolvedSubgraphManifest, SPEC_VERSION_0_0_6}; +use graph::data::subgraph::{SPEC_VERSION_0_0_6, UnresolvedSubgraphManifest}; use graph::data::value::Word; use graph::data_source::causality_region::CausalityRegionSeq; use graph::env::EnvVars; use graph::prelude::{SubgraphInstanceManager as SubgraphInstanceManagerTrait, *}; use graph::{blockchain::BlockchainMap, components::store::DeploymentLocator}; -use graph_runtime_wasm::module::ToAscPtr; use graph_runtime_wasm::RuntimeHostBuilder; +use graph_runtime_wasm::module::ToAscPtr; use tokio::task; -use super::context::OffchainMonitor; use super::SubgraphTriggerProcessor; +use super::context::OffchainMonitor; use crate::{subgraph::runner::SubgraphRunnerError, subgraph_manifest}; #[derive(Clone)] @@ -278,17 +278,17 @@ impl SubgraphInstanceManager { .with_retries(), ); - if let Some(graft) = &manifest.graft { - if self.subgraph_store.is_deployed(&graft.base).await? { - // Makes sure the raw manifest is cached in the subgraph store - let _raw_manifest = subgraph_manifest::load_raw_subgraph_manifest( - &logger, - &*self.subgraph_store, - &*self.link_resolver, - &graft.base, - ) - .await?; - } + if let Some(graft) = &manifest.graft + && self.subgraph_store.is_deployed(&graft.base).await? + { + // Makes sure the raw manifest is cached in the subgraph store + let _raw_manifest = subgraph_manifest::load_raw_subgraph_manifest( + &logger, + &*self.subgraph_store, + &*self.link_resolver, + &graft.base, + ) + .await?; } info!(logger, "Resolve subgraph files using IPFS"; diff --git a/core/src/subgraph/registrar.rs b/core/src/subgraph/registrar.rs index d718b4131f1..e9422671e25 100644 --- a/core/src/subgraph/registrar.rs +++ b/core/src/subgraph/registrar.rs @@ -10,12 +10,12 @@ use graph::components::{ subgraph::Settings, }; use graph::data::{ - subgraph::{schema::DeploymentCreate, Graft}, + subgraph::{Graft, schema::DeploymentCreate}, value::Word, }; -use graph::futures03::{self, future::TryFutureExt, Stream, StreamExt}; +use graph::futures03::{self, Stream, StreamExt, future::TryFutureExt}; use graph::prelude::{CreateSubgraphResult, SubgraphRegistrar as SubgraphRegistrarTrait, *}; -use graph::util::futures::{retry_strategy, RETRY_DEFAULT_LIMIT}; +use graph::util::futures::{RETRY_DEFAULT_LIMIT, retry_strategy}; use tokio_retry::Retry; pub struct SubgraphRegistrar { @@ -420,7 +420,7 @@ async fn resolve_start_block( .expect("cannot identify minimum start block because there are no data sources") { 0 => Ok(None), - min_start_block => Retry::spawn(retry_strategy(Some(2), RETRY_DEFAULT_LIMIT), move || { + min_start_block => Retry::start(retry_strategy(Some(2), RETRY_DEFAULT_LIMIT), move || { chain .block_pointer_from_number(logger, min_start_block - 1) .inspect_err(move |e| warn!(&logger, "Failed to get block number: {}", e)) diff --git a/core/src/subgraph/runner/mod.rs b/core/src/subgraph/runner/mod.rs index 1a6efbc1d6c..026be3dfc27 100644 --- a/core/src/subgraph/runner/mod.rs +++ b/core/src/subgraph/runner/mod.rs @@ -29,19 +29,19 @@ use graph::components::{ use graph::data::store::scalar::Bytes; use graph::data::subgraph::schema::SubgraphError; use graph::data_source::{ - offchain, CausalityRegion, DataSource, DataSourceCreationError, TriggerData, + CausalityRegion, DataSource, DataSourceCreationError, TriggerData, offchain, }; use graph::env::EnvVars; use graph::ext::futures::Cancelable; use graph::futures03::stream::StreamExt; use graph::prelude::{ - anyhow, hex, retry, thiserror, BlockNumber, BlockPtr, BlockState, CancelGuard, CancelHandle, - CancelToken as _, CheapClone as _, EntityCache, EntityModification, Error, - InstanceDSTemplateInfo, LogCode, RunnerMetrics, RuntimeHostBuilder, StopwatchMetrics, - StoreError, StreamExtension, UnfailOutcome, Value, ENV_VARS, + BlockNumber, BlockPtr, BlockState, CancelGuard, CancelHandle, CancelToken as _, + CheapClone as _, ENV_VARS, EntityCache, EntityModification, Error, InstanceDSTemplateInfo, + LogCode, RunnerMetrics, RuntimeHostBuilder, StopwatchMetrics, StoreError, StreamExtension, + UnfailOutcome, Value, anyhow, hex, retry, thiserror, }; use graph::schema::EntityKey; -use graph::slog::{debug, error, info, o, trace, warn, Logger}; +use graph::slog::{Logger, debug, error, info, o, trace, warn}; use graph::util::lfu_cache::EvictStats; use graph::util::{backoff::ExponentialBackoff, lfu_cache::LfuCache}; use std::sync::Arc; @@ -109,6 +109,7 @@ where ), entity_lfu_cache: LfuCache::new(), cached_head_ptr: None, + postponed_indexes_created: false, }, logger, metrics, @@ -290,16 +291,16 @@ where } // Stop subgraph when we reach maximum endblock. - if let Some(max_end_block) = self.inputs.max_end_block { - if max_end_block <= current_ptr.block_number() { - info!(self.logger, "Stopping subgraph as we reached maximum endBlock"; + if let Some(max_end_block) = self.inputs.max_end_block + && max_end_block <= current_ptr.block_number() + { + info!(self.logger, "Stopping subgraph as we reached maximum endBlock"; "max_end_block" => max_end_block, "current_block" => current_ptr.block_number()); - self.inputs.store.flush().await?; - return Ok(RunnerState::Stopped { - reason: StopReason::MaxEndBlockReached, - }); - } + self.inputs.store.flush().await?; + return Ok(RunnerState::Stopped { + reason: StopReason::MaxEndBlockReached, + }); } } @@ -736,6 +737,21 @@ where let is_caught_up = self.is_caught_up(&block_ptr).await.non_deterministic()?; + if !self.state.postponed_indexes_created + && close_to_chain_head( + &block_ptr, + &self.state.cached_head_ptr, + ENV_VARS.postpone_indexes_creation_threshold, + ) + { + self.state.postponed_indexes_created = true; + self.inputs + .store + .create_postponed_indexes() + .await + .non_deterministic()?; + } + self.inputs .store .transact_block_operations( @@ -1303,32 +1319,34 @@ where .unfail_non_deterministic_error(&block_ptr) .await?; - // Stop trying to unfail. - self.state.should_try_unfail_non_deterministic = false; + // Stop trying unless we're still behind the error block. + if outcome != UnfailOutcome::BehindErrorBlock { + self.state.should_try_unfail_non_deterministic = false; - if let UnfailOutcome::Unfailed = outcome { - self.metrics.subgraph.deployment_status.running(); - self.state.backoff.reset(); + if outcome == UnfailOutcome::Unfailed { + self.metrics.subgraph.deployment_status.running(); + self.state.backoff.reset(); + } } } - if let Some(stop_block) = self.inputs.stop_block { - if block_ptr.number >= stop_block { - info!(self.logger, "Stop block reached for subgraph"); - return Ok(Action::Stop); - } + if let Some(stop_block) = self.inputs.stop_block + && block_ptr.number >= stop_block + { + info!(self.logger, "Stop block reached for subgraph"); + return Ok(Action::Stop); } - if let Some(max_end_block) = self.inputs.max_end_block { - if block_ptr.number >= max_end_block { - info!( - self.logger, - "Stopping subgraph as maximum endBlock reached"; - "max_end_block" => max_end_block, - "current_block" => block_ptr.number - ); - return Ok(Action::Stop); - } + if let Some(max_end_block) = self.inputs.max_end_block + && block_ptr.number >= max_end_block + { + info!( + self.logger, + "Stopping subgraph as maximum endBlock reached"; + "max_end_block" => max_end_block, + "current_block" => block_ptr.number + ); + return Ok(Action::Stop); } Ok(action) diff --git a/core/src/subgraph/runner/state.rs b/core/src/subgraph/runner/state.rs index 01ad9648341..d6401842522 100644 --- a/core/src/subgraph/runner/state.rs +++ b/core/src/subgraph/runner/state.rs @@ -3,8 +3,8 @@ //! This module defines the explicit state machine that controls the runner's lifecycle, //! replacing the previous nested loop structure with clear state transitions. -use graph::blockchain::block_stream::{BlockStream, BlockWithTriggers, FirehoseCursor}; use graph::blockchain::Blockchain; +use graph::blockchain::block_stream::{BlockStream, BlockWithTriggers, FirehoseCursor}; use graph::ext::futures::Cancelable; use graph::prelude::BlockPtr; diff --git a/core/src/subgraph/state.rs b/core/src/subgraph/state.rs index 0ce6ab48b15..c1da4b43199 100644 --- a/core/src/subgraph/state.rs +++ b/core/src/subgraph/state.rs @@ -16,4 +16,7 @@ pub struct IndexingState { pub skip_ptr_updates_timer: Instant, pub entity_lfu_cache: EntityLfuCache, pub cached_head_ptr: Option, + /// Set to `true` once postponed indexes have been created. This + /// ensures we only trigger index creation once per subgraph run. + pub postponed_indexes_created: bool, } diff --git a/core/src/subgraph_manifest.rs b/core/src/subgraph_manifest.rs index c02497c10c5..ddc01e0bc69 100644 --- a/core/src/subgraph_manifest.rs +++ b/core/src/subgraph_manifest.rs @@ -6,7 +6,7 @@ use graph::{ }, data::subgraph::DeploymentHash, }; -use slog::{debug, Logger}; +use slog::{Logger, debug}; pub(super) async fn load_raw_subgraph_manifest( logger: &Logger, diff --git a/docs/environment-variables.md b/docs/environment-variables.md index bdb3c3d0ecc..7a601e32e64 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -315,3 +315,55 @@ those. Disabling the store call cache may significantly impact performance; the actual impact depends on the average execution time of an `eth_call` compared to the cost of a database lookup for a cached result. (default: false) + +## Log Store Configuration + +`graph-node` supports storing and querying subgraph logs through multiple backends: Elasticsearch, Loki, local files, or disabled. + +**For complete log store documentation**, including detailed configuration, querying examples, and choosing the right backend, see the **[Log Store Guide](log-store.md)**. + +### Quick Reference + +**Backend selection:** +- `GRAPH_LOG_STORE_BACKEND`: `disabled` (default), `elasticsearch`, `loki`, or `file` + +**Elasticsearch:** +- `GRAPH_LOG_STORE_ELASTICSEARCH_URL`: Elasticsearch endpoint URL (required) +- `GRAPH_LOG_STORE_ELASTICSEARCH_USER`: Username (optional) +- `GRAPH_LOG_STORE_ELASTICSEARCH_PASSWORD`: Password (optional) +- `GRAPH_LOG_STORE_ELASTICSEARCH_INDEX`: Index name (default: `subgraph`) + +**Loki:** +- `GRAPH_LOG_STORE_LOKI_URL`: Loki endpoint URL (required) +- `GRAPH_LOG_STORE_LOKI_TENANT_ID`: Tenant ID (optional) + +**File-based:** +- `GRAPH_LOG_STORE_FILE_DIR`: Log directory (required) +- `GRAPH_LOG_STORE_FILE_MAX_SIZE`: Max file size in bytes (default: 104857600 = 100MB) +- `GRAPH_LOG_STORE_FILE_RETENTION_DAYS`: Retention period (default: 30) + +**Deprecated variables** (will be removed in future versions): +- `GRAPH_ELASTICSEARCH_URL` → use `GRAPH_LOG_STORE_ELASTICSEARCH_URL` +- `GRAPH_ELASTICSEARCH_USER` → use `GRAPH_LOG_STORE_ELASTICSEARCH_USER` +- `GRAPH_ELASTICSEARCH_PASSWORD` → use `GRAPH_LOG_STORE_ELASTICSEARCH_PASSWORD` +- `GRAPH_ELASTIC_SEARCH_INDEX` → use `GRAPH_LOG_STORE_ELASTICSEARCH_INDEX` + +### Example: File-based Logs for Local Development + +```bash +mkdir -p ./graph-logs +export GRAPH_LOG_STORE_BACKEND=file +export GRAPH_LOG_STORE_FILE_DIR=./graph-logs + +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 +``` + +See the **[Log Store Guide](log-store.md)** for: +- Detailed configuration for all backends +- How log stores work internally +- GraphQL query examples +- Choosing the right backend for your use case +- Best practices and troubleshooting diff --git a/docs/log-store.md b/docs/log-store.md new file mode 100644 index 00000000000..8be1cddecd8 --- /dev/null +++ b/docs/log-store.md @@ -0,0 +1,853 @@ +# Log Store Configuration and Usage + +This guide explains how to configure subgraph indexing logs storage in graph-node. + +## Table of Contents + +- [Overview](#overview) +- [How Log Stores Work](#how-log-stores-work) +- [Log Store Types](#log-store-types) + - [File-based Logs](#file-based-logs) + - [Elasticsearch](#elasticsearch) + - [Loki](#loki) + - [Disabled](#disabled) +- [Configuration](#configuration) + - [Environment Variables](#environment-variables) + - [CLI Arguments](#cli-arguments) + - [Configuration Precedence](#configuration-precedence) +- [Querying Logs](#querying-logs) +- [Migrating from Deprecated Configuration](#migrating-from-deprecated-configuration) +- [Choosing the Right Backend](#choosing-the-right-backend) +- [Best Practices](#best-practices) +- [Troubleshooting](#troubleshooting) + +## Overview + +Graph Node supports multiple logs storage backends for subgraph indexing logs. Subgraph indexing logs include: +- **User-generated logs**: Explicit logging from subgraph mapping code (`log.info()`, `log.error()`, etc.) +- **Runtime logs**: Handler execution, event processing, data source activity +- **System logs**: Warnings, errors, and diagnostics from the indexing system + +**Available backends:** +- **File**: JSON Lines files on local filesystem (for local development) +- **Elasticsearch**: Enterprise-grade search and analytics (for production) +- **Loki**: Grafana's lightweight log aggregation system (for production) +- **Disabled**: No log storage (default) + +All backends share the same query interface through GraphQL, making it easy to switch between them. + +**Important Note:** When log storage is disabled (the default), subgraph logs still appear in stdout/stderr as they always have. The "disabled" setting simply means logs are not stored separately in a queryable format. You can still see logs in your terminal or container logs - they just won't be available via the `_logs` GraphQL query. + +## How Log Stores Work + +### Architecture + +``` +┌─────────────────┐ +│ Subgraph Code │ +│ (mappings) │ +└────────┬────────┘ + │ log.info(), log.error(), etc. + ▼ +┌─────────────────┐ +│ Graph Runtime │ +│ (WebAssembly) │ +└────────┬────────┘ + │ Log events + ▼ +┌─────────────────┐ +│ Log Drain │ ◄─── slog-based logging system +└────────┬────────┘ + │ Write + ▼ +┌─────────────────┐ +│ Log Store │ ◄─── Configurable backend +│ (ES/Loki/File) │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ GraphQL API │ ◄─── Unified query interface +│ (port 8000) │ +└─────────────────┘ +``` + +### Log Flow + +1. **Log sources** generate logs from: + - User mapping code (explicit `log.info()`, `log.error()`, etc. calls) + - Subgraph runtime (handler execution, event processing, data source triggers) + - System warnings and errors (indexing issues, constraint violations, etc.) +2. **Graph runtime** captures these logs with metadata (timestamp, level, source location) +3. **Log drain** formats logs and writes to configured backend +4. **Log store** persists logs and handles queries +5. **GraphQL API** exposes logs through the `_logs` query + +### Log Entry Structure + +Each log entry contains: +- **`id`**: Unique identifier +- **`subgraphId`**: Deployment hash (QmXxx...) +- **`timestamp`**: ISO 8601 timestamp (e.g., `2024-01-15T10:30:00.123456789Z`) +- **`level`**: CRITICAL, ERROR, WARNING, INFO, or DEBUG +- **`text`**: Log message +- **`arguments`**: Key-value pairs from structured logging +- **`meta`**: Source location (module, line, column) + +## Log Store Types + +### File-based Logs + +**Best for:** Local development, testing + +#### How It Works + +File-based logs store each subgraph's logs in a separate JSON Lines (`.jsonl`) file: + +``` +graph-logs/ +├── QmSubgraph1Hash.jsonl +├── QmSubgraph2Hash.jsonl +└── QmSubgraph3Hash.jsonl +``` + +Each line in the file is a complete JSON object representing one log entry. + +#### Storage Format + +```json +{"id":"QmTest-2024-01-15T10:30:00.123456789Z","subgraphId":"QmTest","timestamp":"2024-01-15T10:30:00.123456789Z","level":"error","text":"Handler execution failed, retries: 3","arguments":[{"key":"retries","value":"3"}],"meta":{"module":"mapping.ts","line":42,"column":10}} +``` + +#### Query Performance + +File-based logs stream through files line-by-line with bounded memory usage. + +**Performance characteristics:** +- Query time: O(n) where n = number of log entries +- Memory usage: O(skip + first) - only matching entries kept in memory +- Suitable for: Development and testing + +#### Configuration + +**Minimum configuration (CLI):** +```bash +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend file \ + --log-store-file-dir ./graph-logs +``` + +**Full configuration (environment variables):** +```bash +export GRAPH_LOG_STORE_BACKEND=file +export GRAPH_LOG_STORE_FILE_DIR=/var/log/graph-node +export GRAPH_LOG_STORE_FILE_MAX_SIZE=104857600 # 100MB +export GRAPH_LOG_STORE_FILE_RETENTION_DAYS=30 +``` + +#### Features + +**Advantages:** +- No external dependencies +- Simple setup (just specify a directory) +- Human-readable format (JSON Lines) +- Easy to inspect with standard tools (`jq`, `grep`, etc.) +- Good for debugging during development + +**Limitations:** +- Not suitable for production with high log volume +- No indexing (O(n) query time scales with file size) +- No automatic log rotation or retention management +- Single file per subgraph (no sharding) + +#### When to Use + +Use file-based logs when: +- Developing subgraphs locally +- Testing on a development machine +- Running low-traffic subgraphs (< 1000 total logs/day including system logs) +- You want simple log access without external services + +### Elasticsearch + +**Best for:** Production deployments, high log volume, advanced search + +#### How It Works + +Elasticsearch stores logs in indices with full-text search capabilities, making it ideal for production deployments with high log volume. + +**Architecture:** +``` +graph-node → Elasticsearch HTTP API → Elasticsearch cluster + → Index: subgraph-logs-* + → Query DSL for filtering +``` + +#### Features + +**Advantages:** +- **Indexed searching**: Fast queries even with millions of logs +- **Full-text search**: Powerful text search across log messages +- **Scalability**: Handles billions of log entries +- **High availability**: Supports clustering and replication +- **Kibana integration**: Rich visualization and dashboards for operators +- **Time-based indices**: Efficient retention management + +**Considerations:** +- Requires Elasticsearch cluster (infrastructure overhead) +- Resource-intensive (CPU, memory, disk) + +#### Configuration + +**Minimum configuration (CLI):** +```bash +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend elasticsearch \ + --log-store-elasticsearch-url http://localhost:9200 +``` + +**Full configuration with authentication:** +```bash +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend elasticsearch \ + --log-store-elasticsearch-url https://es.example.com:9200 \ + --log-store-elasticsearch-user elastic \ + --log-store-elasticsearch-password secret \ + --log-store-elasticsearch-index subgraph-logs +``` + +**Environment variables:** +```bash +export GRAPH_LOG_STORE_BACKEND=elasticsearch +export GRAPH_LOG_STORE_ELASTICSEARCH_URL=http://localhost:9200 +export GRAPH_LOG_STORE_ELASTICSEARCH_USER=elastic +export GRAPH_LOG_STORE_ELASTICSEARCH_PASSWORD=secret +export GRAPH_LOG_STORE_ELASTICSEARCH_INDEX=subgraph-logs +``` + +#### Index Configuration + +Logs are stored in the configured index (default: `subgraph`). The index mapping is automatically created. + +**Recommended index settings for production:** +```json +{ + "settings": { + "number_of_shards": 3, + "number_of_replicas": 1, + "refresh_interval": "5s" + } +} +``` + +#### Query Performance + +**Performance characteristics:** +- Query time: O(log n) with indexing +- Memory usage: Minimal (server-side filtering) +- Suitable for: Millions to billions of log entries + +#### When to Use + +Use Elasticsearch when: +- Running production deployments +- High log volume +- Need advanced search and filtering +- Want to build dashboards with Kibana +- Need high availability and scalability +- Have DevOps resources to manage Elasticsearch or can set up a managed ElasticSearch deployment + +### Loki + +**Best for:** Production deployments, Grafana users, cost-effective at scale + +#### How It Works + +Loki is Grafana's log aggregation system, designed to be cost-effective and easy to operate. Unlike Elasticsearch, Loki only indexes metadata (not full-text), making it more efficient for time-series log data. + +**Architecture:** +``` +graph-node → Loki HTTP API → Loki + → Stores compressed chunks + → Indexes labels only +``` + +#### Features + +**Advantages:** +- **Cost-effective**: Lower storage costs than Elasticsearch +- **Grafana integration**: Native integration with Grafana +- **Horizontal scalability**: Designed for cloud-native deployments +- **Multi-tenancy**: Built-in tenant isolation +- **Efficient compression**: Optimized for log data +- **LogQL**: Powerful query language similar to PromQL +- **Lower resource usage**: Less CPU/memory than Elasticsearch + +**Considerations:** +- No full-text indexing (slower text searches) +- Best used with Grafana (less tooling than Elasticsearch) +- Younger ecosystem than Elasticsearch +- Query performance depends on label cardinality + +#### Configuration + +**Minimum configuration (CLI):** +```bash +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend loki \ + --log-store-loki-url http://localhost:3100 +``` + +**With multi-tenancy:** +```bash +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 \ + --log-store-backend loki \ + --log-store-loki-url http://localhost:3100 \ + --log-store-loki-tenant-id my-graph-node +``` + +**Environment variables:** +```bash +export GRAPH_LOG_STORE_BACKEND=loki +export GRAPH_LOG_STORE_LOKI_URL=http://localhost:3100 +export GRAPH_LOG_STORE_LOKI_TENANT_ID=my-graph-node +``` + +#### Labels + +Loki uses labels for indexing. Graph Node automatically creates labels: +- `subgraph_id`: Deployment hash +- `level`: Log level +- `job`: "graph-node" + +#### Query Performance + +**Performance characteristics:** +- Query time: O(n) for text searches, O(log n) for label queries +- Memory usage: Minimal (server-side processing) +- Suitable for: Millions to billions of log entries +- Best performance with label-based filtering + +#### When to Use + +Use Loki when: +- Already using Grafana for monitoring +- Need cost-effective log storage at scale +- Want simpler operations than Elasticsearch +- Multi-tenancy is required +- Log volume is very high (> 1M logs/day) +- Full-text search is not critical + +### Disabled + +**Best for:** Minimalist deployments, reduced overhead + +#### How It Works + +When log storage is disabled (the default), subgraph logs are **still written to stdout/stderr** along with all other graph-node logs. They are just **not stored separately** in a queryable format. + +**Important:** "Disabled" does NOT mean logs are discarded. It means: +- Logs appear in stdout/stderr (traditional behavior) +- Logs are not stored in a separate queryable backend +- The `_logs` GraphQL query returns empty results + +This is the default behavior - logs continue to work exactly as they did before this feature was added. + +#### Configuration + +**Explicitly disable:** +```bash +export GRAPH_LOG_STORE_BACKEND=disabled +``` + +**Or simply don't configure a backend** (defaults to disabled): +```bash +# No log store configuration = disabled +graph-node \ + --postgres-url postgresql://graph:pass@localhost/graph-node \ + --ethereum-rpc mainnet:https://... \ + --ipfs 127.0.0.1:5001 +``` + +#### Features + +**Advantages:** +- Zero additional overhead +- No external dependencies +- Minimal configuration +- Logs still appear in stdout/stderr for debugging + +**Limitations:** +- Cannot query logs via GraphQL (`_logs` returns empty results) +- No separation of subgraph logs from other graph-node logs in stdout +- Logs mixed with system logs (harder to filter programmatically) +- No structured querying or filtering capabilities + +#### When to Use + +Use disabled log storage when: +- Running minimal test deployments with less dependencies +- Exposing logs to users is not required for your use case +- You'd like subgraph logs sent to external log collection (e.g., container logs) + +## Configuration + +### Environment Variables + +Environment variables are the recommended way to configure log stores, especially in containerized deployments. + +#### Backend Selection + +```bash +GRAPH_LOG_STORE_BACKEND= +``` +Valid values: `disabled`, `elasticsearch`, `loki`, `file` + +#### Elasticsearch + +```bash +GRAPH_LOG_STORE_ELASTICSEARCH_URL=http://localhost:9200 +GRAPH_LOG_STORE_ELASTICSEARCH_USER=elastic # Optional +GRAPH_LOG_STORE_ELASTICSEARCH_PASSWORD=secret # Optional +GRAPH_LOG_STORE_ELASTICSEARCH_INDEX=subgraph # Default: "subgraph" +``` + +#### Loki + +```bash +GRAPH_LOG_STORE_LOKI_URL=http://localhost:3100 +GRAPH_LOG_STORE_LOKI_TENANT_ID=my-tenant # Optional +``` + +#### File + +```bash +GRAPH_LOG_STORE_FILE_DIR=/var/log/graph-node +GRAPH_LOG_STORE_FILE_MAX_SIZE=104857600 # Default: 100MB +GRAPH_LOG_STORE_FILE_RETENTION_DAYS=30 # Default: 30 +``` + +### CLI Arguments + +CLI arguments provide the same functionality as environment variables and the two can be mixed together. + +#### Backend Selection + +```bash +--log-store-backend +``` + +#### Elasticsearch + +```bash +--log-store-elasticsearch-url +--log-store-elasticsearch-user +--log-store-elasticsearch-password +--log-store-elasticsearch-index +``` + +#### Loki + +```bash +--log-store-loki-url +--log-store-loki-tenant-id +``` + +#### File + +```bash +--log-store-file-dir +--log-store-file-max-size +--log-store-file-retention-days +``` + +### Configuration Precedence + +When multiple configuration methods are used: + +1. **CLI arguments** take highest precedence +2. **Environment variables** are used if no CLI args provided +3. **Defaults** are used if neither is set + +## Querying Logs + +All log backends share the same GraphQL query interface. Logs are queried through the subgraph-specific GraphQL endpoint: + +- **Subgraph by deployment**: `http://localhost:8000/subgraphs/id/` +- **Subgraph by name**: `http://localhost:8000/subgraphs/name/` + +The `_logs` query is automatically scoped to the subgraph in the URL, so you don't need to pass a `subgraphId` parameter. + +**Note**: Queries return all log types - both user-generated logs from mapping code and system-generated runtime logs (handler execution, events, warnings, etc.). Use the `search` filter to search for specific messages, or `level` to filter by severity. + +### Basic Query + +Query the `_logs` field at your subgraph's GraphQL endpoint: + +```graphql +query { + _logs( + first: 100 + ) { + id + timestamp + level + text + } +} +``` + +**Example endpoint**: `http://localhost:8000/subgraphs/id/QmYourDeploymentHash` + +### Query with Filters + +```graphql +query { + _logs( + level: ERROR + from: "2024-01-01T00:00:00Z" + to: "2024-01-31T23:59:59Z" + search: "timeout" + first: 50 + skip: 0 + ) { + id + timestamp + level + text + arguments { + key + value + } + meta { + module + line + column + } + } +} +``` + +### Available Filters + +| Filter | Type | Description | +|--------|------|-------------| +| `level` | LogLevel | Filter by level: CRITICAL, ERROR, WARNING, INFO, DEBUG | +| `from` | String | Start timestamp (ISO 8601) | +| `to` | String | End timestamp (ISO 8601) | +| `search` | String | Case-insensitive substring search in log messages | +| `first` | Int | Number of results to return (default: 100, max: 1000) | +| `skip` | Int | Number of results to skip for pagination (max: 10000) | + +### Response Fields + +| Field | Type | Description | +|-------|------|-------------| +| `id` | String | Unique log entry ID | +| `timestamp` | String | ISO 8601 timestamp with nanosecond precision | +| `level` | LogLevel | Log level (CRITICAL, ERROR, WARNING, INFO, DEBUG) | +| `text` | String | Complete log message with arguments | +| `arguments` | [(String, String)] | Structured key-value pairs | +| `meta.module` | String | Source file name | +| `meta.line` | Int | Line number | +| `meta.column` | Int | Column number | + +### Query Examples + +#### Recent Errors + +```graphql +query RecentErrors { + _logs( + level: ERROR + first: 20 + ) { + timestamp + text + meta { + module + line + } + } +} +``` + +#### Search for Specific Text + +```graphql +query SearchTimeout { + _logs( + search: "timeout" + first: 50 + ) { + timestamp + level + text + } +} +``` + +#### Handler Execution Logs + +```graphql +query HandlerLogs { + _logs( + search: "handler" + first: 50 + ) { + timestamp + level + text + } +} +``` + +#### Time Range Query + +```graphql +query LogsInRange { + _logs( + from: "2024-01-15T00:00:00Z" + to: "2024-01-15T23:59:59Z" + first: 1000 + ) { + timestamp + level + text + } +} +``` + +#### Pagination + +```graphql +# First page +query Page1 { + _logs( + first: 100 + skip: 0 + ) { + id + text + } +} + +# Second page +query Page2 { + _logs( + first: 100 + skip: 100 + ) { + id + text + } +} +``` + +### Querying the logs store using cURL + +```bash +curl -X POST http://localhost:8000/subgraphs/id/ \ + -H "Content-Type: application/json" \ + -d '{ + "query": "{ _logs(level: ERROR, first: 10) { timestamp level text } }" + }' +``` + +### Performance Considerations + +**File-based:** _for development only_ +- Streams through files line-by-line (bounded memory usage) +- Memory usage limited to O(skip + first) entries +- Query time is O(n) where n = total log entries in file + +**Elasticsearch:** +- Indexed queries are fast regardless of size +- Text searches are optimized with full-text indexing +- Can handle billions of log entries +- Best for production with high query volume + +**Loki:** +- Label-based queries are fast (indexed) +- Text searches scan compressed chunks (slower than Elasticsearch) +- Good performance with proper label filtering +- Best for production with Grafana integration + +## Choosing the Right Backend + +### Decision Matrix + +| Scenario | Recommended Backend | Reason | +|----------|-------------------|-----------------------------------------------------------------------------------| +| Local development | **File** | Simple, no dependencies, easy to inspect | +| Testing/staging | **File** or **Elasticsearch** | File for simplicity, ES if testing production config | +| Production | **Elasticsearch** or **Loki** | Both handle scale well | +| Using Grafana | **Loki** | Native integration | +| Cost-sensitive at scale | **Loki** | Lower storage costs | +| Want rich ecosystem | **Elasticsearch** | More tools and plugins | +| Minimal deployment | **Disabled** | No overhead | + +### Resource Requirements + +#### File-based +- **Disk**: Minimal (log files only) +- **Memory**: Depends on file size during queries +- **CPU**: Minimal +- **Network**: None +- **External services**: None + +#### Elasticsearch +- **Disk**: High (indices + replicas) +- **Memory**: 4-8GB minimum for small deployments +- **CPU**: Medium to high +- **Network**: HTTP API calls +- **External services**: Elasticsearch cluster + +#### Loki +- **Disk**: Medium (compressed chunks) +- **Memory**: 2-4GB minimum +- **CPU**: Low to medium +- **Network**: HTTP API calls +- **External services**: Loki server + +## Best Practices + +### General + +1. **Start with file-based for development** - Simplest setup, easy debugging +2. **Use Elasticsearch or Loki for production** - Better performance and features +3. **Monitor log volume** - Set up alerts if log volume grows unexpectedly (includes both user logs and system-generated runtime logs) +4. **Set retention policies** - Don't keep logs forever (disk space and cost) +5. **Use structured logging** - Pass key-value pairs to log functions for better filtering + +### File-based Logs + +1. **Monitor file size** - While queries use bounded memory, larger files take longer to scan (O(n) query time) +2. **Archive old logs** - Manually archive/delete old files or implement external rotation +3. **Monitor disk usage** - Files can grow quickly with verbose logging +4. **Use JSON tools** - `jq` is excellent for inspecting .jsonl files locally + +**Example local inspection:** +```bash +# Count logs by level +cat graph-logs/QmExample.jsonl | jq -r '.level' | sort | uniq -c + +# Find errors in last 1000 lines +tail -n 1000 graph-logs/QmExample.jsonl | jq 'select(.level == "error")' + +# Search for specific text +cat graph-logs/QmExample.jsonl | jq 'select(.text | contains("timeout"))' +``` + +### Elasticsearch + +1. **Use index patterns** - Time-based indices for easier management +2. **Configure retention** - Use Index Lifecycle Management (ILM) +3. **Monitor cluster health** - Set up Elasticsearch monitoring +4. **Tune for your workload** - Adjust shards/replicas based on log volume +5. **Use Kibana** - Visualize and explore logs effectively + +**Example Elasticsearch retention policy:** +```json +{ + "policy": "graph-logs-policy", + "phases": { + "hot": { "min_age": "0ms", "actions": {} }, + "warm": { "min_age": "7d", "actions": {} }, + "delete": { "min_age": "30d", "actions": { "delete": {} } } + } +} +``` + +### Loki + +1. **Use proper labels** - Don't over-index, keep label cardinality low +2. **Configure retention** - Set retention period in Loki config +3. **Use Grafana** - Native integration provides best experience +4. **Compress efficiently** - Loki's compression works best with batch writes +5. **Multi-tenancy** - Use tenant IDs if running multiple environments + +**Example Grafana query:** +```logql +{subgraph_id="QmExample", level="error"} |= "timeout" +``` + +## Troubleshooting + +### File-based Logs + +**Problem: Log file doesn't exist** +- Check `GRAPH_LOG_STORE_FILE_DIR` is set correctly +- Verify directory is writable by graph-node + +**Problem: Queries are slow** +- Subgraph logs file may be very large +- Consider archiving old logs or implementing retention +- For high-volume production use, switch to Elasticsearch or Loki + +**Problem: Disk filling up** +- Implement log rotation +- Reduce log verbosity in subgraph code +- Set up monitoring for disk usage + +### Elasticsearch + +**Problem: Cannot connect to Elasticsearch** +- Verify `GRAPH_LOG_STORE_ELASTICSEARCH_URL` is correct +- Check Elasticsearch is running: `curl http://localhost:9200` +- Verify authentication credentials if using security features +- Check network connectivity and firewall rules + +**Problem: No logs appearing in Elasticsearch** +- Check Elasticsearch cluster health +- Verify index exists: `curl http://localhost:9200/_cat/indices` +- Check graph-node logs for write errors +- Verify Elasticsearch has disk space + +**Problem: Queries are slow** +- Check Elasticsearch cluster health and resources +- Verify indices are not over-sharded +- Consider adding replicas for query performance +- Review query patterns and add appropriate indices + +### Loki + +**Problem: Cannot connect to Loki** +- Verify `GRAPH_LOG_STORE_LOKI_URL` is correct +- Check Loki is running: `curl http://localhost:3100/ready` +- Verify tenant ID if using multi-tenancy +- Check network connectivity + +**Problem: No logs appearing in Loki** +- Check Loki service health +- Verify Loki has disk space for chunks +- Check graph-node logs for write errors +- Verify Loki retention settings aren't deleting logs immediately + +**Problem: Queries return no results in Grafana** +- Check label selectors match what graph-node is sending +- Verify time range includes when logs were written +- Check Loki retention period +- Verify tenant ID matches if using multi-tenancy + +## Further Reading + +- [Environment Variables Reference](environment-variables.md) +- [Graph Node Configuration](config.md) +- [Elasticsearch Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) +- [Grafana Loki Documentation](https://grafana.com/docs/loki/latest/) diff --git a/gnd/README.md b/gnd/README.md index 7d6ed59c7db..375e1ef0e01 100644 --- a/gnd/README.md +++ b/gnd/README.md @@ -26,11 +26,11 @@ gnd build # Deploy to a local Graph Node gnd create --node http://localhost:8020 my-name/my-subgraph -gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 my-name/my-subgraph +gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 -l v0.0.1 my-name/my-subgraph # Or deploy to Subgraph Studio gnd auth YOUR_DEPLOY_KEY -gnd deploy my-name/my-subgraph +gnd deploy -l v0.0.1 my-name/my-subgraph ``` ## Commands @@ -165,7 +165,7 @@ gnd deploy [MANIFEST] | `--node` | `-g` | Graph Node URL (defaults to Subgraph Studio) | | `--ipfs` | `-i` | IPFS node URL | | `--deploy-key` | | Deploy key for authentication | -| `--version-label` | `-l` | Version label for the deployment | +| `--version-label` | `-l` | Version label for the deployment (required in non-interactive mode) | | `--ipfs-hash` | | IPFS hash of already-uploaded manifest | | `--output-dir` | `-o` | Build output directory (default: `build/`) | | `--skip-migrations` | | Skip manifest migrations | @@ -173,17 +173,20 @@ gnd deploy [MANIFEST] | `--network-file` | | Path to networks config | | `--debug-fork` | | Fork subgraph ID for debugging | +If `--version-label` is omitted in an interactive terminal, `gnd deploy` prompts for it. +In non-interactive environments (CI/scripts), you must pass `--version-label`. + **Examples:** ```bash # Deploy to Subgraph Studio (uses saved auth key) -gnd deploy my-name/my-subgraph +gnd deploy -l v1.0.0 my-name/my-subgraph # Deploy to local Graph Node -gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 my-name/my-subgraph +gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 -l v1.0.0 my-name/my-subgraph -# Deploy with version label -gnd deploy -l v1.0.0 my-name/my-subgraph +# Deploy without --version-label in an interactive terminal (prompts) +gnd deploy my-name/my-subgraph ``` ### `gnd publish` @@ -378,6 +381,52 @@ gnd dev [OPTIONS] | `--ethereum-rpc` | | Ethereum RPC URL | | `--ipfs` | | IPFS node URL | +### `gnd indexer` + +Manage indexer operations via [`indexer-cli`](https://github.com/graphprotocol/indexer/tree/main/packages/indexer-cli). + +Requires `graph-indexer` to be installed and on `$PATH`: + +```bash +npm install -g @graphprotocol/indexer-cli +``` + +```bash +gnd indexer [args...] +``` + +**Help:** + +There are two ways to get help: + +| Command | What it shows | +|---------|---------------| +| `gnd indexer --help` | gnd's own help for the indexer subcommand (works without `graph-indexer` installed) | +| `gnd indexer help` | Full `graph-indexer` help with all available commands (requires `graph-indexer`) | + +**Examples:** + +```bash +# Check indexer status +gnd indexer status --network arbitrum-one + +# Manage indexing rules +gnd indexer rules get all --network mainnet +gnd indexer rules set decisionBasis always --network mainnet + +# Manage allocations +gnd indexer allocations get --network arbitrum-one + +# Manage cost models +gnd indexer cost get + +# View available indexer commands +gnd indexer help + +# Check graph-indexer version +gnd indexer version +``` + ### `gnd completions` Generate shell completions. diff --git a/gnd/docs/migrating-from-graph-cli.md b/gnd/docs/migrating-from-graph-cli.md index 792f5727d06..6203a6f2f21 100644 --- a/gnd/docs/migrating-from-graph-cli.md +++ b/gnd/docs/migrating-from-graph-cli.md @@ -15,7 +15,7 @@ graph deploy --studio my-subgraph # Use: gnd codegen gnd build -gnd deploy my-subgraph # defaults to Studio +gnd deploy my-subgraph # defaults to Studio; prompts for version label in interactive terminals ``` ## Command Mapping @@ -25,7 +25,7 @@ gnd deploy my-subgraph # defaults to Studio | `graph init` | `gnd init` | Identical flags | | `graph codegen` | `gnd codegen` | Identical flags | | `graph build` | `gnd build` | Identical flags | -| `graph deploy` | `gnd deploy` | Defaults to Studio if `--node` not provided | +| `graph deploy` | `gnd deploy` | Defaults to Studio if `--node` not provided; pass `--version-label` in non-interactive mode | | `graph create` | `gnd create` | Identical flags | | `graph remove` | `gnd remove` | Identical flags | | `graph auth` | `gnd auth` | Identical flags | @@ -33,6 +33,7 @@ gnd deploy my-subgraph # defaults to Studio | `graph test` | `gnd test` | Identical flags | | `graph clean` | `gnd clean` | Identical flags (new in graph-cli 0.80+) | | `graph publish` | `gnd publish` | Identical flags | +| `graph indexer` | `gnd indexer` | Delegates to `graph-indexer` — requires `indexer-cli` installed | | `graph local` | N/A | Not implemented - use graph-node's test infrastructure | | `graph node` | N/A | Not implemented - use `graphman` | @@ -67,6 +68,7 @@ Same success checkmarks, step descriptions, and progress indicators: - `0` for success - `1` for any error +- `gnd indexer` passes through the exit code from `graph-indexer` ### Configuration Files @@ -83,6 +85,20 @@ Code generation produces identical AssemblyScript output (after formatting). You ## What's Different +### Indexer Commands + +`gnd indexer` provides access to indexer management commands via [`indexer-cli`](https://github.com/graphprotocol/indexer/tree/main/packages/indexer-cli). Requires `graph-indexer` on `$PATH`: + +```bash +npm install -g @graphprotocol/indexer-cli + +gnd indexer status --network arbitrum-one +gnd indexer rules get all --network mainnet +gnd indexer allocations get --network arbitrum-one +``` + +Note: `gnd indexer --help` shows gnd's own help and works without `graph-indexer` installed. Use `gnd indexer help` to see the full list of `graph-indexer` commands. + ### Commands Not Available #### `graph local` @@ -192,12 +208,12 @@ Replace `graph` with `gnd` in your CI configuration: # Before - run: graph codegen - run: graph build -- run: graph deploy --studio ${{ secrets.SUBGRAPH_NAME }} +- run: graph deploy --studio -l ${{ github.sha }} ${{ secrets.SUBGRAPH_NAME }} # After - run: gnd codegen - run: gnd build -- run: gnd deploy ${{ secrets.SUBGRAPH_NAME }} +- run: gnd deploy -l ${{ github.sha }} ${{ secrets.SUBGRAPH_NAME }} ``` ### Step 5: Update package.json Scripts (Optional) @@ -209,11 +225,13 @@ If you have npm scripts calling graph-cli: "scripts": { "codegen": "gnd codegen", "build": "gnd build", - "deploy": "gnd deploy" + "deploy": "gnd deploy -l $VERSION_LABEL" } } ``` +Set `VERSION_LABEL` in your environment (for example, from a git tag or commit SHA). + ## Troubleshooting ### "Command not found: gnd" diff --git a/gnd/src/abi.rs b/gnd/src/abi.rs index 49ca4727ee1..0a5fa695cf4 100644 --- a/gnd/src/abi.rs +++ b/gnd/src/abi.rs @@ -3,7 +3,7 @@ //! Handles extraction of bare ABI arrays from various artifact formats //! (raw arrays, Hardhat/Foundry, Truffle). -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; /// Normalize ABI JSON to extract the actual ABI array from various artifact formats. /// @@ -21,19 +21,18 @@ pub fn normalize_abi_json(abi_str: &str) -> Result { } // Case 2: Object with "abi" field (Foundry/Hardhat format) - if let Some(abi) = value.get("abi") { - if abi.is_array() { - return Ok(abi.clone()); - } + if let Some(abi) = value.get("abi") + && abi.is_array() + { + return Ok(abi.clone()); } // Case 3: Object with "compilerOutput.abi" field (Truffle format) - if let Some(compiler_output) = value.get("compilerOutput") { - if let Some(abi) = compiler_output.get("abi") { - if abi.is_array() { - return Ok(abi.clone()); - } - } + if let Some(compiler_output) = value.get("compilerOutput") + && let Some(abi) = compiler_output.get("abi") + && abi.is_array() + { + return Ok(abi.clone()); } Err(anyhow!( @@ -92,9 +91,11 @@ mod tests { let invalid_abi = r#"{"contractName": "MyContract"}"#; let result = normalize_abi_json(invalid_abi); assert!(result.is_err()); - assert!(result - .unwrap_err() - .to_string() - .contains("Invalid ABI format")); + assert!( + result + .unwrap_err() + .to_string() + .contains("Invalid ABI format") + ); } } diff --git a/gnd/src/codegen/abi.rs b/gnd/src/codegen/abi.rs index 292a303260c..9b881fdcbe9 100644 --- a/gnd/src/codegen/abi.rs +++ b/gnd/src/codegen/abi.rs @@ -1375,6 +1375,7 @@ fn indexed_input_type(param_type: &DynSolType) -> DynSolType { #[cfg(test)] mod tests { + use super::*; fn parse_abi(json: &str) -> JsonAbi { @@ -1397,8 +1398,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "Token"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "Token"); + let types = generator.generate_types(); assert!(types.iter().any(|c| c.name == "Transfer")); assert!(types.iter().any(|c| c.name == "Transfer__Params")); @@ -1417,17 +1418,19 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "Token"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "Token"); + let types = generator.generate_types(); assert!(types.iter().any(|c| c.name == "Token")); let token_class = types.iter().find(|c| c.name == "Token").unwrap(); assert!(token_class.methods.iter().any(|m| m.name == "balanceOf")); - assert!(token_class - .methods - .iter() - .any(|m| m.name == "try_balanceOf")); + assert!( + token_class + .methods + .iter() + .any(|m| m.name == "try_balanceOf") + ); } #[test] @@ -1443,8 +1446,8 @@ mod tests { #[test] fn test_name_sanitization() { - let gen = AbiCodeGenerator::new(JsonAbi::default(), "Test!Contract@Name"); - assert_eq!(gen.name, "Test_Contract_Name"); + let generator = AbiCodeGenerator::new(JsonAbi::default(), "Test!Contract@Name"); + assert_eq!(generator.name, "Test_Contract_Name"); } #[test] @@ -1500,8 +1503,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "Token"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "Token"); + let types = generator.generate_types(); // Get all event class names let event_names: Vec<&str> = types @@ -1555,8 +1558,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "Token"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "Token"); + let types = generator.generate_types(); // Find the Token contract class let token_class = types.iter().find(|c| c.name == "Token").unwrap(); @@ -1612,8 +1615,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "TestContract"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "TestContract"); + let types = generator.generate_types(); // Get class names let class_names: Vec<&str> = types.iter().map(|c| c.name.as_str()).collect(); @@ -1699,8 +1702,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "TestContract"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "TestContract"); + let types = generator.generate_types(); // Get class names let class_names: Vec<&str> = types.iter().map(|c| c.name.as_str()).collect(); @@ -1758,8 +1761,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "TestContract"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "TestContract"); + let types = generator.generate_types(); // Get class names let class_names: Vec<&str> = types.iter().map(|c| c.name.as_str()).collect(); @@ -1803,8 +1806,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "TestContract"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "TestContract"); + let types = generator.generate_types(); // Find the contract class let contract_class = types.iter().find(|c| c.name == "TestContract").unwrap(); @@ -1846,8 +1849,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "Token"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "Token"); + let types = generator.generate_types(); // Find the params class let params_class = types @@ -1924,8 +1927,8 @@ mod tests { ]"#; let contract = parse_abi(abi_json); - let gen = AbiCodeGenerator::new(contract, "TestContract"); - let types = gen.generate_types(); + let generator = AbiCodeGenerator::new(contract, "TestContract"); + let types = generator.generate_types(); // Find the contract class let contract_class = types.iter().find(|c| c.name == "TestContract").unwrap(); diff --git a/gnd/src/codegen/mod.rs b/gnd/src/codegen/mod.rs index 3b300e5eb94..4c8f5fdbd98 100644 --- a/gnd/src/codegen/mod.rs +++ b/gnd/src/codegen/mod.rs @@ -15,6 +15,6 @@ pub use abi::AbiCodeGenerator; pub use schema::SchemaCodeGenerator; pub use template::{Template, TemplateCodeGenerator, TemplateKind}; pub use typescript::{ - ArrayType, Class, ClassMember, Method, ModuleImports, NamedType, NullableType, Param, - StaticMethod, GENERATED_FILE_NOTE, + ArrayType, Class, ClassMember, GENERATED_FILE_NOTE, Method, ModuleImports, NamedType, + NullableType, Param, StaticMethod, }; diff --git a/gnd/src/codegen/schema.rs b/gnd/src/codegen/schema.rs index 97118cfb2a2..a8a276f1ca0 100644 --- a/gnd/src/codegen/schema.rs +++ b/gnd/src/codegen/schema.rs @@ -2,7 +2,7 @@ //! //! Generates AssemblyScript entity classes from GraphQL schemas. -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use graphql_tools::parser::schema::{ Definition, Document, Field, ObjectType, Type, TypeDefinition, }; @@ -210,50 +210,50 @@ impl SchemaCodeGenerator { // First pass: collect entity names and their ID types for def in &document.definitions { - if let Definition::TypeDefinition(TypeDefinition::Object(obj)) = def { - if is_entity_type(obj) { - entity_names.insert(obj.name.clone()); - let id_field = obj.fields.iter().find(|f| f.name == "id"); - let id_kind = id_field - .map(|f| IdFieldKind::from_type_name(&get_base_type_name(&f.field_type))) - .unwrap_or(IdFieldKind::String); - entity_id_kinds.insert(obj.name.clone(), id_kind); - } + if let Definition::TypeDefinition(TypeDefinition::Object(obj)) = def + && is_entity_type(obj) + { + entity_names.insert(obj.name.clone()); + let id_field = obj.fields.iter().find(|f| f.name == "id"); + let id_kind = id_field + .map(|f| IdFieldKind::from_type_name(&get_base_type_name(&f.field_type))) + .unwrap_or(IdFieldKind::String); + entity_id_kinds.insert(obj.name.clone(), id_kind); } } // Second pass: collect entity info for def in &document.definitions { - if let Definition::TypeDefinition(TypeDefinition::Object(obj)) = def { - if is_entity_type(obj) { - let name = obj.name.clone(); - - // Find ID field - let id_field = obj.fields.iter().find(|f| f.name == "id"); - let id_kind = id_field - .map(|f| IdFieldKind::from_type_name(&get_base_type_name(&f.field_type))) - .unwrap_or(IdFieldKind::String); - - // Collect field info - let fields: Vec<_> = obj - .fields - .iter() - .map(|f| FieldInfo { - name: f.name.clone(), - is_derived: is_derived_field(f), - base_type: get_base_type_name(&f.field_type), - is_nullable: is_nullable(&f.field_type), - list_depth: list_depth(&f.field_type), - member_nullable: is_list_member_nullable(&f.field_type), - }) - .collect(); - - entities.push(EntityInfo { - name, - id_kind, - fields, - }); - } + if let Definition::TypeDefinition(TypeDefinition::Object(obj)) = def + && is_entity_type(obj) + { + let name = obj.name.clone(); + + // Find ID field + let id_field = obj.fields.iter().find(|f| f.name == "id"); + let id_kind = id_field + .map(|f| IdFieldKind::from_type_name(&get_base_type_name(&f.field_type))) + .unwrap_or(IdFieldKind::String); + + // Collect field info + let fields: Vec<_> = obj + .fields + .iter() + .map(|f| FieldInfo { + name: f.name.clone(), + is_derived: is_derived_field(f), + base_type: get_base_type_name(&f.field_type), + is_nullable: is_nullable(&f.field_type), + list_depth: list_depth(&f.field_type), + member_nullable: is_list_member_nullable(&f.field_type), + }) + .collect(); + + entities.push(EntityInfo { + name, + id_kind, + fields, + }); } } @@ -713,6 +713,7 @@ enum StoreMethod { #[cfg(test)] mod tests { use super::*; + use graphql_tools::parser::parse_schema; #[test] @@ -726,9 +727,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let transfer = &classes[0]; @@ -747,9 +748,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); // Check that we have methods for nullable and non-nullable fields @@ -802,9 +803,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let counter = &classes[0]; @@ -846,9 +847,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let event = &classes[0]; @@ -890,9 +891,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let user = &classes[0]; @@ -937,11 +938,11 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); // The Post.author field should be treated as a string (entity ID reference) - assert!(gen.entity_names.contains("User")); - assert!(gen.entity_names.contains("Post")); + assert!(generator.entity_names.contains("User")); + assert!(generator.entity_names.contains("Post")); } #[test] @@ -953,9 +954,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let token = &classes[0]; @@ -989,9 +990,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); assert_eq!(classes.len(), 1); let matrix = &classes[0]; @@ -1100,19 +1101,19 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); // Find the entity - let entity = &gen.entities[0]; + let entity = &generator.entities[0]; // Find each field and check its value type let scalar_field = entity.fields.iter().find(|f| f.name == "scalar").unwrap(); let array_field = entity.fields.iter().find(|f| f.name == "array").unwrap(); let matrix_field = entity.fields.iter().find(|f| f.name == "matrix").unwrap(); - assert_eq!(gen.value_type_from_field(scalar_field), "String"); - assert_eq!(gen.value_type_from_field(array_field), "[String]"); - assert_eq!(gen.value_type_from_field(matrix_field), "[[String]]"); + assert_eq!(generator.value_type_from_field(scalar_field), "String"); + assert_eq!(generator.value_type_from_field(array_field), "[String]"); + assert_eq!(generator.value_type_from_field(matrix_field), "[[String]]"); } #[test] @@ -1129,9 +1130,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); let balance = classes.iter().find(|c| c.name == "Balance").unwrap(); let output = balance.to_string(); @@ -1170,9 +1171,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); let snapshot = classes.iter().find(|c| c.name == "Snapshot").unwrap(); let output = snapshot.to_string(); @@ -1211,9 +1212,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); let token = classes.iter().find(|c| c.name == "Token").unwrap(); let output = token.to_string(); @@ -1244,9 +1245,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); let balance = classes.iter().find(|c| c.name == "Balance").unwrap(); let output = balance.to_string(); @@ -1272,9 +1273,9 @@ mod tests { } "#; let doc = parse_schema::(schema).unwrap(); - let gen = SchemaCodeGenerator::new(&doc).unwrap(); + let generator = SchemaCodeGenerator::new(&doc).unwrap(); - let classes = gen.generate_types(true); + let classes = generator.generate_types(true); let token = classes.iter().find(|c| c.name == "Token").unwrap(); let output = token.to_string(); diff --git a/gnd/src/codegen/template.rs b/gnd/src/codegen/template.rs index d067ea928c2..72a27f9e733 100644 --- a/gnd/src/codegen/template.rs +++ b/gnd/src/codegen/template.rs @@ -159,6 +159,7 @@ impl TemplateCodeGenerator { #[cfg(test)] mod tests { + use super::*; #[test] @@ -185,16 +186,16 @@ mod tests { #[test] fn test_ethereum_template() { let template = Template::new("DynamicToken", TemplateKind::Ethereum); - let gen = TemplateCodeGenerator::new(vec![template]); + let generator = TemplateCodeGenerator::new(vec![template]); - let imports = gen.generate_module_imports(); + let imports = generator.generate_module_imports(); assert_eq!(imports.len(), 1); let import_names: Vec<_> = imports[0].names.iter().collect(); assert!(import_names.contains(&&"DataSourceTemplate".to_string())); assert!(import_names.contains(&&"DataSourceContext".to_string())); assert!(import_names.contains(&&"Address".to_string())); - let types = gen.generate_types(); + let types = generator.generate_types(); assert_eq!(types.len(), 1); let klass = &types[0]; @@ -218,9 +219,9 @@ mod tests { #[test] fn test_file_ipfs_template() { let template = Template::new("TokenMetadata", TemplateKind::FileIpfs); - let gen = TemplateCodeGenerator::new(vec![template]); + let generator = TemplateCodeGenerator::new(vec![template]); - let imports = gen.generate_module_imports(); + let imports = generator.generate_module_imports(); assert_eq!(imports.len(), 1); let import_names: Vec<_> = imports[0].names.iter().collect(); assert!(import_names.contains(&&"DataSourceTemplate".to_string())); @@ -228,7 +229,7 @@ mod tests { // No Address for file templates assert!(!import_names.contains(&&"Address".to_string())); - let types = gen.generate_types(); + let types = generator.generate_types(); assert_eq!(types.len(), 1); let klass = &types[0]; @@ -246,30 +247,30 @@ mod tests { Template::new("DynamicToken", TemplateKind::Ethereum), Template::new("TokenMetadata", TemplateKind::FileIpfs), ]; - let gen = TemplateCodeGenerator::new(templates); + let generator = TemplateCodeGenerator::new(templates); - let imports = gen.generate_module_imports(); + let imports = generator.generate_module_imports(); // Should have Address because of Ethereum template let import_names: Vec<_> = imports[0].names.iter().collect(); assert!(import_names.contains(&&"Address".to_string())); - let types = gen.generate_types(); + let types = generator.generate_types(); assert_eq!(types.len(), 2); } #[test] fn test_empty_templates() { - let gen = TemplateCodeGenerator::new(vec![]); - assert!(gen.generate_module_imports().is_empty()); - assert!(gen.generate_types().is_empty()); + let generator = TemplateCodeGenerator::new(vec![]); + assert!(generator.generate_module_imports().is_empty()); + assert!(generator.generate_types().is_empty()); } #[test] fn test_generated_output() { let template = Template::new("DynamicToken", TemplateKind::Ethereum); - let gen = TemplateCodeGenerator::new(vec![template]); + let generator = TemplateCodeGenerator::new(vec![template]); - let types = gen.generate_types(); + let types = generator.generate_types(); let output = types[0].to_string(); assert!(output.contains("export class DynamicToken extends DataSourceTemplate")); diff --git a/gnd/src/commands/add.rs b/gnd/src/commands/add.rs index 4a6191a6274..ef936884dfe 100644 --- a/gnd/src/commands/add.rs +++ b/gnd/src/commands/add.rs @@ -3,19 +3,23 @@ //! This command adds a new data source to an existing subgraph, generating //! the necessary manifest entries, schema types, and mapping stubs. +use std::collections::HashSet; use std::fs; use std::path::{Path, PathBuf}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use clap::Parser; -use inflector::Inflector; +use graphql_tools::parser::schema as gql; use serde_json::Value as JsonValue; use crate::config::networks::update_networks_file; use crate::formatter::format_typescript; -use crate::output::{step, Step}; -use crate::scaffold::manifest::{extract_events_from_abi, EventInfo}; -use crate::scaffold::ScaffoldOptions; +use crate::output::{Step, step}; +use crate::scaffold::manifest::{EventInfo, extract_events_from_abi}; +use crate::scaffold::{ + MAPPING_API_VERSION, ResolvedEvent, ScaffoldOptions, disambiguate_events, + generate_event_entity, generate_event_handlers, to_kebab_case, +}; use crate::services::ContractService; #[derive(Clone, Debug, Parser)] @@ -97,6 +101,14 @@ pub async fn run_add(opt: AddOpt) -> Result<()> { // Fetch or load ABI let (abi, contract_name, start_block) = get_contract_info(&opt, &network).await?; + // A data source / template name must be unique within the subgraph. + if existing_source_names(&manifest).contains(&contract_name) { + return Err(anyhow!( + "Data source or template named '{}' already exists. Choose a different name with --contract-name.", + contract_name + )); + } + // Get project directory let project_dir = crate::manifest::manifest_dir(&opt.manifest); @@ -111,14 +123,20 @@ pub async fn run_add(opt: AddOpt) -> Result<()> { index_events: true, // Always index events for add command }; - // Extract events from ABI + // Extract events from the ABI and resolve their names against the entities + // already present in the subgraph (handles overloads and collisions). Both + // the manifest's entity lists and the types declared in schema.graphql count + // as existing, since either can be the source of a name collision. let events = extract_events_from_abi(&scaffold_options); + let mut existing = existing_entities(&manifest); + existing.extend(schema_entity_types(project_dir, &manifest)); + let resolved = resolve_events(events, &existing, &contract_name, opt.merge_entities)?; // Add ABI file add_abi_file(project_dir, &contract_name, &abi)?; // Add mapping file - add_mapping_file(project_dir, &contract_name, &events)?; + add_mapping_file(project_dir, &contract_name, &resolved)?; // Update manifest update_manifest( @@ -127,22 +145,27 @@ pub async fn run_add(opt: AddOpt) -> Result<()> { &contract_name, &network, start_block, - &events, + &resolved, )?; - // Update networks.json + // Declare the new event entities in the schema so codegen/build succeed. + add_schema_entities(project_dir, &manifest, &resolved)?; + + // Update networks.json if the subgraph uses one. let networks_path = project_dir.join(&opt.network_file); - update_networks_file( - &networks_path, - &network, - &contract_name, - &opt.address, - start_block, - )?; - step( - Step::Write, - &format!("Updated {}", opt.network_file.display()), - ); + if networks_path.exists() { + update_networks_file( + &networks_path, + &network, + &contract_name, + &opt.address, + start_block, + )?; + step( + Step::Write, + &format!("Updated {}", opt.network_file.display()), + ); + } step(Step::Done, &format!("Added data source: {}", contract_name)); @@ -232,41 +255,16 @@ fn add_abi_file(project_dir: &Path, contract_name: &str, abi: &JsonValue) -> Res Ok(()) } -/// Sanitize a field name for GraphQL. -fn sanitize_field_name(name: &str) -> String { - if name.is_empty() { - return "value".to_string(); - } - - let mut result = name.to_string(); - - // Convert to camelCase if starts with uppercase - if result - .chars() - .next() - .map(|c| c.is_uppercase()) - .unwrap_or(false) - { - let mut chars = result.chars(); - if let Some(first) = chars.next() { - result = first.to_lowercase().collect::() + chars.as_str(); - } - } - - // Avoid reserved words - match result.as_str() { - "id" => "eventId".to_string(), - "type" => "eventType".to_string(), - _ => result, - } -} - /// Add mapping file for the new data source. -fn add_mapping_file(project_dir: &Path, contract_name: &str, events: &[EventInfo]) -> Result<()> { +fn add_mapping_file( + project_dir: &Path, + contract_name: &str, + events: &[ResolvedEvent], +) -> Result<()> { let src_dir = project_dir.join("src"); fs::create_dir_all(&src_dir).context("Failed to create src directory")?; - let mapping_file = src_dir.join(format!("{}.ts", contract_name.to_kebab_case())); + let mapping_file = src_dir.join(format!("{}.ts", to_kebab_case(contract_name))); if mapping_file.exists() { step( @@ -276,7 +274,7 @@ fn add_mapping_file(project_dir: &Path, contract_name: &str, events: &[EventInfo return Ok(()); } - let mapping_content = generate_mapping(contract_name, events); + let mapping_content = generate_event_handlers(contract_name, events); let formatted = format_typescript(&mapping_content).unwrap_or(mapping_content); step( @@ -288,74 +286,167 @@ fn add_mapping_file(project_dir: &Path, contract_name: &str, events: &[EventInfo Ok(()) } -/// Generate mapping handlers for events. -fn generate_mapping(contract_name: &str, events: &[EventInfo]) -> String { - let mut imports = String::new(); - let mut handlers = String::new(); - - imports.push_str("import { BigInt, Bytes } from \"@graphprotocol/graph-ts\"\n"); +/// Collect the names of all existing data sources and templates in the manifest. +fn existing_source_names(manifest: &serde_yaml::Value) -> HashSet { + let mut names = HashSet::new(); + for key in ["dataSources", "templates"] { + if let Some(seq) = manifest.get(key).and_then(|v| v.as_sequence()) { + for item in seq { + if let Some(name) = item.get("name").and_then(|n| n.as_str()) { + names.insert(name.to_string()); + } + } + } + } + names +} - if events.is_empty() { - return imports; +/// Collect the entity names already declared by existing data sources / templates. +fn existing_entities(manifest: &serde_yaml::Value) -> HashSet { + let mut entities = HashSet::new(); + for key in ["dataSources", "templates"] { + if let Some(seq) = manifest.get(key).and_then(|v| v.as_sequence()) { + for item in seq { + if let Some(list) = item + .get("mapping") + .and_then(|m| m.get("entities")) + .and_then(|e| e.as_sequence()) + { + for entity in list.iter().filter_map(|e| e.as_str()) { + entities.insert(entity.to_string()); + } + } + } + } } + entities +} - // Import event types - let event_imports: Vec = events - .iter() - .map(|e| format!("{} as {}Event", e.name, e.name)) - .collect(); +/// Collect the `@entity` type names declared in the subgraph's schema.graphql. +/// +/// The schema is the real source of truth for declared types, so a hand-written +/// `type Foo @entity` that no mapping lists in its `entities` still counts as a +/// collision. Returns empty on a missing or unparseable schema (falling back to +/// the manifest's entity lists). +fn schema_entity_types(project_dir: &Path, manifest: &serde_yaml::Value) -> HashSet { + let schema_file = manifest + .get("schema") + .and_then(|s| s.get("file")) + .and_then(|f| f.as_str()) + .unwrap_or("schema.graphql"); + let Ok(content) = fs::read_to_string(project_dir.join(schema_file)) else { + return HashSet::new(); + }; + entity_types_in_schema(&content) +} - imports.push_str(&format!( - "import {{ {} }} from \"../generated/{}/{}\"\n", - event_imports.join(", "), - contract_name, - contract_name - )); - - // Import entity types - let entity_imports: Vec = events.iter().map(|e| e.name.clone()).collect(); - - imports.push_str(&format!( - "import {{ {} }} from \"../generated/schema\"\n", - entity_imports.join(", ") - )); - - // Generate handler for each event - for event in events { - handlers.push('\n'); - handlers.push_str(&generate_event_handler(event)); +/// Parse GraphQL schema text and return the names of object types marked +/// `@entity`. Returns empty if the schema does not parse. +fn entity_types_in_schema(content: &str) -> HashSet { + let Ok(ast) = gql::parse_schema::(content) else { + return HashSet::new(); + }; + ast.definitions + .into_iter() + .filter_map(|def| match def { + gql::Definition::TypeDefinition(gql::TypeDefinition::Object(obj)) + if obj.directives.iter().any(|d| d.name == "entity") => + { + Some(obj.name) + } + _ => None, + }) + .collect() +} + +/// Resolve event names against the entities already present in the subgraph. +/// +/// - Events overloaded within this ABI are disambiguated (`Transfer`, `Transfer1`). +/// - An event whose name collides with an existing entity is either merged into +/// that entity (`merge_entities`: reuse it, keeping the handler so this +/// contract's events are still indexed, but don't redeclare the type) or +/// renamed with the contract prefix so both entities can coexist. +fn resolve_events( + events: Vec, + existing: &HashSet, + contract_name: &str, + merge_entities: bool, +) -> Result> { + let mut resolved = disambiguate_events(events); + + for r in &mut resolved { + // Check the name we would actually declare (the disambiguated alias), + // not the raw event name, so an overload alias like `Transfer1` that + // collides with an existing entity is still caught. + if !existing.contains(&r.entity_name) { + continue; + } + if merge_entities { + // Reuse the existing entity (entity_name already equals it). Merge is + // by name only, so a signature mismatch surfaces at codegen/build. + r.declare_in_schema = false; + } else { + let prefixed = format!("{}{}", contract_name, r.alias); + if existing.contains(&prefixed) { + return Err(anyhow!( + "Entity '{}' already exists; cannot rename '{}' to avoid a collision. Choose a different contract name.", + prefixed, + r.entity_name + )); + } + r.entity_name = prefixed; + } } - format!("{}\n{}", imports, handlers) + Ok(resolved) } -/// Generate a handler function for an event. -fn generate_event_handler(event: &EventInfo) -> String { - let event_name = &event.name; - - let mut field_assignments = String::new(); - for input in &event.inputs { - let field_name = sanitize_field_name(&input.name); - field_assignments.push_str(&format!( - " entity.{} = event.params.{}\n", - field_name, input.name +/// Append entity type definitions for the new events to the subgraph schema. +/// +/// The mapping and manifest reference one entity per event; without this the +/// referenced types never exist in schema.graphql and codegen/build fail. +fn add_schema_entities( + project_dir: &Path, + manifest: &serde_yaml::Value, + events: &[ResolvedEvent], +) -> Result<()> { + let mut additions = String::new(); + for resolved in events { + // Reused entities already exist in the schema; don't redeclare them. + if !resolved.declare_in_schema { + continue; + } + additions.push('\n'); + additions.push_str(&generate_event_entity( + &resolved.entity_name, + &resolved.event.inputs, )); + additions.push('\n'); + } + + if additions.is_empty() { + return Ok(()); } - format!( - r#"export function handle{event_name}(event: {event_name}Event): void {{ - let entity = new {event_name}( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) + let schema_file = manifest + .get("schema") + .and_then(|s| s.get("file")) + .and_then(|f| f.as_str()) + .unwrap_or("schema.graphql"); + let schema_path = project_dir.join(schema_file); -{field_assignments} entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash + step(Step::Write, &format!("Updating {}", schema_path.display())); - entity.save() -}} -"# - ) + use std::io::Write; + let mut file = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&schema_path) + .with_context(|| format!("Failed to open schema file: {}", schema_path.display()))?; + file.write_all(additions.as_bytes()) + .context("Failed to append entities to schema")?; + + Ok(()) } /// Update the manifest with the new data source. @@ -365,7 +456,7 @@ fn update_manifest( contract_name: &str, network: &str, start_block: Option, - events: &[EventInfo], + events: &[ResolvedEvent], ) -> Result<()> { let content = fs::read_to_string(manifest_path).context("Failed to read manifest")?; @@ -391,15 +482,15 @@ fn update_manifest( // Build event handlers let mut event_handlers = Vec::new(); - for event in events { + for resolved in events { let mut handler = serde_yaml::Mapping::new(); handler.insert( serde_yaml::Value::String("event".to_string()), - serde_yaml::Value::String(event.signature.clone()), + serde_yaml::Value::String(resolved.event.signature.clone()), ); handler.insert( serde_yaml::Value::String("handler".to_string()), - serde_yaml::Value::String(format!("handle{}", event.name)), + serde_yaml::Value::String(format!("handle{}", resolved.alias)), ); event_handlers.push(serde_yaml::Value::Mapping(handler)); } @@ -407,7 +498,7 @@ fn update_manifest( // Build entities list let entities: Vec = events .iter() - .map(|e| serde_yaml::Value::String(e.name.clone())) + .map(|e| serde_yaml::Value::String(e.entity_name.clone())) .collect(); // Build ABI entry @@ -429,7 +520,7 @@ fn update_manifest( ); mapping.insert( serde_yaml::Value::String("apiVersion".to_string()), - serde_yaml::Value::String("0.0.9".to_string()), + serde_yaml::Value::String(MAPPING_API_VERSION.to_string()), ); mapping.insert( serde_yaml::Value::String("language".to_string()), @@ -449,7 +540,7 @@ fn update_manifest( ); mapping.insert( serde_yaml::Value::String("file".to_string()), - serde_yaml::Value::String(format!("./src/{}.ts", contract_name.to_kebab_case())), + serde_yaml::Value::String(format!("./src/{}.ts", to_kebab_case(contract_name))), ); // Build the data source @@ -494,7 +585,6 @@ fn update_manifest( #[cfg(test)] mod tests { use super::*; - use crate::scaffold::manifest::{EventInfo, EventInput}; #[tokio::test] async fn test_invalid_address() { @@ -511,91 +601,12 @@ mod tests { let result = run_add(opt).await; assert!(result.is_err()); - assert!(result - .unwrap_err() - .to_string() - .contains("Invalid contract address")); - } - - #[test] - fn test_sanitize_field_name() { - assert_eq!(sanitize_field_name("owner"), "owner"); - assert_eq!(sanitize_field_name("Owner"), "owner"); - assert_eq!(sanitize_field_name(""), "value"); - // Reserved words - assert_eq!(sanitize_field_name("id"), "eventId"); - assert_eq!(sanitize_field_name("type"), "eventType"); - } - - #[test] - fn test_to_kebab_case() { - assert_eq!("MyContract".to_kebab_case(), "my-contract"); - assert_eq!("SimpleToken".to_kebab_case(), "simple-token"); - assert_eq!("Contract".to_kebab_case(), "contract"); - assert_eq!("contract".to_kebab_case(), "contract"); - assert_eq!("ERC20Token".to_kebab_case(), "erc20-token"); - } - - #[test] - fn test_generate_event_handler() { - let event = EventInfo { - name: "Approval".to_string(), - signature: "Approval(address,address,uint256)".to_string(), - inputs: vec![ - EventInput { - name: "owner".to_string(), - solidity_type: "address".to_string(), - indexed: true, - }, - EventInput { - name: "spender".to_string(), - solidity_type: "address".to_string(), - indexed: true, - }, - EventInput { - name: "value".to_string(), - solidity_type: "uint256".to_string(), - indexed: false, - }, - ], - }; - - let handler = generate_event_handler(&event); - assert!(handler.contains("export function handleApproval")); - assert!(handler.contains("event: ApprovalEvent")); - assert!(handler.contains("new Approval(")); - assert!(handler.contains("entity.owner = event.params.owner")); - assert!(handler.contains("entity.spender = event.params.spender")); - assert!(handler.contains("entity.value = event.params.value")); - assert!(handler.contains("entity.save()")); - } - - #[test] - fn test_generate_mapping() { - let events = vec![EventInfo { - name: "Transfer".to_string(), - signature: "Transfer(address,address,uint256)".to_string(), - inputs: vec![EventInput { - name: "from".to_string(), - solidity_type: "address".to_string(), - indexed: true, - }], - }]; - - let mapping = generate_mapping("Token", &events); - assert!(mapping.contains("import { BigInt, Bytes }")); - assert!(mapping.contains("Transfer as TransferEvent")); - assert!(mapping.contains("../generated/Token/Token")); - assert!(mapping.contains("import { Transfer }")); - assert!(mapping.contains("../generated/schema")); - } - - #[test] - fn test_generate_mapping_empty_events() { - let events: Vec = vec![]; - let mapping = generate_mapping("Empty", &events); - assert!(mapping.contains("import { BigInt, Bytes }")); - assert!(!mapping.contains("export function handle")); + assert!( + result + .unwrap_err() + .to_string() + .contains("Invalid contract address") + ); } #[tokio::test] @@ -615,4 +626,111 @@ mod tests { assert!(result.is_err()); assert!(result.unwrap_err().to_string().contains("Manifest file")); } + + fn ev(name: &str) -> EventInfo { + EventInfo { + name: name.to_string(), + signature: format!("{}()", name), + inputs: vec![], + } + } + + fn entities(names: &[&str]) -> HashSet { + names.iter().map(|s| s.to_string()).collect() + } + + #[test] + fn test_resolve_events_no_collision() { + let resolved = + resolve_events(vec![ev("Transfer")], &entities(&[]), "Token", false).unwrap(); + assert_eq!(resolved.len(), 1); + assert_eq!(resolved[0].alias, "Transfer"); + assert_eq!(resolved[0].entity_name, "Transfer"); + assert!(resolved[0].declare_in_schema); + } + + #[test] + fn test_resolve_events_overload_disambiguates() { + // Two events named Transfer in one ABI get distinct aliases. + let resolved = resolve_events( + vec![ev("Transfer"), ev("Transfer")], + &entities(&[]), + "Token", + false, + ) + .unwrap(); + assert_eq!(resolved[0].alias, "Transfer"); + assert_eq!(resolved[1].alias, "Transfer1"); + assert_eq!(resolved[1].entity_name, "Transfer1"); + } + + #[test] + fn test_resolve_events_collision_merge_reuses() { + let resolved = resolve_events( + vec![ev("Transfer")], + &entities(&["Transfer"]), + "Token", + true, + ) + .unwrap(); + // Reuse the existing entity, don't redeclare it, but keep the handler. + assert_eq!(resolved[0].entity_name, "Transfer"); + assert!(!resolved[0].declare_in_schema); + } + + #[test] + fn test_resolve_events_collision_no_merge_renames() { + let resolved = resolve_events( + vec![ev("Transfer")], + &entities(&["Transfer"]), + "Token", + false, + ) + .unwrap(); + assert_eq!(resolved[0].entity_name, "TokenTransfer"); + assert!(resolved[0].declare_in_schema); + } + + #[test] + fn test_resolve_events_collision_renamed_also_exists_errors() { + let result = resolve_events( + vec![ev("Transfer")], + &entities(&["Transfer", "TokenTransfer"]), + "Token", + false, + ); + assert!(result.is_err()); + } + + #[test] + fn test_resolve_events_overload_alias_collision_renames() { + // The second overload's disambiguated alias (Transfer1) collides with an + // existing entity; the collision must be detected on the alias, not the + // raw event name. + let resolved = resolve_events( + vec![ev("Transfer"), ev("Transfer")], + &entities(&["Transfer1"]), + "Token", + false, + ) + .unwrap(); + assert_eq!(resolved[0].entity_name, "Transfer"); + assert_eq!(resolved[1].alias, "Transfer1"); + assert_eq!(resolved[1].entity_name, "TokenTransfer1"); + } + + #[test] + fn test_entity_types_in_schema() { + let schema = r#" + type Foo @entity { id: Bytes! } + type Bar @entity(immutable: true) { id: Bytes! } + type NotAnEntity { id: Bytes! } + "#; + let types = entity_types_in_schema(schema); + assert!(types.contains("Foo")); + assert!(types.contains("Bar")); + assert!(!types.contains("NotAnEntity")); + // A schema that doesn't parse yields no types rather than erroring. + assert!(entity_types_in_schema("this is not graphql {{{").is_empty()); + } } diff --git a/gnd/src/commands/build.rs b/gnd/src/commands/build.rs index 2d9c7b36bd7..b33731330aa 100644 --- a/gnd/src/commands/build.rs +++ b/gnd/src/commands/build.rs @@ -8,16 +8,16 @@ use std::collections::HashMap; use std::fs; use std::path::{Path, PathBuf}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use clap::Parser; use sha1::{Digest, Sha1}; use crate::abi::normalize_abi_json; -use crate::compiler::{compile_mapping, find_graph_ts, AscCompileOptions}; +use crate::compiler::{AscCompileOptions, compile_mapping, find_graph_ts}; use crate::config::{apply_network_config, get_network_config, load_networks_config}; -use crate::manifest::{load_manifest, resolve_path, DataSource, Manifest, Template}; +use crate::manifest::{DataSource, Manifest, Template, load_manifest, resolve_path}; use crate::migrations; -use crate::output::{step, Step}; +use crate::output::{Step, step}; use crate::services::IpfsClient; use crate::validation::{ collect_handler_names, collect_template_handler_names, format_manifest_errors, @@ -496,35 +496,34 @@ fn create_ipfs_manifest( .unwrap_or("schema.graphql"); // Find the hash for this file - if let Some(hash) = uploaded.path_to_ipfs.get(schema_name) { - if let Some(schema) = value.get_mut("schema") { - if let Some(file) = schema.get_mut("file") { - *file = create_ipfs_link(hash); - } - } + if let Some(hash) = uploaded.path_to_ipfs.get(schema_name) + && let Some(schema) = value.get_mut("schema") + && let Some(file) = schema.get_mut("file") + { + *file = create_ipfs_link(hash); } } // Update data source paths - if let Some(data_sources) = value.get_mut("dataSources") { - if let Some(arr) = data_sources.as_sequence_mut() { - for (i, ds_value) in arr.iter_mut().enumerate() { - if i < manifest.data_sources.len() { - let ds = &manifest.data_sources[i]; - update_data_source_ipfs_paths(ds_value, ds, uploaded); - } + if let Some(data_sources) = value.get_mut("dataSources") + && let Some(arr) = data_sources.as_sequence_mut() + { + for (i, ds_value) in arr.iter_mut().enumerate() { + if i < manifest.data_sources.len() { + let ds = &manifest.data_sources[i]; + update_data_source_ipfs_paths(ds_value, ds, uploaded); } } } // Update template paths - if let Some(templates) = value.get_mut("templates") { - if let Some(arr) = templates.as_sequence_mut() { - for (i, template_value) in arr.iter_mut().enumerate() { - if i < manifest.templates.len() { - let template = &manifest.templates[i]; - update_template_ipfs_paths(template_value, template, uploaded); - } + if let Some(templates) = value.get_mut("templates") + && let Some(arr) = templates.as_sequence_mut() + { + for (i, template_value) in arr.iter_mut().enumerate() { + if i < manifest.templates.len() { + let template = &manifest.templates[i]; + update_template_ipfs_paths(template_value, template, uploaded); } } } @@ -558,16 +557,16 @@ fn update_data_source_ipfs_paths( } // Update ABIs - if let Some(abis) = mapping.get_mut("abis") { - if let Some(arr) = abis.as_sequence_mut() { - for (j, abi_value) in arr.iter_mut().enumerate() { - if j < ds.abis.len() { - let abi = &ds.abis[j]; - if let Some(file) = abi_value.get_mut("file") { - let abi_path = format!("{}/{}.json", ds.name, abi.name); - if let Some(hash) = uploaded.path_to_ipfs.get(&abi_path) { - *file = create_ipfs_link(hash); - } + if let Some(abis) = mapping.get_mut("abis") + && let Some(arr) = abis.as_sequence_mut() + { + for (j, abi_value) in arr.iter_mut().enumerate() { + if j < ds.abis.len() { + let abi = &ds.abis[j]; + if let Some(file) = abi_value.get_mut("file") { + let abi_path = format!("{}/{}.json", ds.name, abi.name); + if let Some(hash) = uploaded.path_to_ipfs.get(&abi_path) { + *file = create_ipfs_link(hash); } } } @@ -592,16 +591,16 @@ fn update_template_ipfs_paths( } // Update ABIs - if let Some(abis) = mapping.get_mut("abis") { - if let Some(arr) = abis.as_sequence_mut() { - for (j, abi_value) in arr.iter_mut().enumerate() { - if j < template.abis.len() { - let abi = &template.abis[j]; - if let Some(file) = abi_value.get_mut("file") { - let abi_path = format!("templates/{}/{}.json", template.name, abi.name); - if let Some(hash) = uploaded.path_to_ipfs.get(&abi_path) { - *file = create_ipfs_link(hash); - } + if let Some(abis) = mapping.get_mut("abis") + && let Some(arr) = abis.as_sequence_mut() + { + for (j, abi_value) in arr.iter_mut().enumerate() { + if j < template.abis.len() { + let abi = &template.abis[j]; + if let Some(file) = abi_value.get_mut("file") { + let abi_path = format!("templates/{}/{}.json", template.name, abi.name); + if let Some(hash) = uploaded.path_to_ipfs.get(&abi_path) { + *file = create_ipfs_link(hash); } } } @@ -751,38 +750,37 @@ fn write_output_manifest( let mut value: serde_yaml::Value = serde_yaml::from_str(&manifest_str)?; // Update schema path - if let Some(schema) = value.get_mut("schema") { - if let Some(file) = schema.get_mut("file") { - if let Some(schema_path) = manifest.schema.as_ref() { - let schema_name = Path::new(schema_path) - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or("schema.graphql"); - *file = serde_yaml::Value::String(schema_name.to_string()); - } - } + if let Some(schema) = value.get_mut("schema") + && let Some(file) = schema.get_mut("file") + && let Some(schema_path) = manifest.schema.as_ref() + { + let schema_name = Path::new(schema_path) + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("schema.graphql"); + *file = serde_yaml::Value::String(schema_name.to_string()); } // Update data source paths - if let Some(data_sources) = value.get_mut("dataSources") { - if let Some(arr) = data_sources.as_sequence_mut() { - for (i, ds) in arr.iter_mut().enumerate() { - if i < manifest.data_sources.len() { - let ds_name = &manifest.data_sources[i].name; - update_data_source_paths(ds, ds_name, output_format); - } + if let Some(data_sources) = value.get_mut("dataSources") + && let Some(arr) = data_sources.as_sequence_mut() + { + for (i, ds) in arr.iter_mut().enumerate() { + if i < manifest.data_sources.len() { + let ds_name = &manifest.data_sources[i].name; + update_data_source_paths(ds, ds_name, output_format); } } } // Update template paths - if let Some(templates) = value.get_mut("templates") { - if let Some(arr) = templates.as_sequence_mut() { - for (i, template) in arr.iter_mut().enumerate() { - if i < manifest.templates.len() { - let template_name = &manifest.templates[i].name; - update_template_paths(template, template_name, output_format); - } + if let Some(templates) = value.get_mut("templates") + && let Some(arr) = templates.as_sequence_mut() + { + for (i, template) in arr.iter_mut().enumerate() { + if i < manifest.templates.len() { + let template_name = &manifest.templates[i].name; + update_template_paths(template, template_name, output_format); } } } @@ -804,19 +802,19 @@ fn update_data_source_paths(ds: &mut serde_yaml::Value, ds_name: &str, output_fo } // Update ABI paths - if let Some(abis) = mapping.get_mut("abis") { - if let Some(arr) = abis.as_sequence_mut() { - for abi in arr.iter_mut() { - // Extract name first to avoid borrow conflicts - let abi_name = abi - .get("name") - .and_then(|n| n.as_str()) - .map(|s| s.to_string()); - if let Some(name) = abi_name { - if let Some(file) = abi.get_mut("file") { - *file = serde_yaml::Value::String(format!("{}/{}.json", ds_name, name)); - } - } + if let Some(abis) = mapping.get_mut("abis") + && let Some(arr) = abis.as_sequence_mut() + { + for abi in arr.iter_mut() { + // Extract name first to avoid borrow conflicts + let abi_name = abi + .get("name") + .and_then(|n| n.as_str()) + .map(|s| s.to_string()); + if let Some(name) = abi_name + && let Some(file) = abi.get_mut("file") + { + *file = serde_yaml::Value::String(format!("{}/{}.json", ds_name, name)); } } } @@ -840,22 +838,22 @@ fn update_template_paths( } // Update ABI paths - if let Some(abis) = mapping.get_mut("abis") { - if let Some(arr) = abis.as_sequence_mut() { - for abi in arr.iter_mut() { - // Extract name first to avoid borrow conflicts - let abi_name = abi - .get("name") - .and_then(|n| n.as_str()) - .map(|s| s.to_string()); - if let Some(name) = abi_name { - if let Some(file) = abi.get_mut("file") { - *file = serde_yaml::Value::String(format!( - "templates/{}/{}.json", - template_name, name - )); - } - } + if let Some(abis) = mapping.get_mut("abis") + && let Some(arr) = abis.as_sequence_mut() + { + for abi in arr.iter_mut() { + // Extract name first to avoid borrow conflicts + let abi_name = abi + .get("name") + .and_then(|n| n.as_str()) + .map(|s| s.to_string()); + if let Some(name) = abi_name + && let Some(file) = abi.get_mut("file") + { + *file = serde_yaml::Value::String(format!( + "templates/{}/{}.json", + template_name, name + )); } } } diff --git a/gnd/src/commands/codegen.rs b/gnd/src/commands/codegen.rs index fafa88d2b43..deb0feb0ca5 100644 --- a/gnd/src/commands/codegen.rs +++ b/gnd/src/commands/codegen.rs @@ -9,7 +9,7 @@ use std::fs; use std::path::{Path, PathBuf}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use clap::Parser; use graph::abi::JsonAbi; use graphql_tools::parser::schema as gql; @@ -17,13 +17,13 @@ use semver::Version; use crate::abi::normalize_abi_json; use crate::codegen::{ - AbiCodeGenerator, Class, ModuleImports, SchemaCodeGenerator, Template as CodegenTemplate, - TemplateCodeGenerator, TemplateKind, GENERATED_FILE_NOTE, + AbiCodeGenerator, Class, GENERATED_FILE_NOTE, ModuleImports, SchemaCodeGenerator, + Template as CodegenTemplate, TemplateCodeGenerator, TemplateKind, }; use crate::formatter::try_format_typescript; -use crate::manifest::{load_manifest, resolve_path, DataSource, Manifest, Template}; +use crate::manifest::{DataSource, Manifest, Template, load_manifest, resolve_path}; use crate::migrations; -use crate::output::{step, Step}; +use crate::output::{Step, step}; use crate::services::IpfsClient; use crate::validation::{ format_manifest_errors, format_schema_errors, validate_manifest_files, validate_schema, @@ -209,7 +209,7 @@ fn generate_schema_types( step(Step::Generate, "Generate types for GraphQL schema"); let generator = match SchemaCodeGenerator::new(&ast) { - Ok(gen) => gen, + Ok(generator) => generator, Err(e) => { // Schema validation failed - skip schema.ts generation but don't fail eprintln!("Warning: {}", e); @@ -277,13 +277,13 @@ fn preprocess_abi_json(abi_str: &str) -> Result { fn add_default_event_param_names(params: &mut serde_json::Value) { if let Some(params_arr) = params.as_array_mut() { for (index, param) in params_arr.iter_mut().enumerate() { - if let Some(obj) = param.as_object_mut() { - if !obj.contains_key("name") { - obj.insert( - "name".to_string(), - serde_json::Value::String(format!("param{}", index)), - ); - } + if let Some(obj) = param.as_object_mut() + && !obj.contains_key("name") + { + obj.insert( + "name".to_string(), + serde_json::Value::String(format!("param{}", index)), + ); } } } @@ -407,7 +407,7 @@ async fn generate_subgraph_source_types( // Generate entity types WITHOUT store methods (false = no store methods) let generator = match SchemaCodeGenerator::new(&ast) { - Ok(gen) => gen, + Ok(generator) => generator, Err(e) => { eprintln!( "Warning: Failed to create schema generator for subgraph {} ({}): {}", diff --git a/gnd/src/commands/deploy.rs b/gnd/src/commands/deploy.rs index 7c305c72d11..5c9e744ba02 100644 --- a/gnd/src/commands/deploy.rs +++ b/gnd/src/commands/deploy.rs @@ -3,15 +3,19 @@ //! This command builds a subgraph (unless an IPFS hash is provided), //! uploads it to IPFS, and deploys it to a Graph Node. -use std::path::PathBuf; +use std::{ + io::{self, IsTerminal}, + path::PathBuf, +}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use clap::Parser; use url::Url; use crate::commands::auth::get_deploy_key; -use crate::commands::build::{run_build, BuildOpt}; -use crate::output::{step, Step}; +use crate::commands::build::{BuildOpt, run_build}; +use crate::output::{Step, step}; +use crate::prompt::{normalize_version_label, prompt_version_label}; use crate::services::GraphNodeClient; /// Default IPFS URL used by The Graph @@ -91,6 +95,12 @@ pub async fn run_deploy(opt: DeployOpt) -> Result<()> { None => get_deploy_key(node)?, }; + let version_label = + match resolve_version_label(opt.version_label.as_deref(), io::stdin().is_terminal())? { + Some(label) => label, + None => prompt_version_label()?, + }; + // Get or build the IPFS hash let ipfs_hash = match &opt.ipfs_hash { Some(hash) => { @@ -104,7 +114,14 @@ pub async fn run_deploy(opt: DeployOpt) -> Result<()> { }; // Deploy to Graph Node - deploy_to_node(&opt, node, &ipfs_hash, deploy_key.as_deref()).await + deploy_to_node( + &opt, + node, + &ipfs_hash, + &version_label, + deploy_key.as_deref(), + ) + .await } /// Validate that a URL is well-formed. @@ -127,6 +144,32 @@ fn validate_url(url: &str, name: &str) -> Result<()> { Ok(()) } +/// Parse and validate a normalized version label. +fn parse_version_label(label: &str) -> Result { + let normalized = normalize_version_label(label); + if normalized.is_empty() { + return Err(anyhow!("Version label cannot be empty")); + } + Ok(normalized) +} + +/// Resolve version label from flag or interactive prompt mode. +fn resolve_version_label( + version_label: Option<&str>, + stdin_is_terminal: bool, +) -> Result> { + match version_label { + Some(label) => parse_version_label(label) + .context("Invalid --version-label value") + .map(Some), + None if stdin_is_terminal => Ok(None), + None => Err(anyhow!( + "--version-label is required in non-interactive mode. \ + Pass --version-label