go-ethereum/portalnetwork/beacon/light_client.go
2024-09-06 22:51:51 +08:00

703 lines
22 KiB
Go

package beacon
import (
"errors"
"fmt"
"time"
"github.com/ethereum/go-ethereum/log"
"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/beacon/deneb"
"github.com/protolambda/zrnt/eth2/configs"
"github.com/protolambda/zrnt/eth2/util/merkle"
"github.com/ethereum/go-ethereum/common/hexutil"
blsu "github.com/protolambda/bls12-381-util"
"github.com/protolambda/ztyp/tree"
"github.com/protolambda/ztyp/view"
)
var (
ErrInsufficientParticipation = errors.New("insufficient participation")
ErrInvalidTimestamp = errors.New("invalid timestamp")
ErrInvalidPeriod = errors.New("invalid sync committee period")
ErrNotRelevant = errors.New("update not relevant")
ErrInvalidFinalityProof = errors.New("invalid finality proof")
ErrInvalidNextSyncCommitteeProof = errors.New("invalid next sync committee proof")
ErrInvalidSignature = errors.New("invalid sync committee signature")
)
type ConsensusAPI interface {
GetBootstrap(blockRoot common.Root) (common.SpecObj, error)
GetUpdates(firstPeriod, count uint64) ([]common.SpecObj, error)
GetFinalityUpdate() (common.SpecObj, error)
GetOptimisticUpdate() (common.SpecObj, error)
ChainID() uint64
Name() string
}
type LightClientStore struct {
FinalizedHeader *common.BeaconBlockHeader
CurrentSyncCommittee *common.SyncCommittee
NextSyncCommittee *common.SyncCommittee
OptimisticHeader *common.BeaconBlockHeader
PreviousMaxActiveParticipants view.Uint64View
CurrentMaxActiveParticipants view.Uint64View
}
type ConsensusLightClient struct {
Store LightClientStore
API ConsensusAPI
InitialCheckpoint common.Root
LastCheckpoint common.Root
Config *Config
Logger log.Logger
}
type Config struct {
ConsensusAPI string
Port uint64
DefaultCheckpoint common.Root
Checkpoint common.Root
DataDir string
Chain ChainConfig
Spec *common.Spec
MaxCheckpointAge uint64
Fallback string
LoadExternalFallback bool
StrictCheckpointAge bool
}
type ChainConfig struct {
ChainID uint64
GenesisTime uint64
GenesisRoot common.Root
}
type GenericUpdate struct {
AttestedHeader *common.BeaconBlockHeader
SyncAggregate *altair.SyncAggregate
SignatureSlot common.Slot
NextSyncCommittee *common.SyncCommittee
NextSyncCommitteeBranch *altair.SyncCommitteeProofBranch
FinalizedHeader *common.BeaconBlockHeader
FinalityBranch *altair.FinalizedRootProofBranch
}
type GenericBootstrap struct {
Header *common.BeaconBlockHeader
CurrentSyncCommittee common.SyncCommittee
CurrentSyncCommitteeBranch altair.SyncCommitteeProofBranch
}
func FromBootstrap(commonBootstrap common.SpecObj) (*GenericBootstrap, error) {
switch bootstrap := commonBootstrap.(type) {
case *deneb.LightClientBootstrap:
return &GenericBootstrap{
Header: &bootstrap.Header.Beacon,
CurrentSyncCommittee: bootstrap.CurrentSyncCommittee,
CurrentSyncCommitteeBranch: bootstrap.CurrentSyncCommitteeBranch,
}, nil
case *capella.LightClientBootstrap:
return &GenericBootstrap{
Header: &bootstrap.Header.Beacon,
CurrentSyncCommittee: bootstrap.CurrentSyncCommittee,
CurrentSyncCommitteeBranch: bootstrap.CurrentSyncCommitteeBranch,
}, nil
case *altair.LightClientBootstrap:
return &GenericBootstrap{
Header: &bootstrap.Header.Beacon,
CurrentSyncCommittee: bootstrap.CurrentSyncCommittee,
CurrentSyncCommitteeBranch: bootstrap.CurrentSyncCommitteeBranch,
}, nil
}
return nil, errors.New("unknown bootstrap type")
}
func NewConsensusLightClient(api ConsensusAPI, config *Config, checkpointBlockRoot common.Root, logger log.Logger) (*ConsensusLightClient, error) {
client := &ConsensusLightClient{
API: api,
Config: config,
Logger: logger,
InitialCheckpoint: checkpointBlockRoot,
}
err := client.bootstrap()
if err != nil {
return nil, err
}
return client, nil
}
func (c *ConsensusLightClient) GetHeader() *common.BeaconBlockHeader {
return c.Store.OptimisticHeader
}
func (c *ConsensusLightClient) GetFinalityHeader() *common.BeaconBlockHeader {
return c.Store.FinalizedHeader
}
func (c *ConsensusLightClient) Sync() error {
err := c.bootstrap()
if err != nil {
return err
}
bootstrapPeriod := CalcSyncPeriod(uint64(c.Store.FinalizedHeader.Slot))
updates := make([]common.SpecObj, 0)
if c.API.Name() == "portal" {
currentPeriod := CalcSyncPeriod(uint64(c.expectedCurrentSlot()))
for i := bootstrapPeriod; i < currentPeriod; i++ {
update, err := c.API.GetUpdates(i, 1)
if err != nil {
return err
}
updates = append(updates, update...)
}
} else {
updates, err = c.API.GetUpdates(bootstrapPeriod, MaxRequestLightClientUpdates)
if err != nil {
return err
}
}
for _, update := range updates {
err = c.VerifyUpdate(update)
if err != nil {
return err
}
c.ApplyUpdate(update)
}
finalityUpdate, err := c.API.GetFinalityUpdate()
if err != nil {
return err
}
err = c.VerifyFinalityUpdate(finalityUpdate)
if err != nil {
return err
}
c.ApplyFinalityUpdate(finalityUpdate)
optimisticUpdate, err := c.API.GetOptimisticUpdate()
if err != nil {
return err
}
err = c.VerifyOptimisticUpdate(optimisticUpdate)
if err != nil {
return err
}
c.ApplyOptimisticUpdate(optimisticUpdate)
c.Logger.Info("Light client in sync with ", "checkpoint", hexutil.Encode(c.InitialCheckpoint[:]))
return nil
}
func (c *ConsensusLightClient) Advance() error {
finalityUpdate, err := c.API.GetFinalityUpdate()
if err != nil {
return err
}
err = c.VerifyFinalityUpdate(finalityUpdate)
if err != nil {
return err
}
c.ApplyFinalityUpdate(finalityUpdate)
optimisticUpdate, err := c.API.GetOptimisticUpdate()
if err != nil {
return err
}
err = c.VerifyOptimisticUpdate(optimisticUpdate)
if err != nil {
return err
}
c.ApplyOptimisticUpdate(optimisticUpdate)
if c.Store.NextSyncCommittee == nil {
c.Logger.Debug("checking for sync committee update")
currentPeriod := CalcSyncPeriod(uint64(c.Store.FinalizedHeader.Slot))
updates, err := c.API.GetUpdates(currentPeriod, 1)
if err != nil {
return err
}
if len(updates) == 1 {
update := updates[0]
err = c.VerifyUpdate(update)
if err != nil {
return err
}
c.Logger.Info("updating sync committee")
c.ApplyUpdate(update)
}
}
return nil
}
func (c *ConsensusLightClient) bootstrap() error {
forkedBootstrap, err := c.API.GetBootstrap(c.InitialCheckpoint)
if err != nil {
return err
}
bootstrap, err := FromBootstrap(forkedBootstrap)
if err != nil {
return err
}
isValid := c.isValidCheckpoint(bootstrap.Header.Slot)
if !isValid {
if c.Config.StrictCheckpointAge {
return errors.New("checkpoint is too old")
} else {
c.Logger.Warn("checkpoint is too old")
}
}
committeeValid := c.isCurrentCommitteeProofValid(*bootstrap.Header, bootstrap.CurrentSyncCommittee, bootstrap.CurrentSyncCommitteeBranch)
headerHash := bootstrap.Header.HashTreeRoot(tree.GetHashFn()).String()
expectedHash := c.InitialCheckpoint.String()
headerValid := headerHash == expectedHash
if !headerValid {
return fmt.Errorf("header hash %s does not match expected hash %s", headerHash, expectedHash)
}
if !committeeValid {
return errors.New("committee proof is invalid")
}
c.Store = LightClientStore{
FinalizedHeader: bootstrap.Header,
CurrentSyncCommittee: &bootstrap.CurrentSyncCommittee,
OptimisticHeader: bootstrap.Header,
PreviousMaxActiveParticipants: view.Uint64View(0),
CurrentMaxActiveParticipants: view.Uint64View(0),
}
return nil
}
func (c *ConsensusLightClient) isValidCheckpoint(blockHashSlot common.Slot) bool {
currentSlot := c.expectedCurrentSlot()
currentSlotTimestamp, err := c.slotTimestamp(currentSlot)
if err != nil {
return false
}
blockHashSlotTimestamp, err := c.slotTimestamp(blockHashSlot)
if err != nil {
return false
}
slotAge := currentSlotTimestamp - blockHashSlotTimestamp
return uint64(slotAge) < c.Config.MaxCheckpointAge
}
func (c *ConsensusLightClient) VerifyGenericUpdate(update *GenericUpdate) error {
bits := c.getBits(update.SyncAggregate.SyncCommitteeBits)
if bits == 0 {
return ErrInsufficientParticipation
}
updateFinalizedSlot := common.Slot(0)
if update.FinalizedHeader != nil {
updateFinalizedSlot = update.FinalizedHeader.Slot
}
validTime := uint64(c.expectedCurrentSlot()) >= uint64(update.SignatureSlot) && update.SignatureSlot > update.AttestedHeader.Slot && update.AttestedHeader.Slot >= updateFinalizedSlot
if !validTime {
return ErrInvalidTimestamp
}
storePeriod := CalcSyncPeriod(uint64(c.Store.FinalizedHeader.Slot))
updateSigPeriod := CalcSyncPeriod(uint64(update.SignatureSlot))
validPeriod := false
if c.Store.NextSyncCommittee != nil {
validPeriod = updateSigPeriod == storePeriod || updateSigPeriod == storePeriod+1
} else {
validPeriod = updateSigPeriod == storePeriod
}
if !validPeriod {
return ErrInvalidPeriod
}
updateAttestedPeriod := CalcSyncPeriod(uint64(update.AttestedHeader.Slot))
updateHasNextCommittee := c.Store.NextSyncCommittee == nil && update.NextSyncCommittee != nil && updateAttestedPeriod == storePeriod
if update.AttestedHeader.Slot <= c.Store.FinalizedHeader.Slot && !updateHasNextCommittee {
return ErrNotRelevant
}
if update.FinalizedHeader != nil && update.FinalityBranch != nil {
isValid := IsFinalityProofValid(*update.AttestedHeader, *update.FinalizedHeader, *update.FinalityBranch)
if !isValid {
return ErrInvalidFinalityProof
}
}
if update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch != nil {
isValid := IsNextCommitteeProofValid(*update.AttestedHeader, *update.NextSyncCommittee, *update.NextSyncCommitteeBranch)
if !isValid {
return ErrInvalidNextSyncCommitteeProof
}
}
var syncCommittee *common.SyncCommittee
if updateSigPeriod == storePeriod {
syncCommittee = c.Store.CurrentSyncCommittee
} else {
syncCommittee = c.Store.NextSyncCommittee
}
pks := c.getParticipatingKeys(*syncCommittee, update.SyncAggregate.SyncCommitteeBits)
isValidSig, err := c.VerifySyncCommitteeSignature(pks, *update.AttestedHeader, update.SyncAggregate.SyncCommitteeSignature, update.SignatureSlot)
if err != nil {
return err
}
if !isValidSig {
return ErrInvalidSignature
}
return nil
}
func (c *ConsensusLightClient) VerifyUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientUpdate(update)
if err != nil {
return err
}
return c.VerifyGenericUpdate(genericUpdate)
}
func (c *ConsensusLightClient) VerifyFinalityUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientFinalityUpdate(update)
if err != nil {
return err
}
return c.VerifyGenericUpdate(genericUpdate)
}
func (c *ConsensusLightClient) VerifyOptimisticUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientOptimisticUpdate(update)
if err != nil {
return err
}
return c.VerifyGenericUpdate(genericUpdate)
}
func (c *ConsensusLightClient) ApplyGenericUpdate(update *GenericUpdate) {
commiteeBits := c.getBits(update.SyncAggregate.SyncCommitteeBits)
if c.Store.CurrentMaxActiveParticipants < view.Uint64View(commiteeBits) {
c.Store.CurrentMaxActiveParticipants = view.Uint64View(commiteeBits)
}
shouldUpdateOptimistic := commiteeBits > c.safetyThreshold() && update.AttestedHeader.Slot > c.Store.OptimisticHeader.Slot
if shouldUpdateOptimistic {
c.Store.OptimisticHeader = update.AttestedHeader
c.logFinalityUpdate(update)
}
updateAttestedPeriod := CalcSyncPeriod(uint64(update.AttestedHeader.Slot))
updateFinalizedSlot := common.Slot(0)
if update.FinalizedHeader != nil {
updateFinalizedSlot = update.FinalizedHeader.Slot
}
updateFinalizedPeriod := CalcSyncPeriod(uint64(updateFinalizedSlot))
updateHasFinalizedNextCommittee := c.Store.NextSyncCommittee == nil &&
c.hasSyncUpdate(update) &&
c.hasFinalityUpdate(update) &&
updateFinalizedPeriod == updateAttestedPeriod
hasMajority := commiteeBits*3 >= 512*2
updateIsNewer := updateFinalizedSlot > c.Store.FinalizedHeader.Slot
goodUpdate := updateIsNewer || updateHasFinalizedNextCommittee
shouldApplyUpdate := hasMajority && goodUpdate
if shouldApplyUpdate {
storePeriod := CalcSyncPeriod(uint64(c.Store.FinalizedHeader.Slot))
if c.Store.NextSyncCommittee == nil {
c.Store.NextSyncCommittee = update.NextSyncCommittee
} else if updateFinalizedPeriod == storePeriod+1 {
c.Logger.Info("sync committee updated")
c.Store.CurrentSyncCommittee = c.Store.NextSyncCommittee
c.Store.NextSyncCommittee = update.NextSyncCommittee
c.Store.PreviousMaxActiveParticipants = c.Store.CurrentMaxActiveParticipants
c.Store.CurrentMaxActiveParticipants = 0
}
if updateFinalizedSlot > c.Store.FinalizedHeader.Slot {
c.Store.FinalizedHeader = update.FinalizedHeader
c.logFinalityUpdate(update)
if c.Store.FinalizedHeader.Slot%32 == 0 {
checkpoint := c.Store.FinalizedHeader.HashTreeRoot(tree.GetHashFn())
c.LastCheckpoint = checkpoint
}
if c.Store.FinalizedHeader.Slot > c.Store.OptimisticHeader.Slot {
c.Store.OptimisticHeader = c.Store.FinalizedHeader
}
}
}
}
func (c *ConsensusLightClient) ApplyUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientUpdate(update)
if err != nil {
return err
}
c.ApplyGenericUpdate(genericUpdate)
return nil
}
func (c *ConsensusLightClient) ApplyFinalityUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientFinalityUpdate(update)
if err != nil {
return err
}
c.ApplyGenericUpdate(genericUpdate)
return nil
}
func (c *ConsensusLightClient) ApplyOptimisticUpdate(update common.SpecObj) error {
genericUpdate, err := FromLightClientOptimisticUpdate(update)
if err != nil {
return err
}
c.ApplyGenericUpdate(genericUpdate)
return nil
}
func (c *ConsensusLightClient) VerifySyncCommitteeSignature(pks []common.BLSPubkey, attestedHeader common.BeaconBlockHeader, signature common.BLSSignature, signatureSlot common.Slot) (bool, error) {
headerRoot := attestedHeader.HashTreeRoot(tree.GetHashFn())
signingRoot := c.ComputeCommitteeSignRoot(headerRoot, signatureSlot)
blsuPubKeys := make([]*blsu.Pubkey, 0, len(pks))
for _, p := range pks {
blsuPubKey, err := p.Pubkey()
if err != nil {
return false, err
}
blsuPubKeys = append(blsuPubKeys, blsuPubKey)
}
blsuSig, err := signature.Signature()
if err != nil {
return false, err
}
return blsu.FastAggregateVerify(blsuPubKeys, signingRoot[:], blsuSig), nil
}
func (c *ConsensusLightClient) ComputeCommitteeSignRoot(headerRoot tree.Root, slot common.Slot) common.Root {
genesisRoot := c.Config.Chain.GenesisRoot
domainType := hexutil.MustDecode("0x07000000")
forkVersion := c.Config.Spec.ForkVersion(slot)
domain := common.ComputeDomain(common.BLSDomainType(domainType), forkVersion, genesisRoot)
return ComputeSigningRoot(headerRoot, domain)
}
func (c *ConsensusLightClient) expectedCurrentSlot() common.Slot {
return c.Config.Spec.TimeToSlot(common.Timestamp(time.Now().Unix()), common.Timestamp(c.Config.Chain.GenesisTime))
}
func (c *ConsensusLightClient) slotTimestamp(slot common.Slot) (common.Timestamp, error) {
atSlot, err := c.Config.Spec.TimeAtSlot(slot, common.Timestamp(c.Config.Chain.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 (c *ConsensusLightClient) safetyThreshold() uint64 {
if c.Store.CurrentMaxActiveParticipants > c.Store.PreviousMaxActiveParticipants {
return uint64(c.Store.CurrentMaxActiveParticipants) / 2
} else {
return uint64(c.Store.PreviousMaxActiveParticipants) / 2
}
}
func (c *ConsensusLightClient) hasSyncUpdate(update *GenericUpdate) bool {
return update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch != nil
}
func (c *ConsensusLightClient) hasFinalityUpdate(update *GenericUpdate) bool {
return update.FinalizedHeader != nil && update.FinalityBranch != nil
}
func (c *ConsensusLightClient) logFinalityUpdate(update *GenericUpdate) {
count := c.getBits(update.SyncAggregate.SyncCommitteeBits)
participation := float32(count) / 512 * 100
decimals := 0
if participation == 100.0 {
decimals = 1
} else {
decimals = 2
}
slot := c.Store.OptimisticHeader.Slot
age, err := c.age(slot)
if err != nil {
c.Logger.Error("failed to get age", "slot is", slot, "err is", err)
return
}
days := int(age.Hours() / 24)
hours := int(age.Hours()) % 24
minutes := int(age.Minutes()) % 60
secs := int(age.Seconds()) % 60
ageStr := fmt.Sprintf("%d:%d:%d:%d", days, hours, minutes, secs)
c.Logger.Info("update header", "slot=", slot, "confidence=", decimals, "age", ageStr)
}
func (c *ConsensusLightClient) age(slot common.Slot) (time.Duration, error) {
expectTime, err := c.slotTimestamp(slot)
if err != nil {
return time.Duration(0), err
}
return time.Since(time.Unix(int64(expectTime), 0)), nil
}
func (c *ConsensusLightClient) getBits(sync altair.SyncCommitteeBits) uint64 {
res := 0
for i := 0; i < int(c.Config.Spec.SYNC_COMMITTEE_SIZE); i++ {
if sync.GetBit(uint64(i)) {
res++
}
}
return uint64(res)
}
func (c *ConsensusLightClient) getParticipatingKeys(committee common.SyncCommittee, syncBits altair.SyncCommitteeBits) []common.BLSPubkey {
res := make([]common.BLSPubkey, 0)
for i := 0; i < int(c.Config.Spec.SYNC_COMMITTEE_SIZE); i++ {
if syncBits.GetBit(uint64(i)) {
res = append(res, committee.Pubkeys[i])
}
}
return res
}
func FromLightClientUpdate(commonUpdate common.SpecObj) (*GenericUpdate, error) {
switch update := commonUpdate.(type) {
case *deneb.LightClientUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
NextSyncCommittee: &update.NextSyncCommittee,
NextSyncCommitteeBranch: &update.NextSyncCommitteeBranch,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}, nil
case *capella.LightClientUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
NextSyncCommittee: &update.NextSyncCommittee,
NextSyncCommitteeBranch: &update.NextSyncCommitteeBranch,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}, nil
case *altair.LightClientUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
NextSyncCommittee: &update.NextSyncCommittee,
NextSyncCommitteeBranch: &update.NextSyncCommitteeBranch,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}, nil
}
return nil, errors.New("unknown update type")
}
func FromLightClientFinalityUpdate(commonFinalityUpdate common.SpecObj) (*GenericUpdate, error) {
switch update := commonFinalityUpdate.(type) {
case *deneb.LightClientFinalityUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}, nil
case *capella.LightClientFinalityUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
FinalizedHeader: &update.FinalizedHeader.Beacon,
FinalityBranch: &update.FinalityBranch,
}, nil
case *altair.LightClientFinalityUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
FinalizedHeader: &update.FinalizedHeader,
FinalityBranch: &update.FinalityBranch,
}, nil
}
return nil, errors.New("unknown finality update type")
}
func FromLightClientOptimisticUpdate(commonOptimisticUpdate common.SpecObj) (*GenericUpdate, error) {
switch update := commonOptimisticUpdate.(type) {
case *deneb.LightClientOptimisticUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}, nil
case *capella.LightClientOptimisticUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}, nil
case *altair.LightClientOptimisticUpdate:
return &GenericUpdate{
AttestedHeader: &update.AttestedHeader.Beacon,
SyncAggregate: &update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}, nil
}
return nil, errors.New("unknown optimistic update type")
}
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(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)
}