mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
feat: add validation for post merge and pre capella header
This commit is contained in:
parent
05041f4bb5
commit
c23c10fb3f
5 changed files with 293 additions and 3 deletions
|
|
@ -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 (
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
BIN
portalnetwork/history/assets/historical_roots.ssz
Normal file
BIN
portalnetwork/history/assets/historical_roots.ssz
Normal file
Binary file not shown.
|
|
@ -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
portalnetwork/history/types_zrnt.go
Normal file
195
portalnetwork/history/types_zrnt.go
Normal file
|
|
@ -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))
|
||||
}
|
||||
Loading…
Reference in a new issue