Skip to content

Commit

Permalink
Add tests for blob sidecar signature
Browse files Browse the repository at this point in the history
  • Loading branch information
dankrad committed Mar 12, 2023
1 parent 29b5309 commit 96ad61b
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 53 deletions.
11 changes: 11 additions & 0 deletions specs/deneb/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ class BlobIdentifier(Container):
index: BlobIndex
```

### Helpers

#### `verify_sidecar_signature`

```python
def verify_blob_sidecar_signature(state: BeaconState, signed_blob_sidecar: SignedBlobSidecar) -> bool:
proposer = state.validators[signed_blob_sidecar.message.proposer_index]
signing_root = compute_signing_root(signed_blob_sidecar.message, get_domain(state, DOMAIN_BLOB_SIDECAR))
return bls.Verify(proposer.pubkey, signing_root, signed_blob_sidecar.signature)
```

## The gossip domain: gossipsub

Some gossip meshes are upgraded in the fork of Deneb to support upgraded types.
Expand Down
9 changes: 6 additions & 3 deletions specs/deneb/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ Note: This API is *unstable*. `get_blobs_and_kzg_commitments` and `get_payload`
Implementers may also retrieve blobs individually per transaction.

```python
def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment], Sequence[KZGProof]]:
def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> \
Tuple[Sequence[BLSFieldElement], Sequence[KZGCommitment], Sequence[KZGProof]]:
# pylint: disable=unused-argument
...
```
Expand Down Expand Up @@ -88,7 +89,9 @@ Blobs associated with a block are packaged into sidecar objects for distribution

Each `sidecar` is obtained from:
```python
def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobSidecar]:
def get_blob_sidecars(block: BeaconBlock,
blobs: Sequence[Blob],
blob_kzg_proofs: Sequence[KZGProof]) -> Sequence[BlobSidecar]:
return [
BlobSidecar(
block_root=hash_tree_root(block),
Expand All @@ -97,7 +100,7 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo
block_parent_root=block.parent_root,
blob=blob,
kzg_commitment=block.body.blob_kzg_commitments[index],
kzg_proof=compute_blob_kzg_proof(blob, block.body.blob_kzg_commitments[index]),
kzg_proof=blob_kzg_proofs[index],
)
for index, blob in enumerate(blobs)
]
Expand Down
4 changes: 2 additions & 2 deletions tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_one_blob(spec, state):
yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)
opaque_tx, _, blob_kzg_commitments = get_sample_opaque_tx(spec)
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
Expand All @@ -38,7 +38,7 @@ def test_max_blobs(spec, state):
yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)
opaque_tx, _, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=spec.MAX_BLOBS_PER_BLOCK)
opaque_tx, _, blob_kzg_commitments, _ = get_sample_opaque_tx(spec, blob_count=spec.MAX_BLOBS_PER_BLOCK)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@

def _run_validate_blobs(spec, state, blob_count):
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count)
opaque_tx, blobs, blob_kzg_commitments, kzg_proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
state_transition_and_sign_block(spec, state, block)

