From 50d7b0d0ac97b9b6ae6e6dc01d3a596f86286992 Mon Sep 17 00:00:00 2001 From: fearlseefe <505380967@qq.com> Date: Thu, 5 Sep 2024 17:42:09 +0800 Subject: [PATCH] feat: beacon validation add validation for HistoricalSummariesWithProof --- portalnetwork/beacon/beacon_network.go | 36 +++++++++++- portalnetwork/beacon/types.go | 80 ++++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 8 deletions(-) diff --git a/portalnetwork/beacon/beacon_network.go b/portalnetwork/beacon/beacon_network.go index a2d196ca3a..874cba9a64 100644 --- a/portalnetwork/beacon/beacon_network.go +++ b/portalnetwork/beacon/beacon_network.go @@ -14,6 +14,7 @@ import ( ssz "github.com/ferranbt/fastssz" "github.com/protolambda/zrnt/eth2/beacon/common" "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/zrnt/eth2/util/merkle" "github.com/protolambda/ztyp/codec" "github.com/protolambda/ztyp/tree" ) @@ -32,7 +33,7 @@ type BeaconNetwork struct { log log.Logger closeCtx context.Context closeFunc context.CancelFunc - // lightClient *ConsensusLightClient + lightClient *ConsensusLightClient } func NewBeaconNetwork(portalProtocol *discover.PortalProtocol) *BeaconNetwork { @@ -252,8 +253,29 @@ func (bn *BeaconNetwork) validateContent(contentKey []byte, content []byte) erro return nil // TODO: VERIFY case HistoricalSummaries: - var historicalSummaries HistoricalSummariesProof - return historicalSummaries.Deserialize(codec.NewDecodingReader(bytes.NewReader(content), uint64(len(content)))) + key := &HistoricalSummariesWithProofKey{} + err := key.Deserialize(codec.NewDecodingReader(bytes.NewReader(contentKey[1:]), uint64(len(contentKey[1:])))) + if err != nil { + return err + } + forkedHistoricalSummariesWithProof := &ForkedHistoricalSummariesWithProof{} + err = forkedHistoricalSummariesWithProof.Deserialize(bn.spec, codec.NewDecodingReader(bytes.NewReader(content), uint64(len(content)))) + if err != nil { + return err + } + if forkedHistoricalSummariesWithProof.HistoricalSummariesWithProof.EPOCH != common.Epoch(key.Epoch) { + return fmt.Errorf("historical summaries with proof epoch does not match the content key epoch: %d != %d", forkedHistoricalSummariesWithProof.HistoricalSummariesWithProof.EPOCH, key.Epoch) + } + + // TODO get root from light client + header := bn.lightClient.GetFinalityHeader() + latestFinalizedRoot := header.StateRoot + + valid := bn.stateSummariesValidation(*forkedHistoricalSummariesWithProof, latestFinalizedRoot) + if !valid { + return errors.New("merkle proof validation failed for HistoricalSummariesProof") + } + return nil default: return fmt.Errorf("unknown content type %v", contentKey[0]) } @@ -306,3 +328,11 @@ func (bn *BeaconNetwork) processContentLoop(ctx context.Context) { } } } + +func (bn *BeaconNetwork) stateSummariesValidation(f ForkedHistoricalSummariesWithProof, latestFinalizedRoot common.Root) bool { + proof := f.HistoricalSummariesWithProof.Proof + summariesRoot := f.HistoricalSummariesWithProof.HistoricalSummaries.HashTreeRoot(bn.spec, tree.GetHashFn()) + + gIndex := 59 + return merkle.VerifyMerkleBranch(summariesRoot, proof.Proof[:], 5, uint64(gIndex), latestFinalizedRoot) +} diff --git a/portalnetwork/beacon/types.go b/portalnetwork/beacon/types.go index 56279ed5c5..b29a490135 100644 --- a/portalnetwork/beacon/types.go +++ b/portalnetwork/beacon/types.go @@ -1,6 +1,7 @@ package beacon import ( + "encoding/binary" "errors" "github.com/protolambda/zrnt/eth2/beacon/altair" @@ -38,6 +39,37 @@ type LightClientOptimisticUpdateKey struct { OptimisticSlot uint64 } +type HistoricalSummariesWithProofKey struct { + Epoch uint64 +} + +func (v HistoricalSummariesWithProofKey) ByteLength() uint64 { + return 8 +} + +func (v HistoricalSummariesWithProofKey) FixedLength() uint64 { + return 8 +} + +func (v HistoricalSummariesWithProofKey) Serialize(w *codec.EncodingWriter) error { + return w.WriteUint64(v.Epoch) +} + +func (v *HistoricalSummariesWithProofKey) Deserialize(r *codec.DecodingReader) error { + d, err := r.ReadUint64() + if err != nil { + return err + } + v.Epoch = d + return nil +} + +func (v HistoricalSummariesWithProofKey) HashTreeRoot(h tree.HashFn) common.Root { + newRoot := common.Root{} + binary.LittleEndian.PutUint64(newRoot[:], v.Epoch) + return newRoot +} + type ForkedLightClientBootstrap struct { ForkDigest common.ForkDigest Bootstrap common.SpecObj @@ -305,22 +337,60 @@ type HistoricalSummariesWithProof struct { Proof *HistoricalSummariesProof } -func (hswp *HistoricalSummariesWithProof) Deserialize(spec *common.Spec, dr *codec.DecodingReader) error { +func (hswp HistoricalSummariesWithProof) Deserialize(spec *common.Spec, dr *codec.DecodingReader) error { return dr.Container(&hswp.EPOCH, spec.Wrap(&hswp.HistoricalSummaries), hswp.Proof) } -func (hswp *HistoricalSummariesWithProof) Serialize(spec *common.Spec, w *codec.EncodingWriter) error { +func (hswp HistoricalSummariesWithProof) Serialize(spec *common.Spec, w *codec.EncodingWriter) error { return w.Container(hswp.EPOCH, spec.Wrap(&hswp.HistoricalSummaries), hswp.Proof) } -func (hswp *HistoricalSummariesWithProof) ByteLength(spec *common.Spec) uint64 { +func (hswp HistoricalSummariesWithProof) ByteLength(spec *common.Spec) uint64 { return codec.ContainerLength(hswp.EPOCH, spec.Wrap(&hswp.HistoricalSummaries), hswp.Proof) } -func (hswp *HistoricalSummariesWithProof) FixedLength(_ *common.Spec) uint64 { +func (hswp HistoricalSummariesWithProof) FixedLength(_ *common.Spec) uint64 { return 0 } -func (hswp *HistoricalSummariesWithProof) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root { +func (hswp HistoricalSummariesWithProof) HashTreeRoot(spec *common.Spec, hFn tree.HashFn) common.Root { return hFn.HashTreeRoot(hswp.EPOCH, spec.Wrap(&hswp.HistoricalSummaries), hswp.Proof) } + +type ForkedHistoricalSummariesWithProof struct { + ForkDigest common.ForkDigest + HistoricalSummariesWithProof HistoricalSummariesWithProof +} + +func (fhswp *ForkedHistoricalSummariesWithProof) Deserialize(spec *common.Spec, dr *codec.DecodingReader) error { + _, err := dr.Read(fhswp.ForkDigest[:]) + if err != nil { + return err + } + + err = fhswp.HistoricalSummariesWithProof.Deserialize(spec, dr) + if err != nil { + return err + } + + return nil +} + +func (fhswp *ForkedHistoricalSummariesWithProof) Serialize(spec *common.Spec, w *codec.EncodingWriter) error { + if err := w.Write(fhswp.ForkDigest[:]); err != nil { + return err + } + return fhswp.HistoricalSummariesWithProof.Serialize(spec, w) +} + +func (fhswp ForkedHistoricalSummariesWithProof) FixedLength(_ *common.Spec) uint64 { + return 0 +} + +func (fhswp ForkedHistoricalSummariesWithProof) ByteLength(spec *common.Spec) uint64 { + return 4 + fhswp.HistoricalSummariesWithProof.ByteLength(spec) +} + +func (fhswp ForkedHistoricalSummariesWithProof) HashTreeRoot(spec *common.Spec, h tree.HashFn) common.Root { + return h.HashTreeRoot(fhswp.ForkDigest, spec.Wrap(common.SpecObj(fhswp.HistoricalSummariesWithProof))) +}