Skip to content

[DO NOT MERGE] DIPS#967

Draft
MoonBoi9001 wants to merge 5 commits intomainfrom
main-dips
Draft

[DO NOT MERGE] DIPS#967
MoonBoi9001 wants to merge 5 commits intomainfrom
main-dips

Conversation

@MoonBoi9001
Copy link
Copy Markdown
Member

No description provided.

MoonBoi9001 and others added 5 commits February 17, 2026 13:04
…RCA (#942)

* feat(dips): implement SignedRCA validation and storage

Implement RecurringCollectionAgreement (RCA) protocol for DIPS,
aligned with the on-chain IndexingAgreement contract.

Changes:
- RcaStore trait and PostgreSQL implementation for RCA storage
- EIP-712 signature verification via escrow-based authorization
- validate_and_create_rca() with full validation pipeline:
  signature, IPFS manifest, network, pricing, deadline/expiry
- Database migration for pending_rca_proposals table

The indexer agent queries pending_rca_proposals directly and
decides acceptance on-chain via RecurringCollector contract.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(dips): improve configuration ergonomics and validation

- Add #[serde(default)] to DipsConfig for minimal config files
- Validate recurring_collector != Address::ZERO at startup
- Warn when tokens_per_second is empty (all proposals rejected)
- Bump pricing rejection logs to info level for visibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(dips): add module-level documentation

Add comprehensive documentation explaining architecture,
validation flow, trust model, and component responsibilities.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(dips): expand unit test coverage to 43 tests

Add comprehensive test suite with AAA pattern:
- validate_and_create_rca: 11 tests covering all validation paths
- PriceCalculator: 7 tests (previously 0)
- SignerValidator implementations: 5 tests
- Test doubles: FailingIpfsFetcher, FailingRcaStore, RejectingSignerValidator

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(dips): add IPFS fetch timeout and retry with backoff

Add resilience to IPFS manifest fetching:
- 30 second timeout per attempt
- Up to 4 attempts with exponential backoff (10s, 20s, 40s)
- Worst case: ~190 seconds before rejection

Dipper gRPC timeout should be >= 220s. See edgeandnode/dipper#557.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…etworks (#947)

* feat(dips): improve config ergonomics with GRT pricing and explicit networks

Changes human-readable GRT per 30 days pricing config and adds explicit
network support list. Addresses #943 and #944.

Config changes:
- Add supported_networks list (proposals for unlisted networks rejected)
- Add min_grt_per_30_days per-network base pricing (GRT/30 days)
- Add min_grt_per_million_entities_per_30_days global entity pricing
- Add 90+ networks with calculated pricing examples from IISA model

Pricing derived from archive node costs (storage $25/TB, memory $1.50/GB,
CPU $10/vCPU) divided by expected subgraph count per indexer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(dips): add startup validation tests and fix backoff comment

- Fix IPFS retry comment: actual delays are 10s, 20s, 40s (not 1s, 2s, 4s)
- Add 5 tests for DIPS startup validation:
  - test_dips_absent_in_minimal_config
  - test_dips_config_defaults_recurring_collector_zero
  - test_dips_config_defaults_empty_supported_networks
  - test_dips_partial_config_uses_defaults
  - test_dips_maximal_config_parses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(dips): use ceiling division to protect indexer minimums

When converting GRT/30days to wei/second, truncating division caused
indexers to accept slightly less than their configured minimum (up to
0.2% loss). Changed to ceiling division so minimums round UP, ensuring
indexers never accept offers below their stated price floor.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When Dipper sends an RCA and times out (network partition, crash after
INSERT but before response), it retries. Previously, the retry failed
with a duplicate key error, causing Dipper to mark the agreement as
failed even though it was stored successfully.

Now uses ON CONFLICT DO NOTHING so retries succeed. Both first attempt
and retry return success, enabling Dipper to safely retry without
creating inconsistent state.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…n reasons (#954)

* feat(dips): add /dips/info endpoint and rejection reasons to gRPC

Add a public /dips/info HTTP endpoint on port 7600 that advertises the
indexer's DIPS pricing configuration (min GRT per 30 days per network,
min GRT per million entities, supported networks, and protocol version).
This allows the Dipper to discover indexer pricing before sending RCA
proposals.

Update the gRPC protobuf to include a RejectReason enum on
SubmitAgreementProposalResponse, distinguishing PRICE_TOO_LOW from OTHER
rejection reasons. The server maps DipsError::TokensPerSecondTooLow and
TokensPerEntityPerSecondTooLow to PRICE_TOO_LOW, with all other errors
mapped to OTHER.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(dips): gate EscrowSignerValidator behind db feature

The signers module was importing indexer_monitor unconditionally, but
that crate is only available with the db feature. This caused compilation
failures when using only the rpc feature (as dipper does).

Changes:
- Move EscrowSignerValidator and its imports into a conditionally compiled
  module (#[cfg(feature = "db")])
- Keep SignerValidator trait, NoopSignerValidator, and RejectingSignerValidator
  always available since they have no external dependencies
- Gate escrow validator tests with #[cfg(all(test, feature = "db"))]
- Restore dips_cancellation_eip712_domain function that was accidentally
  removed during the V2 migration (needed for backwards compatibility)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(dips): rename proto enum values to follow naming conventions

The protobuf convention is to prefix enum values with the enum name.
Changed PRICE_TOO_LOW -> REJECT_REASON_PRICE_TOO_LOW and
OTHER -> REJECT_REASON_OTHER to match REJECT_REASON_UNSPECIFIED.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(dips): add unit tests for reject_reason_from_error

Tests verify the mapping from DipsError variants to RejectReason:
- TokensPerSecondTooLow -> PriceTooLow
- TokensPerEntityPerSecondTooLow -> PriceTooLow
- All other errors (UnsupportedNetwork, InvalidSignature, etc.) -> Other

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(dips): extract GRT formatting to helper function

The format_grt() function converts wei (10^-18 GRT) to a human-readable
GRT string with up to 18 decimal places, trimming trailing zeros.
This removes duplicated formatting logic in the dips_info_state setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(dips): add tests for GRT formatting edge cases

Tests cover:
- Zero value
- Whole numbers (1, 1000 GRT)
- Small values less than 1 GRT (0.5 GRT)
- Very small values (1 wei = 0.000000000000000001 GRT)
- Mixed values with decimals
- Trailing zeros are trimmed
- Values with many decimal places
- Large values with decimals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: apply nightly rustfmt

* fix: use maybe_dips_info for optional builder field

* fix: make DipsInfoResponse and DipsInfoPricing public

* chore: remove dips_version field from /dips/info response

V1 never existed in production, so versioning is unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: use GRT per billion entities instead of per million

The entity pricing unit has been changed from "GRT per million entities"
to "GRT per billion entities" for better human readability. At scale,
"0.2 GRT per million entities" sounds negligible but actually translates
to ~$4.50/TB/month - a meaningful cost that indexers might overlook.

Using "200 GRT per billion entities" makes the cost more apparent.

Changes:
- Config: min_grt_per_million_entities_per_30_days -> min_grt_per_billion_entities_per_30_days
- Default value: 0.2 -> 200 (same economics, just different unit)
- /dips/info endpoint: field renamed in response
- Internal conversion divisor: 1_000_000 -> 1_000_000_000

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(dips): add SIGNER_NOT_AUTHORISED rejection reason (#961)

SignerNotAuthorised errors were mapped to RejectReason::Other, which
causes dipper to block the indexer for 30 days. Signer authorization
is a transient config issue that resolves once the operator registers
the signer on the escrow contract, so a dedicated rejection reason
allows dipper to apply a much shorter lookback window.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat(dips): align RCA struct with indexing-payments-management-audit contracts (#964)

The RecurringCollector contract on the `indexing-payments-management-audit`
branch removed `bytes16 agreementId` from the RCA struct and replaced it with
`uint256 nonce`. Agreement IDs are now derived on-chain via
`bytes16(keccak256(abi.encode(payer, dataService, serviceProvider, deadline, nonce)))`.
The `deadline` and `endsAt` fields also changed from `uint256` to `uint64`.

Updates the sol! struct definition, adds `derive_agreement_id`, simplifies
`validate_and_create_rca` by removing fallible U256-to-u64 conversion, and
updates all test RCA constructions.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove misleading "v2" from DIPs migration and docs (#965)

There is no DIPs v1 -- the off-chain voucher system was abandoned before
deployment. DIPs refers exclusively to the on-chain RCA system. Rename
the migration from dips_v2 to dips_pending_proposals and clean up doc
comments that referenced "V2".

Also clarifies the migration ownership comment in service.rs: the
indexer-service does not run migrations by convention, the agent owns
DDL, and the SQL files here are for local dev and tests only.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat(dips): add specific rejection reasons to gRPC proto (#966)

The RejectReason proto enum only had 4 values (Unspecified, PriceTooLow,
Other, SignerNotAuthorised), so 6 of the 8 validation failures in
indexer-service mapped to the generic Other. Dipper uses the reason to
set exclusion periods and Other gets 30 days, meaning transient issues
like DeadlineExpired would incorrectly exclude an indexer for a month.

Added DeadlineExpired, UnsupportedNetwork, SubgraphManifestUnavailable,
UnexpectedServiceProvider, AgreementExpired, and
UnsupportedMetadataVersion to the proto and updated
reject_reason_from_error to map each DipsError variant to its specific
reason.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 4, 2026

Pull Request Test Coverage Report for Build 22678528353

Details

  • 1074 of 1248 (86.06%) changed or added relevant lines in 13 files are covered.
  • 39 unchanged lines in 5 files lost coverage.
  • Overall coverage increased (+0.3%) to 71.448%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/config/src/grt.rs 36 38 94.74%
crates/dips/src/database.rs 0 2 0.0%
crates/service/src/service/router.rs 4 6 66.67%
crates/dips/src/price.rs 85 88 96.59%
crates/dips/src/store.rs 56 59 94.92%
crates/dips/src/signers.rs 64 69 92.75%
crates/config/src/config.rs 52 60 86.67%
crates/service/src/routes/dips_info.rs 0 11 0.0%
crates/dips/src/ipfs.rs 54 79 68.35%
crates/dips/src/lib.rs 508 533 95.31%
Files with Coverage Reduction New Missed Lines %
crates/dips/src/ipfs.rs 1 69.72%
crates/dips/src/database.rs 3 0.0%
crates/dips/src/price.rs 4 92.93%
crates/service/src/service.rs 4 19.57%
crates/dips/src/lib.rs 27 90.79%
Totals Coverage Status
Change from base Build 22581500625: 0.3%
Covered Lines: 10808
Relevant Lines: 15127

💛 - Coveralls

@MoonBoi9001 MoonBoi9001 added the DIPs Decentralized Indexing Payments label Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DIPs Decentralized Indexing Payments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant