feat: added kzg specs to gossip validation rules, fixed peerdas from C API
This commit is contained in:
parent
4c390323d3
commit
26519f68a0
|
@ -13,7 +13,7 @@ import
|
||||||
results,
|
results,
|
||||||
# Internals
|
# Internals
|
||||||
../spec/[
|
../spec/[
|
||||||
beaconstate, state_transition_block, forks, helpers, network, signatures],
|
beaconstate, state_transition_block, forks, helpers, network, signatures, eip7594_helpers],
|
||||||
../consensus_object_pools/[
|
../consensus_object_pools/[
|
||||||
attestation_pool, blockchain_dag, blob_quarantine, block_quarantine,
|
attestation_pool, blockchain_dag, blob_quarantine, block_quarantine,
|
||||||
spec_cache, light_client_pool, sync_committee_msg_pool,
|
spec_cache, light_client_pool, sync_committee_msg_pool,
|
||||||
|
@ -207,6 +207,18 @@ func check_blob_sidecar_inclusion_proof(
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
func check_data_column_sidecar_inclusion_proof(
|
||||||
|
data_column_sidecar: DataColumnSidecar): Result[void, ValidationError] =
|
||||||
|
let res = data_column_sidecar.verify_data_column_sidecar_inclusion_proof()
|
||||||
|
if res.isErr:
|
||||||
|
return errReject(res.error)
|
||||||
|
|
||||||
|
proc check_data_column_sidecar_kzg_proofs(
|
||||||
|
data_column_sidecar: DataColumnSidecar): Result[void, ValidationError] =
|
||||||
|
let res = data_column_sidecar.verify_data_column_sidecar_kzg_proofs()
|
||||||
|
if res.isErr:
|
||||||
|
return errReject(res.error)
|
||||||
|
|
||||||
# Gossip Validation
|
# Gossip Validation
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -502,11 +514,19 @@ proc validateDataColumnSidecar*(
|
||||||
if not (block_header.slot > dag.finalizedHead.slot):
|
if not (block_header.slot > dag.finalizedHead.slot):
|
||||||
return errIgnore("DataColumnSidecar: slot already finalized")
|
return errIgnore("DataColumnSidecar: slot already finalized")
|
||||||
|
|
||||||
# TODO: [REJECT] The sidecar's `kzg_commitments` inclusion proof is valid as verified by
|
# [REJECT] The sidecar's `kzg_commitments` inclusion proof is valid as verified by
|
||||||
# `verify_data_column_sidecar_inclusion_proof(sidecar)`.
|
# `verify_data_column_sidecar_inclusion_proof(sidecar)`.
|
||||||
|
block:
|
||||||
|
let v = check_data_column_sidecar_inclusion_proof(data_column_sidecar)
|
||||||
|
if v.isErr:
|
||||||
|
return dag.checkedReject(v.error)
|
||||||
|
|
||||||
# TODO: [REJECT] The sidecar's column data is valid as
|
# [REJECT] The sidecar's column data is valid as
|
||||||
# verified by `verify_data_column_kzg_proofs(sidecar)`
|
# verified by `verify_data_column_kzg_proofs(sidecar)`
|
||||||
|
block:
|
||||||
|
let r = check_data_column_sidecar_kzg_proofs(data_column_sidecar)
|
||||||
|
if r.isErr:
|
||||||
|
return dag.checkedReject(r.error)
|
||||||
|
|
||||||
# [IGNORE] The sidecar is the first sidecar for the tuple
|
# [IGNORE] The sidecar is the first sidecar for the tuple
|
||||||
# (block_header.slot, block_header.proposer_index, blob_sidecar.index)
|
# (block_header.slot, block_header.proposer_index, blob_sidecar.index)
|
||||||
|
|
|
@ -20,6 +20,8 @@ type
|
||||||
Coset* = array[FIELD_ELEMENTS_PER_CELL, BLSFieldElement]
|
Coset* = array[FIELD_ELEMENTS_PER_CELL, BLSFieldElement]
|
||||||
CosetEvals* = array[FIELD_ELEMENTS_PER_CELL, BLSFieldElement]
|
CosetEvals* = array[FIELD_ELEMENTS_PER_CELL, BLSFieldElement]
|
||||||
Cell* = KzgCell
|
Cell* = KzgCell
|
||||||
|
Cells* = KzgCells
|
||||||
|
CellsAndProofs* = KzgCellsAndKzgProofs
|
||||||
CellID* = uint64
|
CellID* = uint64
|
||||||
RowIndex* = uint64
|
RowIndex* = uint64
|
||||||
ColumnIndex* = uint64
|
ColumnIndex* = uint64
|
||||||
|
@ -34,8 +36,8 @@ const
|
||||||
TARGET_NUMBER_OF_PEERS* = 70
|
TARGET_NUMBER_OF_PEERS* = 70
|
||||||
|
|
||||||
type
|
type
|
||||||
DataColumn* = List[Cell, Limit(MAX_BLOB_COMMITMENTS_PER_BLOCK)]
|
DataColumn* = List[KzgCell, Limit(MAX_BLOB_COMMITMENTS_PER_BLOCK)]
|
||||||
ExtendedMatrix* = List[Cell, Limit(MAX_CELLS_IN_EXTENDED_MATRIX)]
|
ExtendedMatrix* = List[KzgCell, Limit(MAX_CELLS_IN_EXTENDED_MATRIX)]
|
||||||
|
|
||||||
DataColumnSidecar* = object
|
DataColumnSidecar* = object
|
||||||
index*: ColumnIndex # Index of column in extended matrix
|
index*: ColumnIndex # Index of column in extended matrix
|
||||||
|
@ -44,7 +46,7 @@ type
|
||||||
kzg_proofs*: List[KzgProof, Limit(MAX_BLOB_COMMITMENTS_PER_BLOCK)]
|
kzg_proofs*: List[KzgProof, Limit(MAX_BLOB_COMMITMENTS_PER_BLOCK)]
|
||||||
signed_block_header*: SignedBeaconBlockHeader
|
signed_block_header*: SignedBeaconBlockHeader
|
||||||
kzg_commitments_inclusion_proof*:
|
kzg_commitments_inclusion_proof*:
|
||||||
array[KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH, KzgBytes32]
|
array[KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH, Eth2Digest]
|
||||||
|
|
||||||
func shortLog*(v: DataColumnSidecar): auto =
|
func shortLog*(v: DataColumnSidecar): auto =
|
||||||
(
|
(
|
||||||
|
|
|
@ -8,22 +8,21 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
# Uncategorized helper functions from the spec
|
# Uncategorized helper functions from the spec
|
||||||
|
|
||||||
import
|
import
|
||||||
tables,
|
tables,
|
||||||
algorithm,
|
algorithm,
|
||||||
std/macros,
|
std/macros,
|
||||||
results,
|
stew/results,
|
||||||
stew/assign2,
|
ssz_serialization/proofs,
|
||||||
nim-ssz-serialization/ssz_serialization/proofs,
|
|
||||||
chronicles,
|
chronicles,
|
||||||
std/sequtils,
|
|
||||||
./[beacon_time, crypto],
|
./[beacon_time, crypto],
|
||||||
eth/p2p/discoveryv5/[node],
|
eth/p2p/discoveryv5/[node],
|
||||||
./helpers,
|
./helpers,
|
||||||
./datatypes/[eip7594, deneb]
|
./datatypes/[eip7594, deneb]
|
||||||
|
|
||||||
|
|
||||||
|
var ctx: KzgCtx
|
||||||
|
|
||||||
proc sortedColumnIndices*(columnsPerSubnet: ColumnIndex, subnetIds: HashSet[uint64]): seq[ColumnIndex] =
|
proc sortedColumnIndices*(columnsPerSubnet: ColumnIndex, subnetIds: HashSet[uint64]): seq[ColumnIndex] =
|
||||||
var res: seq[ColumnIndex] = @[]
|
var res: seq[ColumnIndex] = @[]
|
||||||
for i in 0 ..< columnsPerSubnet:
|
for i in 0 ..< columnsPerSubnet:
|
||||||
|
@ -33,6 +32,7 @@ proc sortedColumnIndices*(columnsPerSubnet: ColumnIndex, subnetIds: HashSet[uint
|
||||||
res.sort()
|
res.sort()
|
||||||
res
|
res
|
||||||
|
|
||||||
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/das-core.md#get_custody_columns
|
||||||
proc get_custody_columns*(node_id: NodeId, custody_subnet_count: uint64): Result[seq[ColumnIndex], cstring] =
|
proc get_custody_columns*(node_id: NodeId, custody_subnet_count: uint64): Result[seq[ColumnIndex], cstring] =
|
||||||
|
|
||||||
# assert custody_subnet_count <= DATA_COLUMN_SIDECAR_SUBNET_COUNT
|
# assert custody_subnet_count <= DATA_COLUMN_SIDECAR_SUBNET_COUNT
|
||||||
|
@ -65,18 +65,23 @@ proc get_custody_columns*(node_id: NodeId, custody_subnet_count: uint64): Result
|
||||||
|
|
||||||
ok(sortedColumnIndices(ColumnIndex(columns_per_subnet), subnet_ids))
|
ok(sortedColumnIndices(ColumnIndex(columns_per_subnet), subnet_ids))
|
||||||
|
|
||||||
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/das-core.md#compute_extended_matrix
|
||||||
# #### `compute_extended_matrix`
|
|
||||||
|
|
||||||
proc compute_extended_matrix* (blobs: seq[KzgBlob]): Result[ExtendedMatrix, cstring] =
|
proc compute_extended_matrix* (blobs: seq[KzgBlob]): Result[ExtendedMatrix, cstring] =
|
||||||
# This helper demonstrates the relationship between blobs and `ExtendedMatrix`
|
# This helper demonstrates the relationship between blobs and `ExtendedMatrix`
|
||||||
var extended_matrix: ExtendedMatrix
|
var extended_matrix: ExtendedMatrix
|
||||||
for blob in blobs:
|
for blob in blobs:
|
||||||
let computed_cell = computeCellsAndKzgProofs(blob)
|
let res = computeCells(ctx, blob)
|
||||||
discard extended_matrix.add(computed_cell)
|
|
||||||
|
if res.isErr:
|
||||||
|
return err("Error computing kzg cells and kzg proofs")
|
||||||
|
|
||||||
|
discard extended_matrix.add(res.get())
|
||||||
|
|
||||||
ok(extended_matrix)
|
ok(extended_matrix)
|
||||||
|
|
||||||
proc recover_matrix*(cells_dict: Table[(BlobIndex, CellID), Cell], blobCount: uint64): Result[ExtendedMatrix, cstring] =
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/das-core.md#recover_matrix
|
||||||
|
proc recover_matrix*(cells_dict: Table[(BlobIndex, CellID), KzgCell], blobCount: uint64): Result[ExtendedMatrix, cstring] =
|
||||||
|
|
||||||
# This helper demonstrates how to apply recover_all_cells
|
# This helper demonstrates how to apply recover_all_cells
|
||||||
# The data structure for storing cells is implementation-dependent
|
# The data structure for storing cells is implementation-dependent
|
||||||
|
|
||||||
|
@ -92,7 +97,7 @@ proc recover_matrix*(cells_dict: Table[(BlobIndex, CellID), Cell], blobCount: ui
|
||||||
if blIdx == blobIndex:
|
if blIdx == blobIndex:
|
||||||
cellIds.add(cellId)
|
cellIds.add(cellId)
|
||||||
|
|
||||||
var cells: seq[Cell] = @[]
|
var cells: seq[KzgCell] = @[]
|
||||||
for cellId in cellIds:
|
for cellId in cellIds:
|
||||||
var interim_key = (BlobIndex(blobIndex), cellId)
|
var interim_key = (BlobIndex(blobIndex), cellId)
|
||||||
|
|
||||||
|
@ -102,79 +107,91 @@ proc recover_matrix*(cells_dict: Table[(BlobIndex, CellID), Cell], blobCount: ui
|
||||||
cells.add(cell)
|
cells.add(cell)
|
||||||
except:
|
except:
|
||||||
debug "DataColumn: Key not found in Cell Dictionary", interim_key
|
debug "DataColumn: Key not found in Cell Dictionary", interim_key
|
||||||
var allCellsForRow: Cells
|
|
||||||
allCellsForRow = recoverAllCells(cellIds, cells)
|
let allCellsForRow = recoverAllCells(ctx, cellIds, cells)
|
||||||
discard extended_matrix.add(allCellsForRow)
|
discard extended_matrix.add(allCellsForRow.get())
|
||||||
|
|
||||||
ok(extended_matrix)
|
ok(extended_matrix)
|
||||||
|
|
||||||
proc get_data_column_sidecars*(signed_block: deneb.SignedBeaconBlock, blobs: seq[KzgBlob]): Result[seq[DataColumnSidecar]] =
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/das-core.md#get_data_column_sidecars
|
||||||
|
proc get_data_column_sidecars*(signed_block: deneb.SignedBeaconBlock, blobs: seq[KzgBlob]): Result[seq[DataColumnSidecar], cstring] =
|
||||||
# #### `get_data_column_sidecars`
|
|
||||||
|
|
||||||
|
var sidecar: DataColumnSidecar
|
||||||
var signed_block_header: deneb.SignedBeaconBlockHeader
|
var signed_block_header: deneb.SignedBeaconBlockHeader
|
||||||
var blck = signed_block.message
|
var blck = signed_block.message
|
||||||
let
|
|
||||||
kzgCommitmentInclusionProof = build_proof(blck.body, 32'u64)
|
|
||||||
|
|
||||||
if kzgCommitmentInclusionProof.isErr():
|
var cellsAndProofs: seq[KzgCellsAndKzgProofs] = @[]
|
||||||
fatal "EIP7549: Could not compute Merkle proof"
|
|
||||||
|
|
||||||
var cellsAndProofs: seq[CellsAndProofs]
|
|
||||||
|
|
||||||
for blob in blobs:
|
for blob in blobs:
|
||||||
let
|
let
|
||||||
computed_cell = computeCellsAndKzgProofs(blob)
|
computed_cell = computeCellsAndKzgProofs(ctx, blob)
|
||||||
|
|
||||||
if computed_cell.isErr():
|
if computed_cell.isErr():
|
||||||
fatal "EIP7549: Could not compute cells"
|
fatal "EIP7549: Could not compute cells"
|
||||||
|
|
||||||
cellsAndProofs.add(computed_cell)
|
cellsAndProofs.add(computed_cell.get())
|
||||||
|
|
||||||
let blobCount = blobs.len
|
let blobCount = blobs.len
|
||||||
var cells: seq[seq[Cell]] = @[]
|
var
|
||||||
var proofs: seq[seq[KzgProof]] = @[]
|
cells: seq[seq[KzgCell]]
|
||||||
|
proofs: seq[seq[KzgProof]]
|
||||||
|
|
||||||
for i in 0..<blobCount:
|
for i in 0..<blobCount:
|
||||||
cells.add(cellsAndProofs.cells)
|
cells[i].add(cellsAndProofs[i].cells[0])
|
||||||
proofs.add(cellsAndProofs.proofs)
|
proofs[i].add(cellsAndProofs[i].proofs[1])
|
||||||
|
|
||||||
var sidecars: seq[DataColumnSidecar] = @[]
|
var sidecars: seq[DataColumnSidecar] = @[]
|
||||||
|
|
||||||
for columnIndex in 0..<NUMBER_OF_COLUMNS:
|
for columnIndex in 0..<NUMBER_OF_COLUMNS:
|
||||||
var column: DataColumn
|
var column: DataColumn
|
||||||
var cellsForColumn: seq[Cell] = @[]
|
|
||||||
for rowIndex in 0..<blobCount:
|
for rowIndex in 0..<blobCount:
|
||||||
cellsForColumn.add(cells[rowIndex][columnIndex])
|
column[rowIndex] = cells[rowIndex][columnIndex]
|
||||||
column = DataColumn(cellsForColumn)
|
|
||||||
|
|
||||||
var kzgProofOfColumn: seq[KzgProof] = @[]
|
var kzgProofOfColumn: List[KzgProof, Limit(MAX_BLOB_COMMITMENTS_PER_BLOCK)]
|
||||||
for rowIndex in 0..<blobCount:
|
for rowIndex in 0..<blobCount:
|
||||||
kzgProofOfColumn.add(proofs[rowIndex][columnIndex])
|
kzgProofOfColumn[rowIndex] = proofs[rowIndex][columnIndex]
|
||||||
|
|
||||||
var sidecar = DataColumnSidecar(
|
sidecar = DataColumnSidecar(
|
||||||
index: columnIndex,
|
index: uint64(columnIndex),
|
||||||
column: column,
|
column: column,
|
||||||
kzgCommitments: blck.body.blob_kzg_commitments,
|
kzgCommitments: blck.body.blob_kzg_commitments,
|
||||||
kzgProofs: kzgProofOfColumn,
|
kzgProofs: kzgProofOfColumn,
|
||||||
signed_block_header: signed_block_header,
|
signed_block_header: signed_block_header
|
||||||
kzg_commitments_inclusion_proof: kzgCommitmentInclusionProof
|
|
||||||
)
|
)
|
||||||
|
blck.body.build_proof(
|
||||||
|
kzg_commitment_inclusion_proof_gindex(BlobIndex(columnIndex)),
|
||||||
|
sidecar.kzg_commitments_inclusion_proof).expect("Valid gindex")
|
||||||
sidecars.add(sidecar)
|
sidecars.add(sidecar)
|
||||||
|
|
||||||
ok(sidecars)
|
ok(sidecars)
|
||||||
|
|
||||||
|
# Helper function to `verifyCellKzgProofBatch` at https://github.com/ethereum/c-kzg-4844/blob/das/bindings/nim/kzg_ex.nim#L170
|
||||||
|
proc validate_data_column_sidecar*(
|
||||||
|
expected_commitments: seq[KzgCommitment], rowIndex: seq[RowIndex], columnIndex: seq[ColumnIndex], column: seq[KzgCell],
|
||||||
|
proofs: seq[KzgProof]): Result[void, string] =
|
||||||
|
|
||||||
proc verify_data_column_sidecar_kzg_proofs* (sidecar: DataColumnSidecar): Result[bool, cstring] =
|
let res = verifyCellKzgProofBatch(expected_commitments, rowIndex, columnIndex, column, proofs).valueOr:
|
||||||
|
return err("DataColumnSidecar: Proof verification error: " & error())
|
||||||
|
|
||||||
|
if not res:
|
||||||
|
return err("DataColumnSidecar: Proof verification failed")
|
||||||
|
|
||||||
|
ok()
|
||||||
|
|
||||||
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/p2p-interface.md#verify_data_column_sidecar_kzg_proofs
|
||||||
|
proc verify_data_column_sidecar_kzg_proofs*(sidecar: DataColumnSidecar): Result[void, string] =
|
||||||
# Verifying if the KZG proofs are correct
|
# Verifying if the KZG proofs are correct
|
||||||
|
|
||||||
# Check if the data column sidecar index < NUMBER_OF_COLUMNS
|
# Check if the data column sidecar index < NUMBER_OF_COLUMNS
|
||||||
if not (sidecar.index < NUMBER_OF_COLUMNS):
|
if not (sidecar.index < NUMBER_OF_COLUMNS):
|
||||||
return err("EIP7549: Data column sidecar index exceeds the NUMBER_OF_COLUMNS")
|
return err("EIP7594: Data column sidecar index exceeds the NUMBER_OF_COLUMNS")
|
||||||
|
|
||||||
# Check is the sidecar column length == sidecar.kzg_commitments length == sidecar.kzg_proofs mixInLength
|
# Check is the sidecar column length == sidecar.kzg_commitments length == sidecar.kzg_proofs mixInLength
|
||||||
if not (sidecar.column.len == sidecar.kzg_commitments.len and sidecar.kzg_commitments.len == sidecar.kzg_proofs.len):
|
if not (sidecar.column.len == sidecar.kzg_commitments.len):
|
||||||
return err("EIP7549: Data column sidecar column length does not match the kzg_commitments length or kzg_proofs length")
|
return err("EIP7594: Data column sidecar length is not equal to the kzg_commitments length")
|
||||||
|
|
||||||
|
if not (sidecar.kzg_commitments.len == sidecar.kzg_proofs.len):
|
||||||
|
return err("EIP7594: Data column sidecar kzg_commitments length is not equal to the kzg_proofs length")
|
||||||
|
|
||||||
# Iterate through the row indices
|
# Iterate through the row indices
|
||||||
var rowIndices: seq[RowIndex] = @[]
|
var rowIndices: seq[RowIndex] = @[]
|
||||||
|
@ -184,15 +201,36 @@ proc verify_data_column_sidecar_kzg_proofs* (sidecar: DataColumnSidecar): Result
|
||||||
# Iterate through the column indices
|
# Iterate through the column indices
|
||||||
var colIndices: seq[ColumnIndex] = @[]
|
var colIndices: seq[ColumnIndex] = @[]
|
||||||
for i in 0..<sidecar.column.len:
|
for i in 0..<sidecar.column.len:
|
||||||
colIndices.add(ColumnIndex(i))
|
colIndices.add(sidecar.index * uint64(sidecar.column.len))
|
||||||
|
|
||||||
|
let kzgCommits = sidecar.kzg_commitments.asSeq
|
||||||
|
let sidecarCol = sidecar.column.asSeq
|
||||||
|
let kzgProofs = sidecar.kzg_proofs.asSeq
|
||||||
# KZG batch verifies that the cells match the corresponding commitments and KZG proofs
|
# KZG batch verifies that the cells match the corresponding commitments and KZG proofs
|
||||||
var res = verifyCellKzgProofBatch(
|
let res = validate_data_column_sidecar(
|
||||||
sidecar.kzg_commitments,
|
kzgCommits,
|
||||||
rowIndices,
|
rowIndices,
|
||||||
colIndices,
|
colIndices,
|
||||||
sidecar.column,
|
sidecarCol,
|
||||||
sidecar.kzg_proofs
|
kzgProofs)
|
||||||
)
|
|
||||||
|
|
||||||
ok(res)
|
if res.isErr():
|
||||||
|
return err("DataColumnSidecar: validation failed")
|
||||||
|
|
||||||
|
ok()
|
||||||
|
|
||||||
|
# https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/specs/_features/eip7594/p2p-interface.md#verify_data_column_sidecar_inclusion_proof
|
||||||
|
proc verify_data_column_sidecar_inclusion_proof*(sidecar: DataColumnSidecar): Result[void, string] =
|
||||||
|
|
||||||
|
# Verify if the given KZG commitments are included in the beacon block
|
||||||
|
let gindex = kzg_commitment_inclusion_proof_gindex(sidecar.index)
|
||||||
|
if not is_valid_merkle_branch(
|
||||||
|
hash_tree_root(sidecar.kzg_commitments),
|
||||||
|
sidecar.kzg_commitments_inclusion_proof,
|
||||||
|
KZG_COMMITMENT_INCLUSION_PROOF_DEPTH,
|
||||||
|
get_subtree_index(gindex),
|
||||||
|
sidecar.signed_block_header.message.body_root):
|
||||||
|
|
||||||
|
return err("DataColumnSidecar: inclusion proof not valid")
|
||||||
|
|
||||||
|
ok()
|
Loading…
Reference in New Issue