Skip to content

Commit

Permalink
feat: add verify update method
Browse files Browse the repository at this point in the history
  • Loading branch information
fearlessfe committed Apr 10, 2024
1 parent 0483807 commit 50024bd
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 126 deletions.
196 changes: 116 additions & 80 deletions portalnetwork/beacon/light_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/protolambda/zrnt/eth2/beacon/altair"
"github.com/protolambda/zrnt/eth2/beacon/capella"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/zrnt/eth2/configs"
"github.com/protolambda/zrnt/eth2/util/merkle"

"github.com/ethereum/go-ethereum/common/hexutil"
Expand Down Expand Up @@ -75,6 +76,16 @@ type ChainConfig struct {
GenesisRoot common.Root
}

type GenericUpdate struct {
AttestedHeader *common.BeaconBlockHeader
SyncAggregate *altair.SyncAggregate
SingnatureSlot common.Slot
NextSyncCommittee *common.SyncCommittee
NextSyncCommitteeBranch *altair.SyncCommitteeProofBranch
FinalizedHeader *common.BeaconBlockHeader
FinalityBranch *altair.FinalizedRootProofBranch
}

//lint:ignore U1000 placeholder function
func (c *ConsensusLightClient) bootstrap() error {
bootstrap, err := c.API.GetCheckpointData(c.InitialCheckpoint)
Expand Down Expand Up @@ -133,77 +144,21 @@ func (c *ConsensusLightClient) isValidCheckpoint(blockHashSlot common.Slot) bool
return uint64(slotAge) < c.Config.MaxCheckpointAge
}

func (c *ConsensusLightClient) expectedCurrentSlot() common.Slot {
return c.Config.Spec.TimeToSlot(common.Timestamp(time.Now().Unix()), common.Timestamp(c.Config.ChainConfig.GenesisTime))
}

func (c *ConsensusLightClient) slotTimestamp(slot common.Slot) (common.Timestamp, error) {
atSlot, err := c.Config.Spec.TimeAtSlot(slot, common.Timestamp(c.Config.ChainConfig.GenesisTime))
if err != nil {
return 0, err
}

return atSlot, nil
}

func (c *ConsensusLightClient) isCurrentCommitteeProofValid(attestedHeader common.BeaconBlockHeader, currentCommittee common.SyncCommittee, currentCommitteeBranch altair.SyncCommitteeProofBranch) bool {
return merkle.VerifyMerkleBranch(currentCommittee.HashTreeRoot(c.Config.Spec, tree.GetHashFn()), currentCommitteeBranch[:], 5, 22, attestedHeader.StateRoot)
}
type GenericUpdate struct {
AttestedHeader *common.BeaconBlockHeader
SyncAggregate *altair.SyncAggregate
SingnatureSlot common.Slot
NextSyncCommittee *common.SyncCommittee
NextSyncCommitteeBranch *altair.SyncCommitteeProofBranch
FinalizedHeader *common.BeaconBlockHeader
FinalityBranch *altair.FinalizedRootProofBranch
}

func FromLightClientUpdate(update *capella.LightClientUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
NextSyncCommittee: &update.NextSyncCommittee,
NextSyncCommitteeBranch: &update.NextSyncCommitteeBranch,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}
}

func FromLightClientFinalityUpdate(update *capella.LightClientFinalityUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}
}

func FromLightClientOptimisticUpdate(update *capella.LightClientOptimisticUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
}
}

