A stateless JSON-RPC service that lets clients request an aggregate receipt from a list of individual receipts.
TAP Aggregator is run by gateway operators.
As described in the gateway README section on TAP:
The
gateway
acts as a TAP sender, where each indexer request is sent with a TAP receipt. Thegateway
operator is expected to run 2 additional services:
tap-aggregator
(this crate!): public endpoint where indexers can aggregate receipts into RAVs- tap-escrow-manager: maintains escrow balances for the TAP sender. This service requires data exported by the gateway into the "indexer requests" topic to calculate the value of outstanding receipts to each indexer.
The
gateway
operator is also expected to manage at least 2 wallets:
- sender: requires ETH for transaction gas and GRT to allocate into TAP escrow balances for paying indexers
- authorized signer: used by the
gateway
andtap-aggregator
to sign receipts and RAVs
A JSON-RPC service for the Timeline Aggregation Protocol that lets clients request an aggregate receipt from a list of
individual receipts.
Usage: tap_aggregator [OPTIONS] --private-key <PRIVATE_KEY>
Options:
--port <PORT>
Port to listen on for JSON-RPC requests [env: TAP_PORT=] [default: 8080]
--private-key <PRIVATE_KEY>
Sender private key for signing Receipt Aggregate Vouchers, as a hex string [env: TAP_PRIVATE_KEY=]
--max-request-body-size <MAX_REQUEST_BODY_SIZE>
Maximum request body size in bytes. Defaults to 10MB [env: TAP_MAX_REQUEST_BODY_SIZE=] [default: 10485760]
--max-response-body-size <MAX_RESPONSE_BODY_SIZE>
Maximum response body size in bytes. Defaults to 100kB [env: TAP_MAX_RESPONSE_BODY_SIZE=] [default: 102400]
--max-connections <MAX_CONNECTIONS>
Maximum number of concurrent connections. Defaults to 32 [env: TAP_MAX_CONNECTIONS=] [default: 32]
-h, --help
Print help
-V, --version
Print version
Please refer to timeline-aggregation-protocol-contracts for more information about Receipt Aggregate Voucher signing keys.
This is just meant to be a non-exhaustive list of reminders for safely operating the TAP Aggregator. It being an HTTP service, use your best judgement and apply the industry-standard best practices when serving HTTP to the public internet.
- Advertise through a safe DNS service (w/ DNSSEC, etc)
- Expose through HTTPS only (by reverse-proxying)
- Use a WAF, to leverage (if available):
- DDoS protection, rate limiting, etc.
- Geofencing, depending on the operator's jurisdiction.
- HTTP response inspection.
- JSON request and response inspection. To validate the inputs, as well as parse JSON-RPC error codes in the response.
It is also recommended that clients use HTTP compression for their HTTP requests to the TAP Aggregator, as RAV requests can be quite large.
The request format is standard, as described in the official spec.
If the call is successful, the response format is as described in
the official spec, and in addition the result
field is of the
form:
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"data": {...},
"warnings": [
{
"code": -32000,
"message": "Error message",
"data": {...}
}
]
}
}
Field | Type | Description |
---|---|---|
data |
Object |
The response data. Method specific, see each method's documentation. |
warnings |
Array |
(Optional) A list of warnings. If the list is empty, no warning field is added to the JSON-RPC response. |
WARNING: Always check for warnings!
Warning object format (similar to the standard JSON-RPC error object):
Field | Type | Description |
---|---|---|
code |
Integer |
A number that indicates the error type that occurred. |
message |
String |
A short description of the error. |
data |
Object |
(Optional) A primitive or structured value that contains additional information about the error. |
We define these warning codes:
-
-32051
API version deprecationAlso returns an object containing the method's supported versions in the
data
field. Example:{ "id": 0, "jsonrpc": "2.0", "result": { "data": {...}, "warnings": [ { "code": -32051, "data": { "versions_deprecated": [ "0.0" ], "versions_supported": [ "0.0", "0.1" ] }, "message": "The API version 0.0 will be deprecated. Please check https://github.com/semiotic-ai/timeline_aggregation_protocol for more information." } ] } }
If the call fails, the error response format is as described in the official spec.
In addition to the official spec, we define a few special errors:
-
-32001
Invalid API version.Also returns an object containing the method's supported versions in the
data
field. Example:{ "error": { "code": -32001, "data": { "versions_deprecated": [ "0.0" ], "versions_supported": [ "0.0", "0.1" ] }, "message": "Unsupported API version: \"0.2\"." }, "id": 0, "jsonrpc": "2.0" }
-
-32002
Aggregation error.The aggregation function returned an error. Example:
{ "error": { "code": -32002, "message": "Signature verification failed. Expected 0x9858…da94, got 0x3ef9…a4a3" }, "id": 0, "jsonrpc": "2.0" }
source
Returns the versions of the TAP JSON-RPC API implemented by this server.
Example:
Request:
{
"jsonrpc": "2.0",
"id": 0,
"method": "api_versions",
"params": [
null
]
}
Response:
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"data": {
"versions_deprecated": [
"0.0"
],
"versions_supported": [
"0.0",
"0.1"
]
}
}
}
source
Aggregates the given receipts into a receipt aggregate voucher. Returns an error if the user expected API version is not supported.
We recommend that the server is set-up to support a maximum HTTP request size of 10MB, in which case we guarantee that
aggregate_receipts
support a maximum of at least 15,000 receipts per call. If you have more than 15,000 receipts to
aggregate, we recommend calling aggregate_receipts
multiple times.
Example:
Request:
{
"jsonrpc": "2.0",
"id": 0,
"method": "aggregate_receipts",
"params": [
"0.0",
[
{
"message": {
"allocation_id": "0xabababababababababababababababababababab",
"timestamp_ns": 1685670449225087255,
"nonce": 11835827017881841442,
"value": 34
},
"signature": {
"r": "0xa9fa1acf3cc3be503612f75602e68cc22286592db1f4f944c78397cbe529353b",
"s": "0x566cfeb7e80a393021a443d5846c0734d25bcf54ed90d97effe93b1c8aef0911",
"v": 27
}
},
{
"message": {
"allocation_id": "0xabababababababababababababababababababab",
"timestamp_ns": 1685670449225830106,
"nonce": 17711980309995246801,
"value": 23
},
"signature": {
"r": "0x51ca5a2b839558654326d3a3f544a97d94effb9a7dd9cac7492007bc974e91f0",
"s": "0x3d9d398ea6b0dd9fac97726f51c0840b8b314821fb4534cb40383850c431fd9e",
"v": 28
}
}
],
{
"message": {
"allocation_id": "0xabababababababababababababababababababab",
"timestamp_ns": 1685670449224324338,
"value_aggregate": 101
},
"signature": {
"r": "0x601a1f399cf6223d1414a89b7bbc90ee13eeeec006bd59e0c96042266c6ad7dc",
"s": "0x3172e795bd190865afac82e3a8be5f4ccd4b65958529986c779833625875f0b2",
"v": 28
}
}
]
}
Response:
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"data": {
"message": {
"allocation_id": "0xabababababababababababababababababababab",
"timestamp_ns": 1685670449225830106,
"value_aggregate": 158
},
"signature": {
"r": "0x60eb38374119bbabf1ac6960f532124ba2a9c5990d9fb50875b512e611847eb5",
"s": "0x1b9a330cc9e2ecbda340a4757afaee8f55b6dbf278428f8cf49dd5ad8438f83d",
"v": 27
}
}
}
}