|
2 | 2 |
|
3 | 3 | A stateless JSON-RPC service that lets clients request an aggregate receipt from a list of individual receipts. |
4 | 4 |
|
| 5 | +Supports both V1 (allocation-based) and V2 (collection-based) aggregation protocols for seamless migration to the Horizon protocol. |
| 6 | + |
5 | 7 | TAP Aggregator is run by [gateway](https://github.com/edgeandnode/gateway/blob/main/README.md) |
6 | 8 | operators. |
7 | 9 |
|
@@ -189,6 +191,11 @@ In addition to the official spec, we define a few special errors: |
189 | 191 |
|
190 | 192 | ### Methods |
191 | 193 |
|
| 194 | +This aggregator supports both V1 (legacy) and V2 (Horizon) protocols: |
| 195 | + |
| 196 | +- **V1 Endpoints**: `aggregate_receipts` - allocation-based aggregation |
| 197 | +- **V2 Endpoints**: `aggregate_receipts_v2` - collection-based aggregation with enhanced fields |
| 198 | + |
192 | 199 | #### `api_versions()` |
193 | 200 |
|
194 | 201 | [source](server::RpcServer::api_versions) |
@@ -318,3 +325,170 @@ Example: |
318 | 325 | } |
319 | 326 | } |
320 | 327 | ``` |
| 328 | + |
| 329 | +#### `aggregate_receipts_v2(api_version, receipts, previous_rav)` |
| 330 | + |
| 331 | +Aggregates the given V2 receipts into a V2 receipt aggregate voucher using the Horizon protocol. |
| 332 | +This method supports collection-based aggregation with enhanced fields for payer, data service, and service provider tracking. |
| 333 | + |
| 334 | +**V2 Receipt Structure:** |
| 335 | + |
| 336 | +- `collection_id`: 32-byte identifier for the collection (replaces `allocation_id`) |
| 337 | +- `payer`: Address of the payer |
| 338 | +- `data_service`: Address of the data service |
| 339 | +- `service_provider`: Address of the service provider |
| 340 | +- `timestamp_ns`: Timestamp in nanoseconds |
| 341 | +- `nonce`: Unique nonce |
| 342 | +- `value`: Receipt value |
| 343 | + |
| 344 | +**V2 RAV Structure:** |
| 345 | + |
| 346 | +- `collectionId`: Collection identifier (replaces `allocation_id`) |
| 347 | +- `payer`: Payer address |
| 348 | +- `dataService`: Data service address |
| 349 | +- `serviceProvider`: Service provider address |
| 350 | +- `timestampNs`: Latest timestamp |
| 351 | +- `valueAggregate`: Total aggregated value |
| 352 | +- `metadata`: Additional metadata (bytes) |
| 353 | + |
| 354 | +Example: |
| 355 | + |
| 356 | +*Request*: |
| 357 | + |
| 358 | +```json |
| 359 | +{ |
| 360 | + "jsonrpc": "2.0", |
| 361 | + "id": 0, |
| 362 | + "method": "aggregate_receipts_v2", |
| 363 | + "params": [ |
| 364 | + "1.0.0", |
| 365 | + [ |
| 366 | + { |
| 367 | + "message": { |
| 368 | + "collection_id": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 369 | + "payer": "0xabababababababababababababababababababab", |
| 370 | + "data_service": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 371 | + "service_provider": "0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef", |
| 372 | + "timestamp_ns": 1685670449225087255, |
| 373 | + "nonce": 11835827017881841442, |
| 374 | + "value": 34 |
| 375 | + }, |
| 376 | + "signature": { |
| 377 | + "r": "0xa9fa1acf3cc3be503612f75602e68cc22286592db1f4f944c78397cbe529353b", |
| 378 | + "s": "0x566cfeb7e80a393021a443d5846c0734d25bcf54ed90d97effe93b1c8aef0911", |
| 379 | + "v": 27 |
| 380 | + } |
| 381 | + }, |
| 382 | + { |
| 383 | + "message": { |
| 384 | + "collection_id": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 385 | + "payer": "0xabababababababababababababababababababab", |
| 386 | + "data_service": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 387 | + "service_provider": "0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef", |
| 388 | + "timestamp_ns": 1685670449225830106, |
| 389 | + "nonce": 17711980309995246801, |
| 390 | + "value": 23 |
| 391 | + }, |
| 392 | + "signature": { |
| 393 | + "r": "0x51ca5a2b839558654326d3a3f544a97d94effb9a7dd9cac7492007bc974e91f0", |
| 394 | + "s": "0x3d9d398ea6b0dd9fac97726f51c0840b8b314821fb4534cb40383850c431fd9e", |
| 395 | + "v": 28 |
| 396 | + } |
| 397 | + } |
| 398 | + ], |
| 399 | + { |
| 400 | + "message": { |
| 401 | + "collectionId": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 402 | + "payer": "0xabababababababababababababababababababab", |
| 403 | + "dataService": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 404 | + "serviceProvider": "0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef", |
| 405 | + "timestampNs": 1685670449224324338, |
| 406 | + "valueAggregate": 101, |
| 407 | + "metadata": "0x" |
| 408 | + }, |
| 409 | + "signature": { |
| 410 | + "r": "0x601a1f399cf6223d1414a89b7bbc90ee13eeeec006bd59e0c96042266c6ad7dc", |
| 411 | + "s": "0x3172e795bd190865afac82e3a8be5f4ccd4b65958529986c779833625875f0b2", |
| 412 | + "v": 28 |
| 413 | + } |
| 414 | + } |
| 415 | + ] |
| 416 | +} |
| 417 | +``` |
| 418 | + |
| 419 | +*Response*: |
| 420 | + |
| 421 | +```json |
| 422 | +{ |
| 423 | + "id": 0, |
| 424 | + "jsonrpc": "2.0", |
| 425 | + "result": { |
| 426 | + "data": { |
| 427 | + "message": { |
| 428 | + "collectionId": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 429 | + "payer": "0xabababababababababababababababababababab", |
| 430 | + "dataService": "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead", |
| 431 | + "serviceProvider": "0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef", |
| 432 | + "timestampNs": 1685670449225830106, |
| 433 | + "valueAggregate": 158, |
| 434 | + "metadata": "0x" |
| 435 | + }, |
| 436 | + "signature": { |
| 437 | + "r": "0x60eb38374119bbabf1ac6960f532124ba2a9c5990d9fb50875b512e611847eb5", |
| 438 | + "s": "0x1b9a330cc9e2ecbda340a4757afaee8f55b6dbf278428f8cf49dd5ad8438f83d", |
| 439 | + "v": 27 |
| 440 | + } |
| 441 | + } |
| 442 | + } |
| 443 | +} |
| 444 | +``` |
| 445 | + |
| 446 | +## Feature Flags |
| 447 | + |
| 448 | +### V2 Protocol Support |
| 449 | + |
| 450 | +The aggregator supports both V1 and V2 protocols: |
| 451 | + |
| 452 | +- **V2 is enabled by default** via the `v2` feature flag in `tap_aggregator/Cargo.toml` |
| 453 | +- To disable V2: `cargo build --no-default-features` |
| 454 | +- Both protocols can run simultaneously for gradual migration |
| 455 | +- V1 endpoints remain unchanged and fully functional |
| 456 | + |
| 457 | +### Feature Flag Usage |
| 458 | + |
| 459 | +```bash |
| 460 | +# Build with V2 support (default) |
| 461 | +cargo build --release |
| 462 | + |
| 463 | +# Build without V2 support (V1 only) |
| 464 | +cargo build --release --no-default-features |
| 465 | + |
| 466 | +# Explicitly enable V2 feature |
| 467 | +cargo build --release --features v2 |
| 468 | +``` |
| 469 | + |
| 470 | +## Migration Guide |
| 471 | + |
| 472 | +### V1 to V2 Migration |
| 473 | + |
| 474 | +The V2 protocol introduces collection-based aggregation with enhanced tracking. Here's how to migrate: |
| 475 | + |
| 476 | +#### Key Changes |
| 477 | + |
| 478 | +1. **Receipt Structure**: `allocation_id` → `collection_id` + additional fields |
| 479 | +2. **RAV Structure**: `allocation_id` → `collectionId` + additional fields |
| 480 | +3. **New Fields**: `payer`, `data_service`/`dataService`, `service_provider`/`serviceProvider` |
| 481 | +4. **Metadata**: V2 RAVs include optional `metadata` field |
| 482 | + |
| 483 | +#### Migration Steps |
| 484 | + |
| 485 | +1. **Phase 1**: Deploy aggregator with V2 support (both endpoints available) |
| 486 | +2. **Phase 2**: Update clients to use V2 receipt structure |
| 487 | +3. **Phase 3**: Switch clients to `aggregate_receipts_v2` endpoint |
| 488 | +4. **Phase 4**: V1 endpoints remain for backward compatibility |
| 489 | + |
| 490 | +#### Backward Compatibility |
| 491 | + |
| 492 | +- **V1 endpoints**: Unchanged and fully functional |
| 493 | +- **gRPC support**: Both V1 and V2 with automatic conversion |
| 494 | +- **No breaking changes**: Existing V1 clients continue to work |
0 commit comments