Skip to content

Commit

Permalink
feat: add validation for post merge and pre capella header
Browse files Browse the repository at this point in the history
  • Loading branch information
fearlessfe authored and GrapeBaBa committed May 10, 2024
1 parent 05041f4 commit c23c10f
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 3 deletions.
49 changes: 46 additions & 3 deletions portalnetwork/history/accumulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ import (
"github.com/ethereum/go-ethereum/rlp"
ssz "github.com/ferranbt/fastssz"
"github.com/holiman/uint256"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/zrnt/eth2/util/merkle"
"github.com/protolambda/ztyp/codec"
)

const (
epochSize = 8192
mergeBlockNumber uint64 = 15537394
preMergeEpochs = (mergeBlockNumber + epochSize - 1) / epochSize
epochSize = 8192
mergeBlockNumber uint64 = 15537394
shanghaiBlockNumber uint64 = 17_034_870
preMergeEpochs = (mergeBlockNumber + epochSize - 1) / epochSize
)

var (
Expand All @@ -28,6 +32,9 @@ var (
//go:embed assets/merge_macc.txt
var masterAccumulatorHex string

//go:embed assets/historical_roots.ssz
var historicalRootsBytes []byte

var zeroRecordBytes = make([]byte, 64)

type AccumulatorProof [][]byte
Expand Down Expand Up @@ -255,3 +262,39 @@ func NewMasterAccumulator() (MasterAccumulator, error) {
err = masterAcc.UnmarshalSSZ(masterAccumulatorBytes)
return masterAcc, err
}

type HistoricalRootsAccumulator struct {
HistoricalRoots HistoricalRoots
}

func NewHistoricalRootsAccumulator(spec *common.Spec) (HistoricalRootsAccumulator, error) {
historicalRoots := new(HistoricalRoots)
reader := codec.NewDecodingReader(bytes.NewReader(historicalRootsBytes), uint64(len(historicalRootsBytes)))
err := historicalRoots.Deserialize(spec, reader)
return HistoricalRootsAccumulator{HistoricalRoots: *historicalRoots}, err
}

func (h HistoricalRootsAccumulator) VerifyPostMergePreCapellaHeader(blockNumber uint64, headerHash common.Root, proof *HistoricalRootsBlockProof) error {
if blockNumber <= mergeBlockNumber {
return errors.New("invalid historicalRootsBlockProof found for pre-merge header")
}
if blockNumber >= shanghaiBlockNumber {
return errors.New("invalid historicalRootsBlockProof found for post-Shanghai header")
}
if !merkle.VerifyMerkleBranch(headerHash, proof.BeaconBlockBodyProof[:], 8, 412, proof.BeaconBlockBodyRoot) {
return errors.New("merkle proof validation failed for BeaconBlockBodyProof")
}
if !merkle.VerifyMerkleBranch(proof.BeaconBlockBodyRoot, proof.BeaconBlockHeaderProof[:], 3, 12, proof.BeaconBlockHeaderRoot) {
return errors.New("merkle proof validation failed for BeaconBlockHeaderProof")
}

blockRootIndex := proof.Slot % epochSize
genIndex := 2*epochSize + blockRootIndex
historicalRootIndex := proof.Slot / epochSize
historicalRoot := h.HistoricalRoots[historicalRootIndex]

if !merkle.VerifyMerkleBranch(proof.BeaconBlockHeaderRoot, proof.HistoricalRootsProof[:], 14, uint64(genIndex), historicalRoot) {
return errors.New("merkle proof validation failed for HistoricalRootsProof")
}
return nil
}
19 changes: 19 additions & 0 deletions portalnetwork/history/accumulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
"github.com/protolambda/zrnt/eth2/configs"
"github.com/protolambda/ztyp/tree"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestVerifyHeaderWithProofs(t *testing.T) {
Expand Down Expand Up @@ -84,6 +87,22 @@ func TestUpdate(t *testing.T) {
}
}

func TestVerifyPostMergePreCapellaHeader(t *testing.T) {
acc, err := NewHistoricalRootsAccumulator(configs.Mainnet)
require.NoError(t, err)
require.True(t, uint64(len(acc.HistoricalRoots)) < uint64(configs.Mainnet.HISTORICAL_ROOTS_LIMIT))

file, err := os.ReadFile("./testdata/block_proofs_bellatrix/beacon_block_proof-15539558-cdf9ed89b0c43cda17398dc4da9cfc505e5ccd19f7c39e3b43474180f1051e01.yaml")
require.NoError(t, err)
proof := HistoricalRootsBlockProof{}
err = yaml.Unmarshal(file, &proof)
require.NoError(t, err)
// blockNumber and blockHash are from testfile
blockHash := hexutil.MustDecode("0xcdf9ed89b0c43cda17398dc4da9cfc505e5ccd19f7c39e3b43474180f1051e01")
err = acc.VerifyPostMergePreCapellaHeader(15539558, tree.Root(blockHash), &proof)
require.NoError(t, err)
}

// all test blocks are in the same epoch
func parseHeaderWithProof() ([]BlockHeaderWithProof, error) {
headWithProofBytes, err := os.ReadFile("./testdata/header_with_proofs.json")
Expand Down
Binary file added portalnetwork/history/assets/historical_roots.ssz
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# block number: 15539558
execution_block_header: 0xcdf9ed89b0c43cda17398dc4da9cfc505e5ccd19f7c39e3b43474180f1051e01
beacon_block_body_proof:
- 0x72e99d023990f3228488ccd391a6916a65715958ae7e3e3476e6ef3b24a14799
- 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
- 0xa06acb149ac136c27ab9c4b30624f861d4ead5bb9fa725993767ccca90dcfd4d
- 0x44f09e14b80476731f84bf7b3c85bce0259e8f2a3abffb9e0ac8f28d055b2a36
- 0x881452718c4c085088bdee30b957b2a3d943caeacc39c390632af90a65e369bd
- 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
- 0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71
- 0x982c6a980438c3df73968f2c372029add74aa2e0b1b3ccfebb1d9cac7660c61d
beacon_block_body_root: 0x8c7dbf6c53814a2d793a9af8e7b221ff69b5e3b1469ccad397b5561c64886143
beacon_block_header_proof:
- 0x0000000000000000000000000000000000000000000000000000000000000000
- 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
- 0xc694a9f6d954c949cf25b85c4f686d267eaafca8dc86afda41f9434a3a30048e
beacon_block_header_root: 0x4b72c935466fa0857a7320c4fee7c99f892adb686ed7a66aa38f26f4ef3c2f21
historical_roots_proof:
- 0xda1b49bf9408d2e8bf5dd5cba08917973b6948abb17ef6a9d602d9e9575cbf7f
- 0xb9ac7a390e27da1159903a5345e4f4a094fb66509e2899d877e184caa49d7b42
- 0x8577093326bf889b29261d95b02728e73acf5e0bc2bcc9eb90d1c7c41979ae72
- 0xee3d2526ce774ee787b4a6eab4aa9953ae683c90aa3f21d07a8877b43e3627fb
- 0xe2288f273c4be422f7407254408a43ca92b2cc8fe680ea4d14f8e3174c98f527
- 0x63c5ce4b0d6dd285a77dffcb4c944e57f56ea565170a93a45ae9fc64bad5ce0a
- 0x7e1e6e6818e3626663fb02bafe8031ff7896ae87fa9896d7028a2b9e8b99354b
- 0x1da1e4d70d91cf40475cd0b9679de35cbc11fa5c5c2c410935c93fd1ef3b4697
- 0xeb164971bc2c332c0174b7f2bf25f8719bcc95048d2cc3235a789cec1adbb077
- 0x967538697e44dd1c12d2c5f92e9852a09d23063220e0f3e8a1acfbc2eda0afc0
- 0xd7407ca72fc746f5087c4bb5d0754bd9df0af7ab7dbc3be1705a1c1e3cd5b8f8
- 0xf433674c06fd0a3a9cb9615f9c0a37348b106905a960249d17ffd23c20192704
- 0xc1eb114f29abc95642dc93f8d5f38fd248a67b4f8d603ff4157dcb1e8ee09706
- 0x83b655426b47df48bb29e337ea37bcfe2bd9e33a13668ba3bc27919d421a40a6
slot: 4702208
195 changes: 195 additions & 0 deletions portalnetwork/history/types_zrnt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package history

import (
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/ztyp/codec"
"github.com/protolambda/ztyp/tree"
)

const beaconBlockBodyProofLen = 8

type BeaconBlockBodyProof [beaconBlockBodyProofLen]common.Root

func (b *BeaconBlockBodyProof) Deserialize(dr *codec.DecodingReader) error {
roots := b[:]
return tree.ReadRoots(dr, &roots, beaconBlockBodyProofLen)
}

func (b *BeaconBlockBodyProof) Serialize(w *codec.EncodingWriter) error {
return tree.WriteRoots(w, b[:])
}

func (b BeaconBlockBodyProof) ByteLength() (out uint64) {
return beaconBlockBodyProofLen * 32
}

func (b BeaconBlockBodyProof) FixedLength() uint64 {
return beaconBlockBodyProofLen * 32
}

func (b *BeaconBlockBodyProof) HashTreeRoot(hFn tree.HashFn) common.Root {
return hFn.ComplexVectorHTR(func(i uint64) tree.HTR {
if i < beaconBlockBodyProofLen {
return &b[i]
}
return nil
}, beaconBlockBodyProofLen)
}

const beaconBlockHeaderProofLen = 3

type BeaconBlockHeaderProof [beaconBlockHeaderProofLen]common.Root

func (b *BeaconBlockHeaderProof) Deserialize(dr *codec.DecodingReader) error {
roots := b[:]
return tree.ReadRoots(dr, &roots, beaconBlockHeaderProofLen)
}

func (b *BeaconBlockHeaderProof) Serialize(w *codec.EncodingWriter) error {
return tree.WriteRoots(w, b[:])
}

func (b BeaconBlockHeaderProof) ByteLength() (out uint64) {
return beaconBlockHeaderProofLen * 32
}

func (b BeaconBlockHeaderProof) FixedLength() uint64 {
return beaconBlockHeaderProofLen * 32
}

func (b *BeaconBlockHeaderProof) HashTreeRoot(hFn tree.HashFn) common.Root {
return hFn.ComplexVectorHTR(func(i uint64) tree.HTR {
if i < beaconBlockHeaderProofLen {
return &b[i]
}
return nil
}, beaconBlockHeaderProofLen)
}

const historicalRootsProofLen = 14

type HistoricalRootsProof [historicalRootsProofLen]common.Root

func (b *HistoricalRootsProof) Deserialize(dr *codec.DecodingReader) error {
roots := b[:]
return tree.ReadRoots(dr, &roots, historicalRootsProofLen)
}

func (b *HistoricalRootsProof) Serialize(w *codec.EncodingWriter) error {
return tree.WriteRoots(w, b[:])
}

func (b HistoricalRootsProof) ByteLength() (out uint64) {
return historicalRootsProofLen * 32
}

func (b HistoricalRootsProof) FixedLength() uint64 {
return historicalRootsProofLen * 32
}

func (b *HistoricalRootsProof) HashTreeRoot(hFn tree.HashFn) common.Root {
return hFn.ComplexVectorHTR(func(i uint64) tree.HTR {
if i < historicalRootsProofLen {
return &b[i]
}
return nil
}, historicalRootsProofLen)
}

type HistoricalRootsBlockProof struct {
BeaconBlockBodyProof BeaconBlockBodyProof `yaml:"beacon_block_body_proof" json:"beacon_block_body_proof"`
BeaconBlockBodyRoot common.Root `yaml:"beacon_block_body_root" json:"beacon_block_body_root"`
BeaconBlockHeaderProof BeaconBlockHeaderProof `yaml:"beacon_block_header_proof" json:"beacon_block_header_proof"`
BeaconBlockHeaderRoot common.Root `yaml:"beacon_block_header_root" json:"beacon_block_header_root"`
HistoricalRootsProof HistoricalRootsProof `yaml:"historical_roots_proof" json:"historical_roots_proof"`
Slot common.Slot `yaml:"slot" json:"slot"`
}

func (h *HistoricalRootsBlockProof) Deserialize(dr *codec.DecodingReader) error {
return dr.FixedLenContainer(
&h.BeaconBlockBodyProof,
&h.BeaconBlockBodyRoot,
&h.BeaconBlockHeaderProof,
&h.BeaconBlockHeaderProof,
&h.HistoricalRootsProof,
&h.Slot,
)
}

func (h *HistoricalRootsBlockProof) Serialize(w *codec.EncodingWriter) error {
return w.FixedLenContainer(
&h.BeaconBlockBodyProof,
&h.BeaconBlockBodyRoot,
&h.BeaconBlockHeaderProof,
&h.BeaconBlockHeaderProof,
&h.HistoricalRootsProof,
&h.Slot,
)
}

func (h *HistoricalRootsBlockProof) ByteLength(spec *common.Spec) uint64 {
return codec.ContainerLength(
&h.BeaconBlockBodyProof,
&h.BeaconBlockBodyRoot,
&h.BeaconBlockHeaderProof,
&h.BeaconBlockHeaderProof,
&h.HistoricalRootsProof,
&h.Slot,
)
}

func (h *HistoricalRootsBlockProof) FixedLength(spec *common.Spec) uint64 {
return codec.ContainerLength(
&h.BeaconBlockBodyProof,
&h.BeaconBlockBodyRoot,
&h.BeaconBlockHeaderProof,
&h.BeaconBlockHeaderProof,
&h.HistoricalRootsProof,
&h.Slot,
)
}

func (h *HistoricalRootsBlockProof) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root {
return hFn.HashTreeRoot(
&h.BeaconBlockBodyProof,
&h.BeaconBlockBodyRoot,
&h.BeaconBlockHeaderProof,
&h.BeaconBlockHeaderProof,
&h.HistoricalRootsProof,
&h.Slot,
)
}

type HistoricalRoots []common.Root

func (h *HistoricalRoots) Deserialize(spec *common.Spec, dr *codec.DecodingReader) error {
return dr.List(func() codec.Deserializable {
i := len(*h)
*h = append(*h, common.Root{})
return &(*h)[i]
}, common.Root{}.ByteLength(), uint64(spec.HISTORICAL_ROOTS_LIMIT))
}

func (h HistoricalRoots) Serialize(spec *common.Spec, w *codec.EncodingWriter) error {
return w.List(func(i uint64) codec.Serializable {
return &h[i]
}, common.Root{}.ByteLength(), uint64(spec.HISTORICAL_ROOTS_LIMIT))
}

func (h HistoricalRoots) ByteLength(spec *common.Spec) uint64 {
return uint64(len(h)) * (common.Root{}.ByteLength())
}

func (h *HistoricalRoots) FixedLength(_ *common.Spec) uint64 {
return 0
}

func (h HistoricalRoots) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root {
length := uint64(len(h))
return hFn.ComplexListHTR(func(i uint64) tree.HTR {
if i < length {
return &h[i]
}
return nil
}, length, uint64(spec.HISTORICAL_ROOTS_LIMIT))
}

0 comments on commit c23c10f

Please sign in to comment.