diff --git a/Makefile b/Makefile
index ead30b20c..e8838ede5 100644
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,7 @@ clean:
# Builds the protobuf files inside a docker container.
protoc: clean
./api/builder/protoc-docker.sh
+ ./api/builder/generate-docs.sh
# Builds the protobuf files locally (i.e. without docker).
protoc-local: clean
diff --git a/api/builder/generate-docs.sh b/api/builder/generate-docs.sh
new file mode 100755
index 000000000..3701e1b4b
--- /dev/null
+++ b/api/builder/generate-docs.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+
+# This script generates protobuf documentation.
+
+# The location where this script can be found.
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+API_DIR="${SCRIPT_DIR}/.."
+PROTO_DIR="${API_DIR}/proto"
+DOCS_DIR="${API_DIR}/docs"
+
+# Function to get the relative path of file in argument 1 with respect directory in argument 2.
+# Doesn't use the convenient 'realpath --relative-to' because it's not available on macOS.
+relativePath() {
+ python3 -c 'import os.path, sys; print(os.path.relpath(sys.argv[1],sys.argv[2]))' "${1}" "${2}"
+}
+
+# Find all .proto files.
+PROTO_FILES=( $(find "${PROTO_DIR}" -name '*.proto') )
+
+# Make the proto files relative to the proto directory.
+for i in "${!PROTO_FILES[@]}"; do
+ PROTO_FILES[$i]=$(relativePath "${PROTO_FILES[$i]}" "${PROTO_DIR}")
+done
+
+# Generate HTML doc
+docker run --rm \
+ -v "${DOCS_DIR}":/out \
+ -v "${PROTO_DIR}":/protos \
+ pseudomuto/protoc-gen-doc \
+ "${PROTO_FILES[@]}" \
+ --doc_opt=html,eigenda-protos.html
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+# Generate markdown doc
+docker run --rm \
+ -v "${DOCS_DIR}":/out \
+ -v "${PROTO_DIR}":/protos \
+ pseudomuto/protoc-gen-doc \
+ "${PROTO_FILES[@]}" \
+ --doc_opt=markdown,eigenda-protos.md
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
diff --git a/api/docs/README.md b/api/docs/README.md
deleted file mode 100644
index 65c77332f..000000000
--- a/api/docs/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-This folder contains the API documentation for the gRPC services included in the EigenDA platform. Each markdown file contains the protobuf definitions for each respective service including:
-- Churner: a hosted service responsible for maintaining the active set of Operators in the EigenDA network based on their delegated TVL.
-- Disperser: the hosted service and primary point of interaction for Rollup users.
-- Node: individual EigenDA nodes run on the network by EigenLayer Operators.
-- Retriever: a service that users can run on their own infrastructure, which exposes a gRPC endpoint for retrieval of blobs from EigenDA nodes.
-
diff --git a/api/docs/churner.md b/api/docs/churner.md
deleted file mode 100644
index 8faa1c82c..000000000
--- a/api/docs/churner.md
+++ /dev/null
@@ -1,144 +0,0 @@
-# Protocol Documentation
-
-
-## Table of Contents
-
-- [churner.proto](#churner-proto)
- - [ChurnReply](#churner-ChurnReply)
- - [ChurnRequest](#churner-ChurnRequest)
- - [OperatorToChurn](#churner-OperatorToChurn)
- - [SignatureWithSaltAndExpiry](#churner-SignatureWithSaltAndExpiry)
-
- - [Churner](#churner-Churner)
-
-- [Scalar Value Types](#scalar-value-types)
-
-
-
-
-
-
-## churner.proto
-
-
-
-
-
-### ChurnReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| signature_with_salt_and_expiry | [SignatureWithSaltAndExpiry](#churner-SignatureWithSaltAndExpiry) | | The signature signed by the Churner. |
-| operators_to_churn | [OperatorToChurn](#churner-OperatorToChurn) | repeated | A list of existing operators that get churned out. This list will contain all quorums specified in the ChurnRequest even if some quorums may not have any churned out operators. If a quorum has available space, OperatorToChurn object will contain the quorum ID and empty operator and pubkey. The smart contract should only churn out the operators for quorums that are full.
-
-For example, if the ChurnRequest specifies quorums 0 and 1 where quorum 0 is full and quorum 1 has available space, the ChurnReply will contain two OperatorToChurn objects with the respective quorums. OperatorToChurn for quorum 0 will contain the operator to churn out and OperatorToChurn for quorum 1 will contain empty operator (zero address) and pubkey. The smart contract should only churn out the operators for quorum 0 because quorum 1 has available space without having any operators churned. Note: it's possible an operator gets churned out just for one or more quorums (rather than entirely churned out for all quorums). |
-
-
-
-
-
-
-
-
-### ChurnRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| operator_address | [string](#string) | | The Ethereum address (in hex like "0x123abcdef...") of the operator. |
-| operator_to_register_pubkey_g1 | [bytes](#bytes) | | The operator making the churn request. |
-| operator_to_register_pubkey_g2 | [bytes](#bytes) | | |
-| operator_request_signature | [bytes](#bytes) | | The operator's BLS signature signed on the keccak256 hash of concat("ChurnRequest", operator address, g1, g2, salt). |
-| salt | [bytes](#bytes) | | The salt used as part of the message to sign on for operator_request_signature. |
-| quorum_ids | [uint32](#uint32) | repeated | The quorums to register for. Note: - If any of the quorum here has already been registered, this entire request will fail to proceed. - If any of the quorum fails to register, this entire request will fail. - Regardless of whether the specified quorums are full or not, the Churner will return parameters for all quorums specified here. The smart contract will determine whether it needs to churn out existing operators based on whether the quorums have available space. The IDs must be in range [0, 254]. |
-
-
-
-
-
-
-
-
-### OperatorToChurn
-This describes an operator to churn out for a quorum.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| quorum_id | [uint32](#uint32) | | The ID of the quorum of the operator to churn out. |
-| operator | [bytes](#bytes) | | The address of the operator. |
-| pubkey | [bytes](#bytes) | | BLS pubkey (G1 point) of the operator. |
-
-
-
-
-
-
-
-
-### SignatureWithSaltAndExpiry
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| signature | [bytes](#bytes) | | Churner's signature on the Operator's attributes. |
-| salt | [bytes](#bytes) | | Salt is the keccak256 hash of concat("churn", time.Now(), operatorToChurn's OperatorID, Churner's ECDSA private key) |
-| expiry | [int64](#int64) | | When this churn decision will expire. |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-### Churner
-The Churner is a service that handles churn requests from new operators trying to
-join the EigenDA network.
-When the EigenDA network reaches the maximum number of operators, any new operator
-trying to join will have to make a churn request to this Churner, which acts as the
-sole decision maker to decide whether this new operator could join, and if so, which
-existing operator will be churned out (so the max number of operators won't be
-exceeded).
-The max number of operators, as well as the rules to make churn decisions, are
-defined onchain, see details in OperatorSetParam at:
-https://github.com/Layr-Labs/eigenlayer-middleware/blob/master/src/interfaces/IBLSRegistryCoordinatorWithIndices.sol#L24.
-
-| Method Name | Request Type | Response Type | Description |
-| ----------- | ------------ | ------------- | ------------|
-| Churn | [ChurnRequest](#churner-ChurnRequest) | [ChurnReply](#churner-ChurnReply) | |
-
-
-
-
-
-## Scalar Value Types
-
-| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
-| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |
-| double | | double | double | float | float64 | double | float | Float |
-| float | | float | float | float | float32 | float | float | Float |
-| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
-| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
-| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
-| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
-| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| bool | | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |
-| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
-| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
-
diff --git a/api/docs/disperser.md b/api/docs/disperser.md
deleted file mode 100644
index 6def32751..000000000
--- a/api/docs/disperser.md
+++ /dev/null
@@ -1,413 +0,0 @@
-# Protocol Documentation
-
-
-## Table of Contents
-
-- [disperser/disperser.proto](#disperser_disperser-proto)
- - [AuthenticatedReply](#disperser-AuthenticatedReply)
- - [AuthenticatedRequest](#disperser-AuthenticatedRequest)
- - [AuthenticationData](#disperser-AuthenticationData)
- - [BatchHeader](#disperser-BatchHeader)
- - [BatchMetadata](#disperser-BatchMetadata)
- - [BlobAuthHeader](#disperser-BlobAuthHeader)
- - [BlobHeader](#disperser-BlobHeader)
- - [BlobInfo](#disperser-BlobInfo)
- - [BlobQuorumParam](#disperser-BlobQuorumParam)
- - [BlobStatusReply](#disperser-BlobStatusReply)
- - [BlobStatusRequest](#disperser-BlobStatusRequest)
- - [BlobVerificationProof](#disperser-BlobVerificationProof)
- - [DisperseBlobReply](#disperser-DisperseBlobReply)
- - [DisperseBlobRequest](#disperser-DisperseBlobRequest)
- - [RetrieveBlobReply](#disperser-RetrieveBlobReply)
- - [RetrieveBlobRequest](#disperser-RetrieveBlobRequest)
-
- - [BlobStatus](#disperser-BlobStatus)
-
- - [Disperser](#disperser-Disperser)
-
-- [common/common.proto](#common_common-proto)
- - [G1Commitment](#common-G1Commitment)
-
-- [Scalar Value Types](#scalar-value-types)
-
-
-
-
-
-
-## disperser/disperser.proto
-
-
-
-
-
-### AuthenticatedReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| blob_auth_header | [BlobAuthHeader](#disperser-BlobAuthHeader) | | |
-| disperse_reply | [DisperseBlobReply](#disperser-DisperseBlobReply) | | |
-
-
-
-
-
-
-
-
-### AuthenticatedRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| disperse_request | [DisperseBlobRequest](#disperser-DisperseBlobRequest) | | |
-| authentication_data | [AuthenticationData](#disperser-AuthenticationData) | | |
-
-
-
-
-
-
-
-
-### AuthenticationData
-AuthenticationData contains the signature of the BlobAuthHeader.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| authentication_data | [bytes](#bytes) | | |
-
-
-
-
-
-
-
-
-### BatchHeader
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_root | [bytes](#bytes) | | The root of the merkle tree with the hashes of blob headers as leaves. |
-| quorum_numbers | [bytes](#bytes) | | All quorums associated with blobs in this batch. Sorted in ascending order. Ex. [0, 2, 1] => 0x000102 |
-| quorum_signed_percentages | [bytes](#bytes) | | The percentage of stake that has signed for this batch. The quorum_signed_percentages[i] is percentage for the quorum_numbers[i]. |
-| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch was created. The Disperser will encode and disperse the blobs based on the onchain info (e.g. operator stakes) at this block number. |
-
-
-
-
-
-
-
-
-### BatchMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header | [BatchHeader](#disperser-BatchHeader) | | |
-| signatory_record_hash | [bytes](#bytes) | | The hash of all public keys of the operators that did not sign the batch. |
-| fee | [bytes](#bytes) | | The fee payment paid by users for dispersing this batch. It's the bytes representation of a big.Int value. |
-| confirmation_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch is confirmed onchain. |
-| batch_header_hash | [bytes](#bytes) | | This is the hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 The is the message that the operators will sign their signatures on. |
-
-
-
-
-
-
-
-
-### BlobAuthHeader
-BlobAuthHeader contains information about the blob for the client to verify and sign.
-- Once payments are enabled, the BlobAuthHeader will contain the KZG commitment to the blob, which the client
-will verify and sign. Having the client verify the KZG commitment instead of calculating it avoids
-the need for the client to have the KZG structured reference string (SRS), which can be large.
-The signed KZG commitment prevents the disperser from sending a different blob to the DA Nodes
-than the one the client sent.
-- In the meantime, the BlobAuthHeader contains a simple challenge parameter is used to prevent
-replay attacks in the event that a signature is leaked.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| challenge_parameter | [uint32](#uint32) | | |
-
-
-
-
-
-
-
-
-### BlobHeader
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| commitment | [common.G1Commitment](#common-G1Commitment) | | KZG commitment of the blob. |
-| data_length | [uint32](#uint32) | | The length of the blob in symbols (each symbol is 32 bytes). |
-| blob_quorum_params | [BlobQuorumParam](#disperser-BlobQuorumParam) | repeated | The params of the quorums that this blob participates in. |
-
-
-
-
-
-
-
-
-### BlobInfo
-BlobInfo contains information needed to confirm the blob against the EigenDA contracts
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| blob_header | [BlobHeader](#disperser-BlobHeader) | | |
-| blob_verification_proof | [BlobVerificationProof](#disperser-BlobVerificationProof) | | |
-
-
-
-
-
-
-
-
-### BlobQuorumParam
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| quorum_number | [uint32](#uint32) | | The ID of the quorum. |
-| adversary_threshold_percentage | [uint32](#uint32) | | The max percentage of stake within the quorum that can be held by or delegated to adversarial operators. Currently, this and the next parameter are standardized across the quorum using values read from the EigenDA contracts. |
-| confirmation_threshold_percentage | [uint32](#uint32) | | The min percentage of stake that must attest in order to consider the dispersal is successful. |
-| chunk_length | [uint32](#uint32) | | The length of each chunk. |
-
-
-
-
-
-
-
-
-### BlobStatusReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| status | [BlobStatus](#disperser-BlobStatus) | | The status of the blob. |
-| info | [BlobInfo](#disperser-BlobInfo) | | The blob info needed for clients to confirm the blob against the EigenDA contracts. |
-
-
-
-
-
-
-
-
-### BlobStatusRequest
-BlobStatusRequest is used to query the status of a blob.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| request_id | [bytes](#bytes) | | |
-
-
-
-
-
-
-
-
-### BlobVerificationProof
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_id | [uint32](#uint32) | | batch_id is an incremental ID assigned to a batch by EigenDAServiceManager |
-| blob_index | [uint32](#uint32) | | The index of the blob in the batch (which is logically an ordered list of blobs). |
-| batch_metadata | [BatchMetadata](#disperser-BatchMetadata) | | |
-| inclusion_proof | [bytes](#bytes) | | inclusion_proof is a merkle proof for a blob header's inclusion in a batch |
-| quorum_indexes | [bytes](#bytes) | | indexes of quorums in BatchHeader.quorum_numbers that match the quorums in BlobHeader.blob_quorum_params Ex. BlobHeader.blob_quorum_params = [ { quorum_number = 0, ... }, { quorum_number = 3, ... }, { quorum_number = 5, ... }, ] BatchHeader.quorum_numbers = [0, 5, 3] => 0x000503 Then, quorum_indexes = [0, 2, 1] => 0x000201 |
-
-
-
-
-
-
-
-
-### DisperseBlobReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| result | [BlobStatus](#disperser-BlobStatus) | | The status of the blob associated with the request_id. |
-| request_id | [bytes](#bytes) | | The request ID generated by the disperser. Once a request is accepted (although not processed), a unique request ID will be generated. Two different DisperseBlobRequests (determined by the hash of the DisperseBlobRequest) will have different IDs, and the same DisperseBlobRequest sent repeatedly at different times will also have different IDs. The client should use this ID to query the processing status of the request (via the GetBlobStatus API). |
-
-
-
-
-
-
-
-
-### DisperseBlobRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| data | [bytes](#bytes) | | The data to be dispersed. The size of data must be <= 2MiB. Every 32 bytes of data chunk is interpreted as an integer in big endian format where the lower address has more significant bits. The integer must stay in the valid range to be interpreted as a field element on the bn254 curve. The valid range is 0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617 containing slightly less than 254 bits and more than 253 bits. If any one of the 32 bytes chunk is outside the range, the whole request is deemed as invalid, and rejected. |
-| custom_quorum_numbers | [uint32](#uint32) | repeated | The quorums to which the blob will be sent, in addition to the required quorums which are configured on the EigenDA smart contract. If required quorums are included here, an error will be returned. The disperser will ensure that the encoded blobs for each quorum are all processed within the same batch. |
-| account_id | [string](#string) | | The account ID of the client. This should be a hex-encoded string of the ECSDA public key corresponding to the key used by the client to sign the BlobAuthHeader. |
-
-
-
-
-
-
-
-
-### RetrieveBlobReply
-RetrieveBlobReply contains the retrieved blob data
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| data | [bytes](#bytes) | | |
-
-
-
-
-
-
-
-
-### RetrieveBlobRequest
-RetrieveBlobRequest contains parameters to retrieve the blob.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header_hash | [bytes](#bytes) | | |
-| blob_index | [uint32](#uint32) | | |
-
-
-
-
-
-
-
-
-
-
-### BlobStatus
-BlobStatus represents the status of a blob.
-The status of a blob is updated as the blob is processed by the disperser.
-The status of a blob can be queried by the client using the GetBlobStatus API.
-Intermediate states are states that the blob can be in while being processed, and it can be updated to a differet state:
-- PROCESSING
-- DISPERSING
-- CONFIRMED
-Terminal states are states that will not be updated to a different state:
-- FAILED
-- FINALIZED
-- INSUFFICIENT_SIGNATURES
-
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| UNKNOWN | 0 | |
-| PROCESSING | 1 | PROCESSING means that the blob is currently being processed by the disperser |
-| CONFIRMED | 2 | CONFIRMED means that the blob has been dispersed to DA Nodes and the dispersed batch containing the blob has been confirmed onchain |
-| FAILED | 3 | FAILED means that the blob has failed permanently (for reasons other than insufficient signatures, which is a separate state) |
-| FINALIZED | 4 | FINALIZED means that the block containing the blob's confirmation transaction has been finalized on Ethereum |
-| INSUFFICIENT_SIGNATURES | 5 | INSUFFICIENT_SIGNATURES means that the confirmation threshold for the blob was not met for at least one quorum. |
-| DISPERSING | 6 | DISPERSING means that the blob is currently being dispersed to DA Nodes and being confirmed onchain |
-
-
-
-
-
-
-
-
-
-### Disperser
-Disperser defines the public APIs for dispersing blobs.
-
-| Method Name | Request Type | Response Type | Description |
-| ----------- | ------------ | ------------- | ------------|
-| DisperseBlob | [DisperseBlobRequest](#disperser-DisperseBlobRequest) | [DisperseBlobReply](#disperser-DisperseBlobReply) | This API accepts blob to disperse from clients. This executes the dispersal async, i.e. it returns once the request is accepted. The client could use GetBlobStatus() API to poll the processing status of the blob. |
-| DisperseBlobAuthenticated | [AuthenticatedRequest](#disperser-AuthenticatedRequest) stream | [AuthenticatedReply](#disperser-AuthenticatedReply) stream | DisperseBlobAuthenticated is similar to DisperseBlob, except that it requires the client to authenticate itself via the AuthenticationData message. The protoco is as follows: 1. The client sends a DisperseBlobAuthenticated request with the DisperseBlobRequest message 2. The Disperser sends back a BlobAuthHeader message containing information for the client to verify and sign. 3. The client verifies the BlobAuthHeader and sends back the signed BlobAuthHeader in an AuthenticationData message. 4. The Disperser verifies the signature and returns a DisperseBlobReply message. |
-| GetBlobStatus | [BlobStatusRequest](#disperser-BlobStatusRequest) | [BlobStatusReply](#disperser-BlobStatusReply) | This API is meant to be polled for the blob status. |
-| RetrieveBlob | [RetrieveBlobRequest](#disperser-RetrieveBlobRequest) | [RetrieveBlobReply](#disperser-RetrieveBlobReply) | This retrieves the requested blob from the Disperser's backend. This is a more efficient way to retrieve blobs than directly retrieving from the DA Nodes (see detail about this approach in api/proto/retriever/retriever.proto). The blob should have been initially dispersed via this Disperser service for this API to work. |
-
-
-
-
-
-
-
A list of existing operators that get churned out.
+This list will contain all quorums specified in the ChurnRequest even if some quorums
+may not have any churned out operators. If a quorum has available space, OperatorToChurn
+object will contain the quorum ID and empty operator and pubkey. The smart contract should
+only churn out the operators for quorums that are full.
+
+For example, if the ChurnRequest specifies quorums 0 and 1 where quorum 0 is full
+and quorum 1 has available space, the ChurnReply will contain two OperatorToChurn objects
+with the respective quorums. OperatorToChurn for quorum 0 will contain the operator to churn
+out and OperatorToChurn for quorum 1 will contain empty operator (zero address) and pubkey.
+The smart contract should only churn out the operators for quorum 0 because quorum 1
+has available space without having any operators churned.
+Note: it's possible an operator gets churned out just for one or more quorums
+(rather than entirely churned out for all quorums).
The quorums to register for.
+Note:
+ - If any of the quorum here has already been registered, this entire request
+ will fail to proceed.
+ - If any of the quorum fails to register, this entire request will fail.
+ - Regardless of whether the specified quorums are full or not, the Churner
+ will return parameters for all quorums specified here. The smart contract will
+ determine whether it needs to churn out existing operators based on whether
+ the quorums have available space.
+The IDs must be in range [0, 254].
+
+
+
+
+
+
+
+
+
+
OperatorToChurn
+
This describes an operator to churn out for a quorum.
The hash of the ReducedBatchHeader defined onchain, see:
+https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43
+This identifies the batch that this blob belongs to.
Each bundle contains all chunks for a single quorum of the blob.
+The number of bundles must be equal to the total number of quorums associated
+with the blob, and the ordering must be the same as BlobHeader.quorum_headers.
+Note: an operator may be in some but not all of the quorums; in that case the
+bundle corresponding to that quorum will be empty.
Merkle proof that returned blob header belongs to the batch and is
+the batch's MerkleProof.index-th blob.
+This can be checked against the batch root on chain.
+
+
+
+
+
+
+
+
+
+
GetBlobHeaderRequest
+
See RetrieveChunksRequest for documentation of each parameter of GetBlobHeaderRequest.
The hash of the ReducedBatchHeader defined onchain, see:
+https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43
+This identifies which batch to retrieve for.
Which quorum of the blob to retrieve for (note: a blob can have multiple
+quorums and the chunks for different quorums at a Node can be different).
+The ID must be in range [0, 254].
The operator's BLS sgnature signed on the blob header hashes.
+The ordering of the signatures must match the ordering of the blobs sent
+in the request, with empty signatures in the places for discarded blobs.
StoreChunks validates that the chunks match what the Node is supposed to receive (
+different Nodes are responsible for different chunks, as EigenDA is horizontally
+sharded) and is correctly coded (e.g. each chunk must be a valid KZG multiproof)
+according to the EigenDA protocol. It also stores the chunks along with metadata
+for the protocol-defined length of custody. It will return a signature at the
+end to attest to the data in this request it has processed.
StoreBlobs is simiar to StoreChunks, but it stores the blobs using a different storage schema
+so that the stored blobs can later be aggregated by AttestBatch method to a bigger batch.
+StoreBlobs + AttestBatch will eventually replace and deprecate StoreChunks method.
+DEPRECATED: StoreBlobs method is not used
AttestBatch is used to aggregate the batches stored by StoreBlobs method to a bigger batch.
+It will return a signature at the end to attest to the aggregated batch.
+DEPRECATED: AttestBatch method is not used
Which quorum of the blob to retrieve for (note: a blob can have multiple
+quorums and the chunks for different quorums at a Node can be different).
+The ID must be in range [0, 254].
The data to be dispersed.
+The size of data must be <= 16MiB. Every 32 bytes of data is interpreted as an integer in big endian format
+where the lower address has more significant bits. The integer must stay in the valid range to be interpreted
+as a field element on the bn254 curve. The valid range is
+0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617
+If any one of the 32 bytes elements is outside the range, the whole request is deemed as invalid, and rejected.
DisperseBlob accepts blob to disperse from clients.
+This executes the dispersal asynchronously, i.e. it returns once the request
+is accepted. The client could use GetBlobStatus() API to poll the the
+processing status of the blob.
The Ethereum block number at which the batch was created.
+The Disperser will encode and disperse the blobs based on the onchain info
+(e.g. operator stakes) at this block number.
This is the hash of the ReducedBatchHeader defined onchain, see:
+https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43
+The is the message that the operators will sign their signatures on.
+
+
+
+
+
+
+
+
+
+
BlobAuthHeader
+
BlobAuthHeader contains information about the blob for the client to verify and sign.
- Once payments are enabled, the BlobAuthHeader will contain the KZG commitment to the blob, which the client
will verify and sign. Having the client verify the KZG commitment instead of calculating it avoids
the need for the client to have the KZG structured reference string (SRS), which can be large.
The signed KZG commitment prevents the disperser from sending a different blob to the DA Nodes
than the one the client sent.
- In the meantime, the BlobAuthHeader contains a simple challenge parameter is used to prevent
replay attacks in the event that a signature is leaked.
The max percentage of stake within the quorum that can be held by or delegated
+to adversarial operators. Currently, this and the next parameter are standardized
+across the quorum using values read from the EigenDA contracts.
The request ID generated by the disperser.
+Once a request is accepted (although not processed), a unique request ID will be
+generated.
+Two different DisperseBlobRequests (determined by the hash of the DisperseBlobRequest)
+will have different IDs, and the same DisperseBlobRequest sent repeatedly at different
+times will also have different IDs.
+The client should use this ID to query the processing status of the request (via
+the GetBlobStatus API).
The data to be dispersed.
+The size of data must be <= 16MiB. Every 32 bytes of data is interpreted as an integer in big endian format
+where the lower address has more significant bits. The integer must stay in the valid range to be interpreted
+as a field element on the bn254 curve. The valid range is
+0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617
+If any one of the 32 bytes elements is outside the range, the whole request is deemed as invalid, and rejected.
The quorums to which the blob will be sent, in addition to the required quorums which are configured
+on the EigenDA smart contract. If required quorums are included here, an error will be returned.
+The disperser will ensure that the encoded blobs for each quorum are all processed
+within the same batch.
The account ID of the client. This should be a hex-encoded string of the ECSDA public key
+corresponding to the key used by the client to sign the BlobAuthHeader.
The status of a blob is updated as the blob is processed by the disperser.
The status of a blob can be queried by the client using the GetBlobStatus API.
Intermediate states are states that the blob can be in while being processed, and it can be updated to a differet state:
- PROCESSING
- DISPERSING
- CONFIRMED
Terminal states are states that will not be updated to a different state:
- FAILED
- FINALIZED
- INSUFFICIENT_SIGNATURES
+
+
+
Name
Number
Description
+
+
+
+
+
UNKNOWN
+
0
+
+
+
+
+
PROCESSING
+
1
+
PROCESSING means that the blob is currently being processed by the disperser
+
+
+
+
CONFIRMED
+
2
+
CONFIRMED means that the blob has been dispersed to DA Nodes and the dispersed
+batch containing the blob has been confirmed onchain
+
+
+
+
FAILED
+
3
+
FAILED means that the blob has failed permanently (for reasons other than insufficient
+signatures, which is a separate state). This status is somewhat of a catch-all category,
+containg (but not necessarily exclusively as errors can be added in the future):
+ - blob has expired
+ - internal logic error while requesting encoding
+ - blob retry has exceeded its limit while waiting for blob finalization after confirmation.
+ Most likely triggered by a chain reorg: see https://github.com/Layr-Labs/eigenda/blob/master/disperser/batcher/finalizer.go#L179-L189.
+
+
+
+
FINALIZED
+
4
+
FINALIZED means that the block containing the blob's confirmation transaction has been finalized on Ethereum
+
+
+
+
INSUFFICIENT_SIGNATURES
+
5
+
INSUFFICIENT_SIGNATURES means that the confirmation threshold for the blob was not met
+for at least one quorum.
+
+
+
+
DISPERSING
+
6
+
The DISPERSING state is comprised of two separate phases:
+ - Dispersing to DA nodes and collecting signature
+ - Submitting the transaction on chain and waiting for tx receipt
+
+
+
+
+
+
+
+
+
+
Disperser
+
Disperser defines the public APIs for dispersing blobs.
DisperseBlob accepts a single blob to be dispersed.
+This executes the dispersal async, i.e. it returns once the request
+is accepted. The client should use GetBlobStatus() API to poll the
+processing status of the blob.
+
+If DisperseBlob returns the following error codes:
+INVALID_ARGUMENT (400): request is invalid for a reason specified in the error msg.
+RESOURCE_EXHAUSTED (429): request is rate limited for the quorum specified in the error msg.
+ user should retry after the specified duration.
+INTERNAL (500): serious error, user should NOT retry.
DisperseBlobAuthenticated is similar to DisperseBlob, except that it requires the
+client to authenticate itself via the AuthenticationData message. The protoco is as follows:
+1. The client sends a DisperseBlobAuthenticated request with the DisperseBlobRequest message
+2. The Disperser sends back a BlobAuthHeader message containing information for the client to
+ verify and sign.
+3. The client verifies the BlobAuthHeader and sends back the signed BlobAuthHeader in an
+ AuthenticationData message.
+4. The Disperser verifies the signature and returns a DisperseBlobReply message.
This retrieves the requested blob from the Disperser's backend.
+This is a more efficient way to retrieve blobs than directly retrieving
+from the DA Nodes (see detail about this approach in
+api/proto/retriever/retriever.proto).
+The blob should have been initially dispersed via this Disperser service
+for this API to work.
The chunks requested. The order of these chunks will be the same as the order of the requested chunks.
+data is the raw data of the bundle (i.e. serialized byte array of the frames)
If this is an authenticated request, this should hold the ID of the operator. If this
+is an unauthenticated request, this field should be empty. Relays may choose to reject
+unauthenticated requests.
If this is an authenticated request, this field will hold a BLS signature by the requester
+on the hash of this request. Relays may choose to reject unauthenticated requests.
+
+The following describes the schema for computing the hash of this request
+This algorithm is implemented in golang using relay.auth.HashGetChunksRequest().
+
+All integers are encoded as unsigned 4 byte big endian values.
+
+Perform a keccak256 hash on the following data in the following order:
+1. the operator id
+2. for each chunk request:
+ a. if the chunk request is a request by index:
+ i. a one byte ASCII representation of the character "i" (aka Ox69)
+ ii. the blob key
+ iii. the start index
+ iv. the end index
+ b. if the chunk request is a request by range:
+ i. a one byte ASCII representation of the character "r" (aka Ox72)
+ ii. the blob key
+ iii. each requested chunk index, in order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Relay
+
Relay is a service that provides access to public relay functionality.
+
+## churner/churner.proto
+
+
+
+
+
+### ChurnReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| signature_with_salt_and_expiry | [SignatureWithSaltAndExpiry](#churner-SignatureWithSaltAndExpiry) | | The signature signed by the Churner. |
+| operators_to_churn | [OperatorToChurn](#churner-OperatorToChurn) | repeated | A list of existing operators that get churned out. This list will contain all quorums specified in the ChurnRequest even if some quorums may not have any churned out operators. If a quorum has available space, OperatorToChurn object will contain the quorum ID and empty operator and pubkey. The smart contract should only churn out the operators for quorums that are full.
+
+For example, if the ChurnRequest specifies quorums 0 and 1 where quorum 0 is full and quorum 1 has available space, the ChurnReply will contain two OperatorToChurn objects with the respective quorums. OperatorToChurn for quorum 0 will contain the operator to churn out and OperatorToChurn for quorum 1 will contain empty operator (zero address) and pubkey. The smart contract should only churn out the operators for quorum 0 because quorum 1 has available space without having any operators churned. Note: it's possible an operator gets churned out just for one or more quorums (rather than entirely churned out for all quorums). |
+
+
+
+
+
+
+
+
+### ChurnRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| operator_address | [string](#string) | | The Ethereum address (in hex like "0x123abcdef...") of the operator. |
+| operator_to_register_pubkey_g1 | [bytes](#bytes) | | The operator making the churn request. |
+| operator_to_register_pubkey_g2 | [bytes](#bytes) | | |
+| operator_request_signature | [bytes](#bytes) | | The operator's BLS signature signed on the keccak256 hash of concat("ChurnRequest", operator address, g1, g2, salt). |
+| salt | [bytes](#bytes) | | The salt used as part of the message to sign on for operator_request_signature. |
+| quorum_ids | [uint32](#uint32) | repeated | The quorums to register for. Note: - If any of the quorum here has already been registered, this entire request will fail to proceed. - If any of the quorum fails to register, this entire request will fail. - Regardless of whether the specified quorums are full or not, the Churner will return parameters for all quorums specified here. The smart contract will determine whether it needs to churn out existing operators based on whether the quorums have available space. The IDs must be in range [0, 254]. |
+
+
+
+
+
+
+
+
+### OperatorToChurn
+This describes an operator to churn out for a quorum.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| quorum_id | [uint32](#uint32) | | The ID of the quorum of the operator to churn out. |
+| operator | [bytes](#bytes) | | The address of the operator. |
+| pubkey | [bytes](#bytes) | | BLS pubkey (G1 point) of the operator. |
+
+
+
+
+
+
+
+
+### SignatureWithSaltAndExpiry
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| signature | [bytes](#bytes) | | Churner's signature on the Operator's attributes. |
+| salt | [bytes](#bytes) | | Salt is the keccak256 hash of concat("churn", time.Now(), operatorToChurn's OperatorID, Churner's ECDSA private key) |
+| expiry | [int64](#int64) | | When this churn decision will expire. |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Churner
+The Churner is a service that handles churn requests from new operators trying to
+join the EigenDA network.
+When the EigenDA network reaches the maximum number of operators, any new operator
+trying to join will have to make a churn request to this Churner, which acts as the
+sole decision maker to decide whether this new operator could join, and if so, which
+existing operator will be churned out (so the max number of operators won't be
+exceeded).
+The max number of operators, as well as the rules to make churn decisions, are
+defined onchain, see details in OperatorSetParam at:
+https://github.com/Layr-Labs/eigenlayer-middleware/blob/master/src/interfaces/IBLSRegistryCoordinatorWithIndices.sol#L24.
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| Churn | [ChurnRequest](#churner-ChurnRequest) | [ChurnReply](#churner-ChurnReply) | |
+
+
+
+
+
+
+
+
+## retriever/retriever.proto
+
+
+
+
+
+### BlobReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | The blob retrieved and reconstructed from the EigenDA Nodes per BlobRequest. |
+
+
+
+
+
+
+
+
+### BlobRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header_hash | [bytes](#bytes) | | The hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 This identifies the batch that this blob belongs to. |
+| blob_index | [uint32](#uint32) | | Which blob in the batch this is requesting for (note: a batch is logically an ordered list of blobs). |
+| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch for this blob was constructed. |
+| quorum_id | [uint32](#uint32) | | Which quorum of the blob this is requesting for (note a blob can participate in multiple quorums). |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Retriever
+The Retriever is a service for retrieving chunks corresponding to a blob from
+the EigenDA operator nodes and reconstructing the original blob from the chunks.
+This is a client-side library that the users are supposed to operationalize.
+
+Note: Users generally have two ways to retrieve a blob from EigenDA:
+ 1) Retrieve from the Disperser that the user initially used for dispersal: the API
+ is Disperser.RetrieveBlob() as defined in api/proto/disperser/disperser.proto
+ 2) Retrieve directly from the EigenDA Nodes, which is supported by this Retriever.
+
+The Disperser.RetrieveBlob() (the 1st approach) is generally faster and cheaper as the
+Disperser manages the blobs that it has processed, whereas the Retriever.RetrieveBlob()
+(the 2nd approach here) removes the need to trust the Disperser, with the downside of
+worse cost and performance.
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| RetrieveBlob | [BlobRequest](#retriever-BlobRequest) | [BlobReply](#retriever-BlobReply) | This fans out request to EigenDA Nodes to retrieve the chunks and returns the reconstructed original blob in response. |
+
+
+
+
+
+
+
+
+## node/node.proto
+
+
+
+
+
+### AttestBatchReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| signature | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### AttestBatchRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header | [BatchHeader](#node-BatchHeader) | | header of the batch |
+| blob_header_hashes | [bytes](#bytes) | repeated | the header hashes of all blobs in the batch |
+
+
+
+
+
+
+
+
+### BatchHeader
+BatchHeader (see core/data.go#BatchHeader)
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_root | [bytes](#bytes) | | The root of the merkle tree with hashes of blob headers as leaves. |
+| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch is dispersed. |
+
+
+
+
+
+
+
+
+### Blob
+In EigenDA, the original blob to disperse is encoded as a polynomial via taking
+taking different point evaluations (i.e. erasure coding). These points are split
+into disjoint subsets which are assigned to different operator nodes in the EigenDA
+network.
+The data in this message is a subset of these points that are assigned to a
+single operator node.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| header | [BlobHeader](#node-BlobHeader) | | Which (original) blob this is for. |
+| bundles | [Bundle](#node-Bundle) | repeated | Each bundle contains all chunks for a single quorum of the blob. The number of bundles must be equal to the total number of quorums associated with the blob, and the ordering must be the same as BlobHeader.quorum_headers. Note: an operator may be in some but not all of the quorums; in that case the bundle corresponding to that quorum will be empty. |
+
+
+
+
+
+
+
+
+### BlobHeader
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| commitment | [common.G1Commitment](#common-G1Commitment) | | The KZG commitment to the polynomial representing the blob. |
+| length_commitment | [G2Commitment](#node-G2Commitment) | | The KZG commitment to the polynomial representing the blob on G2, it is used for proving the degree of the polynomial |
+| length_proof | [G2Commitment](#node-G2Commitment) | | The low degree proof. It's the KZG commitment to the polynomial shifted to the largest SRS degree. |
+| length | [uint32](#uint32) | | The length of the original blob in number of symbols (in the field where the polynomial is defined). |
+| quorum_headers | [BlobQuorumInfo](#node-BlobQuorumInfo) | repeated | The params of the quorums that this blob participates in. |
+| account_id | [string](#string) | | The ID of the user who is dispersing this blob to EigenDA. |
+| reference_block_number | [uint32](#uint32) | | The reference block number whose state is used to encode the blob |
+
+
+
+
+
+
+
+
+### BlobQuorumInfo
+See BlobQuorumParam as defined in
+api/proto/disperser/disperser.proto
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| quorum_id | [uint32](#uint32) | | |
+| adversary_threshold | [uint32](#uint32) | | |
+| confirmation_threshold | [uint32](#uint32) | | |
+| chunk_length | [uint32](#uint32) | | |
+| ratelimit | [uint32](#uint32) | | |
+
+
+
+
+
+
+
+
+### Bundle
+A Bundle is the collection of chunks associated with a single blob, for a single
+operator and a single quorum.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| chunks | [bytes](#bytes) | repeated | Each chunk corresponds to a collection of points on the polynomial. Each chunk has same number of points. |
+| bundle | [bytes](#bytes) | | All chunks of the bundle encoded in a byte array. |
+
+
+
+
+
+
+
+
+### G2Commitment
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| x_a0 | [bytes](#bytes) | | The A0 element of the X coordinate of G2 point. |
+| x_a1 | [bytes](#bytes) | | The A1 element of the X coordinate of G2 point. |
+| y_a0 | [bytes](#bytes) | | The A0 element of the Y coordinate of G2 point. |
+| y_a1 | [bytes](#bytes) | | The A1 element of the Y coordinate of G2 point. |
+
+
+
+
+
+
+
+
+### GetBlobHeaderReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_header | [BlobHeader](#node-BlobHeader) | | The header of the blob requested per GetBlobHeaderRequest. |
+| proof | [MerkleProof](#node-MerkleProof) | | Merkle proof that returned blob header belongs to the batch and is the batch's MerkleProof.index-th blob. This can be checked against the batch root on chain. |
+
+
+
+
+
+
+
+
+### GetBlobHeaderRequest
+See RetrieveChunksRequest for documentation of each parameter of GetBlobHeaderRequest.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header_hash | [bytes](#bytes) | | |
+| blob_index | [uint32](#uint32) | | |
+| quorum_id | [uint32](#uint32) | | |
+
+
+
+
+
+
+
+
+### MerkleProof
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| hashes | [bytes](#bytes) | repeated | The proof itself. |
+| index | [uint32](#uint32) | | Which index (the leaf of the Merkle tree) this proof is for. |
+
+
+
+
+
+
+
+
+### NodeInfoReply
+Node info reply
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| semver | [string](#string) | | |
+| arch | [string](#string) | | |
+| os | [string](#string) | | |
+| num_cpu | [uint32](#uint32) | | |
+| mem_bytes | [uint64](#uint64) | | |
+
+
+
+
+
+
+
+
+### NodeInfoRequest
+Node info request
+
+
+
+
+
+
+
+
+### RetrieveChunksReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| chunks | [bytes](#bytes) | repeated | All chunks the Node is storing for the requested blob per RetrieveChunksRequest. |
+| chunk_encoding_format | [ChunkEncodingFormat](#node-ChunkEncodingFormat) | | How the above chunks are encoded. |
+
+
+
+
+
+
+
+
+### RetrieveChunksRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header_hash | [bytes](#bytes) | | The hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 This identifies which batch to retrieve for. |
+| blob_index | [uint32](#uint32) | | Which blob in the batch to retrieve for (note: a batch is logically an ordered list of blobs). |
+| quorum_id | [uint32](#uint32) | | Which quorum of the blob to retrieve for (note: a blob can have multiple quorums and the chunks for different quorums at a Node can be different). The ID must be in range [0, 254]. |
+
+
+
+
+
+
+
+
+### StoreBlobsReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| signatures | [google.protobuf.BytesValue](#google-protobuf-BytesValue) | repeated | The operator's BLS sgnature signed on the blob header hashes. The ordering of the signatures must match the ordering of the blobs sent in the request, with empty signatures in the places for discarded blobs. |
+
+
+
+
+
+
+
+
+### StoreBlobsRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blobs | [Blob](#node-Blob) | repeated | Blobs to store |
+| reference_block_number | [uint32](#uint32) | | The reference block number whose state is used to encode the blobs |
+
+
+
+
+
+
+
+
+### StoreChunksReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| signature | [bytes](#bytes) | | The operator's BLS signature signed on the batch header hash. |
+
+
+
+
+
+
+
+
+### StoreChunksRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header | [BatchHeader](#node-BatchHeader) | | Which batch this request is for. |
+| blobs | [Blob](#node-Blob) | repeated | The chunks for each blob in the batch to be stored in an EigenDA Node. |
+
+
+
+
+
+
+
+
+
+
+### ChunkEncodingFormat
+This describes how the chunks returned in RetrieveChunksReply are encoded.
+Used to facilitate the decoding of chunks.
+
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| UNKNOWN | 0 | |
+| GNARK | 1 | |
+| GOB | 2 | |
+
+
+
+
+
+
+
+
+
+### Dispersal
+
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| StoreChunks | [StoreChunksRequest](#node-StoreChunksRequest) | [StoreChunksReply](#node-StoreChunksReply) | StoreChunks validates that the chunks match what the Node is supposed to receive ( different Nodes are responsible for different chunks, as EigenDA is horizontally sharded) and is correctly coded (e.g. each chunk must be a valid KZG multiproof) according to the EigenDA protocol. It also stores the chunks along with metadata for the protocol-defined length of custody. It will return a signature at the end to attest to the data in this request it has processed. |
+| StoreBlobs | [StoreBlobsRequest](#node-StoreBlobsRequest) | [StoreBlobsReply](#node-StoreBlobsReply) | StoreBlobs is simiar to StoreChunks, but it stores the blobs using a different storage schema so that the stored blobs can later be aggregated by AttestBatch method to a bigger batch. StoreBlobs + AttestBatch will eventually replace and deprecate StoreChunks method. DEPRECATED: StoreBlobs method is not used |
+| AttestBatch | [AttestBatchRequest](#node-AttestBatchRequest) | [AttestBatchReply](#node-AttestBatchReply) | AttestBatch is used to aggregate the batches stored by StoreBlobs method to a bigger batch. It will return a signature at the end to attest to the aggregated batch. DEPRECATED: AttestBatch method is not used |
+| NodeInfo | [NodeInfoRequest](#node-NodeInfoRequest) | [NodeInfoReply](#node-NodeInfoReply) | Retrieve node info metadata |
+
+
+
+
+### Retrieval
+
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| RetrieveChunks | [RetrieveChunksRequest](#node-RetrieveChunksRequest) | [RetrieveChunksReply](#node-RetrieveChunksReply) | RetrieveChunks retrieves the chunks for a blob custodied at the Node. |
+| GetBlobHeader | [GetBlobHeaderRequest](#node-GetBlobHeaderRequest) | [GetBlobHeaderReply](#node-GetBlobHeaderReply) | GetBlobHeader is similar to RetrieveChunks, this just returns the header of the blob. |
+| NodeInfo | [NodeInfoRequest](#node-NodeInfoRequest) | [NodeInfoReply](#node-NodeInfoReply) | Retrieve node info metadata |
+
+
+
+
+
+
+
+
+## disperser/v2/disperser_v2.proto
+
+
+
+
+
+### Attestation
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| non_signer_pubkeys | [bytes](#bytes) | repeated | Serialized bytes of non signer public keys (G1 points) |
+| apk_g2 | [bytes](#bytes) | | Serialized bytes of G2 point that represents aggregate public key of all signers |
+| quorum_apks | [bytes](#bytes) | repeated | Serialized bytes of aggregate public keys (G1 points) from all nodes for each quorum |
+| sigma | [bytes](#bytes) | | Serialized bytes of aggregate signature |
+| quorum_numbers | [uint32](#uint32) | repeated | Relevant quorum numbers for the attestation |
+
+
+
+
+
+
+
+
+### BlobCommitmentReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_commitment | [common.BlobCommitment](#common-BlobCommitment) | | |
+
+
+
+
+
+
+
+
+### BlobCommitmentRequest
+Utility method used to generate the commitment of blob given its data.
+This can be used to construct BlobHeader.commitment
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### BlobStatusReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| status | [BlobStatus](#disperser-v2-BlobStatus) | | The status of the blob. |
+| signed_batch | [SignedBatch](#disperser-v2-SignedBatch) | | The signed batch |
+| blob_verification_info | [BlobVerificationInfo](#disperser-v2-BlobVerificationInfo) | | |
+
+
+
+
+
+
+
+
+### BlobStatusRequest
+BlobStatusRequest is used to query the status of a blob.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_key | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### BlobVerificationInfo
+BlobVerificationInfo is the information needed to verify the inclusion of a blob in a batch.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_certificate | [common.v2.BlobCertificate](#common-v2-BlobCertificate) | | |
+| blob_index | [uint32](#uint32) | | blob_index is the index of the blob in the batch |
+| inclusion_proof | [bytes](#bytes) | | inclusion_proof is the inclusion proof of the blob in the batch |
+
+
+
+
+
+
+
+
+### DisperseBlobReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| result | [BlobStatus](#disperser-v2-BlobStatus) | | The status of the blob associated with the blob key. |
+| blob_key | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### DisperseBlobRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | The data to be dispersed. The size of data must be <= 16MiB. Every 32 bytes of data is interpreted as an integer in big endian format where the lower address has more significant bits. The integer must stay in the valid range to be interpreted as a field element on the bn254 curve. The valid range is 0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617 If any one of the 32 bytes elements is outside the range, the whole request is deemed as invalid, and rejected. |
+| blob_header | [common.v2.BlobHeader](#common-v2-BlobHeader) | | |
+
+
+
+
+
+
+
+
+### SignedBatch
+SignedBatch is a batch of blobs with a signature.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| header | [common.v2.BatchHeader](#common-v2-BatchHeader) | | header contains metadata about the batch |
+| attestation | [Attestation](#disperser-v2-Attestation) | | attestation on the batch |
+
+
+
+
+
+
+
+
+
+
+### BlobStatus
+BlobStatus represents the status of a blob.
+The status of a blob is updated as the blob is processed by the disperser.
+The status of a blob can be queried by the client using the GetBlobStatus API.
+Intermediate states are states that the blob can be in while being processed, and it can be updated to a differet state:
+- QUEUED
+- ENCODED
+Terminal states are states that will not be updated to a different state:
+- CERTIFIED
+- FAILED
+- INSUFFICIENT_SIGNATURES
+
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| UNKNOWN | 0 | |
+| QUEUED | 1 | QUEUED means that the blob has been queued by the disperser for processing |
+| ENCODED | 2 | ENCODED means that the blob has been encoded and is ready to be dispersed to DA Nodes |
+| CERTIFIED | 3 | CERTIFIED means the blob has been dispersed and attested by the DA nodes |
+| FAILED | 4 | FAILED means that the blob has failed permanently (for reasons other than insufficient signatures, which is a separate state) |
+| INSUFFICIENT_SIGNATURES | 5 | INSUFFICIENT_SIGNATURES means that the confirmation threshold for the blob was not met for at least one quorum. |
+
+
+
+
+
+
+
+
+
+### Disperser
+Disperser defines the public APIs for dispersing blobs.
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| DisperseBlob | [DisperseBlobRequest](#disperser-v2-DisperseBlobRequest) | [DisperseBlobReply](#disperser-v2-DisperseBlobReply) | DisperseBlob accepts blob to disperse from clients. This executes the dispersal asynchronously, i.e. it returns once the request is accepted. The client could use GetBlobStatus() API to poll the the processing status of the blob. |
+| GetBlobStatus | [BlobStatusRequest](#disperser-v2-BlobStatusRequest) | [BlobStatusReply](#disperser-v2-BlobStatusReply) | GetBlobStatus is meant to be polled for the blob status. |
+| GetBlobCommitment | [BlobCommitmentRequest](#disperser-v2-BlobCommitmentRequest) | [BlobCommitmentReply](#disperser-v2-BlobCommitmentReply) | GetBlobCommitment is a utility method that calculates commitment for a blob payload. |
+
+
+
+
+
+
+
+
+## disperser/disperser.proto
+
+
+
+
+
+### AuthenticatedReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_auth_header | [BlobAuthHeader](#disperser-BlobAuthHeader) | | |
+| disperse_reply | [DisperseBlobReply](#disperser-DisperseBlobReply) | | |
+
+
+
+
+
+
+
+
+### AuthenticatedRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| disperse_request | [DisperseBlobRequest](#disperser-DisperseBlobRequest) | | |
+| authentication_data | [AuthenticationData](#disperser-AuthenticationData) | | |
+
+
+
+
+
+
+
+
+### AuthenticationData
+AuthenticationData contains the signature of the BlobAuthHeader.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| authentication_data | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### BatchHeader
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_root | [bytes](#bytes) | | The root of the merkle tree with the hashes of blob headers as leaves. |
+| quorum_numbers | [bytes](#bytes) | | All quorums associated with blobs in this batch. Sorted in ascending order. Ex. [0, 2, 1] => 0x000102 |
+| quorum_signed_percentages | [bytes](#bytes) | | The percentage of stake that has signed for this batch. The quorum_signed_percentages[i] is percentage for the quorum_numbers[i]. |
+| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch was created. The Disperser will encode and disperse the blobs based on the onchain info (e.g. operator stakes) at this block number. |
+
+
+
+
+
+
+
+
+### BatchMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header | [BatchHeader](#disperser-BatchHeader) | | |
+| signatory_record_hash | [bytes](#bytes) | | The hash of all public keys of the operators that did not sign the batch. |
+| fee | [bytes](#bytes) | | The fee payment paid by users for dispersing this batch. It's the bytes representation of a big.Int value. |
+| confirmation_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch is confirmed onchain. |
+| batch_header_hash | [bytes](#bytes) | | This is the hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 The is the message that the operators will sign their signatures on. |
+
+
+
+
+
+
+
+
+### BlobAuthHeader
+BlobAuthHeader contains information about the blob for the client to verify and sign.
+- Once payments are enabled, the BlobAuthHeader will contain the KZG commitment to the blob, which the client
+will verify and sign. Having the client verify the KZG commitment instead of calculating it avoids
+the need for the client to have the KZG structured reference string (SRS), which can be large.
+The signed KZG commitment prevents the disperser from sending a different blob to the DA Nodes
+than the one the client sent.
+- In the meantime, the BlobAuthHeader contains a simple challenge parameter is used to prevent
+replay attacks in the event that a signature is leaked.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| challenge_parameter | [uint32](#uint32) | | |
+
+
+
+
+
+
+
+
+### BlobHeader
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| commitment | [common.G1Commitment](#common-G1Commitment) | | KZG commitment of the blob. |
+| data_length | [uint32](#uint32) | | The length of the blob in symbols (each symbol is 32 bytes). |
+| blob_quorum_params | [BlobQuorumParam](#disperser-BlobQuorumParam) | repeated | The params of the quorums that this blob participates in. |
+
+
+
+
+
+
+
+
+### BlobInfo
+BlobInfo contains information needed to confirm the blob against the EigenDA contracts
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_header | [BlobHeader](#disperser-BlobHeader) | | |
+| blob_verification_proof | [BlobVerificationProof](#disperser-BlobVerificationProof) | | |
+
+
+
+
+
+
+
+
+### BlobQuorumParam
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| quorum_number | [uint32](#uint32) | | The ID of the quorum. |
+| adversary_threshold_percentage | [uint32](#uint32) | | The max percentage of stake within the quorum that can be held by or delegated to adversarial operators. Currently, this and the next parameter are standardized across the quorum using values read from the EigenDA contracts. |
+| confirmation_threshold_percentage | [uint32](#uint32) | | The min percentage of stake that must attest in order to consider the dispersal is successful. |
+| chunk_length | [uint32](#uint32) | | The length of each chunk. |
+
+
+
+
+
+
+
+
+### BlobStatusReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| status | [BlobStatus](#disperser-BlobStatus) | | The status of the blob. |
+| info | [BlobInfo](#disperser-BlobInfo) | | The blob info needed for clients to confirm the blob against the EigenDA contracts. |
+
+
+
+
+
+
+
+
+### BlobStatusRequest
+BlobStatusRequest is used to query the status of a blob.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| request_id | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### BlobVerificationProof
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_id | [uint32](#uint32) | | batch_id is an incremental ID assigned to a batch by EigenDAServiceManager |
+| blob_index | [uint32](#uint32) | | The index of the blob in the batch (which is logically an ordered list of blobs). |
+| batch_metadata | [BatchMetadata](#disperser-BatchMetadata) | | |
+| inclusion_proof | [bytes](#bytes) | | inclusion_proof is a merkle proof for a blob header's inclusion in a batch |
+| quorum_indexes | [bytes](#bytes) | | indexes of quorums in BatchHeader.quorum_numbers that match the quorums in BlobHeader.blob_quorum_params Ex. BlobHeader.blob_quorum_params = [ { quorum_number = 0, ... }, { quorum_number = 3, ... }, { quorum_number = 5, ... }, ] BatchHeader.quorum_numbers = [0, 5, 3] => 0x000503 Then, quorum_indexes = [0, 2, 1] => 0x000201 |
+
+
+
+
+
+
+
+
+### DisperseBlobReply
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| result | [BlobStatus](#disperser-BlobStatus) | | The status of the blob associated with the request_id. Will always be PROCESSING. |
+| request_id | [bytes](#bytes) | | The request ID generated by the disperser. Once a request is accepted (although not processed), a unique request ID will be generated. Two different DisperseBlobRequests (determined by the hash of the DisperseBlobRequest) will have different IDs, and the same DisperseBlobRequest sent repeatedly at different times will also have different IDs. The client should use this ID to query the processing status of the request (via the GetBlobStatus API). |
+
+
+
+
+
+
+
+
+### DisperseBlobRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | The data to be dispersed. The size of data must be <= 16MiB. Every 32 bytes of data is interpreted as an integer in big endian format where the lower address has more significant bits. The integer must stay in the valid range to be interpreted as a field element on the bn254 curve. The valid range is 0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617 If any one of the 32 bytes elements is outside the range, the whole request is deemed as invalid, and rejected. |
+| custom_quorum_numbers | [uint32](#uint32) | repeated | The quorums to which the blob will be sent, in addition to the required quorums which are configured on the EigenDA smart contract. If required quorums are included here, an error will be returned. The disperser will ensure that the encoded blobs for each quorum are all processed within the same batch. |
+| account_id | [string](#string) | | The account ID of the client. This should be a hex-encoded string of the ECSDA public key corresponding to the key used by the client to sign the BlobAuthHeader. |
+
+
+
+
+
+
+
+
+### DispersePaidBlobRequest
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | The data to be dispersed. Same requirements as DisperseBlobRequest. |
+| quorum_numbers | [uint32](#uint32) | repeated | The quorums to which the blob to be sent |
+| payment_header | [common.PaymentHeader](#common-PaymentHeader) | | Payment header contains AccountID, BinIndex, and CumulativePayment |
+| payment_signature | [bytes](#bytes) | | signature of payment_header |
+
+
+
+
+
+
+
+
+### RetrieveBlobReply
+RetrieveBlobReply contains the retrieved blob data
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | | |
+
+
+
+
+
+
+
+
+### RetrieveBlobRequest
+RetrieveBlobRequest contains parameters to retrieve the blob.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| batch_header_hash | [bytes](#bytes) | | |
+| blob_index | [uint32](#uint32) | | |
+
+
+
+
+
+
+
+
+
+
+### BlobStatus
+BlobStatus represents the status of a blob.
+The status of a blob is updated as the blob is processed by the disperser.
+The status of a blob can be queried by the client using the GetBlobStatus API.
+Intermediate states are states that the blob can be in while being processed, and it can be updated to a differet state:
+- PROCESSING
+- DISPERSING
+- CONFIRMED
+Terminal states are states that will not be updated to a different state:
+- FAILED
+- FINALIZED
+- INSUFFICIENT_SIGNATURES
+
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| UNKNOWN | 0 | |
+| PROCESSING | 1 | PROCESSING means that the blob is currently being processed by the disperser |
+| CONFIRMED | 2 | CONFIRMED means that the blob has been dispersed to DA Nodes and the dispersed batch containing the blob has been confirmed onchain |
+| FAILED | 3 | FAILED means that the blob has failed permanently (for reasons other than insufficient signatures, which is a separate state). This status is somewhat of a catch-all category, containg (but not necessarily exclusively as errors can be added in the future): - blob has expired - internal logic error while requesting encoding - blob retry has exceeded its limit while waiting for blob finalization after confirmation. Most likely triggered by a chain reorg: see https://github.com/Layr-Labs/eigenda/blob/master/disperser/batcher/finalizer.go#L179-L189. |
+| FINALIZED | 4 | FINALIZED means that the block containing the blob's confirmation transaction has been finalized on Ethereum |
+| INSUFFICIENT_SIGNATURES | 5 | INSUFFICIENT_SIGNATURES means that the confirmation threshold for the blob was not met for at least one quorum. |
+| DISPERSING | 6 | The DISPERSING state is comprised of two separate phases: - Dispersing to DA nodes and collecting signature - Submitting the transaction on chain and waiting for tx receipt |
+
+
+
+
+
+
+
+
+
+### Disperser
+Disperser defines the public APIs for dispersing blobs.
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| DisperseBlob | [DisperseBlobRequest](#disperser-DisperseBlobRequest) | [DisperseBlobReply](#disperser-DisperseBlobReply) | DisperseBlob accepts a single blob to be dispersed. This executes the dispersal async, i.e. it returns once the request is accepted. The client should use GetBlobStatus() API to poll the processing status of the blob.
+
+If DisperseBlob returns the following error codes: INVALID_ARGUMENT (400): request is invalid for a reason specified in the error msg. RESOURCE_EXHAUSTED (429): request is rate limited for the quorum specified in the error msg. user should retry after the specified duration. INTERNAL (500): serious error, user should NOT retry. |
+| DisperseBlobAuthenticated | [AuthenticatedRequest](#disperser-AuthenticatedRequest) stream | [AuthenticatedReply](#disperser-AuthenticatedReply) stream | DisperseBlobAuthenticated is similar to DisperseBlob, except that it requires the client to authenticate itself via the AuthenticationData message. The protoco is as follows: 1. The client sends a DisperseBlobAuthenticated request with the DisperseBlobRequest message 2. The Disperser sends back a BlobAuthHeader message containing information for the client to verify and sign. 3. The client verifies the BlobAuthHeader and sends back the signed BlobAuthHeader in an AuthenticationData message. 4. The Disperser verifies the signature and returns a DisperseBlobReply message. |
+| GetBlobStatus | [BlobStatusRequest](#disperser-BlobStatusRequest) | [BlobStatusReply](#disperser-BlobStatusReply) | This API is meant to be polled for the blob status. |
+| RetrieveBlob | [RetrieveBlobRequest](#disperser-RetrieveBlobRequest) | [RetrieveBlobReply](#disperser-RetrieveBlobReply) | This retrieves the requested blob from the Disperser's backend. This is a more efficient way to retrieve blobs than directly retrieving from the DA Nodes (see detail about this approach in api/proto/retriever/retriever.proto). The blob should have been initially dispersed via this Disperser service for this API to work. |
+
+
+
+
+
+
+
+
+## relay/relay.proto
+
+
+
+
+
+### ChunkRequest
+A request for chunks within a specific blob. Requests are fulfilled in all-or-nothing fashion. If any of the
+requested chunks are not found or are unable to be fetched, the entire request will fail.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| by_index | [ChunkRequestByIndex](#node-ChunkRequestByIndex) | | Request chunks by their individual indices. |
+| by_range | [ChunkRequestByRange](#node-ChunkRequestByRange) | | Request chunks by a range of indices. |
+
+
+
+
+
+
+
+
+### ChunkRequestByIndex
+A request for chunks within a specific blob. Each chunk is requested individually by its index.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_key | [bytes](#bytes) | | The blob key. |
+| chunk_indices | [uint32](#uint32) | repeated | The index of the chunk within the blob. |
+
+
+
+
+
+
+
+
+### ChunkRequestByRange
+A request for chunks within a specific blob. Each chunk is requested a range of indices.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_key | [bytes](#bytes) | | The blob key. |
+| start_index | [uint32](#uint32) | | The first index to start fetching chunks from. |
+| end_index | [uint32](#uint32) | | One past the last index to fetch chunks from. Similar semantics to golang slices. |
+
+
+
+
+
+
+
+
+### GetBlobReply
+The reply to a GetBlobs request.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob | [bytes](#bytes) | | The blob requested. |
+
+
+
+
+
+
+
+
+### GetBlobRequest
+A request to fetch one or more blobs.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| blob_key | [bytes](#bytes) | | The key of the blob to fetch. |
+
+
+
+
+
+
+
+
+### GetChunksReply
+The reply to a GetChunks request.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| data | [bytes](#bytes) | repeated | The chunks requested. The order of these chunks will be the same as the order of the requested chunks. data is the raw data of the bundle (i.e. serialized byte array of the frames) |
+
+
+
+
+
+
+
+
+### GetChunksRequest
+Request chunks from blobs stored by this relay.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| chunk_requests | [ChunkRequest](#node-ChunkRequest) | repeated | The chunk requests. Chunks are returned in the same order as they are requested. |
+| operator_id | [bytes](#bytes) | | If this is an authenticated request, this should hold the ID of the operator. If this is an unauthenticated request, this field should be empty. Relays may choose to reject unauthenticated requests. |
+| operator_signature | [bytes](#bytes) | | If this is an authenticated request, this field will hold a BLS signature by the requester on the hash of this request. Relays may choose to reject unauthenticated requests.
+
+The following describes the schema for computing the hash of this request This algorithm is implemented in golang using relay.auth.HashGetChunksRequest().
+
+All integers are encoded as unsigned 4 byte big endian values.
+
+Perform a keccak256 hash on the following data in the following order: 1. the operator id 2. for each chunk request: a. if the chunk request is a request by index: i. a one byte ASCII representation of the character "i" (aka Ox69) ii. the blob key iii. the start index iv. the end index b. if the chunk request is a request by range: i. a one byte ASCII representation of the character "r" (aka Ox72) ii. the blob key iii. each requested chunk index, in order |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Relay
+Relay is a service that provides access to public relay functionality.
+
+| Method Name | Request Type | Response Type | Description |
+| ----------- | ------------ | ------------- | ------------|
+| GetBlob | [GetBlobRequest](#node-GetBlobRequest) | [GetBlobReply](#node-GetBlobReply) | GetBlob retrieves a blob stored by the relay. |
+| GetChunks | [GetChunksRequest](#node-GetChunksRequest) | [GetChunksReply](#node-GetChunksReply) | GetChunks retrieves chunks from blobs stored by the relay. |
+
+
+
+
+
+## Scalar Value Types
+
+| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
+| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |
+| double | | double | double | float | float64 | double | float | Float |
+| float | | float | float | float | float32 | float | float | Float |
+| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
+| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
+| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
+| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
+| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| bool | | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |
+| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
+| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
+
diff --git a/api/docs/node.md b/api/docs/node.md
deleted file mode 100644
index d36a0b5f8..000000000
--- a/api/docs/node.md
+++ /dev/null
@@ -1,462 +0,0 @@
-# Protocol Documentation
-
-
-## Table of Contents
-
-- [node/node.proto](#node_node-proto)
- - [AttestBatchReply](#node-AttestBatchReply)
- - [AttestBatchRequest](#node-AttestBatchRequest)
- - [BatchHeader](#node-BatchHeader)
- - [Blob](#node-Blob)
- - [BlobHeader](#node-BlobHeader)
- - [BlobQuorumInfo](#node-BlobQuorumInfo)
- - [Bundle](#node-Bundle)
- - [G2Commitment](#node-G2Commitment)
- - [GetBlobHeaderReply](#node-GetBlobHeaderReply)
- - [GetBlobHeaderRequest](#node-GetBlobHeaderRequest)
- - [MerkleProof](#node-MerkleProof)
- - [NodeInfoReply](#node-NodeInfoReply)
- - [NodeInfoRequest](#node-NodeInfoRequest)
- - [RetrieveChunksReply](#node-RetrieveChunksReply)
- - [RetrieveChunksRequest](#node-RetrieveChunksRequest)
- - [StoreBlobsReply](#node-StoreBlobsReply)
- - [StoreBlobsRequest](#node-StoreBlobsRequest)
- - [StoreChunksReply](#node-StoreChunksReply)
- - [StoreChunksRequest](#node-StoreChunksRequest)
-
- - [ChunkEncoding](#node-ChunkEncoding)
-
- - [Dispersal](#node-Dispersal)
- - [Retrieval](#node-Retrieval)
-
-- [common/common.proto](#common_common-proto)
- - [G1Commitment](#common-G1Commitment)
-
-- [Scalar Value Types](#scalar-value-types)
-
-
-
-
-
-
-## node/node.proto
-
-
-
-
-
-### AttestBatchReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| signature | [bytes](#bytes) | | |
-
-
-
-
-
-
-
-
-### AttestBatchRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header | [BatchHeader](#node-BatchHeader) | | header of the batch |
-| blob_header_hashes | [bytes](#bytes) | repeated | the header hashes of all blobs in the batch |
-
-
-
-
-
-
-
-
-### BatchHeader
-BatchHeader (see core/data.go#BatchHeader)
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_root | [bytes](#bytes) | | The root of the merkle tree with hashes of blob headers as leaves. |
-| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch is dispersed. |
-
-
-
-
-
-
-
-
-### Blob
-In EigenDA, the original blob to disperse is encoded as a polynomial via taking
-taking different point evaluations (i.e. erasure coding). These points are split
-into disjoint subsets which are assigned to different operator nodes in the EigenDA
-network.
-The data in this message is a subset of these points that are assigned to a
-single operator node.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| header | [BlobHeader](#node-BlobHeader) | | Which (original) blob this is for. |
-| bundles | [Bundle](#node-Bundle) | repeated | Each bundle contains all chunks for a single quorum of the blob. The number of bundles must be equal to the total number of quorums associated with the blob, and the ordering must be the same as BlobHeader.quorum_headers. Note: an operator may be in some but not all of the quorums; in that case the bundle corresponding to that quorum will be empty. |
-
-
-
-
-
-
-
-
-### BlobHeader
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| commitment | [common.G1Commitment](#common-G1Commitment) | | The KZG commitment to the polynomial representing the blob. |
-| length_commitment | [G2Commitment](#node-G2Commitment) | | The KZG commitment to the polynomial representing the blob on G2, it is used for proving the degree of the polynomial |
-| length_proof | [G2Commitment](#node-G2Commitment) | | The low degree proof. It's the KZG commitment to the polynomial shifted to the largest SRS degree. |
-| length | [uint32](#uint32) | | The length of the original blob in number of symbols (in the field where the polynomial is defined). |
-| quorum_headers | [BlobQuorumInfo](#node-BlobQuorumInfo) | repeated | The params of the quorums that this blob participates in. |
-| account_id | [string](#string) | | The ID of the user who is dispersing this blob to EigenDA. |
-| reference_block_number | [uint32](#uint32) | | The reference block number whose state is used to encode the blob |
-
-
-
-
-
-
-
-
-### BlobQuorumInfo
-See BlobQuorumParam as defined in
-api/proto/disperser/disperser.proto
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| quorum_id | [uint32](#uint32) | | |
-| adversary_threshold | [uint32](#uint32) | | |
-| confirmation_threshold | [uint32](#uint32) | | |
-| chunk_length | [uint32](#uint32) | | |
-| ratelimit | [uint32](#uint32) | | |
-
-
-
-
-
-
-
-
-### Bundle
-A Bundle is the collection of chunks associated with a single blob, for a single
-operator and a single quorum.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| chunks | [bytes](#bytes) | repeated | Each chunk corresponds to a collection of points on the polynomial. Each chunk has same number of points. |
-| bundle | [bytes](#bytes) | | All chunks of the bundle encoded in a byte array. |
-
-
-
-
-
-
-
-
-### G2Commitment
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| x_a0 | [bytes](#bytes) | | The A0 element of the X coordinate of G2 point. |
-| x_a1 | [bytes](#bytes) | | The A1 element of the X coordinate of G2 point. |
-| y_a0 | [bytes](#bytes) | | The A0 element of the Y coordinate of G2 point. |
-| y_a1 | [bytes](#bytes) | | The A1 element of the Y coordinate of G2 point. |
-
-
-
-
-
-
-
-
-### GetBlobHeaderReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| blob_header | [BlobHeader](#node-BlobHeader) | | The header of the blob requested per GetBlobHeaderRequest. |
-| proof | [MerkleProof](#node-MerkleProof) | | Merkle proof that returned blob header belongs to the batch and is the batch's MerkleProof.index-th blob. This can be checked against the batch root on chain. |
-
-
-
-
-
-
-
-
-### GetBlobHeaderRequest
-See RetrieveChunksRequest for documentation of each parameter of GetBlobHeaderRequest.
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header_hash | [bytes](#bytes) | | |
-| blob_index | [uint32](#uint32) | | |
-| quorum_id | [uint32](#uint32) | | |
-
-
-
-
-
-
-
-
-### MerkleProof
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| hashes | [bytes](#bytes) | repeated | The proof itself. |
-| index | [uint32](#uint32) | | Which index (the leaf of the Merkle tree) this proof is for. |
-
-
-
-
-
-
-
-
-### NodeInfoReply
-Node info reply
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| semver | [string](#string) | | |
-| arch | [string](#string) | | |
-| os | [string](#string) | | |
-| num_cpu | [uint32](#uint32) | | |
-| mem_bytes | [uint64](#uint64) | | |
-
-
-
-
-
-
-
-
-### NodeInfoRequest
-Node info request
-
-
-
-
-
-
-
-
-### RetrieveChunksReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| chunks | [bytes](#bytes) | repeated | All chunks the Node is storing for the requested blob per RetrieveChunksRequest. |
-| encoding | [ChunkEncoding](#node-ChunkEncoding) | | How the above chunks encoded. |
-
-
-
-
-
-
-
-
-### RetrieveChunksRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header_hash | [bytes](#bytes) | | The hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 This identifies which batch to retrieve for. |
-| blob_index | [uint32](#uint32) | | Which blob in the batch to retrieve for (note: a batch is logically an ordered list of blobs). |
-| quorum_id | [uint32](#uint32) | | Which quorum of the blob to retrieve for (note: a blob can have multiple quorums and the chunks for different quorums at a Node can be different). The ID must be in range [0, 254]. |
-
-
-
-
-
-
-
-
-### StoreBlobsReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| signatures | [google.protobuf.BytesValue](#google-protobuf-BytesValue) | repeated | The operator's BLS sgnature signed on the blob header hashes. The ordering of the signatures must match the ordering of the blobs sent in the request, with empty signatures in the places for discarded blobs. |
-
-
-
-
-
-
-
-
-### StoreBlobsRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| blobs | [Blob](#node-Blob) | repeated | Blobs to store |
-| reference_block_number | [uint32](#uint32) | | The reference block number whose state is used to encode the blobs |
-
-
-
-
-
-
-
-
-### StoreChunksReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| signature | [bytes](#bytes) | | The operator's BLS signature signed on the batch header hash. |
-
-
-
-
-
-
-
-
-### StoreChunksRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header | [BatchHeader](#node-BatchHeader) | | Which batch this request is for. |
-| blobs | [Blob](#node-Blob) | repeated | The chunks for each blob in the batch to be stored in an EigenDA Node. |
-
-
-
-
-
-
-
-
-
-
-### ChunkEncoding
-This describes how the chunks returned in RetrieveChunksReply are encoded.
-Used to facilitate the decoding of chunks.
-
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| UNKNOWN | 0 | |
-| GNARK | 1 | |
-| GOB | 2 | |
-
-
-
-
-
-
-
-
-
-### Dispersal
-
-
-| Method Name | Request Type | Response Type | Description |
-| ----------- | ------------ | ------------- | ------------|
-| StoreChunks | [StoreChunksRequest](#node-StoreChunksRequest) | [StoreChunksReply](#node-StoreChunksReply) | StoreChunks validates that the chunks match what the Node is supposed to receive ( different Nodes are responsible for different chunks, as EigenDA is horizontally sharded) and is correctly coded (e.g. each chunk must be a valid KZG multiproof) according to the EigenDA protocol. It also stores the chunks along with metadata for the protocol-defined length of custody. It will return a signature at the end to attest to the data in this request it has processed. |
-| StoreBlobs | [StoreBlobsRequest](#node-StoreBlobsRequest) | [StoreBlobsReply](#node-StoreBlobsReply) | StoreBlobs is simiar to StoreChunks, but it stores the blobs using a different storage schema so that the stored blobs can later be aggregated by AttestBatch method to a bigger batch. StoreBlobs + AttestBatch will eventually replace and deprecate StoreChunks method. |
-| AttestBatch | [AttestBatchRequest](#node-AttestBatchRequest) | [AttestBatchReply](#node-AttestBatchReply) | AttestBatch is used to aggregate the batches stored by StoreBlobs method to a bigger batch. It will return a signature at the end to attest to the aggregated batch. |
-| NodeInfo | [NodeInfoRequest](#node-NodeInfoRequest) | [NodeInfoReply](#node-NodeInfoReply) | Retrieve node info metadata |
-
-
-
-
-### Retrieval
-
-
-| Method Name | Request Type | Response Type | Description |
-| ----------- | ------------ | ------------- | ------------|
-| RetrieveChunks | [RetrieveChunksRequest](#node-RetrieveChunksRequest) | [RetrieveChunksReply](#node-RetrieveChunksReply) | RetrieveChunks retrieves the chunks for a blob custodied at the Node. |
-| GetBlobHeader | [GetBlobHeaderRequest](#node-GetBlobHeaderRequest) | [GetBlobHeaderReply](#node-GetBlobHeaderReply) | GetBlobHeader is similar to RetrieveChunks, this just returns the header of the blob. |
-| NodeInfo | [NodeInfoRequest](#node-NodeInfoRequest) | [NodeInfoReply](#node-NodeInfoReply) | Retrieve node info metadata |
-
-
-
-
-
-
-
-
-## retriever/retriever.proto
-
-
-
-
-
-### BlobReply
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| data | [bytes](#bytes) | | The blob retrieved and reconstructed from the EigenDA Nodes per BlobRequest. |
-
-
-
-
-
-
-
-
-### BlobRequest
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| batch_header_hash | [bytes](#bytes) | | The hash of the ReducedBatchHeader defined onchain, see: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43 This identifies the batch that this blob belongs to. |
-| blob_index | [uint32](#uint32) | | Which blob in the batch this is requesting for (note: a batch is logically an ordered list of blobs). |
-| reference_block_number | [uint32](#uint32) | | The Ethereum block number at which the batch for this blob was constructed. |
-| quorum_id | [uint32](#uint32) | | Which quorum of the blob this is requesting for (note a blob can participate in multiple quorums). |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-### Retriever
-The Retriever is a service for retrieving chunks corresponding to a blob from
-the EigenDA operator nodes and reconstructing the original blob from the chunks.
-This is a client-side library that the users are supposed to operationalize.
-
-Note: Users generally have two ways to retrieve a blob from EigenDA:
- 1) Retrieve from the Disperser that the user initially used for dispersal: the API
- is Disperser.RetrieveBlob() as defined in api/proto/disperser/disperser.proto
- 2) Retrieve directly from the EigenDA Nodes, which is supported by this Retriever.
-
-The Disperser.RetrieveBlob() (the 1st approach) is generally faster and cheaper as the
-Disperser manages the blobs that it has processed, whereas the Retriever.RetrieveBlob()
-(the 2nd approach here) removes the need to trust the Disperser, with the downside of
-worse cost and performance.
-
-| Method Name | Request Type | Response Type | Description |
-| ----------- | ------------ | ------------- | ------------|
-| RetrieveBlob | [BlobRequest](#retriever-BlobRequest) | [BlobReply](#retriever-BlobReply) | This fans out request to EigenDA Nodes to retrieve the chunks and returns the reconstructed original blob in response. |
-
-
-
-
-
-
-