Skip to content

Commit ac722ca

Browse files
MoonBoi9001claude
andcommitted
fix(dips): warn when accepted rows can't be retired without the subgraph
Accepting a proposal needs the indexing-payments subgraph, so the local accepted rows can only appear without one if it was unset after acceptance. The retirement path then can't run and the rules are kept silently; warn with the stuck deployments so the misconfiguration is visible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 122d1e1 commit ac722ca

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

packages/indexer-common/src/indexing-fees/__tests__/dips.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,50 @@ describe('DipsManager', () => {
617617
expect(markCompleted).toHaveBeenCalledWith('accepted-1')
618618
})
619619

620+
test('keeps accepted rows and warns when no indexing-payments subgraph is configured', async () => {
621+
await managementModels.IndexingRule.create({
622+
identifier: testDeploymentId,
623+
identifierType: SubgraphIdentifierType.DEPLOYMENT,
624+
decisionBasis: IndexingDecisionBasis.DIPS,
625+
protocolNetwork: 'eip155:421614',
626+
allocationLifetime: 3600,
627+
})
628+
jest
629+
.spyOn(dipsManager.pendingRcaConsumer!, 'getPendingProposals')
630+
.mockResolvedValue([])
631+
jest
632+
.spyOn(dipsManager.pendingRcaConsumer!, 'getAcceptedProposals')
633+
.mockResolvedValue([
634+
{
635+
id: 'accepted-1',
636+
agreementId: testAgreementId,
637+
status: 'accepted',
638+
createdAt: new Date(),
639+
updatedAt: new Date(),
640+
subgraphDeploymentId: new SubgraphDeploymentID(testDeploymentId),
641+
minSecondsPerCollection: 60,
642+
maxSecondsPerCollection: 3600,
643+
} as never,
644+
])
645+
const markCompleted = jest.spyOn(dipsManager.pendingRcaConsumer!, 'markCompleted')
646+
const warn = jest.spyOn(logger, 'warn')
647+
// No subgraph configured: it can't drive retirement, so the rule is kept and
648+
// the stuck state is surfaced rather than lingering silently forever.
649+
network.indexingPaymentsSubgraph = undefined
650+
651+
await dipsManager.ensureAgreementRules()
652+
653+
expect(markCompleted).not.toHaveBeenCalled()
654+
expect(warn).toHaveBeenCalledWith(
655+
expect.stringContaining(
656+
'cannot be retired without the indexing-payments subgraph',
657+
),
658+
expect.objectContaining({
659+
stuckDeployments: [new SubgraphDeploymentID(testDeploymentId).toString()],
660+
}),
661+
)
662+
})
663+
620664
test('retires the accepted row and reaps its rule once the subgraph catches up but the agreement is gone', async () => {
621665
await managementModels.IndexingRule.create({
622666
identifier: testDeploymentId,

packages/indexer-common/src/indexing-fees/dips.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ export class DipsManager {
235235
})
236236
}
237237
}
238+
} else if (fromAcceptedProposals.length > 0) {
239+
// No subgraph configured but accepted rows exist (it was unset after they
240+
// were accepted): we can't tell if their agreements still live, so surface
241+
// the stuck rows instead of silently keeping their rules forever.
242+
this.logger.warn(
243+
'DIPS accepted rows cannot be retired without the indexing-payments subgraph; ' +
244+
'their rules will be kept until it is configured',
245+
{
246+
stuckDeployments: fromAcceptedProposals.map((p) =>
247+
p.subgraphDeploymentId.toString(),
248+
),
249+
},
250+
)
238251
}
239252
}
240253

0 commit comments

Comments
 (0)