Skip to content

core: keep the full trigger filter when a template handler is address-scoped - #6757

Open
lx3133584 wants to merge 1 commit into
graphprotocol:masterfrom
lx3133584:fix/static-filters-call-block-handler
Open

lx3133584 wants to merge 1 commit into
graphprotocol:masterfrom
lx3133584:fix/static-filters-call-block-handler

Conversation

@lx3133584

Copy link
Copy Markdown

Fixes #6750

Problem

With static filters on — EXPERIMENTAL_STATIC_FILTERS=true, or automatically once
a subgraph exceeds GRAPH_STATIC_FILTERS_THRESHOLD — a blockHandler with
filter: { kind: call } declared in a template never fired for the data
sources created from that template. In default mode it fired normally.

Nothing was logged. The subgraph stayed healthy and kept indexing, while its
entities and PoI diverged from a node running in default mode. A subgraph that
crosses the threshold would stop seeing these handlers from the restart at which
it switched.

Two things have to line up for this:

  • Static filters are built from the static data sources plus
    extend_with_template, and the block stream is not restarted when a data
    source is created, so the created address never enters the filter.
  • EthereumBlockFilter::from_mapping runs for the template. It sets
    trigger_every_block for any block handler and leaves contract_addresses
    empty, so the data source created from it receives Start/End triggers,
    which a Call handler cannot match.

from_data_sources does handle this correctly for a data source that already
has an address — that path is why default mode works.

Fix

The runner decides whether to use static filters before it builds either
filter, so the condition is recorded on the template itself:
DataSourceTemplate::has_address_scoped_block_handler. Ethereum answers it from
the mapping it already had a helper for; the trait default is false, so chains
without an equivalent construct are unaffected.

When a template reports it, is_static_filters_enabled returns false and the
subgraph keeps the full filter, which is rebuilt on data source creation and
therefore includes the created address. The reason is logged once, at info, so an
operator can tell why the optimization is not in effect for that subgraph.

The alternative — an "any address" mode for the block call filter, mirroring
wildcard_signatures for call handlers — keeps the optimization but asks for
traces on every block for these subgraphs. That is the second option in the
issue and is left for a follow-up; correctness first.

Testing

Added chain/ethereum/src/data_source.rs unit tests covering the predicate the
runner reads:

  • a Call-filtered block handler reports true
  • None, Once and Polling handlers report false
  • a template with no block handlers reports false
  • one Call-filtered handler among others still reports true

The last three keep the test honest about the direction of the check: an
implementation that answered true unconditionally would pass the first case
alone.

$ cargo test -p graph-chain-ethereum --lib
test result: ok. 69 passed; 0 failed; 0 ignored

$ cargo test -p graph --lib
test result: FAILED. 537 passed; 3 failed
$ cargo test -p graph-core --lib
test result: FAILED. 7 passed; 1 failed

The four failures above are the IPFS tests (link_resolver::ipfs::tests,
polling_monitor::ipfs_service::test), which need network access this machine
does not have. They fail identically on unmodified master, so they are
unrelated to this change.

cargo fmt --all -- --check and cargo clippy -p graph -p graph-core -p graph-chain-ethereum --all-targets are clean.

Deployment note

Subgraphs that already indexed with such a template under static filters have a
PoI computed without these handlers. After this change they need to be rewound to
before the block at which static filters took effect, otherwise the new
(complete) indexing starts from an inconsistent base.

…-scoped

A blockHandler with `filter: { kind: call }` declared in a template never
fired under static filters. Static filters deliberately drop the addresses of
created data sources, and the template contributes only trigger_every_block
through EthereumBlockFilter::from_mapping, so the Start/End triggers a data
source created from that template receives never match a Call handler. Nothing
was logged, and the subgraph kept indexing while its entities and PoI drifted
from a node running in default mode.

Report the condition on the template trait and let the runner fall back to the
full filter, which rebuilds on data source creation and therefore does include
the created address. Chains without an equivalent construct keep the default,
so their behaviour does not change.

Subgraphs that already indexed in static filters with such a template have a
PoI computed from the missing handlers; they need to be rewound to before the
block where static filters took effect.

Signed-off-by: Liang Xu <24490353+lx3133584@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Static filters silently drop call-filtered block handlers declared in templates (wrong data and PoI, no error)

1 participant