# `postStateQuery` & `postBlockQuery` API Specification
> [!Note]
> Implementing these endpoints is a part of [EPF6](https://github.com/eth-protocol-fellows/cohort-six) project by [Jun](https://github.com/syjn99) and [Nando](https://github.com/fernantho). You could check our project [proposal](https://hackmd.io/@junsong/HkQ9XBEHel) to get more context ([motivation](https://hackmd.io/@junsong/HkQ9XBEHel#Motivation), progress, etc.).
## Introduction
Handles single query on `BeaconState` and `BeaconBlock` with proof of inclusion. Returns as bytes serialized by SSZ.
## Common objects
### Request Body
| Name | Type | Description |
| --- | --- | --- |
| `query` | `string` | A merkle path to the item |
| `include_proof` | `boolean` | Whether including a merkle proof or not. Default to false. |
Every request MUST satisfy the JSON schema below, otherwise will return `400 Bad Request`. See [Example sections](#Example) for example requests.
```json
{
"$schema": "https://json-schema.org/draft-07/schema",
"title": "Query Object for SSZ QL",
"description": "Schema for SSZ query object",
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "A merkle path to the item"
},
"include_proof": {
"type": "boolean",
"description": "Whether including a merkle proof or not. Default to false."
}
},
"required": [
"query"
]
}
```
### Response
| Code | Description | Content |
| --- | --- | --- |
| `200` | Success | Response as bytes serialized by SSZ. See [SSZ definition below](#Response-Schema). `Eth-Consensus-Version` is included in header for indicating the active consensus version to which the data belongs. |
| `400` | Invalid ID or malformed request | N/A |
| `404` | Not found | N/A |
| `406` | Accepted media type is not supported. | N/A |
| `500` | Internal server error | N/A |
| `503` | Beacon node is currently syncing and not serving request on that endpoint | N/A |
See [Example sections](#Example) for example responses.
#### Response Schema
We need to define new SSZ containers for the query response.
First, we define constants below:
| Name | Value | Description |
| --- | --- | --- |
| `SSZ_QUERY_MAX_TREE_DEPTH` | `uint64(64)` | Maxium depth that SSZ-QL traverses through a merkle tree. Inspired from `VALIDATOR_REGISTRY_LIMIT`(= `2**40`), we need at least `50` to query `.validators[0].activation_epoch`. |
| `SSZ_QUERY_MAX_RESULT_LENGTH` | `uint64(2**30)` (= 1GB) | Maximum size that the query result can have. |
Here's the definition of necessary container, with descriptions of each fields. Note that `ResponseWithProof` is only used when `include_proof` sets to `true`.
```python
class SSZQueryProof(Container):
leaf: Bytes32
gindex: uint64
proofs: List[Bytes32, SSZ_QUERY_MAX_TREE_DEPTH]
class SSZQueryResponse(Container):
root: Bytes32
result: ByteList[SSZ_QUERY_MAX_RESULT_LENGTH]
class SSZQueryResponseWithProof(Container):
root: Bytes32
result: ByteList[SSZ_QUERY_MAX_RESULT_LENGTH]
proof: Proof
```
| Field | Type | Description |
| --- | --- | --- |
| `root` | `Bytes32` | The root value of requested state or block. |
| `result` | `ByteList[SSZ_QUERY_MAX_RESULT_LENGTH]` | The requested query result. |
| `leaf` | `Bytes32` | An hash value corresponding to the queried path. |
| `gindex` | `uint64` | A generalized index for the queired path. |
| `proofs` | `List[Bytes32, SSZ_QUERY_MAX_TREE_DEPTH]` | An array of proof that are sorted **descending order** by the generalized index. |
---
## `postStateQuery` Specification
- Endpoint: `/eth/v1/beacon/states/{state_id}/query`
- Method: `POST`
- HTTP Header
- `accept`: `application/octet-stream`, otherwise it will return `406` error.
### Parameters
| Name | Type | Description | Possible Values |
|---|---|---|---|
| `state_id` | `string` (path) | State identifier. | Can be one of: "head" (canonical head in node's view), "genesis", "finalized", "justified", \<slot\>, \<hex encoded stateRoot with 0x prefix\> |
---
## `postBlockQuery` Specification
- Endpoint: `/eth/v1/beacon/blocks/{block_id}/query`
- Method: `POST`
- HTTP Header
- `accept`: `application/octet-stream`, otherwise it will return `406` error.
### Parameters
| Name | Type | Description | Possible Values |
|---|---|---|---|
| `block_id` | `string` (path) | Block identifier. | Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \<slot\>, \<hex encoded blockRoot with 0x prefix\> |
---
## Example
### 1. Without proof (`include_proof` is false)
Request:
```
POST /eth/v1/beacon/states/finalized/query
```
Request body:
```json
{
"query": ".genesis_validators_root",
"include_proof": false
}
```
If we decode the response by SSZ:
```json
{
"root": "0xf1f2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1",
"result": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"
}
```
---
Request:
```
POST /eth/v1/beacon/states/finalized/query
```
Request body:
```json
{
"query": ".validators[100]",
"include_proof": false
}
```
If we decode the response by SSZ:
```json
{
"root": "0xf1f2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1",
"result": {
"pubkey": "0x8f2a41e5b6c71234abcd5678ef90ff11223344556677889900aabbccddeeff0",
"withdrawal_credentials": "0x00aa2753bbcc...99",
"effective_balance": "32000000000",
"slashed": false,
"activation_eligibility_epoch": "64",
"activation_epoch": "64",
"exit_epoch": "18446744073709551615",
"withdrawable_epoch": "18446744073709551615"
}
}
```
### 2. With proof
Request:
```
POST /eth/v1/beacon/states/finalized/query
```
Request body:
```json
{
"query": ".genesis_validators_root",
"include_proof": true
}
```
If we decode the response by SSZ:
```json
{
"root": "0xf1f2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1",
"result": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
"proof": {
"leaf": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
"gindex": "65",
"proofs": [
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
]
}
}
```
---
Request:
```
POST /eth/v1/beacon/states/finalized/query
```
Request body:
```json
{
"query": ".validators[100]",
"include_proof": true
}
```
If we decode the response by SSZ:
```json
{
"root": "0xf1f2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1",
"result": {
"pubkey": "0x8f2a41e5b6c71234abcd5678ef90ff11223344556677889900aabbccddeeff0",
"withdrawal_credentials": "0x00aa2753bbcc...99",
"effective_balance": "32000000000",
"slashed": false,
"activation_eligibility_epoch": "64",
"activation_epoch": "64",
"exit_epoch": "18446744073709551615",
"withdrawable_epoch": "18446744073709551615"
},
"proof": {
"leaf": "0x12345678deadbeefcafebabef00dabad12345678deadbeefcafebabef00dabad",
"gindex": "8796093023233",
"proofs": [
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
]
}
}
```