These methods retrieve cryptographic proofs for data cells in the Kate commitment matrix. Use kate_queryProof for individual cell proofs or kate_queryMultiProof for optimized batch queries.
kate_queryProof
Query individual KZG proofs for specific cells in the data availability matrix.
Method Signature
async fn query_proof(
&self,
cells: Cells,
at: Option<HashOf<Block>>
) -> RpcResult<Vec<GDataProof>>
Parameters
Array of cell coordinates to query.Type: BoundedVec<Cell, MaxCells> where MaxCells is configurable (default 10,000)Cell Structure:
row: Row index (u32)
col: Column index (u32)
Maximum: Configured via --kate-max-cells-size (default 10,000 cells per request)Example: [{"row": 0, "col": 0}, {"row": 0, "col": 1}]
Block hash at which to query the proofs. If not provided, uses the best (latest finalized) block.Format: 32-byte hexadecimal hash prefixed with 0x
Returns
Array of data proofs, one for each requested cell.Type Definition:pub type GDataProof = (GRawScalar, GProof);
pub type GRawScalar = U256;
pub struct GProof([u8; 48]);
Each GDataProof is a tuple containing:
- Cell Data: 256-bit scalar value (32 bytes as hex string)
- KZG Proof: 48-byte proof (as hex string)
Example Request
curl -X POST http://localhost:9944 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "kate_queryProof",
"params": [
[{"row": 0, "col": 0}, {"row": 0, "col": 1}],
"0xa1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
],
"id": 1
}'
Example Response
{
"jsonrpc": "2.0",
"result": [
[
"0x1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890",
"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba"
],
[
"0x234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12",
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
],
"id": 1
}
Each element in the result array is a tuple [cellData, proof]:
- cellData (32 bytes): The actual data value stored in the cell as a 256-bit scalar
- proof (48 bytes): The KZG polynomial commitment proof for this cell
kate_queryMultiProof
Query an optimized multi-proof for multiple cells. This method generates a single aggregated proof for all requested cells, which is more efficient than individual proofs when verifying multiple cells.
Method Signature
async fn query_multiproof(
&self,
cells: Cells,
at: Option<HashOf<Block>>
) -> RpcResult<Vec<(GMultiProof, GCellBlock)>>
Parameters
Array of cell coordinates to include in the multi-proof.Maximum: Configured via --kate-max-cells-size (default 10,000 cells per request)
Block hash at which to query the multi-proof.
Returns
result
Vec<(GMultiProof, GCellBlock)>
Array of multi-proof tuples.Type Definitions:pub type GMultiProof = (Vec<GRawScalar>, GProof);
pub struct GCellBlock {
pub start_x: u32,
pub start_y: u32,
pub end_x: u32,
pub end_y: u32,
}
Each tuple contains:
- GMultiProof: Tuple of cell data vector and aggregated proof
Vec<GRawScalar>: All cell data values
GProof: Single aggregated proof for all cells
- GCellBlock: Bounding box defining the cell region
start_x: Starting column index
start_y: Starting row index
end_x: Ending column index
end_y: Ending row index
Example Request
curl -X POST http://localhost:9944 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "kate_queryMultiProof",
"params": [
[{"row": 0, "col": 0}, {"row": 0, "col": 1}, {"row": 1, "col": 0}],
"0xa1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
],
"id": 1
}'
Example Response
{
"jsonrpc": "2.0",
"result": [
[
[
[
"0x1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890",
"0x234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12",
"0x34567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234"
],
"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba"
],
{
"start_x": 0,
"start_y": 0,
"end_x": 1,
"end_y": 1
}
]
],
"id": 1
}
The response structure is:
[
[
[
[cellData1, cellData2, cellData3, ...], // All cell data
aggregatedProof // Single proof for all cells
],
{
"start_x": 0, // Bounding box for queried cells
"start_y": 0,
"end_x": 1,
"end_y": 1
}
]
]
Error Responses
Cell Limit Exceeded
If requesting more cells than configured max_cells_size:
{
"jsonrpc": "2.0",
"error": {
"code": 1,
"message": "Cannot query (15000) more than 10000 amount of cells per request. Either increase the max cells size (--kate-max-cells-size) or query less amount of cells per request."
},
"id": 1
}
Empty Commitments
{
"jsonrpc": "2.0",
"error": {
"code": 1,
"message": "Requested block 0xa1b2...7890 has empty commitments"
},
"id": 1
}
Block Not Finalized
{
"jsonrpc": "2.0",
"error": {
"code": 1,
"message": "Requested block 0xa1b2...7890 is not finalized"
},
"id": 1
}
Implementation Details
kate_queryProof Source
From /rpc/kate-rpc/src/lib.rs:226-262:
async fn query_proof(
&self,
cells: Cells,
at: Option<HashOf<Block>>,
) -> RpcResult<Vec<GDataProof>> {
if cells.len() > self.max_cells_size {
return Err(
internal_err!(
"Cannot query ({}) more than {} amount of cells per request...",
cells.len(),
self.max_cells_size
)
);
}
let _metric_observer = MetricObserver::new(ObserveKind::KateQueryProof);
let (api, at, number, block_len, extrinsics, header) = self.scope(at)?;
match header.extension() {
HeaderExtension::V3(ext) => {
if ext.commitment.commitment.is_empty() {
return Err(internal_err!("Requested block {at} has empty commitments"));
}
},
};
let cells = cells
.into_iter()
.map(|cell| (cell.row.0, cell.col.0))
.collect::<Vec<_>>();
let proof = api
.proof(at, number, extrinsics, block_len, cells)
.map_err(|kate_err| internal_err!("KateApi::proof failed: {kate_err:?}"))?
.map_err(|api_err| internal_err!("Failed API: {api_err:?}"))?;
Ok(proof)
}
kate_queryMultiProof Source
From /rpc/kate-rpc/src/lib.rs:264-300:
async fn query_multiproof(
&self,
cells: Cells,
at: Option<HashOf<Block>>,
) -> RpcResult<Vec<(GMultiProof, GCellBlock)>> {
if cells.len() > self.max_cells_size {
return Err(
internal_err!(
"Cannot query ({}) more than {} amount of cells per request...",
cells.len(),
self.max_cells_size
)
);
}
let _metric_observer = MetricObserver::new(ObserveKind::KateQueryProof);
let (api, at, number, block_len, extrinsics, header) = self.scope(at)?;
match header.extension() {
HeaderExtension::V3(ext) => {
if ext.commitment.commitment.is_empty() {
return Err(internal_err!("Requested block {at} has empty commitments"));
}
},
};
let cells = cells
.into_iter()
.map(|cell| (cell.row.0, cell.col.0))
.collect::<Vec<_>>();
let proof = api
.multiproof(at, number, extrinsics, block_len, cells)
.map_err(|kate_err| internal_err!("KateApi::proof failed: {kate_err:?}"))?
.map_err(|api_err| internal_err!("Failed API: {api_err:?}"))?;
Ok(proof)
}
Use Cases
Individual Cell Verification
Verify specific cells against the block commitment:
// Query proof for cell at row 0, col 0
const proofs = await rpc('kate_queryProof', [
[{row: 0, col: 0}],
blockHash
]);
const [cellData, proof] = proofs[0];
// Verify using KZG verification against block header commitment
Batch Verification with Multi-Proof
Efficiently verify multiple cells with a single proof:
// Query multi-proof for 100 cells
const cells = [];
for (let i = 0; i < 100; i++) {
cells.push({row: Math.floor(i / 10), col: i % 10});
}
const multiProofs = await rpc('kate_queryMultiProof', [cells, blockHash]);
const [[cellsData, aggregatedProof], boundingBox] = multiProofs[0];
// Verify all 100 cells with single proof verification
Data Availability Sampling
Randomly sample cells for DA verification:
// Random sampling strategy
const randomCells = [];
for (let i = 0; i < 30; i++) {
randomCells.push({
row: Math.floor(Math.random() * 256),
col: Math.floor(Math.random() * 256)
});
}
const proofs = await rpc('kate_queryProof', [randomCells, blockHash]);
// Verify each proof to ensure data availability
When to Use kate_queryProof
- Querying small number of cells (< 10)
- Need individual proofs for each cell
- Verifying cells independently
When to Use kate_queryMultiProof
- Querying many cells (> 10)
- Cells are in same region/block
- Want to minimize proof size
- Batch verification is acceptable
Proof Size Comparison
- kate_queryProof: 48 bytes × number of cells
- kate_queryMultiProof: 48 bytes (single proof) regardless of cell count
For 100 cells:
- Individual proofs: 4,800 bytes
- Multi-proof: 48 bytes (100× smaller)