# Also test the proof generation in `get_blob_sidecars`
blob_sidecars = spec.get_blob_sidecars(block, blobs)
blob_sidecars = spec.get_blob_sidecars(block, blobs, kzg_proofs)
blobs = [sidecar.blob for sidecar in blob_sidecars]
kzg_proofs = [sidecar.kzg_proof for sidecar in blob_sidecars]
spec.validate_blobs(blob_kzg_commitments, blobs, kzg_proofs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@spec_state_test
@with_presets([MINIMAL])
def test_tx_peek_blob_versioned_hashes(spec, state):
otx, blobs, commitments = get_sample_opaque_tx(spec)
otx, _, commitments, _ = get_sample_opaque_tx(spec)
data_hashes = spec.tx_peek_blob_versioned_hashes(otx)
expected = [spec.kzg_commitment_to_versioned_hash(blob_commitment) for blob_commitment in commitments]
assert expected == data_hashes
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import random

from eth2spec.test.context import (
always_bls,
spec_state_test,
with_deneb_and_later,
expect_assertion_error
Expand All @@ -14,8 +13,8 @@
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot
)
from eth2spec.test.helpers.state import (
state_transition_and_sign_block,
from eth2spec.test.helpers.keys import (
pubkey_to_privkey
)
from eth2spec.utils import bls
from eth2spec.utils.bls import BLS_MODULUS
Expand Down Expand Up @@ -49,15 +48,11 @@ def test_validate_blobs_and_kzg_commitments(spec, state):
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)

blob_sidecars = spec.get_blob_sidecars(block, blobs)
blobs = [sidecar.blob for sidecar in blob_sidecars]
proofs = [sidecar.kzg_proof for sidecar in blob_sidecars]

spec.validate_blobs_and_kzg_commitments(block.body.execution_payload,
blobs,
blob_kzg_commitments,
Expand All @@ -72,21 +67,18 @@ def test_validate_blobs_and_kzg_commitments_missing_blob(spec, state):
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
# state_transition_and_sign_block(spec, state, block)

blob_sidecars = spec.get_blob_sidecars(block, blobs)
blobs = [sidecar.blob for sidecar in blob_sidecars][:-1]
proofs = [sidecar.kzg_proof for sidecar in blob_sidecars]

expect_assertion_error(lambda:
spec.validate_blobs_and_kzg_commitments(block.body.execution_payload,
blobs,
blob_kzg_commitments,
proofs)
expect_assertion_error(
lambda: spec.validate_blobs_and_kzg_commitments(
block.body.execution_payload,
blobs[:-1],
blob_kzg_commitments,
proofs
)
)


Expand All @@ -98,21 +90,18 @@ def test_validate_blobs_and_kzg_commitments_missing_proof(spec, state):
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
# state_transition_and_sign_block(spec, state, block)

blob_sidecars = spec.get_blob_sidecars(block, blobs)
blobs = [sidecar.blob for sidecar in blob_sidecars]
proofs = [sidecar.kzg_proof for sidecar in blob_sidecars][:-1]

expect_assertion_error(lambda:
spec.validate_blobs_and_kzg_commitments(block.body.execution_payload,
blobs,
blob_kzg_commitments,
proofs)
expect_assertion_error(
lambda: spec.validate_blobs_and_kzg_commitments(
block.body.execution_payload,
blobs,
blob_kzg_commitments,
proofs[:-1]
)
)


Expand All @@ -124,21 +113,68 @@ def test_validate_blobs_and_kzg_commitments_incorrect_blob(spec, state):
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
# state_transition_and_sign_block(spec, state, block)

blob_sidecars = spec.get_blob_sidecars(block, blobs)
blobs = [sidecar.blob for sidecar in blob_sidecars]
proofs = [sidecar.kzg_proof for sidecar in blob_sidecars]

blobs[1] = spec.Blob(blobs[1][:13] + bytes([(blobs[1][13] + 1) % 256]) + blobs[1][14:])

expect_assertion_error(lambda:
spec.validate_blobs_and_kzg_commitments(block.body.execution_payload,
blobs,
blob_kzg_commitments,
proofs)
)
expect_assertion_error(
lambda: spec.validate_blobs_and_kzg_commitments(
block.body.execution_payload,
blobs,
blob_kzg_commitments,
proofs
)
)


@with_deneb_and_later
@spec_state_test
def test_blob_sidecar_signature(spec, state):
"""
Test `get_blob_sidecar_signature`
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)

blob_sidecars = spec.get_blob_sidecars(block, blobs, proofs)
proposer = state.validators[blob_sidecars[1].proposer_index]
privkey = pubkey_to_privkey[proposer.pubkey]
sidecar_signature = spec.get_blob_sidecar_signature(state,
blob_sidecars[1],
privkey)

signed_blob_sidecar = spec.SignedBlobSidecar(message=blob_sidecars[1], signature=sidecar_signature)

assert spec.verify_blob_sidecar_signature(state, signed_blob_sidecar)


@with_deneb_and_later
@spec_state_test
@always_bls
def test_blob_sidecar_signature_incorrect(spec, state):
"""
Test `get_blob_sidecar_signature`
"""
blob_count = 4
block = build_empty_block_for_next_slot(spec, state)
opaque_tx, blobs, blob_kzg_commitments, proofs = get_sample_opaque_tx(spec, blob_count=blob_count)
block.body.blob_kzg_commitments = blob_kzg_commitments
block.body.execution_payload.transactions = [opaque_tx]
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)

blob_sidecars = spec.get_blob_sidecars(block, blobs, proofs)

sidecar_signature = spec.get_blob_sidecar_signature(state,
blob_sidecars[1],
123)

signed_blob_sidecar = spec.SignedBlobSidecar(message=blob_sidecars[1], signature=sidecar_signature)

assert not spec.verify_blob_sidecar_signature(state, signed_blob_sidecar)
5 changes: 4 additions & 1 deletion tests/core/pyspec/eth2spec/test/helpers/sharding.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,16 @@ def get_poly_in_both_forms(spec, rng=None):
def get_sample_opaque_tx(spec, blob_count=1, rng=None):
blobs = []
blob_kzg_commitments = []
blob_kzg_proofs = []
blob_versioned_hashes = []
for _ in range(blob_count):
blob = get_sample_blob(spec, rng)
blob_commitment = spec.KZGCommitment(spec.blob_to_kzg_commitment(blob))
blob_kzg_proof = spec.compute_blob_kzg_proof(blob, blob_commitment)
blob_versioned_hash = spec.kzg_commitment_to_versioned_hash(blob_commitment)
blobs.append(blob)
blob_kzg_commitments.append(blob_commitment)
blob_kzg_proofs.append(blob_kzg_proof)
blob_versioned_hashes.append(blob_versioned_hash)

signed_blob_tx = SignedBlobTransaction(
Expand All @@ -117,4 +120,4 @@ def get_sample_opaque_tx(spec, blob_count=1, rng=None):
)
serialized_tx = serialize(signed_blob_tx)
opaque_tx = spec.uint_to_bytes(spec.BLOB_TX_TYPE) + serialized_tx
return opaque_tx, blobs, blob_kzg_commitments
return opaque_tx, blobs, blob_kzg_commitments, blob_kzg_proofs

0 comments on commit 96ad61b

Please sign in to comment.