diff --git a/Cargo.lock b/Cargo.lock index a0c04723ed1..921ffa9eb28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,12 +110,12 @@ dependencies = [ "auto_impl", "borsh", "c-kzg", - "derive_more 2.1.1", + "derive_more", "either", "k256", "once_cell", "rand 0.8.5", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_json", "serde_with", @@ -252,7 +252,7 @@ dependencies = [ "auto_impl", "borsh", "c-kzg", - "derive_more 2.1.1", + "derive_more", "either", "serde", "serde_with", @@ -321,7 +321,7 @@ dependencies = [ "alloy-sol-types", "async-trait", "auto_impl", - "derive_more 2.1.1", + "derive_more", "futures-utils-wasm", "serde", "serde_json", @@ -352,7 +352,7 @@ dependencies = [ "bytes", "cfg-if 1.0.0", "const-hex", - "derive_more 2.1.1", + "derive_more", "foldhash 0.2.0", "hashbrown 0.16.1", "indexmap 2.11.4", @@ -534,7 +534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bab1ebed118b701c497e6541d2d11dfa6f3c6ae31a3c52999daa802fcdcc16b7" dependencies = [ "alloy-primitives", - "derive_more 2.1.1", + "derive_more", "serde", "serde_with", ] @@ -551,7 +551,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "arbitrary", - "derive_more 2.1.1", + "derive_more", "rand 0.8.5", "serde", "strum", @@ -730,7 +730,7 @@ dependencies = [ "alloy-json-rpc", "auto_impl", "base64 0.22.1", - "derive_more 2.1.1", + "derive_more", "futures 0.3.31", "futures-utils-wasm", "parking_lot", @@ -775,7 +775,7 @@ dependencies = [ "serde", "serde_json", "tokio", - "tokio-util 0.7.18", + "tokio-util", "tracing", ] @@ -807,7 +807,7 @@ dependencies = [ "arbitrary", "arrayvec 0.7.4", "derive_arbitrary", - "derive_more 2.1.1", + "derive_more", "nybbles", "proptest", "proptest-derive 0.5.1", @@ -1429,7 +1429,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tokio-util 0.7.18", + "tokio-util", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1682,12 +1682,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -1827,15 +1821,6 @@ dependencies = [ "constant_time_eq 0.3.1", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -2071,7 +2056,7 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util 0.7.18", + "tokio-util", ] [[package]] @@ -2146,12 +2131,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.10.0" @@ -2745,19 +2724,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "derive_more" -version = "0.99.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn 2.0.114", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -2773,7 +2739,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case 0.10.0", + "convert_case", "proc-macro2", "quote", "rustc_version 0.4.0", @@ -2898,7 +2864,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -3485,12 +3451,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.31" @@ -3641,7 +3601,7 @@ dependencies = [ "pgtemp", "pq-sys", "tokio", - "tokio-util 0.7.18", + "tokio-util", ] [[package]] @@ -3727,7 +3687,7 @@ dependencies = [ "tokio", "tokio-retry", "tokio-stream", - "tokio-util 0.7.18", + "tokio-util", "toml 0.9.11+spec-1.1.0", "tonic", "tonic-prost", @@ -3815,7 +3775,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-retry", - "tokio-util 0.7.18", + "tokio-util", "tower 0.5.3", "tower-test", "wiremock", @@ -3867,7 +3827,7 @@ dependencies = [ "shellexpand", "termcolor", "tokio", - "tokio-util 0.7.18", + "tokio-util", "url", ] @@ -3962,7 +3922,7 @@ dependencies = [ "chrono", "clap", "deadpool", - "derive_more 2.1.1", + "derive_more", "diesel", "diesel-async", "diesel-derive-enum", @@ -4008,14 +3968,12 @@ dependencies = [ "graph-runtime-wasm", "graph-server-index-node", "graph-store-postgres", - "secp256k1 0.21.3", "serde", "serde_yaml", "slog", "tokio", "tokio-stream", - "tokio-util 0.7.18", - "web3", + "tokio-util", ] [[package]] @@ -4122,7 +4080,7 @@ dependencies = [ "indexmap 2.11.4", "slab", "tokio", - "tokio-util 0.7.18", + "tokio-util", "tracing", ] @@ -4141,7 +4099,7 @@ dependencies = [ "indexmap 2.11.4", "slab", "tokio", - "tokio-util 0.7.18", + "tokio-util", "tracing", ] @@ -4218,30 +4176,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "headers" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" -dependencies = [ - "base64 0.21.7", - "bytes", - "headers-core", - "http 1.4.0", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" -dependencies = [ - "http 1.4.0", -] - [[package]] name = "heck" version = "0.4.1" @@ -4674,17 +4608,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.1.0" @@ -5286,12 +5209,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.8.4" @@ -5643,12 +5560,6 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.75" @@ -6599,7 +6510,7 @@ dependencies = [ "sha1_smol", "socket2 0.6.0", "tokio", - "tokio-util 0.7.18", + "tokio-util", "url", "xxhash-rust", ] @@ -6714,7 +6625,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-util 0.7.18", + "tokio-util", "tower 0.5.2", "tower-http", "tower-service 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7011,15 +6922,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260" -dependencies = [ - "secp256k1-sys 0.4.2", -] - [[package]] name = "secp256k1" version = "0.30.0" @@ -7028,19 +6930,10 @@ checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", "rand 0.8.5", - "secp256k1-sys 0.10.1", + "secp256k1-sys", "serde", ] -[[package]] -name = "secp256k1-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" -dependencies = [ - "cc", -] - [[package]] name = "secp256k1-sys" version = "0.10.1" @@ -7273,19 +7166,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha1" version = "0.10.6" @@ -7493,21 +7373,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "soketto" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" -dependencies = [ - "base64 0.13.1", - "bytes", - "futures 0.3.31", - "httparse", - "log", - "rand 0.8.5", - "sha-1", -] - [[package]] name = "spin" version = "0.9.8" @@ -8032,7 +7897,7 @@ dependencies = [ "rand 0.9.2", "socket2 0.6.0", "tokio", - "tokio-util 0.7.18", + "tokio-util", "whoami", ] @@ -8066,7 +7931,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util 0.7.18", + "tokio-util", ] [[package]] @@ -8110,21 +7975,6 @@ dependencies = [ "tungstenite 0.28.0", ] -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -8308,7 +8158,7 @@ dependencies = [ "slab", "sync_wrapper", "tokio", - "tokio-util 0.7.18", + "tokio-util", "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)", "tracing", @@ -8327,7 +8177,7 @@ dependencies = [ "slab", "sync_wrapper", "tokio", - "tokio-util 0.7.18", + "tokio-util", "tower-layer 0.3.3 (git+https://github.com/tower-rs/tower.git)", "tower-service 0.3.3 (git+https://github.com/tower-rs/tower.git)", "tracing", @@ -8596,7 +8446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna 1.1.0", + "idna", "percent-encoding", "serde", ] @@ -9179,53 +9029,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web3" -version = "0.19.0-graph" -source = "git+https://github.com/graphprotocol/rust-web3?branch=graph-patches-onto-0.18#f9f27f45ce23bf489d8bd010b50b2b207eb316cb" -dependencies = [ - "arrayvec 0.7.4", - "base64 0.13.1", - "bytes", - "derive_more 0.99.19", - "ethabi", - "ethereum-types", - "futures 0.3.31", - "futures-timer", - "headers", - "hex", - "idna 0.2.3", - "jsonrpc-core", - "log", - "once_cell", - "parking_lot", - "pin-project", - "reqwest", - "rlp", - "secp256k1 0.21.3", - "serde", - "serde_json", - "soketto", - "tiny-keccak 2.0.2", - "tokio", - "tokio-stream", - "tokio-util 0.6.10", - "url", - "web3-async-native-tls", -] - -[[package]] -name = "web3-async-native-tls" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f6d8d1636b2627fe63518d5a9b38a569405d9c9bc665c43c9c341de57227ebb" -dependencies = [ - "native-tls", - "thiserror 1.0.61", - "tokio", - "url", -] - [[package]] name = "webpki-roots" version = "0.26.11" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9276137fd13..4fab0a09157 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -308,12 +308,6 @@ importers: specifier: 0.31.0 version: 0.31.0 - tests/runner-tests/substreams: - devDependencies: - '@graphprotocol/graph-cli': - specifier: 0.61.0 - version: 0.61.0(@types/node@24.3.0)(bufferutil@4.0.9)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.9.2)(utf-8-validate@5.0.10) - tests/runner-tests/typename: devDependencies: '@graphprotocol/graph-cli': @@ -419,11 +413,6 @@ packages: engines: {node: '>=14'} hasBin: true - '@graphprotocol/graph-cli@0.61.0': - resolution: {integrity: sha512-gc3+DioZ/K40sQCt6DsNvbqfPTc9ZysuSz3I9MJ++bD6SftaSSweWwfpPysDMzDuxvUAhLAsJ6QjBACPngT2Kw==} - engines: {node: '>=14'} - hasBin: true - '@graphprotocol/graph-cli@0.69.0': resolution: {integrity: sha512-DoneR0TRkZYumsygdi/RST+OB55TgwmhziredI21lYzfj0QNXGEHZOagTOKeFKDFEpP3KR6BAq6rQIrkprJ1IQ==} engines: {node: '>=18'} @@ -3450,47 +3439,6 @@ snapshots: - typescript - utf-8-validate - '@graphprotocol/graph-cli@0.61.0(@types/node@24.3.0)(bufferutil@4.0.9)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.9.2)(utf-8-validate@5.0.10)': - dependencies: - '@float-capital/float-subgraph-uncrashable': 0.0.0-internal-testing.5 - '@oclif/core': 2.8.6(@types/node@24.3.0)(typescript@5.9.2) - '@oclif/plugin-autocomplete': 2.3.10(@types/node@24.3.0)(typescript@5.9.2) - '@oclif/plugin-not-found': 2.4.3(@types/node@24.3.0)(typescript@5.9.2) - '@whatwg-node/fetch': 0.8.8 - assemblyscript: 0.19.23 - binary-install-raw: 0.0.13(debug@4.3.4) - chalk: 3.0.0 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - docker-compose: 0.23.19 - dockerode: 2.5.8 - fs-extra: 9.1.0 - glob: 9.3.5 - gluegun: 5.1.2(debug@4.3.4) - graphql: 15.5.0 - immutable: 4.2.1 - ipfs-http-client: 55.0.0(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13)) - jayson: 4.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - js-yaml: 3.14.1 - prettier: 1.19.1 - request: 2.88.2 - semver: 7.4.0 - sync-request: 6.1.0 - tmp-promise: 3.0.3 - web3-eth-abi: 1.7.0 - which: 2.0.2 - yaml: 1.10.2 - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - bufferutil - - encoding - - node-fetch - - supports-color - - typescript - - utf-8-validate - '@graphprotocol/graph-cli@0.69.0(@types/node@24.3.0)(bufferutil@4.0.9)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@float-capital/float-subgraph-uncrashable': 0.0.0-internal-testing.5 diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 955c8d80449..6de710f6561 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -20,15 +20,7 @@ serde = { workspace = true } serde_yaml = { workspace = true } slog = { workspace = true } tokio = { version = "1.49.0", features = ["rt", "macros", "process"] } -# Once graph upgrades to web3 0.19, we don't need this anymore. The version -# here needs to be kept in sync with the web3 version that the graph crate -# uses until then -secp256k1 = { version = "0.21", features = ["recovery"] } tokio-util.workspace = true -web3 = { git = "https://github.com/graphprotocol/rust-web3", branch = "graph-patches-onto-0.18", features = [ - "arbitrary_precision", - "test", -] } [dev-dependencies] anyhow = "1.0.100" diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 19dfa1f86c5..c05228f8418 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -22,7 +22,7 @@ services: anvil: # Pinned to specific version since newer versions do not produce # deterministic block hashes. Unpin once that's fixed upstream - image: ghcr.io/foundry-rs/foundry:v1.2.3 + image: ghcr.io/foundry-rs/foundry:v1.4.0 ports: - '3021:8545' command: "'anvil --host 0.0.0.0 --gas-limit 100000000000 --base-fee 1 --block-time 2 --timestamp 1743944919 --mnemonic \"test test test test test test test test test test test junk\"'" diff --git a/tests/integration-tests/grafted/subgraph.yaml b/tests/integration-tests/grafted/subgraph.yaml index c0435df9c11..6cd33f93006 100644 --- a/tests/integration-tests/grafted/subgraph.yaml +++ b/tests/integration-tests/grafted/subgraph.yaml @@ -26,5 +26,5 @@ dataSources: features: - grafting graft: - base: QmTQbJ234d2Po7xKZS5wKPiYuMYsCAqqY4df5czESjEXn4 - block: 2 \ No newline at end of file + base: '@base@' + block: 2 diff --git a/tests/integration-tests/topic-filter/schema.graphql b/tests/integration-tests/topic-filter/schema.graphql index 1ff0f94adab..01dfa0433dd 100644 --- a/tests/integration-tests/topic-filter/schema.graphql +++ b/tests/integration-tests/topic-filter/schema.graphql @@ -1,5 +1,5 @@ type AnotherTriggerEntity @entity { - id: ID! + id: Int8! a: BigInt b: BigInt c: BigInt diff --git a/tests/integration-tests/topic-filter/src/mapping.ts b/tests/integration-tests/topic-filter/src/mapping.ts index 9a5ab36b221..53a38f42117 100644 --- a/tests/integration-tests/topic-filter/src/mapping.ts +++ b/tests/integration-tests/topic-filter/src/mapping.ts @@ -3,7 +3,7 @@ import { AnotherTrigger } from "../generated/Contract/Contract"; import { AnotherTriggerEntity } from "../generated/schema"; export function handleAnotherTrigger(event: AnotherTrigger): void { - let entity = new AnotherTriggerEntity(event.transaction.hash.toHex()); + let entity = new AnotherTriggerEntity("auto"); entity.a = event.params.a; entity.b = event.params.b; entity.c = event.params.c; diff --git a/tests/src/contract.rs b/tests/src/contract.rs index 80a9ba57031..ffd92fe5e34 100644 --- a/tests/src/contract.rs +++ b/tests/src/contract.rs @@ -1,57 +1,81 @@ -use std::str::FromStr; - use graph::prelude::{ - lazy_static, + alloy::{ + contract::{ContractInstance, Interface}, + dyn_abi::DynSolValue, + json_abi::JsonAbi, + network::{Ethereum, TransactionBuilder}, + primitives::{Address, Bytes, U256}, + providers::{Provider, ProviderBuilder, WalletProvider}, + rpc::types::{Block, TransactionReceipt, TransactionRequest}, + signers::local::PrivateKeySigner, + }, + hex, lazy_static, serde_json::{self, Value}, }; -use web3::{ - api::{Eth, Namespace}, - contract::{tokens::Tokenize, Contract as Web3Contract, Options}, - transports::Http, - types::{Address, Block, BlockId, BlockNumber, Bytes, TransactionReceipt, H256}, -}; -// web3 version 0.18 does not expose this; once the graph crate updates to -// version 0.19, we can use web3::signing::SecretKey from the graph crate -use secp256k1::SecretKey; - use crate::{error, helpers::TestFile, status, CONFIG}; // `FROM` and `FROM_KEY` are the address and private key of the first // account that anvil prints on startup lazy_static! { - static ref FROM: Address = - Address::from_str("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266").unwrap(); - static ref FROM_KEY: SecretKey = { - SecretKey::from_str("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") - .unwrap() - }; + static ref FROM: Address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + .parse() + .unwrap(); + static ref FROM_KEY: PrivateKeySigner = + "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + .parse() + .unwrap(); static ref CONTRACTS: Vec = { vec![ Contract { name: "SimpleContract".to_string(), - address: Address::from_str("0x5fbdb2315678afecb367f032d93f642f64180aa3").unwrap(), + address: "0x5fbdb2315678afecb367f032d93f642f64180aa3" + .parse() + .unwrap(), }, Contract { name: "LimitedContract".to_string(), - address: Address::from_str("0xb7f8bc63bbcad18155201308c8f3540b07f84f5e").unwrap(), + address: "0x0b306bf915c4d645ff596e518faf3f9669b97016" + .parse() + .unwrap(), }, Contract { name: "RevertingContract".to_string(), - address: Address::from_str("0xa51c1fc2f0d1a1b8494ed1fe312d7c3a78ed91c0").unwrap(), + address: "0x959922be3caee4b8cd9a407cc3ac1c251c2007b1" + .parse() + .unwrap(), }, Contract { name: "OverloadedContract".to_string(), - address: Address::from_str("0x0dcd1bf9a1b36ce34237eeafef220932846bcd82").unwrap(), + address: "0x9a9f2ccfde556a7e9ff0848998aa4a0cfd8863ae" + .parse() + .unwrap(), }, Contract { name: "DeclaredCallsContract".to_string(), - address: Address::from_str("0x9a676e781a523b5d0c0e43731313a708cb607508").unwrap(), + address: "0x68b1d87f95878fe05b998f19b66f4baba5de1aed" + .parse() + .unwrap(), }, ] }; } +/// Helper function to create a DynSolValue::Uint from a u64 value +pub fn uint(val: u64, bits: usize) -> DynSolValue { + DynSolValue::Uint(U256::from(val), bits) +} + +/// Helper function to create a DynSolValue::Address +pub fn addr(a: Address) -> DynSolValue { + DynSolValue::Address(a) +} + +/// Helper function to create a DynSolValue::String +pub fn string(s: &str) -> DynSolValue { + DynSolValue::String(s.to_string()) +} + #[derive(Debug, Clone)] pub struct Contract { pub name: String, @@ -59,66 +83,74 @@ pub struct Contract { } impl Contract { - fn eth() -> Eth { - let web3 = Http::new(&CONFIG.eth.url()).unwrap(); - Eth::new(web3) + fn provider() -> impl Provider + WalletProvider + Clone { + ProviderBuilder::new() + .wallet(FROM_KEY.clone()) + .connect_http(CONFIG.eth.url().parse().unwrap()) } async fn exists(&self) -> bool { let bytes = self.code().await; - !bytes.0.is_empty() + !bytes.is_empty() } pub async fn code(&self) -> Bytes { - let eth = Self::eth(); - eth.code(self.address, None).await.unwrap() + let provider = Self::provider(); + provider.get_code_at(self.address).await.unwrap() } - fn code_and_abi(name: &str) -> anyhow::Result<(String, Vec)> { - let src = TestFile::new(&format!("contracts/src/{}.sol", name)); + fn code_and_abi(name: &str) -> anyhow::Result<(Bytes, JsonAbi)> { let bin = TestFile::new(&format!("contracts/out/{}.sol/{}.json", name, name)); - if src.newer(&bin) { - println!( - "The source {} is newer than the compiled contract {}. Please recompile.", - src, bin - ); - } let json: Value = serde_json::from_reader(bin.reader()?).unwrap(); - let abi = serde_json::to_string(&json["abi"]).unwrap(); - let code = json["bytecode"]["object"].as_str().unwrap(); - Ok((code.to_string(), abi.as_bytes().to_vec())) + let abi: JsonAbi = serde_json::from_value(json["abi"].clone())?; + let code_hex = json["bytecode"]["object"].as_str().unwrap(); + let code = Bytes::from(hex::decode(code_hex.trim_start_matches("0x"))?); + Ok((code, abi)) } pub async fn deploy(name: &str) -> anyhow::Result { - let eth = Self::eth(); - let (code, abi) = Self::code_and_abi(name)?; - let contract = Web3Contract::deploy(eth, &abi) - .unwrap() - .confirmations(1) - .execute(code, (), FROM.to_owned()) - .await - .unwrap(); + let provider = Self::provider(); + let (code, _abi) = Self::code_and_abi(name)?; + + let deploy_tx = TransactionRequest::default().with_deploy_code(code); + + let receipt = provider + .send_transaction(deploy_tx) + .await? + .with_required_confirmations(1) + .get_receipt() + .await?; + + let address = receipt + .contract_address + .ok_or_else(|| anyhow::anyhow!("No contract address in receipt"))?; Ok(Self { name: name.to_string(), - address: contract.address(), + address, }) } pub async fn call( &self, func: &str, - params: impl Tokenize, + params: &[DynSolValue], ) -> anyhow::Result { - let eth = Self::eth(); + let provider = Self::provider(); let (_, abi) = Self::code_and_abi(&self.name)?; - let contract = Web3Contract::from_json(eth, self.address, &abi)?; - let options = Options::default(); + + let interface = Interface::new(abi); + let contract = ContractInstance::new(self.address, provider, interface); + let receipt = contract - .signed_call_with_confirmations(func, params, options, 1, &*FROM_KEY) - .await - .unwrap(); + .function(func, params)? + .send() + .await? + .with_required_confirmations(1) + .get_receipt() + .await?; + Ok(receipt) } @@ -154,54 +186,79 @@ impl Contract { // Some tests want 10 calls to `emitTrigger` in place if contract.name == "SimpleContract" { status!("contracts", "Calling SimpleContract.emitTrigger 10 times"); - for i in 1..=10 { - contract.call("emitTrigger", (i as u16,)).await.unwrap(); + for i in 1u64..=10 { + contract.call("emitTrigger", &[uint(i, 16)]).await.unwrap(); } } // Declared calls tests need a Transfer if contract.name == "DeclaredCallsContract" { status!("contracts", "Emitting transfers from DeclaredCallsContract"); - let addr1 = "0x1111111111111111111111111111111111111111" - .parse::() + let addr1: Address = "0x1111111111111111111111111111111111111111" + .parse() .unwrap(); - let addr2 = "0x2222222222222222222222222222222222222222" - .parse::() + let addr2: Address = "0x2222222222222222222222222222222222222222" + .parse() .unwrap(); - let addr3 = "0x3333333333333333333333333333333333333333" - .parse::() + let addr3: Address = "0x3333333333333333333333333333333333333333" + .parse() .unwrap(); - let addr4 = "0x4444444444444444444444444444444444444444" - .parse::() + let addr4: Address = "0x4444444444444444444444444444444444444444" + .parse() .unwrap(); contract - .call("emitTransfer", (addr1, addr2, 100u64)) + .call( + "emitTransfer", + &[addr(addr1), addr(addr2), uint(100u64, 256)], + ) .await .unwrap(); // Emit an asset transfer event to trigger struct field declared calls contract - .call("emitAssetTransfer", (addr1, 150u64, true, addr3)) + .call( + "emitAssetTransfer", + &[ + addr(addr1), + uint(150u64, 256), + DynSolValue::Bool(true), + addr(addr3), + ], + ) .await .unwrap(); // Also emit a complex asset event for nested struct testing - let values = vec![1u64, 2u64, 3u64]; + let values = + DynSolValue::Array(vec![uint(1u64, 256), uint(2u64, 256), uint(3u64, 256)]); contract .call( "emitComplexAssetCreated", - ( - addr4, - 250u64, - true, - "Complex Asset Metadata".to_string(), + &[ + addr(addr4), + uint(250u64, 256), + DynSolValue::Bool(true), + string("Complex Asset Metadata"), values, - 99u64, - ), + uint(99u64, 256), + ], ) .await .unwrap(); } + // The topic-filter test needs some events emitted + if contract.name == "SimpleContract" { + status!("contracts", "Emitting anotherTrigger from SimpleContract"); + let args = &[ + [uint(1, 256), uint(2, 256), uint(3, 256), string("abc")], + [uint(1, 256), uint(1, 256), uint(1, 256), string("abc")], + [uint(4, 256), uint(2, 256), uint(3, 256), string("abc")], + [uint(4, 256), uint(4, 256), uint(3, 256), string("abc")], + ]; + for arg in args { + contract.call("emitAnotherTrigger", arg).await.unwrap(); + } + } } else { status!( "contracts", @@ -215,12 +272,12 @@ impl Contract { Ok(contracts) } - pub async fn latest_block() -> Option> { - let eth = Self::eth(); - let block = eth - .block(BlockId::Number(BlockNumber::Latest)) + pub async fn latest_block() -> Option { + let provider = Self::provider(); + provider + .get_block_by_number(Default::default()) .await - .unwrap_or_default(); - block + .ok() + .flatten() } } diff --git a/tests/src/subgraph.rs b/tests/src/subgraph.rs index e1057fccdcb..67513f49ca0 100644 --- a/tests/src/subgraph.rs +++ b/tests/src/subgraph.rs @@ -47,16 +47,41 @@ impl Subgraph { Ok(()) } + /// Patch source subgraph placeholders in the manifest with their deployment hashes. + /// This must be called after `patch()` since it reads from `subgraph.yaml.patched`. + pub fn patch_sources(dir: &TestFile, sources: &[(String, String)]) -> anyhow::Result<()> { + if sources.is_empty() { + return Ok(()); + } + + let patched_path = dir.path.join("subgraph.yaml.patched"); + let mut content = fs::read_to_string(&patched_path)?; + + for (placeholder, deployment_hash) in sources { + let repl = format!("@{}@", placeholder); + content = content.replace(&repl, deployment_hash); + } + + fs::write(&patched_path, content)?; + Ok(()) + } + /// Prepare the subgraph for deployment by patching contracts and checking for subgraph datasources pub async fn prepare( name: &str, contracts: &[Contract], + sources: Option<&[(String, String)]>, ) -> anyhow::Result<(TestFile, String, bool)> { let dir = Self::dir(name); let name = format!("test/{name}"); Self::patch(&dir, contracts).await?; + // Patch source subgraph placeholders if provided + if let Some(sources) = sources { + Self::patch_sources(&dir, sources)?; + } + // Check if subgraph has subgraph datasources let yaml_content = fs::read_to_string(dir.path.join("subgraph.yaml.patched"))?; let yaml: serde_yaml::Value = serde_yaml::from_str(&yaml_content)?; @@ -68,9 +93,15 @@ impl Subgraph { Ok((dir, name, has_subgraph_datasource)) } - /// Deploy the subgraph by running the required `graph` commands - pub async fn deploy(name: &str, contracts: &[Contract]) -> anyhow::Result { - let (dir, name, has_subgraph_datasource) = Self::prepare(name, contracts).await?; + /// Deploy the subgraph by running the required `graph` commands. + /// If `sources` is provided, the deployment hashes will be used to patch + /// source subgraph placeholders (e.g., `@source-subgraph@`) in the manifest. + pub async fn deploy( + name: &str, + contracts: &[Contract], + sources: Option<&[(String, String)]>, + ) -> anyhow::Result { + let (dir, name, has_subgraph_datasource) = Self::prepare(name, contracts, sources).await?; // graph codegen subgraph.yaml let mut prog = Command::new(&CONFIG.graph_cli); diff --git a/tests/tests/gnd_tests.rs b/tests/tests/gnd_tests.rs index 3e3a2e0f448..0ed1ac5ec8a 100644 --- a/tests/tests/gnd_tests.rs +++ b/tests/tests/gnd_tests.rs @@ -104,7 +104,7 @@ async fn gnd_tests() -> anyhow::Result<()> { .enumerate() .map(|(index, case)| { let subgraph_name = format!("subgraph-{}", num_sources + index); - case.check_health_and_test(&contracts, subgraph_name) + case.check_health_and_test(subgraph_name) }) .buffered(CONFIG.num_parallel_tests); diff --git a/tests/tests/integration_tests.rs b/tests/tests/integration_tests.rs index b5c7d3405ca..adaa1732024 100644 --- a/tests/tests/integration_tests.rs +++ b/tests/tests/integration_tests.rs @@ -9,21 +9,29 @@ //! tasks are really worth parallelizing, and applying this trick //! indiscriminately will only result in messy code and diminishing returns. +use std::collections::HashMap; use std::future::Future; use std::pin::Pin; use std::time::{self, Duration, Instant}; use anyhow::{anyhow, bail, Context, Result}; +use graph::components::subgraph::{ + ProofOfIndexing, ProofOfIndexingEvent, ProofOfIndexingFinisher, ProofOfIndexingVersion, +}; +use graph::data::store::Id; +use graph::entity; use graph::futures03::StreamExt; use graph::itertools::Itertools; use graph::prelude::serde_json::{json, Value}; +use graph::prelude::{alloy::primitives::Address, hex, BlockPtr, DeploymentHash}; +use graph::schema::InputSchema; +use graph::slog::{o, Discard, Logger}; use graph_tests::contract::Contract; use graph_tests::subgraph::Subgraph; use graph_tests::{error, status, CONFIG}; use tokio::process::Child; use tokio::task::JoinError; use tokio::time::sleep; -use web3::types::U256; const SUBGRAPH_LAST_GRAFTING_BLOCK: i32 = 3; @@ -35,7 +43,6 @@ type TestFn = Box< pub struct TestContext { pub subgraph: Subgraph, - pub contracts: Vec, } pub enum TestStatus { @@ -172,7 +179,7 @@ impl TestCase { contracts: &[Contract], ) -> Result { status!(&self.name, "Deploying subgraph"); - let subgraph_name = match Subgraph::deploy(subgraph_name, contracts).await { + let subgraph_name = match Subgraph::deploy(subgraph_name, contracts, None).await { Ok(name) => name, Err(e) => { error!(&self.name, "Deploy failed"); @@ -199,31 +206,33 @@ impl TestCase { } pub async fn prepare(&self, contracts: &[Contract]) -> anyhow::Result { - // If a subgraph has subgraph datasources, prepare them first - if let Some(_subgraphs) = &self.source_subgraph { - if let Err(e) = self.prepare_multiple_sources(contracts).await { - error!(&self.name, "source subgraph deployment failed: {:?}", e); - return Err(e); + // If a subgraph has subgraph datasources, prepare them first and collect their deployment hashes + let source_mappings = if let Some(_subgraphs) = &self.source_subgraph { + match self.prepare_multiple_sources(contracts).await { + Ok(mappings) => Some(mappings), + Err(e) => { + error!(&self.name, "source subgraph deployment failed: {:?}", e); + return Err(e); + } } - } + } else { + None + }; status!(&self.name, "Preparing subgraph"); - let (_, subgraph_name, _) = match Subgraph::prepare(&self.name, contracts).await { - Ok(name) => name, - Err(e) => { - error!(&self.name, "Prepare failed: {:?}", e); - return Err(e); - } - }; + let (_, subgraph_name, _) = + match Subgraph::prepare(&self.name, contracts, source_mappings.as_deref()).await { + Ok(name) => name, + Err(e) => { + error!(&self.name, "Prepare failed: {:?}", e); + return Err(e); + } + }; Ok(subgraph_name) } - pub async fn check_health_and_test( - self, - contracts: &[Contract], - subgraph_name: String, - ) -> TestResult { + pub async fn check_health_and_test(self, subgraph_name: String) -> TestResult { status!( &self.name, "Waiting for subgraph ({}) to become ready", @@ -249,7 +258,6 @@ impl TestCase { let ctx = TestContext { subgraph: subgraph.clone(), - contracts: contracts.to_vec(), }; status!(&self.name, "Starting test"); @@ -276,45 +284,64 @@ impl TestCase { } } - async fn run(self, contracts: &[Contract]) -> TestResult { - // If a subgraph has subgraph datasources, deploy them first - if let Some(_subgraphs) = &self.source_subgraph { - if let Err(e) = self.deploy_multiple_sources(contracts).await { - error!(&self.name, "source subgraph deployment failed"); - return TestResult { - name: self.name.clone(), - subgraph: None, - status: TestStatus::Err(e), - }; + pub async fn run(self, contracts: &[Contract]) -> TestResult { + // If a subgraph has subgraph datasources, deploy them first and collect their deployment hashes + let source_mappings = if let Some(_subgraphs) = &self.source_subgraph { + match self.deploy_multiple_sources(contracts).await { + Ok(mappings) => Some(mappings), + Err(e) => { + error!(&self.name, "source subgraph deployment failed"); + return TestResult { + name: self.name.clone(), + subgraph: None, + status: TestStatus::Err(e), + }; + } } - } + } else { + None + }; status!(&self.name, "Deploying subgraph"); - let subgraph_name = match Subgraph::deploy(&self.name, contracts).await { - Ok(name) => name, - Err(e) => { - error!(&self.name, "Deploy failed"); - return TestResult { - name: self.name.clone(), - subgraph: None, - status: TestStatus::Err(e.context("Deploy failed")), - }; - } - }; + let subgraph_name = + match Subgraph::deploy(&self.name, contracts, source_mappings.as_deref()).await { + Ok(name) => name, + Err(e) => { + error!(&self.name, "Deploy failed"); + return TestResult { + name: self.name.clone(), + subgraph: None, + status: TestStatus::Err(e.context("Deploy failed")), + }; + } + }; - self.check_health_and_test(contracts, subgraph_name).await + self.check_health_and_test(subgraph_name).await } - async fn prepare_multiple_sources(&self, contracts: &[Contract]) -> Result<()> { + async fn prepare_multiple_sources( + &self, + contracts: &[Contract], + ) -> Result> { + let mut mappings = Vec::new(); if let Some(sources) = &self.source_subgraph { for source in sources { - let _ = Subgraph::prepare(source.test_name(), contracts).await?; + // Source subgraphs don't have their own sources, so pass None + let _ = Subgraph::prepare(source.test_name(), contracts, None).await?; + // If the source has an alias (pre-known IPFS hash), use it for the mapping + if let Some(alias) = source.alias() { + mappings.push((source.test_name().to_string(), alias.to_string())); + } } } - Ok(()) + Ok(mappings) } - async fn deploy_multiple_sources(&self, contracts: &[Contract]) -> Result<()> { + async fn deploy_multiple_sources( + &self, + contracts: &[Contract], + ) -> Result> { + let mut mappings = Vec::new(); if let Some(sources) = &self.source_subgraph { for source in sources { let subgraph = self.deploy_and_wait(source.test_name(), contracts).await?; @@ -323,9 +350,11 @@ impl TestCase { "Source subgraph deployed with hash {}", subgraph.deployment ); + // Use the test_name as the placeholder key + mappings.push((source.test_name().to_string(), subgraph.deployment.clone())); } } - Ok(()) + Ok(mappings) } } @@ -635,63 +664,7 @@ async fn test_topic_filters(ctx: TestContext) -> anyhow::Result<()> { let subgraph = ctx.subgraph; assert!(subgraph.healthy); - let contract = ctx - .contracts - .iter() - .find(|x| x.name == "SimpleContract") - .unwrap(); - - contract - .call( - "emitAnotherTrigger", - ( - U256::from(1), - U256::from(2), - U256::from(3), - "abc".to_string(), - ), - ) - .await - .unwrap(); - - contract - .call( - "emitAnotherTrigger", - ( - U256::from(1), - U256::from(1), - U256::from(1), - "abc".to_string(), - ), - ) - .await - .unwrap(); - - contract - .call( - "emitAnotherTrigger", - ( - U256::from(4), - U256::from(2), - U256::from(3), - "abc".to_string(), - ), - ) - .await - .unwrap(); - - contract - .call( - "emitAnotherTrigger", - ( - U256::from(4), - U256::from(4), - U256::from(3), - "abc".to_string(), - ), - ) - .await - .unwrap(); + // Events we need are already emitted from Contract::deploy_all let exp = json!({ "anotherTriggerEntities": [ @@ -892,21 +865,22 @@ async fn test_subgraph_grafting(ctx: TestContext) -> anyhow::Result<()> { assert!(subgraph.healthy); + // Fixed block hashes from deterministic Anvil config let block_hashes: Vec<&str> = vec![ "e26fccbd24dcc76074b432becf29cad3bcba11a8467a7b770fad109c2b5d14c2", "249dbcbee975c22f8c9cc937536945ca463568c42d8933a3f54129dec352e46b", "408675f81c409dede08d0eeb2b3420a73b067c4fa8c5f0fc49ce369289467c33", ]; - let pois: Vec<&str> = vec![ - "0x606c1ed77564ef9ab077e0438da9f3c6af79a991603aecf74650971a88d05b65", - "0xbb21d5cf5fd62892159f95211da4a02f0dfa1b43d68aeb64baa52cc67fbb6c8e", - "0x5a01b371017c924e8cedd62a76cf8dcf05987f80d2b91aaf3fb57872ab75887f", - ]; + // The deployment hash is dynamic (depends on the base subgraph's hash) + let deployment_hash = DeploymentHash::new(&subgraph.deployment).unwrap(); + + // Compute the expected POI values dynamically + let expected_pois = compute_expected_pois(&deployment_hash, &block_hashes); for i in 1..4 { let block_hash = get_block_hash(i).await.unwrap(); - // We need to make sure that the preconditions for POI are fulfiled + // We need to make sure that the preconditions for POI are fulfilled // namely that the blockchain produced the proper block hashes for the // blocks of which we will check the POI. assert_eq!(block_hash, block_hashes[(i - 1) as usize]); @@ -938,12 +912,146 @@ async fn test_subgraph_grafting(ctx: TestContext) -> anyhow::Result<()> { // Change on the block #2 would mean a change in the transitioning // from the old to the new algorithm hence would be reflected only // subgraphs that are grafting from pre 0.0.5 to 0.0.6 or newer. - assert_eq!(poi, pois[(i - 1) as usize]); + assert_eq!( + poi, + expected_pois[(i - 1) as usize], + "POI mismatch for block {}", + i + ); } Ok(()) } +/// Compute the expected POI values for the grafted subgraph. +/// +/// The grafted subgraph: +/// - Spec version 0.0.6 (uses Fast POI algorithm) +/// - Grafts from base subgraph at block 2 +/// - Creates GraftedData entities starting from block 3 +/// +/// The base subgraph: +/// - Spec version 0.0.5 (uses Legacy POI algorithm) +/// - Creates BaseData entities for each block +/// +/// POI algorithm transition: +/// - Blocks 0-2: Legacy POI digests (from base subgraph) +/// - Block 3+: Fast POI algorithm with transition from Legacy +fn compute_expected_pois(deployment_hash: &DeploymentHash, block_hashes: &[&str]) -> Vec { + let logger = Logger::root(Discard, o!()); + let causality_region = "ethereum/test"; + + // Create schemas for the entity types + let base_schema = InputSchema::parse_latest( + "type BaseData @entity(immutable: true) { id: ID!, data: String!, blockNumber: BigInt! }", + deployment_hash.clone(), + ) + .unwrap(); + + let grafted_schema = InputSchema::parse_latest( + "type GraftedData @entity(immutable: true) { id: ID!, data: String!, blockNumber: BigInt! }", + deployment_hash.clone(), + ) + .unwrap(); + + // Compute POI digests at each block checkpoint + // Store the accumulated state after each block so we can compute POI at any block + let mut db_at_block: HashMap>> = HashMap::new(); + let mut db: HashMap> = HashMap::new(); + + // Process blocks 0-3: + // - Blocks 0-2: Legacy POI (from base subgraph, creates BaseData entities) + // - Block 3: Fast POI (grafted subgraph starts here, creates GraftedData entity) + // + // The base subgraph starts from block 0 (genesis block triggers handlers in Anvil). + // + // The grafted subgraph: + // - spec version 0.0.6 → uses Fast POI algorithm + // - grafts from base subgraph at block 2 + // - inherits POI digests from base for blocks 0-2 + // - transitions from Legacy to Fast at block 3 + for block_i in 0..=3i32 { + let version = if block_i <= 2 { + ProofOfIndexingVersion::Legacy + } else { + ProofOfIndexingVersion::Fast + }; + + let mut stream = ProofOfIndexing::new(block_i, version); + + if block_i <= 2 { + // Base subgraph creates BaseData + let id_str = block_i.to_string(); + let entity = entity! { + base_schema => + id: &id_str, + data: "from base", + blockNumber: graph::prelude::Value::BigInt(block_i.into()), + }; + + let event = ProofOfIndexingEvent::SetEntity { + entity_type: "BaseData", + id: &id_str, + data: &entity, + }; + stream.write(&logger, causality_region, &event); + } else { + // Grafted subgraph creates GraftedData + let id_str = block_i.to_string(); + let entity = entity! { + grafted_schema => + id: &id_str, + data: "to grafted", + blockNumber: graph::prelude::Value::BigInt(block_i.into()), + }; + + let event = ProofOfIndexingEvent::SetEntity { + entity_type: "GraftedData", + id: &id_str, + data: &entity, + }; + stream.write(&logger, causality_region, &event); + } + + for (name, region) in stream.take() { + let prev = db.get(&name); + let update = region.pause(prev.map(|v| &v[..])); + db.insert(name, update); + } + + db_at_block.insert(block_i, db.clone()); + } + + // Compute POI for blocks 1, 2, 3 + let mut pois = Vec::new(); + for (block_idx, block_hash_hex) in block_hashes.iter().enumerate() { + let block_number = (block_idx + 1) as i32; + + // Get the POI version for this block - grafted subgraph uses Fast (spec 0.0.6) + let version = ProofOfIndexingVersion::Fast; + + let block_hash_bytes = hex::decode(block_hash_hex).unwrap(); + let block_ptr = BlockPtr::from((block_hash_bytes, block_number as u64)); + + // Use zero address to match the test query's indexer parameter + let indexer = Some(Address::ZERO); + let mut finisher = + ProofOfIndexingFinisher::new(&block_ptr, deployment_hash, &indexer, version); + + if let Some(db_state) = db_at_block.get(&block_number) { + for (name, region) in db_state.iter() { + finisher.add_causality_region(name, region); + } + } + + let poi_bytes = finisher.finish(); + let poi = format!("0x{}", hex::encode(poi_bytes)); + pois.push(poi); + } + + pois +} + async fn test_poi_for_failed_subgraph(ctx: TestContext) -> anyhow::Result<()> { let subgraph = ctx.subgraph; const INDEXING_STATUS: &str = r#" @@ -1040,8 +1148,6 @@ pub async fn test_multiple_subgraph_datasources(ctx: TestContext) -> anyhow::Res let subgraph = ctx.subgraph; assert!(subgraph.healthy); - println!("subgraph: {:?}", subgraph); - // Test querying data aggregated from multiple sources let exp = json!({ "aggregatedDatas": [ @@ -1292,10 +1398,9 @@ async fn wait_for_blockchain_block(block_number: i32) -> bool { while start.elapsed() < STATUS_WAIT { let latest_block = Contract::latest_block().await; if let Some(latest_block) = latest_block { - if let Some(number) = latest_block.number { - if number >= block_number.into() { - return true; - } + let number = latest_block.header.number; + if number >= block_number as u64 { + return true; } } tokio::time::sleep(REQUEST_REPEATING).await;