tap_aggregator 0.3.2

A JSON-RPC service for the Timeline Aggregation Protocol that lets clients request an aggregate receipt from a list of individual receipts.
Documentation
# TAP Aggregator

A stateless JSON-RPC service that lets clients request an aggregate receipt from a list of individual receipts.

## Settings

```txt
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](https://github.com/semiotic-ai/timeline-aggregation-protocol-contracts) for
more information about Receipt Aggregate Voucher signing keys.

## Operational recommendations

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.

## JSON-RPC API

### Common interface

#### Request format

The request format is standard, as described in
[the official spec](https://www.jsonrpc.org/specification#request_object).

#### Successful response format

If the call is successful, the response format is as described in
[the official spec](https://www.jsonrpc.org/specification#response_object), and in addition the `result` field is of the
form:

```json
{
    "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 deprecation

  Also returns an object containing the method's supported versions in the `data` field. Example:

  ```json
  {
      "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."
              }
          ]
      }
  }
  ```

#### Error response format

If the call fails, the error response format is as described in
[the official spec](https://www.jsonrpc.org/specification#error_object).

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:

  ```json
  {
      "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:

  ```json
  {
      "error": {
          "code": -32002,
          "message": "Signature verification failed. Expected 0x9858…da94, got 0x3ef9…a4a3"
      },
      "id": 0,
      "jsonrpc": "2.0"
  }
  ```

### Methods

#### `api_versions()`

[source](server::RpcServer::api_versions)

Returns the versions of the TAP JSON-RPC API implemented by this server.

Example:

*Request*:

```json
{
    "jsonrpc": "2.0",
    "id": 0,
    "method": "api_versions",
    "params": [
        null
    ]
}
```

*Response*:

```json
{
    "id": 0,
    "jsonrpc": "2.0",
    "result": {
        "data": {
            "versions_deprecated": [
               "0.0"
            ],
            "versions_supported": [
                "0.0",
                "0.1"
            ]
        }
    }
}
```

#### `aggregate_receipts(api_version, receipts, previous_rav)`

[source](server::RpcServer::aggregate_receipts)

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*:

```json
{
  "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*:

```json
{
  "id": 0,
  "jsonrpc": "2.0",
  "result": {
    "data": {
      "message": {
        "allocation_id": "0xabababababababababababababababababababab",
        "timestamp_ns": 1685670449225830106,
        "value_aggregate": 158
      },
      "signature": {
        "r": "0x60eb38374119bbabf1ac6960f532124ba2a9c5990d9fb50875b512e611847eb5",
        "s": "0x1b9a330cc9e2ecbda340a4757afaee8f55b6dbf278428f8cf49dd5ad8438f83d",
        "v": 27
      }
    }
  }
}
```