func (clc *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) error {
func (c *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) error {
bits := bitfield.Bitlist(update.SyncAggregate.SyncCommitteeBits).Count()
if bits == 0 {
return ErrInsufficientParticipation
}
updateFinalizedSlot := update.FinalizedHeader.Slot
validTime := clc.CurrentSlot() >= uint64(update.SingnatureSlot) && update.SingnatureSlot > update.AttestedHeader.Slot && update.AttestedHeader.Slot >= updateFinalizedSlot
validTime := uint64(c.expectedCurrentSlot()) >= uint64(update.SingnatureSlot) && update.SingnatureSlot > update.AttestedHeader.Slot && update.AttestedHeader.Slot >= updateFinalizedSlot
if !validTime {
return ErrInvalidTimestamp
}

storePeriod := CalcSyncPeriod(uint64(clc.Store.FinalizedHeader.Slot))
storePeriod := CalcSyncPeriod(uint64(c.Store.FinalizedHeader.Slot))
updateSigPeriod := CalcSyncPeriod(uint64(update.SingnatureSlot))
validPeriod := false
if clc.Store.NextSyncCommittee != nil {
if c.Store.NextSyncCommittee != nil {
validPeriod = (updateSigPeriod == storePeriod || updateSigPeriod == storePeriod+1)
} else {
validPeriod = (updateSigPeriod == storePeriod)
Expand All @@ -213,9 +168,9 @@ func (clc *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) erro
}

updateAttestedPeriod := CalcSyncPeriod(uint64(update.AttestedHeader.Slot))
updateHasNextCommittee := (clc.Store.NextSyncCommittee == nil && update.NextSyncCommittee != nil && updateAttestedPeriod == storePeriod)
updateHasNextCommittee := (c.Store.NextSyncCommittee == nil && update.NextSyncCommittee != nil && updateAttestedPeriod == storePeriod)

if update.AttestedHeader.Slot <= clc.Store.FinalizedHeader.Slot && !updateHasNextCommittee {
if update.AttestedHeader.Slot <= c.Store.FinalizedHeader.Slot && !updateHasNextCommittee {
return ErrNotRelevant
}
if update.FinalizedHeader != nil && update.FinalityBranch != nil {
Expand All @@ -225,22 +180,22 @@ func (clc *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) erro
}
}
if update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch != nil {
isValid := IsNextCommitteeProofValid(clc.Config.Spec, *update.AttestedHeader, *update.NextSyncCommittee, *update.NextSyncCommitteeBranch)
isValid := IsNextCommitteeProofValid(c.Config.Spec, *update.AttestedHeader, *update.NextSyncCommittee, *update.NextSyncCommitteeBranch)
if !isValid {
return ErrInvalidNextSyncCommitteeProof
}
}
var syncCommittee *common.SyncCommittee

if updateSigPeriod == storePeriod {
syncCommittee = clc.Store.CurrentSyncCommittee
syncCommittee = c.Store.CurrentSyncCommittee
} else {
syncCommittee = clc.Store.NextSyncCommittee
syncCommittee = c.Store.NextSyncCommittee
}

pks := GetParticipatingKeys(*syncCommittee, update.SyncAggregate.SyncCommitteeBits)

isValidSig, err := clc.VerifySyncCommitteeSignature(pks, *update.AttestedHeader, update.SyncAggregate.SyncCommitteeSignature, update.SingnatureSlot)
isValidSig, err := c.VerifySyncCommitteeSignature(pks, *update.AttestedHeader, update.SyncAggregate.SyncCommitteeSignature, update.SingnatureSlot)
if err != nil {
return err
}
Expand All @@ -250,19 +205,24 @@ func (clc *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) erro
return nil
}

func (clc *ConsensusLightClient) VerifyFinalityUpdate(update *capella.LightClientFinalityUpdate) error {
func (c *ConsensusLightClient) VerifyUpdate(update *capella.LightClientUpdate) error {
genericUpdate := FromLightClientUpdate(update)
return c.VerifyGenericUpdate(genericUpdate)
}

func (c *ConsensusLightClient) VerifyFinalityUpdate(update *capella.LightClientFinalityUpdate) error {
genericUpdate := FromLightClientFinalityUpdate(update)
return clc.VerifyGenericUpdate(genericUpdate)
return c.VerifyGenericUpdate(genericUpdate)
}

func (clc *ConsensusLightClient) VerifyOptimisticUpdate(update *capella.LightClientOptimisticUpdate) error {
func (c *ConsensusLightClient) VerifyOptimisticUpdate(update *capella.LightClientOptimisticUpdate) error {
genericUpdate := FromLightClientOptimisticUpdate(update)
return clc.VerifyGenericUpdate(genericUpdate)
return c.VerifyGenericUpdate(genericUpdate)
}

func (clc *ConsensusLightClient) VerifySyncCommitteeSignature(pks []common.BLSPubkey, attestedHeader common.BeaconBlockHeader, signature common.BLSSignature, signatureSlot common.Slot) (bool, error) {
func (c *ConsensusLightClient) VerifySyncCommitteeSignature(pks []common.BLSPubkey, attestedHeader common.BeaconBlockHeader, signature common.BLSSignature, signatureSlot common.Slot) (bool, error) {
headerRoot := attestedHeader.HashTreeRoot(tree.GetHashFn())
signingRoot := clc.ComputeCommitteeSignRoot(headerRoot, signatureSlot)
signingRoot := c.ComputeCommitteeSignRoot(headerRoot, signatureSlot)
blsuPubKeys := make([]*blsu.Pubkey, 0, len(pks))
for _, p := range pks {
blsuPubKey, err := p.Pubkey()
Expand All @@ -278,17 +238,93 @@ func (clc *ConsensusLightClient) VerifySyncCommitteeSignature(pks []common.BLSPu
return blsu.FastAggregateVerify(blsuPubKeys, signingRoot[:], blsuSig), nil
}

func (clc *ConsensusLightClient) ComputeCommitteeSignRoot(headerRoot tree.Root, slot common.Slot) common.Root {
genesisRoot := clc.Config.ChainConfig.GenesisRoot
func (c *ConsensusLightClient) ComputeCommitteeSignRoot(headerRoot tree.Root, slot common.Slot) common.Root {
genesisRoot := c.Config.ChainConfig.GenesisRoot
domainType := hexutil.MustDecode("0x07000000")
forkVersion := clc.Config.Spec.ForkVersion(slot)
forkVersion := c.Config.Spec.ForkVersion(slot)
domain := common.ComputeDomain(common.BLSDomainType(domainType), forkVersion, genesisRoot)
return ComputeSigningRoot(headerRoot, domain)
}

func (clc *ConsensusLightClient) CurrentSlot() uint64 {
now := time.Now().Unix()
genesisTime := clc.Config.ChainConfig.GenesisTime
sinceGenesis := now - int64(genesisTime)
return uint64(sinceGenesis / 2)
func (c *ConsensusLightClient) expectedCurrentSlot() common.Slot {
return c.Config.Spec.TimeToSlot(common.Timestamp(time.Now().Unix()), common.Timestamp(c.Config.ChainConfig.GenesisTime))
}

func (c *ConsensusLightClient) slotTimestamp(slot common.Slot) (common.Timestamp, error) {
atSlot, err := c.Config.Spec.TimeAtSlot(slot, common.Timestamp(c.Config.ChainConfig.GenesisTime))
if err != nil {
return 0, err
}

return atSlot, nil
}

func (c *ConsensusLightClient) isCurrentCommitteeProofValid(attestedHeader common.BeaconBlockHeader, currentCommittee common.SyncCommittee, currentCommitteeBranch altair.SyncCommitteeProofBranch) bool {
return merkle.VerifyMerkleBranch(currentCommittee.HashTreeRoot(c.Config.Spec, tree.GetHashFn()), currentCommitteeBranch[:], 5, 22, attestedHeader.StateRoot)
}

func FromLightClientUpdate(update *capella.LightClientUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
NextSyncCommittee: &update.NextSyncCommittee,
NextSyncCommitteeBranch: &update.NextSyncCommitteeBranch,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}
}

func FromLightClientFinalityUpdate(update *capella.LightClientFinalityUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}
}

func FromLightClientOptimisticUpdate(update *capella.LightClientOptimisticUpdate) *GenericUpdate {
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SingnatureSlot: update.SignatureSlot,
}
}

func ComputeSigningRoot(root common.Root, domain common.BLSDomain) common.Root {
data := common.SigningData{
ObjectRoot: root,
Domain: domain,
}
return data.HashTreeRoot(tree.GetHashFn())
}

func CalcSyncPeriod(slot uint64) uint64 {
epoch := slot / 32 // 32 slots per epoch
return epoch / 256 // 256 epochs per sync committee
}

func IsFinalityProofValid(attestedHeader common.BeaconBlockHeader, finalityHeader common.BeaconBlockHeader, finalityBranch altair.FinalizedRootProofBranch) bool {
leaf := finalityHeader.HashTreeRoot(tree.GetHashFn())
root := attestedHeader.StateRoot
return merkle.VerifyMerkleBranch(leaf, finalityBranch[:], 6, 41, root)
}

func IsNextCommitteeProofValid(spec *common.Spec, attestedHeader common.BeaconBlockHeader, nextCommittee common.SyncCommittee, nextCommitteeBranch altair.SyncCommitteeProofBranch) bool {
leaf := nextCommittee.HashTreeRoot(configs.Mainnet, tree.GetHashFn())
root := attestedHeader.StateRoot
return merkle.VerifyMerkleBranch(leaf, nextCommitteeBranch[:], 5, 23, root)
}

func GetParticipatingKeys(committee common.SyncCommittee, syncBits altair.SyncCommitteeBits) []common.BLSPubkey {
bits := bitfield.Bitlist(syncBits)
res := make([]common.BLSPubkey, 0, bits.Count())
for i := 0; i < int(bits.Len()); i++ {
if bits.BitAt(uint64(i)) {
res = append(res, committee.Pubkeys[i])
}
}
return res
}
46 changes: 0 additions & 46 deletions portalnetwork/beacon/light_client_helper.go

This file was deleted.

0 comments on commit 50024bd

Please sign in to comment.