From 7948898c04dc7b32a5aecce9a747f9788f46d824 Mon Sep 17 00:00:00 2001 From: "Daniel N. Werner" <1497784+dwerner@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:45:14 -0800 Subject: [PATCH] Fix/always deployments paused (#1157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomás Migone --- docs/networks/arbitrum-sepolia.md | 4 +- lerna.json | 2 +- packages/indexer-agent/package.json | 4 +- packages/indexer-agent/src/__tests__/agent.ts | 120 ++++++++++++++++++ packages/indexer-agent/src/agent.ts | 65 +++++++--- packages/indexer-cli/package.json | 4 +- packages/indexer-common/package.json | 2 +- scripts/run-tests.sh | 2 +- 8 files changed, 177 insertions(+), 26 deletions(-) diff --git a/docs/networks/arbitrum-sepolia.md b/docs/networks/arbitrum-sepolia.md index 85113a2af..ca646954e 100644 --- a/docs/networks/arbitrum-sepolia.md +++ b/docs/networks/arbitrum-sepolia.md @@ -7,8 +7,8 @@ The Graph Network's testnet is on Arbitrum Sepolia (eip155:421614). Sepolia netw | Component | Release | | ------------------ | ------------------------------------------------------------------------------------ | | contracts | [5.3.3](https://github.com/graphprotocol/contracts/releases/tag/v5.3.3) | -| indexer-agent | [0.25.4](https://github.com/graphprotocol/indexer/releases/tag/v0.25.4) | -| indexer-cli | [0.25.4](https://github.com/graphprotocol/indexer/releases/tag/v0.25.4) | +| indexer-agent | [0.25.5](https://github.com/graphprotocol/indexer/releases/tag/v0.25.5) | +| indexer-cli | [0.25.5](https://github.com/graphprotocol/indexer/releases/tag/v0.25.5) | | indexer-service-rs | [1.0.0](https://github.com/graphprotocol/indexer-rs/releases/tag/v1.0.0) | | tap-agent | [1.0.0](https://github.com/graphprotocol/indexer-rs/releases/tag/v1.0.0) | | graph-node | [0.35.1](https://github.com/graphprotocol/graph-node/releases/tag/v0.35.1) | diff --git a/lerna.json b/lerna.json index 6fabcdf11..14b056fbe 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "0.25.4" + "version": "0.25.5" } diff --git a/packages/indexer-agent/package.json b/packages/indexer-agent/package.json index 5dcf6a95b..08b77ac5d 100644 --- a/packages/indexer-agent/package.json +++ b/packages/indexer-agent/package.json @@ -1,6 +1,6 @@ { "name": "@graphprotocol/indexer-agent", - "version": "0.25.4", + "version": "0.25.5", "description": "Indexer agent", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -30,7 +30,7 @@ }, "dependencies": { "@graphprotocol/common-ts": "3.0.1", - "@graphprotocol/indexer-common": "0.25.4", + "@graphprotocol/indexer-common": "0.25.5", "@thi.ng/heaps": "^1.3.1", "axios": "0.26.1", "bs58": "5.0.0", diff --git a/packages/indexer-agent/src/__tests__/agent.ts b/packages/indexer-agent/src/__tests__/agent.ts index 700e15f98..f3ed83482 100644 --- a/packages/indexer-agent/src/__tests__/agent.ts +++ b/packages/indexer-agent/src/__tests__/agent.ts @@ -1,6 +1,7 @@ import { convertSubgraphBasedRulesToDeploymentBased, consolidateAllocationDecisions, + resolveTargetDeployments, } from '../agent' import { INDEXING_RULE_GLOBAL, @@ -208,3 +209,122 @@ describe('consolidateAllocationDecisions function', () => { expect(result).not.toContain(a) }) }) + +describe('resolveTargetDeployments function', () => { + const alwaysDeployment = new SubgraphDeploymentID( + 'QmXZiV6S13ha6QXq4dmaM3TB4CHcDxBMvGexSNu9Kc28EH', + ) + const offchainDeployment = new SubgraphDeploymentID( + 'QmRKs2ZfuwvmZA3QAWmCqrGUjV9pxtBUDP3wuc6iVGnjA2', + ) + const allocationDeployment = new SubgraphDeploymentID( + 'QmULAfA3eS5yojxeSR2KmbyuiwCGYPjymsFcpa6uYsu6CJ', + ) + const offchainArgDeployment = new SubgraphDeploymentID( + 'QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz', + ) + + it('includes OFFCHAIN rules when allocationDecisions is empty (manual mode)', () => { + const rules = { + 'eip155:42161': [ + { + identifier: offchainDeployment.ipfsHash, + identifierType: SubgraphIdentifierType.DEPLOYMENT, + decisionBasis: IndexingDecisionBasis.OFFCHAIN, + } as IndexingRuleAttributes, + ], + } + + const result = resolveTargetDeployments({}, rules, []) + + expect(result.size).toBe(1) + expect([...result].map(d => d.ipfsHash)).toContain( + offchainDeployment.ipfsHash, + ) + }) + + it('includes offchainSubgraphs from startup args', () => { + const result = resolveTargetDeployments({}, {}, [offchainArgDeployment]) + + expect(result.size).toBe(1) + expect([...result].map(d => d.ipfsHash)).toContain( + offchainArgDeployment.ipfsHash, + ) + }) + + it('includes deployments from allocationDecisions', () => { + const allocationDecisions = { + 'eip155:42161': [{ deployment: allocationDeployment, toAllocate: true }], + } + + const result = resolveTargetDeployments(allocationDecisions, {}, []) + + expect(result.size).toBe(1) + expect(result).toContain(allocationDeployment) + }) + + /** + * BUG TEST: In manual allocation mode, networkDeploymentAllocationDecisions is empty + * because evaluateDeployments is skipped. This means decisionBasis: ALWAYS rules + * are not included in targetDeployments, causing those subgraphs to be paused. + * + * This test should FAIL with the current buggy code and PASS after the fix. + */ + it('includes ALWAYS rules when allocationDecisions is empty (manual mode)', () => { + const rules = { + 'eip155:42161': [ + { + identifier: alwaysDeployment.ipfsHash, + identifierType: SubgraphIdentifierType.DEPLOYMENT, + decisionBasis: IndexingDecisionBasis.ALWAYS, + } as IndexingRuleAttributes, + ], + } + + // In manual mode, allocationDecisions is empty because evaluateDeployments is skipped + const result = resolveTargetDeployments({}, rules, []) + + // ALWAYS rules should still be included in targetDeployments + expect(result.size).toBe(1) + expect([...result].map(d => d.ipfsHash)).toContain( + alwaysDeployment.ipfsHash, + ) + }) + + it('combines all sources correctly', () => { + const allocationDecisions = { + 'eip155:42161': [{ deployment: allocationDeployment, toAllocate: true }], + } + const rules = { + 'eip155:42161': [ + { + identifier: offchainDeployment.ipfsHash, + identifierType: SubgraphIdentifierType.DEPLOYMENT, + decisionBasis: IndexingDecisionBasis.OFFCHAIN, + } as IndexingRuleAttributes, + { + identifier: alwaysDeployment.ipfsHash, + identifierType: SubgraphIdentifierType.DEPLOYMENT, + decisionBasis: IndexingDecisionBasis.ALWAYS, + } as IndexingRuleAttributes, + ], + } + + const result = resolveTargetDeployments(allocationDecisions, rules, [ + offchainArgDeployment, + ]) + + // Should include: allocationDeployment, offchainDeployment, alwaysDeployment, offchainArgDeployment + expect(result.size).toBe(4) + expect(result).toContain(allocationDeployment) + expect([...result].map(d => d.ipfsHash)).toContain( + offchainDeployment.ipfsHash, + ) + expect([...result].map(d => d.ipfsHash)).toContain( + alwaysDeployment.ipfsHash, + ) + expect([...result].map(d => d.ipfsHash)).toContain( + offchainArgDeployment.ipfsHash, + ) + }) +}) diff --git a/packages/indexer-agent/src/agent.ts b/packages/indexer-agent/src/agent.ts index f9f93d066..c0a41a2f5 100644 --- a/packages/indexer-agent/src/agent.ts +++ b/packages/indexer-agent/src/agent.ts @@ -425,23 +425,13 @@ export class Agent { }).tryMap( async ({ indexingRules, networkDeploymentAllocationDecisions }) => { logger.trace('Resolving target deployments') - const targetDeploymentIDs: Set = - consolidateAllocationDecisions(networkDeploymentAllocationDecisions) - - // Add offchain subgraphs to the deployment list from rules - Object.values(indexingRules) - .flat() - .filter( - rule => rule?.decisionBasis === IndexingDecisionBasis.OFFCHAIN, - ) - .forEach(rule => { - targetDeploymentIDs.add(new SubgraphDeploymentID(rule.identifier)) - }) - // From startup args - this.offchainSubgraphs.forEach(deployment => { - targetDeploymentIDs.add(deployment) - }) - return [...targetDeploymentIDs] + return [ + ...resolveTargetDeployments( + networkDeploymentAllocationDecisions, + indexingRules, + this.offchainSubgraphs, + ), + ] }, { onError: error => @@ -1231,3 +1221,44 @@ export function consolidateAllocationDecisions( .map(decision => decision.deployment), ) } + +/** + * Resolves the set of target deployments that should be synced by graph-node. + * This combines: + * 1. Deployments from allocation decisions (where toAllocate=true) + * 2. Deployments with OFFCHAIN and ALWAYS decision basis from rules + * 3. Deployments from --offchain-subgraphs startup args + */ +export function resolveTargetDeployments( + networkDeploymentAllocationDecisions: Record< + string, + AllocationDecisionInterface[] + >, + indexingRules: Record, + offchainSubgraphs: SubgraphDeploymentID[], +): Set { + const targetDeploymentIDs: Set = + consolidateAllocationDecisions(networkDeploymentAllocationDecisions) + + // Add offchain and always subgraphs to the deployment list from rules. + // ALWAYS rules must be handled here because in manual allocation mode, + // evaluateDeployments is skipped, so ALWAYS rules would otherwise not + // be included in targetDeployments. + Object.values(indexingRules) + .flat() + .filter( + rule => + rule?.decisionBasis === IndexingDecisionBasis.OFFCHAIN || + rule?.decisionBasis === IndexingDecisionBasis.ALWAYS, + ) + .forEach(rule => { + targetDeploymentIDs.add(new SubgraphDeploymentID(rule.identifier)) + }) + + // From startup args + offchainSubgraphs.forEach(deployment => { + targetDeploymentIDs.add(deployment) + }) + + return targetDeploymentIDs +} diff --git a/packages/indexer-cli/package.json b/packages/indexer-cli/package.json index 77dc28927..1a14afa6b 100644 --- a/packages/indexer-cli/package.json +++ b/packages/indexer-cli/package.json @@ -1,6 +1,6 @@ { "name": "@graphprotocol/indexer-cli", - "version": "0.25.4", + "version": "0.25.5", "description": "Indexer CLI for The Graph Network", "main": "./dist/cli.js", "files": [ @@ -27,7 +27,7 @@ }, "dependencies": { "@graphprotocol/common-ts": "3.0.1", - "@graphprotocol/indexer-common": "0.25.4", + "@graphprotocol/indexer-common": "0.25.5", "@iarna/toml": "2.2.5", "@thi.ng/iterators": "5.1.74", "@urql/core": "3.1.0", diff --git a/packages/indexer-common/package.json b/packages/indexer-common/package.json index 5bfa7b0b3..b1f1f3269 100644 --- a/packages/indexer-common/package.json +++ b/packages/indexer-common/package.json @@ -1,6 +1,6 @@ { "name": "@graphprotocol/indexer-common", - "version": "0.25.4", + "version": "0.25.5", "description": "Common library for Graph Protocol indexer components", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index a2849cb93..020b7bfdd 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -40,4 +40,4 @@ POSTGRES_TEST_DATABASE=indexer_tests \ POSTGRES_TEST_USERNAME=testuser \ POSTGRES_TEST_PASSWORD=testpass \ NODE_OPTIONS="--dns-result-order=ipv4first" \ -yarn test:ci +${TEST_CMD:-yarn test:ci}