diff --git a/beacon/light/canonical.go b/beacon/light/canonical.go
deleted file mode 100644
index b5371493b4..0000000000
--- a/beacon/light/canonical.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2023 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package light
-
-import (
- "encoding/binary"
- "fmt"
-
- "github.com/ethereum/go-ethereum/common/lru"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/rlp"
-)
-
-// canonicalStore stores instances of the given type in a database and caches
-// them in memory, associated with a continuous range of period numbers.
-// Note: canonicalStore is not thread safe and it is the caller's responsibility
-// to avoid concurrent access.
-type canonicalStore[T any] struct {
- keyPrefix []byte
- periods periodRange
- cache *lru.Cache[uint64, T]
-}
-
-// newCanonicalStore creates a new canonicalStore and loads all keys associated
-// with the keyPrefix in order to determine the ranges available in the database.
-func newCanonicalStore[T any](db ethdb.Iteratee, keyPrefix []byte) (*canonicalStore[T], error) {
- cs := &canonicalStore[T]{
- keyPrefix: keyPrefix,
- cache: lru.NewCache[uint64, T](100),
- }
- var (
- iter = db.NewIterator(keyPrefix, nil)
- kl = len(keyPrefix)
- first = true
- )
- defer iter.Release()
-
- for iter.Next() {
- if len(iter.Key()) != kl+8 {
- log.Warn("Invalid key length in the canonical chain database", "key", fmt.Sprintf("%#x", iter.Key()))
- continue
- }
- period := binary.BigEndian.Uint64(iter.Key()[kl : kl+8])
- if first {
- cs.periods.Start = period
- } else if cs.periods.End != period {
- return nil, fmt.Errorf("gap in the canonical chain database between periods %d and %d", cs.periods.End, period-1)
- }
- first = false
- cs.periods.End = period + 1
- }
- return cs, nil
-}
-
-// databaseKey returns the database key belonging to the given period.
-func (cs *canonicalStore[T]) databaseKey(period uint64) []byte {
- return binary.BigEndian.AppendUint64(append([]byte{}, cs.keyPrefix...), period)
-}
-
-// add adds the given item to the database. It also ensures that the range remains
-// continuous. Can be used either with a batch or database backend.
-func (cs *canonicalStore[T]) add(backend ethdb.KeyValueWriter, period uint64, value T) error {
- if !cs.periods.canExpand(period) {
- return fmt.Errorf("period expansion is not allowed, first: %d, next: %d, period: %d", cs.periods.Start, cs.periods.End, period)
- }
- enc, err := rlp.EncodeToBytes(value)
- if err != nil {
- return err
- }
- if err := backend.Put(cs.databaseKey(period), enc); err != nil {
- return err
- }
- cs.cache.Add(period, value)
- cs.periods.expand(period)
- return nil
-}
-
-// deleteFrom removes items starting from the given period.
-func (cs *canonicalStore[T]) deleteFrom(db ethdb.KeyValueWriter, fromPeriod uint64) (deleted periodRange) {
- keepRange, deleteRange := cs.periods.split(fromPeriod)
- deleteRange.each(func(period uint64) {
- db.Delete(cs.databaseKey(period))
- cs.cache.Remove(period)
- })
- cs.periods = keepRange
- return deleteRange
-}
-
-// get returns the item at the given period or the null value of the given type
-// if no item is present.
-func (cs *canonicalStore[T]) get(backend ethdb.KeyValueReader, period uint64) (T, bool) {
- var null, value T
- if !cs.periods.contains(period) {
- return null, false
- }
- if value, ok := cs.cache.Get(period); ok {
- return value, true
- }
- enc, err := backend.Get(cs.databaseKey(period))
- if err != nil {
- log.Error("Canonical store value not found", "period", period, "start", cs.periods.Start, "end", cs.periods.End)
- return null, false
- }
- if err := rlp.DecodeBytes(enc, &value); err != nil {
- log.Error("Error decoding canonical store value", "error", err)
- return null, false
- }
- cs.cache.Add(period, value)
- return value, true
-}
diff --git a/beacon/light/committee_chain.go b/beacon/light/committee_chain.go
deleted file mode 100644
index d707f8cc34..0000000000
--- a/beacon/light/committee_chain.go
+++ /dev/null
@@ -1,514 +0,0 @@
-// Copyright 2023 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package light
-
-import (
- "errors"
- "fmt"
- "math"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/beacon/params"
- "github.com/ethereum/go-ethereum/beacon/types"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/lru"
- "github.com/ethereum/go-ethereum/common/mclock"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
-)
-
-var (
- ErrNeedCommittee = errors.New("sync committee required")
- ErrInvalidUpdate = errors.New("invalid committee update")
- ErrInvalidPeriod = errors.New("invalid update period")
- ErrWrongCommitteeRoot = errors.New("wrong committee root")
- ErrCannotReorg = errors.New("can not reorg committee chain")
-)
-
-// CommitteeChain is a passive data structure that can validate, hold and update
-// a chain of beacon light sync committees and updates. It requires at least one
-// externally set fixed committee root at the beginning of the chain which can
-// be set either based on a BootstrapData or a trusted source (a local beacon
-// full node). This makes the structure useful for both light client and light
-// server setups.
-//
-// It always maintains the following consistency constraints:
-// - a committee can only be present if its root hash matches an existing fixed
-// root or if it is proven by an update at the previous period
-// - an update can only be present if a committee is present at the same period
-// and the update signature is valid and has enough participants.
-// The committee at the next period (proven by the update) should also be
-// present (note that this means they can only be added together if neither
-// is present yet). If a fixed root is present at the next period then the
-// update can only be present if it proves the same committee root.
-//
-// Once synced to the current sync period, CommitteeChain can also validate
-// signed beacon headers.
-type CommitteeChain struct {
- // chainmu guards against concurrent access to the canonicalStore structures
- // (updates, committees, fixedCommitteeRoots) and ensures that they stay consistent
- // with each other and with committeeCache.
- chainmu sync.RWMutex
- db ethdb.KeyValueStore
- updates *canonicalStore[*types.LightClientUpdate]
- committees *canonicalStore[*types.SerializedSyncCommittee]
- fixedCommitteeRoots *canonicalStore[common.Hash]
- committeeCache *lru.Cache[uint64, syncCommittee] // cache deserialized committees
-
- clock mclock.Clock // monotonic clock (simulated clock in tests)
- unixNano func() int64 // system clock (simulated clock in tests)
- sigVerifier committeeSigVerifier // BLS sig verifier (dummy verifier in tests)
-
- config *types.ChainConfig
- signerThreshold int
- minimumUpdateScore types.UpdateScore
- enforceTime bool // enforceTime specifies whether the age of a signed header should be checked
-}
-
-// NewCommitteeChain creates a new CommitteeChain.
-func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain {
- return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() })
-}
-
-// newCommitteeChain creates a new CommitteeChain with the option of replacing the
-// clock source and signature verification for testing purposes.
-func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
- s := &CommitteeChain{
- committeeCache: lru.NewCache[uint64, syncCommittee](10),
- db: db,
- sigVerifier: sigVerifier,
- clock: clock,
- unixNano: unixNano,
- config: config,
- signerThreshold: signerThreshold,
- enforceTime: enforceTime,
- minimumUpdateScore: types.UpdateScore{
- SignerCount: uint32(signerThreshold),
- SubPeriodIndex: params.SyncPeriodLength / 16,
- },
- }
-
- var err1, err2, err3 error
- if s.fixedCommitteeRoots, err1 = newCanonicalStore[common.Hash](db, rawdb.FixedCommitteeRootKey); err1 != nil {
- log.Error("Error creating fixed committee root store", "error", err1)
- }
- if s.committees, err2 = newCanonicalStore[*types.SerializedSyncCommittee](db, rawdb.SyncCommitteeKey); err2 != nil {
- log.Error("Error creating committee store", "error", err2)
- }
- if s.updates, err3 = newCanonicalStore[*types.LightClientUpdate](db, rawdb.BestUpdateKey); err3 != nil {
- log.Error("Error creating update store", "error", err3)
- }
- if err1 != nil || err2 != nil || err3 != nil || !s.checkConstraints() {
- log.Info("Resetting invalid committee chain")
- s.Reset()
- }
- // roll back invalid updates (might be necessary if forks have been changed since last time)
- for !s.updates.periods.isEmpty() {
- update, ok := s.updates.get(s.db, s.updates.periods.End-1)
- if !ok {
- log.Error("Sync committee update missing", "period", s.updates.periods.End-1)
- s.Reset()
- break
- }
- if valid, err := s.verifyUpdate(update); err != nil {
- log.Error("Error validating update", "period", s.updates.periods.End-1, "error", err)
- } else if valid {
- break
- }
- if err := s.rollback(s.updates.periods.End); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- }
- }
- if !s.committees.periods.isEmpty() {
- log.Trace("Sync committee chain loaded", "first period", s.committees.periods.Start, "last period", s.committees.periods.End-1)
- }
- return s
-}
-
-// checkConstraints checks committee chain validity constraints
-func (s *CommitteeChain) checkConstraints() bool {
- isNotInFixedCommitteeRootRange := func(r periodRange) bool {
- return s.fixedCommitteeRoots.periods.isEmpty() ||
- r.Start < s.fixedCommitteeRoots.periods.Start ||
- r.Start >= s.fixedCommitteeRoots.periods.End
- }
-
- valid := true
- if !s.updates.periods.isEmpty() {
- if isNotInFixedCommitteeRootRange(s.updates.periods) {
- log.Error("Start update is not in the fixed roots range")
- valid = false
- }
- if s.committees.periods.Start > s.updates.periods.Start || s.committees.periods.End <= s.updates.periods.End {
- log.Error("Missing committees in update range")
- valid = false
- }
- }
- if !s.committees.periods.isEmpty() {
- if isNotInFixedCommitteeRootRange(s.committees.periods) {
- log.Error("Start committee is not in the fixed roots range")
- valid = false
- }
- if s.committees.periods.End > s.fixedCommitteeRoots.periods.End && s.committees.periods.End > s.updates.periods.End+1 {
- log.Error("Last committee is neither in the fixed roots range nor proven by updates")
- valid = false
- }
- }
- return valid
-}
-
-// Reset resets the committee chain.
-func (s *CommitteeChain) Reset() {
- s.chainmu.Lock()
- defer s.chainmu.Unlock()
-
- if err := s.rollback(0); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- }
-}
-
-// CheckpointInit initializes a CommitteeChain based on the checkpoint.
-// Note: if the chain is already initialized and the committees proven by the
-// checkpoint do match the existing chain then the chain is retained and the
-// new checkpoint becomes fixed.
-func (s *CommitteeChain) CheckpointInit(bootstrap *types.BootstrapData) error {
- s.chainmu.Lock()
- defer s.chainmu.Unlock()
-
- if err := bootstrap.Validate(); err != nil {
- return err
- }
-
- period := bootstrap.Header.SyncPeriod()
- if err := s.deleteFixedCommitteeRootsFrom(period + 2); err != nil {
- s.Reset()
- return err
- }
- if s.addFixedCommitteeRoot(period, bootstrap.CommitteeRoot) != nil {
- s.Reset()
- if err := s.addFixedCommitteeRoot(period, bootstrap.CommitteeRoot); err != nil {
- s.Reset()
- return err
- }
- }
- if err := s.addFixedCommitteeRoot(period+1, common.Hash(bootstrap.CommitteeBranch[0])); err != nil {
- s.Reset()
- return err
- }
- if err := s.addCommittee(period, bootstrap.Committee); err != nil {
- s.Reset()
- return err
- }
- return nil
-}
-
-// addFixedCommitteeRoot sets a fixed committee root at the given period.
-// Note that the period where the first committee is added has to have a fixed
-// root which can either come from a BootstrapData or a trusted source.
-func (s *CommitteeChain) addFixedCommitteeRoot(period uint64, root common.Hash) error {
- if root == (common.Hash{}) {
- return ErrWrongCommitteeRoot
- }
-
- batch := s.db.NewBatch()
- oldRoot := s.getCommitteeRoot(period)
- if !s.fixedCommitteeRoots.periods.canExpand(period) {
- // Note: the fixed committee root range should always be continuous and
- // therefore the expected syncing method is to forward sync and optionally
- // backward sync periods one by one, starting from a checkpoint. The only
- // case when a root that is not adjacent to the already fixed ones can be
- // fixed is when the same root has already been proven by an update chain.
- // In this case the all roots in between can and should be fixed.
- // This scenario makes sense when a new trusted checkpoint is added to an
- // existing chain, ensuring that it will not be rolled back (might be
- // important in case of low signer participation rate).
- if root != oldRoot {
- return ErrInvalidPeriod
- }
- // if the old root exists and matches the new one then it is guaranteed
- // that the given period is after the existing fixed range and the roots
- // in between can also be fixed.
- for p := s.fixedCommitteeRoots.periods.End; p < period; p++ {
- if err := s.fixedCommitteeRoots.add(batch, p, s.getCommitteeRoot(p)); err != nil {
- return err
- }
- }
- }
- if oldRoot != (common.Hash{}) && (oldRoot != root) {
- // existing old root was different, we have to reorg the chain
- if err := s.rollback(period); err != nil {
- return err
- }
- }
- if err := s.fixedCommitteeRoots.add(batch, period, root); err != nil {
- return err
- }
- if err := batch.Write(); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- return err
- }
- return nil
-}
-
-// deleteFixedCommitteeRootsFrom deletes fixed roots starting from the given period.
-// It also maintains chain consistency, meaning that it also deletes updates and
-// committees if they are no longer supported by a valid update chain.
-func (s *CommitteeChain) deleteFixedCommitteeRootsFrom(period uint64) error {
- if period >= s.fixedCommitteeRoots.periods.End {
- return nil
- }
- batch := s.db.NewBatch()
- s.fixedCommitteeRoots.deleteFrom(batch, period)
- if s.updates.periods.isEmpty() || period <= s.updates.periods.Start {
- // Note: the first period of the update chain should always be fixed so if
- // the fixed root at the first update is removed then the entire update chain
- // and the proven committees have to be removed. Earlier committees in the
- // remaining fixed root range can stay.
- s.updates.deleteFrom(batch, period)
- s.deleteCommitteesFrom(batch, period)
- } else {
- // The update chain stays intact, some previously fixed committee roots might
- // get unfixed but are still proven by the update chain. If there were
- // committees present after the range proven by updates, those should be
- // removed if the belonging fixed roots are also removed.
- fromPeriod := s.updates.periods.End + 1 // not proven by updates
- if period > fromPeriod {
- fromPeriod = period // also not justified by fixed roots
- }
- s.deleteCommitteesFrom(batch, fromPeriod)
- }
- if err := batch.Write(); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- return err
- }
- return nil
-}
-
-// deleteCommitteesFrom deletes committees starting from the given period.
-func (s *CommitteeChain) deleteCommitteesFrom(batch ethdb.Batch, period uint64) {
- deleted := s.committees.deleteFrom(batch, period)
- for period := deleted.Start; period < deleted.End; period++ {
- s.committeeCache.Remove(period)
- }
-}
-
-// addCommittee adds a committee at the given period if possible.
-func (s *CommitteeChain) addCommittee(period uint64, committee *types.SerializedSyncCommittee) error {
- if !s.committees.periods.canExpand(period) {
- return ErrInvalidPeriod
- }
- root := s.getCommitteeRoot(period)
- if root == (common.Hash{}) {
- return ErrInvalidPeriod
- }
- if root != committee.Root() {
- return ErrWrongCommitteeRoot
- }
- if !s.committees.periods.contains(period) {
- if err := s.committees.add(s.db, period, committee); err != nil {
- return err
- }
- s.committeeCache.Remove(period)
- }
- return nil
-}
-
-// InsertUpdate adds a new update if possible.
-func (s *CommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
- s.chainmu.Lock()
- defer s.chainmu.Unlock()
-
- period := update.AttestedHeader.Header.SyncPeriod()
- if !s.updates.periods.canExpand(period) || !s.committees.periods.contains(period) {
- return ErrInvalidPeriod
- }
- if s.minimumUpdateScore.BetterThan(update.Score()) {
- return ErrInvalidUpdate
- }
- oldRoot := s.getCommitteeRoot(period + 1)
- reorg := oldRoot != (common.Hash{}) && oldRoot != update.NextSyncCommitteeRoot
- if oldUpdate, ok := s.updates.get(s.db, period); ok && !update.Score().BetterThan(oldUpdate.Score()) {
- // a better or equal update already exists; no changes, only fail if new one tried to reorg
- if reorg {
- return ErrCannotReorg
- }
- return nil
- }
- if s.fixedCommitteeRoots.periods.contains(period+1) && reorg {
- return ErrCannotReorg
- }
- if ok, err := s.verifyUpdate(update); err != nil {
- return err
- } else if !ok {
- return ErrInvalidUpdate
- }
- addCommittee := !s.committees.periods.contains(period+1) || reorg
- if addCommittee {
- if nextCommittee == nil {
- return ErrNeedCommittee
- }
- if nextCommittee.Root() != update.NextSyncCommitteeRoot {
- return ErrWrongCommitteeRoot
- }
- }
- if reorg {
- if err := s.rollback(period + 1); err != nil {
- return err
- }
- }
- batch := s.db.NewBatch()
- if addCommittee {
- if err := s.committees.add(batch, period+1, nextCommittee); err != nil {
- return err
- }
- s.committeeCache.Remove(period + 1)
- }
- if err := s.updates.add(batch, period, update); err != nil {
- return err
- }
- if err := batch.Write(); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- return err
- }
- log.Info("Inserted new committee update", "period", period, "next committee root", update.NextSyncCommitteeRoot)
- return nil
-}
-
-// NextSyncPeriod returns the next period where an update can be added and also
-// whether the chain is initialized at all.
-func (s *CommitteeChain) NextSyncPeriod() (uint64, bool) {
- s.chainmu.RLock()
- defer s.chainmu.RUnlock()
-
- if s.committees.periods.isEmpty() {
- return 0, false
- }
- if !s.updates.periods.isEmpty() {
- return s.updates.periods.End, true
- }
- return s.committees.periods.End - 1, true
-}
-
-// rollback removes all committees and fixed roots from the given period and updates
-// starting from the previous period.
-func (s *CommitteeChain) rollback(period uint64) error {
- max := s.updates.periods.End + 1
- if s.committees.periods.End > max {
- max = s.committees.periods.End
- }
- if s.fixedCommitteeRoots.periods.End > max {
- max = s.fixedCommitteeRoots.periods.End
- }
- for max > period {
- max--
- batch := s.db.NewBatch()
- s.deleteCommitteesFrom(batch, max)
- s.fixedCommitteeRoots.deleteFrom(batch, max)
- if max > 0 {
- s.updates.deleteFrom(batch, max-1)
- }
- if err := batch.Write(); err != nil {
- log.Error("Error writing batch into chain database", "error", err)
- return err
- }
- }
- return nil
-}
-
-// getCommitteeRoot returns the committee root at the given period, either fixed,
-// proven by a previous update or both. It returns an empty hash if the committee
-// root is unknown.
-func (s *CommitteeChain) getCommitteeRoot(period uint64) common.Hash {
- if root, ok := s.fixedCommitteeRoots.get(s.db, period); ok || period == 0 {
- return root
- }
- if update, ok := s.updates.get(s.db, period-1); ok {
- return update.NextSyncCommitteeRoot
- }
- return common.Hash{}
-}
-
-// getSyncCommittee returns the deserialized sync committee at the given period.
-func (s *CommitteeChain) getSyncCommittee(period uint64) (syncCommittee, error) {
- if c, ok := s.committeeCache.Get(period); ok {
- return c, nil
- }
- if sc, ok := s.committees.get(s.db, period); ok {
- c, err := s.sigVerifier.deserializeSyncCommittee(sc)
- if err != nil {
- return nil, fmt.Errorf("Sync committee #%d deserialization error: %v", period, err)
- }
- s.committeeCache.Add(period, c)
- return c, nil
- }
- return nil, fmt.Errorf("Missing serialized sync committee #%d", period)
-}
-
-// VerifySignedHeader returns true if the given signed header has a valid signature
-// according to the local committee chain. The caller should ensure that the
-// committees advertised by the same source where the signed header came from are
-// synced before verifying the signature.
-// The age of the header is also returned (the time elapsed since the beginning
-// of the given slot, according to the local system clock). If enforceTime is
-// true then negative age (future) headers are rejected.
-func (s *CommitteeChain) VerifySignedHeader(head types.SignedHeader) (bool, time.Duration, error) {
- s.chainmu.RLock()
- defer s.chainmu.RUnlock()
-
- return s.verifySignedHeader(head)
-}
-
-func (s *CommitteeChain) verifySignedHeader(head types.SignedHeader) (bool, time.Duration, error) {
- var age time.Duration
- now := s.unixNano()
- if head.Header.Slot < (uint64(now-math.MinInt64)/uint64(time.Second)-s.config.GenesisTime)/12 {
- age = time.Duration(now - int64(time.Second)*int64(s.config.GenesisTime+head.Header.Slot*12))
- } else {
- age = time.Duration(math.MinInt64)
- }
- if s.enforceTime && age < 0 {
- return false, age, nil
- }
- committee, err := s.getSyncCommittee(types.SyncPeriod(head.SignatureSlot))
- if err != nil {
- return false, 0, err
- }
- if committee == nil {
- return false, age, nil
- }
- if signingRoot, err := s.config.Forks.SigningRoot(head.Header); err == nil {
- return s.sigVerifier.verifySignature(committee, signingRoot, &head.Signature), age, nil
- }
- return false, age, nil
-}
-
-// verifyUpdate checks whether the header signature is correct and the update
-// fits into the specified constraints (assumes that the update has been
-// successfully validated previously)
-func (s *CommitteeChain) verifyUpdate(update *types.LightClientUpdate) (bool, error) {
- // Note: SignatureSlot determines the sync period of the committee used for signature
- // verification. Though in reality SignatureSlot is always bigger than update.Header.Slot,
- // setting them as equal here enforces the rule that they have to be in the same sync
- // period in order for the light client update proof to be meaningful.
- ok, age, err := s.verifySignedHeader(update.AttestedHeader)
- if age < 0 {
- log.Warn("Future committee update received", "age", age)
- }
- return ok, err
-}
diff --git a/beacon/light/committee_chain_test.go b/beacon/light/committee_chain_test.go
deleted file mode 100644
index 60ea2a0efd..0000000000
--- a/beacon/light/committee_chain_test.go
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2022 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package light
-
-import (
- "crypto/rand"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/beacon/params"
- "github.com/ethereum/go-ethereum/beacon/types"
- "github.com/ethereum/go-ethereum/common/mclock"
- "github.com/ethereum/go-ethereum/ethdb/memorydb"
-)
-
-var (
- testGenesis = newTestGenesis()
- testGenesis2 = newTestGenesis()
-
- tfBase = newTestForks(testGenesis, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
- })
- tfAlternative = newTestForks(testGenesis, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
- &types.Fork{Epoch: 0x700, Version: []byte{1}},
- })
- tfAnotherGenesis = newTestForks(testGenesis2, types.Forks{
- &types.Fork{Epoch: 0, Version: []byte{0}},
- })
-
- tcBase = newTestCommitteeChain(nil, tfBase, true, 0, 10, 400, false)
- tcBaseWithInvalidUpdates = newTestCommitteeChain(tcBase, tfBase, false, 5, 10, 200, false) // signer count too low
- tcBaseWithBetterUpdates = newTestCommitteeChain(tcBase, tfBase, false, 5, 10, 440, false)
- tcReorgWithWorseUpdates = newTestCommitteeChain(tcBase, tfBase, true, 5, 10, 400, false)
- tcReorgWithWorseUpdates2 = newTestCommitteeChain(tcBase, tfBase, true, 5, 10, 380, false)
- tcReorgWithBetterUpdates = newTestCommitteeChain(tcBase, tfBase, true, 5, 10, 420, false)
- tcReorgWithFinalizedUpdates = newTestCommitteeChain(tcBase, tfBase, true, 5, 10, 400, true)
- tcFork = newTestCommitteeChain(tcBase, tfAlternative, true, 7, 10, 400, false)
- tcAnotherGenesis = newTestCommitteeChain(nil, tfAnotherGenesis, true, 0, 10, 400, false)
-)
-
-func TestCommitteeChainFixedCommitteeRoots(t *testing.T) {
- for _, reload := range []bool{false, true} {
- c := newCommitteeChainTest(t, tfBase, 300, true)
- c.setClockPeriod(7)
- c.addFixedCommitteeRoot(tcBase, 4, nil)
- c.addFixedCommitteeRoot(tcBase, 5, nil)
- c.addFixedCommitteeRoot(tcBase, 6, nil)
- c.addFixedCommitteeRoot(tcBase, 8, ErrInvalidPeriod) // range has to be continuous
- c.addFixedCommitteeRoot(tcBase, 3, nil)
- c.addFixedCommitteeRoot(tcBase, 2, nil)
- if reload {
- c.reloadChain()
- }
- c.addCommittee(tcBase, 4, nil)
- c.addCommittee(tcBase, 6, ErrInvalidPeriod) // range has to be continuous
- c.addCommittee(tcBase, 5, nil)
- c.addCommittee(tcBase, 6, nil)
- c.addCommittee(tcAnotherGenesis, 3, ErrWrongCommitteeRoot)
- c.addCommittee(tcBase, 3, nil)
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcBase, 3, 6)
- }
-}
-
-func TestCommitteeChainCheckpointSync(t *testing.T) {
- for _, enforceTime := range []bool{false, true} {
- for _, reload := range []bool{false, true} {
- c := newCommitteeChainTest(t, tfBase, 300, enforceTime)
- if enforceTime {
- c.setClockPeriod(6)
- }
- c.insertUpdate(tcBase, 3, true, ErrInvalidPeriod)
- c.addFixedCommitteeRoot(tcBase, 3, nil)
- c.addFixedCommitteeRoot(tcBase, 4, nil)
- c.insertUpdate(tcBase, 4, true, ErrInvalidPeriod) // still no committee
- c.addCommittee(tcBase, 3, nil)
- c.addCommittee(tcBase, 4, nil)
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcBase, 3, 4)
- c.insertUpdate(tcBase, 3, false, nil) // update can be added without committee here
- c.insertUpdate(tcBase, 4, false, ErrNeedCommittee) // but not here as committee 5 is not there yet
- c.insertUpdate(tcBase, 4, true, nil)
- c.verifyRange(tcBase, 3, 5)
- c.insertUpdate(tcBaseWithInvalidUpdates, 5, true, ErrInvalidUpdate) // signer count too low
- c.insertUpdate(tcBase, 5, true, nil)
- if reload {
- c.reloadChain()
- }
- if enforceTime {
- c.insertUpdate(tcBase, 6, true, ErrInvalidUpdate) // future update rejected
- c.setClockPeriod(7)
- }
- c.insertUpdate(tcBase, 6, true, nil) // when the time comes it's accepted
- if reload {
- c.reloadChain()
- }
- if enforceTime {
- c.verifyRange(tcBase, 3, 6) // committee 7 is there but still in the future
- c.setClockPeriod(8)
- }
- c.verifyRange(tcBase, 3, 7) // now period 7 can also be verified
- // try reverse syncing an update
- c.insertUpdate(tcBase, 2, false, ErrInvalidPeriod) // fixed committee is needed first
- c.addFixedCommitteeRoot(tcBase, 2, nil)
- c.addCommittee(tcBase, 2, nil)
- c.insertUpdate(tcBase, 2, false, nil)
- c.verifyRange(tcBase, 2, 7)
- }
- }
-}
-
-func TestCommitteeChainReorg(t *testing.T) {
- for _, reload := range []bool{false, true} {
- for _, addBetterUpdates := range []bool{false, true} {
- c := newCommitteeChainTest(t, tfBase, 300, true)
- c.setClockPeriod(11)
- c.addFixedCommitteeRoot(tcBase, 3, nil)
- c.addFixedCommitteeRoot(tcBase, 4, nil)
- c.addCommittee(tcBase, 3, nil)
- for period := uint64(3); period < 10; period++ {
- c.insertUpdate(tcBase, period, true, nil)
- }
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcBase, 3, 10)
- c.insertUpdate(tcReorgWithWorseUpdates, 5, true, ErrCannotReorg)
- c.insertUpdate(tcReorgWithWorseUpdates2, 5, true, ErrCannotReorg)
- if addBetterUpdates {
- // add better updates for the base chain and expect first reorg to fail
- // (only add updates as committees should be the same)
- for period := uint64(5); period < 10; period++ {
- c.insertUpdate(tcBaseWithBetterUpdates, period, false, nil)
- }
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcBase, 3, 10) // still on the same chain
- c.insertUpdate(tcReorgWithBetterUpdates, 5, true, ErrCannotReorg)
- } else {
- // reorg with better updates
- c.insertUpdate(tcReorgWithBetterUpdates, 5, false, ErrNeedCommittee)
- c.verifyRange(tcBase, 3, 10) // no success yet, still on the base chain
- c.verifyRange(tcReorgWithBetterUpdates, 3, 5)
- c.insertUpdate(tcReorgWithBetterUpdates, 5, true, nil)
- // successful reorg, base chain should only match before the reorg period
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcBase, 3, 5)
- c.verifyRange(tcReorgWithBetterUpdates, 3, 6)
- for period := uint64(6); period < 10; period++ {
- c.insertUpdate(tcReorgWithBetterUpdates, period, true, nil)
- }
- c.verifyRange(tcReorgWithBetterUpdates, 3, 10)
- }
- // reorg with finalized updates; should succeed even if base chain updates
- // have been improved because a finalized update beats everything else
- c.insertUpdate(tcReorgWithFinalizedUpdates, 5, false, ErrNeedCommittee)
- c.insertUpdate(tcReorgWithFinalizedUpdates, 5, true, nil)
- if reload {
- c.reloadChain()
- }
- c.verifyRange(tcReorgWithFinalizedUpdates, 3, 6)
- for period := uint64(6); period < 10; period++ {
- c.insertUpdate(tcReorgWithFinalizedUpdates, period, true, nil)
- }
- c.verifyRange(tcReorgWithFinalizedUpdates, 3, 10)
- }
- }
-}
-
-func TestCommitteeChainFork(t *testing.T) {
- c := newCommitteeChainTest(t, tfAlternative, 300, true)
- c.setClockPeriod(11)
- // trying to sync a chain on an alternative fork with the base chain data
- c.addFixedCommitteeRoot(tcBase, 0, nil)
- c.addFixedCommitteeRoot(tcBase, 1, nil)
- c.addCommittee(tcBase, 0, nil)
- // shared section should sync without errors
- for period := uint64(0); period < 7; period++ {
- c.insertUpdate(tcBase, period, true, nil)
- }
- c.insertUpdate(tcBase, 7, true, ErrInvalidUpdate) // wrong fork
- // committee root #7 is still the same but signatures are already signed with
- // a different fork id so period 7 should only verify on the alternative fork
- c.verifyRange(tcBase, 0, 6)
- c.verifyRange(tcFork, 0, 7)
- for period := uint64(7); period < 10; period++ {
- c.insertUpdate(tcFork, period, true, nil)
- }
- c.verifyRange(tcFork, 0, 10)
- // reload the chain while switching to the base fork
- c.config = tfBase
- c.reloadChain()
- // updates 7..9 should be rolled back now
- c.verifyRange(tcFork, 0, 6) // again, period 7 only verifies on the right fork
- c.verifyRange(tcBase, 0, 7)
- c.insertUpdate(tcFork, 7, true, ErrInvalidUpdate) // wrong fork
- for period := uint64(7); period < 10; period++ {
- c.insertUpdate(tcBase, period, true, nil)
- }
- c.verifyRange(tcBase, 0, 10)
-}
-
-type committeeChainTest struct {
- t *testing.T
- db *memorydb.Database
- clock *mclock.Simulated
- config types.ChainConfig
- signerThreshold int
- enforceTime bool
- chain *CommitteeChain
-}
-
-func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThreshold int, enforceTime bool) *committeeChainTest {
- c := &committeeChainTest{
- t: t,
- db: memorydb.New(),
- clock: &mclock.Simulated{},
- config: config,
- signerThreshold: signerThreshold,
- enforceTime: enforceTime,
- }
- c.chain = newCommitteeChain(c.db, &config, signerThreshold, enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) })
- return c
-}
-
-func (c *committeeChainTest) reloadChain() {
- c.chain = newCommitteeChain(c.db, &c.config, c.signerThreshold, c.enforceTime, dummyVerifier{}, c.clock, func() int64 { return int64(c.clock.Now()) })
-}
-
-func (c *committeeChainTest) setClockPeriod(period float64) {
- target := mclock.AbsTime(period * float64(time.Second*12*params.SyncPeriodLength))
- wait := time.Duration(target - c.clock.Now())
- if wait < 0 {
- c.t.Fatalf("Invalid setClockPeriod")
- }
- c.clock.Run(wait)
-}
-
-func (c *committeeChainTest) addFixedCommitteeRoot(tc *testCommitteeChain, period uint64, expErr error) {
- if err := c.chain.addFixedCommitteeRoot(period, tc.periods[period].committee.Root()); err != expErr {
- c.t.Errorf("Incorrect error output from addFixedCommitteeRoot at period %d (expected %v, got %v)", period, expErr, err)
- }
-}
-
-func (c *committeeChainTest) addCommittee(tc *testCommitteeChain, period uint64, expErr error) {
- if err := c.chain.addCommittee(period, tc.periods[period].committee); err != expErr {
- c.t.Errorf("Incorrect error output from addCommittee at period %d (expected %v, got %v)", period, expErr, err)
- }
-}
-
-func (c *committeeChainTest) insertUpdate(tc *testCommitteeChain, period uint64, addCommittee bool, expErr error) {
- var committee *types.SerializedSyncCommittee
- if addCommittee {
- committee = tc.periods[period+1].committee
- }
- if err := c.chain.InsertUpdate(tc.periods[period].update, committee); err != expErr {
- c.t.Errorf("Incorrect error output from InsertUpdate at period %d (expected %v, got %v)", period, expErr, err)
- }
-}
-
-func (c *committeeChainTest) verifySignedHeader(tc *testCommitteeChain, period float64, expOk bool) {
- slot := uint64(period * float64(params.SyncPeriodLength))
- signedHead := GenerateTestSignedHeader(types.Header{Slot: slot}, &tc.config, tc.periods[types.SyncPeriod(slot)].committee, slot+1, 400)
- if ok, _, _ := c.chain.VerifySignedHeader(signedHead); ok != expOk {
- c.t.Errorf("Incorrect output from VerifySignedHeader at period %f (expected %v, got %v)", period, expOk, ok)
- }
-}
-
-func (c *committeeChainTest) verifyRange(tc *testCommitteeChain, begin, end uint64) {
- if begin > 0 {
- c.verifySignedHeader(tc, float64(begin)-0.5, false)
- }
- for period := begin; period <= end; period++ {
- c.verifySignedHeader(tc, float64(period)+0.5, true)
- }
- c.verifySignedHeader(tc, float64(end)+1.5, false)
-}
-
-func newTestGenesis() types.ChainConfig {
- var config types.ChainConfig
- rand.Read(config.GenesisValidatorsRoot[:])
- return config
-}
-
-func newTestForks(config types.ChainConfig, forks types.Forks) types.ChainConfig {
- for _, fork := range forks {
- config.AddFork(fork.Name, fork.Epoch, fork.Version)
- }
- return config
-}
-
-func newTestCommitteeChain(parent *testCommitteeChain, config types.ChainConfig, newCommittees bool, begin, end int, signerCount int, finalizedHeader bool) *testCommitteeChain {
- tc := &testCommitteeChain{
- config: config,
- }
- if parent != nil {
- tc.periods = make([]testPeriod, len(parent.periods))
- copy(tc.periods, parent.periods)
- }
- if newCommittees {
- if begin == 0 {
- tc.fillCommittees(begin, end+1)
- } else {
- tc.fillCommittees(begin+1, end+1)
- }
- }
- tc.fillUpdates(begin, end, signerCount, finalizedHeader)
- return tc
-}
-
-type testPeriod struct {
- committee *types.SerializedSyncCommittee
- update *types.LightClientUpdate
-}
-
-type testCommitteeChain struct {
- periods []testPeriod
- config types.ChainConfig
-}
-
-func (tc *testCommitteeChain) fillCommittees(begin, end int) {
- if len(tc.periods) <= end {
- tc.periods = append(tc.periods, make([]testPeriod, end+1-len(tc.periods))...)
- }
- for i := begin; i <= end; i++ {
- tc.periods[i].committee = GenerateTestCommittee()
- }
-}
-
-func (tc *testCommitteeChain) fillUpdates(begin, end int, signerCount int, finalizedHeader bool) {
- for i := begin; i <= end; i++ {
- tc.periods[i].update = GenerateTestUpdate(&tc.config, uint64(i), tc.periods[i].committee, tc.periods[i+1].committee, signerCount, finalizedHeader)
- }
-}
diff --git a/beacon/light/range.go b/beacon/light/range.go
deleted file mode 100644
index 76ebe2381a..0000000000
--- a/beacon/light/range.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2023 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package light
-
-// periodRange represents a (possibly zero-length) range of integers (sync periods).
-type periodRange struct {
- Start, End uint64
-}
-
-// isEmpty returns true if the length of the range is zero.
-func (a periodRange) isEmpty() bool {
- return a.End == a.Start
-}
-
-// contains returns true if the range includes the given period.
-func (a periodRange) contains(period uint64) bool {
- return period >= a.Start && period < a.End
-}
-
-// canExpand returns true if the range includes or can be expanded with the given
-// period (either the range is empty or the given period is inside, right before or
-// right after the range).
-func (a periodRange) canExpand(period uint64) bool {
- return a.isEmpty() || (period+1 >= a.Start && period <= a.End)
-}
-
-// expand expands the range with the given period.
-// This method assumes that canExpand returned true: otherwise this is a no-op.
-func (a *periodRange) expand(period uint64) {
- if a.isEmpty() {
- a.Start, a.End = period, period+1
- return
- }
- if a.Start == period+1 {
- a.Start--
- }
- if a.End == period {
- a.End++
- }
-}
-
-// split splits the range into two ranges. The 'fromPeriod' will be the first
-// element in the second range (if present).
-// The original range is unchanged by this operation
-func (a *periodRange) split(fromPeriod uint64) (periodRange, periodRange) {
- if fromPeriod <= a.Start {
- // First range empty, everything in second range,
- return periodRange{}, *a
- }
- if fromPeriod >= a.End {
- // Second range empty, everything in first range,
- return *a, periodRange{}
- }
- x := periodRange{a.Start, fromPeriod}
- y := periodRange{fromPeriod, a.End}
- return x, y
-}
-
-// each invokes the supplied function fn once per period in range
-func (a *periodRange) each(fn func(uint64)) {
- for p := a.Start; p < a.End; p++ {
- fn(p)
- }
-}
diff --git a/beacon/light/test_helpers.go b/beacon/light/test_helpers.go
deleted file mode 100644
index f537d963a6..0000000000
--- a/beacon/light/test_helpers.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2023 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package light
-
-import (
- "crypto/rand"
- "crypto/sha256"
- mrand "math/rand"
-
- "github.com/ethereum/go-ethereum/beacon/merkle"
- "github.com/ethereum/go-ethereum/beacon/params"
- "github.com/ethereum/go-ethereum/beacon/types"
- "github.com/ethereum/go-ethereum/common"
-)
-
-func GenerateTestCommittee() *types.SerializedSyncCommittee {
- s := new(types.SerializedSyncCommittee)
- rand.Read(s[:32])
- return s
-}
-
-func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nextCommittee *types.SerializedSyncCommittee, signerCount int, finalizedHeader bool) *types.LightClientUpdate {
- update := new(types.LightClientUpdate)
- update.NextSyncCommitteeRoot = nextCommittee.Root()
- var attestedHeader types.Header
- if finalizedHeader {
- update.FinalizedHeader = new(types.Header)
- *update.FinalizedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+100, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot))
- attestedHeader, update.FinalityBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexFinalBlock, merkle.Value(update.FinalizedHeader.Hash()))
- } else {
- attestedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+2000, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot))
- }
- update.AttestedHeader = GenerateTestSignedHeader(attestedHeader, config, committee, attestedHeader.Slot+1, signerCount)
- return update
-}
-
-func GenerateTestSignedHeader(header types.Header, config *types.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader {
- bitmask := makeBitmask(signerCount)
- signingRoot, _ := config.Forks.SigningRoot(header)
- c, _ := dummyVerifier{}.deserializeSyncCommittee(committee)
- return types.SignedHeader{
- Header: header,
- Signature: types.SyncAggregate{
- Signers: bitmask,
- Signature: makeDummySignature(c.(dummySyncCommittee), signingRoot, bitmask),
- },
- SignatureSlot: signatureSlot,
- }
-}
-
-func GenerateTestCheckpoint(period uint64, committee *types.SerializedSyncCommittee) *types.BootstrapData {
- header, branch := makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexSyncCommittee, merkle.Value(committee.Root()))
- return &types.BootstrapData{
- Header: header,
- Committee: committee,
- CommitteeRoot: committee.Root(),
- CommitteeBranch: branch,
- }
-}
-
-func makeBitmask(signerCount int) (bitmask [params.SyncCommitteeBitmaskSize]byte) {
- for i := 0; i < params.SyncCommitteeSize; i++ {
- if mrand.Intn(params.SyncCommitteeSize-i) < signerCount {
- bitmask[i/8] += byte(1) << (i & 7)
- signerCount--
- }
- }
- return
-}
-
-func makeTestHeaderWithMerkleProof(slot, index uint64, value merkle.Value) (types.Header, merkle.Values) {
- var branch merkle.Values
- hasher := sha256.New()
- for index > 1 {
- var proofHash merkle.Value
- rand.Read(proofHash[:])
- hasher.Reset()
- if index&1 == 0 {
- hasher.Write(value[:])
- hasher.Write(proofHash[:])
- } else {
- hasher.Write(proofHash[:])
- hasher.Write(value[:])
- }
- hasher.Sum(value[:0])
- index >>= 1
- branch = append(branch, proofHash)
- }
- return types.Header{Slot: slot, StateRoot: common.Hash(value)}, branch
-}
-
-// syncCommittee holds either a blsSyncCommittee or a fake dummySyncCommittee used for testing
-type syncCommittee interface{}
-
-// committeeSigVerifier verifies sync committee signatures (either proper BLS
-// signatures or fake signatures used for testing)
-type committeeSigVerifier interface {
- deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error)
- verifySignature(committee syncCommittee, signedRoot common.Hash, aggregate *types.SyncAggregate) bool
-}
-
-// blsVerifier implements committeeSigVerifier
-type blsVerifier struct{}
-
-// deserializeSyncCommittee implements committeeSigVerifier
-func (blsVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) {
- return s.Deserialize()
-}
-
-// verifySignature implements committeeSigVerifier
-func (blsVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool {
- return committee.(*types.SyncCommittee).VerifySignature(signingRoot, aggregate)
-}
-
-type dummySyncCommittee [32]byte
-
-// dummyVerifier implements committeeSigVerifier
-type dummyVerifier struct{}
-
-// deserializeSyncCommittee implements committeeSigVerifier
-func (dummyVerifier) deserializeSyncCommittee(s *types.SerializedSyncCommittee) (syncCommittee, error) {
- var sc dummySyncCommittee
- copy(sc[:], s[:32])
- return sc, nil
-}
-
-// verifySignature implements committeeSigVerifier
-func (dummyVerifier) verifySignature(committee syncCommittee, signingRoot common.Hash, aggregate *types.SyncAggregate) bool {
- return aggregate.Signature == makeDummySignature(committee.(dummySyncCommittee), signingRoot, aggregate.Signers)
-}
-
-func makeDummySignature(committee dummySyncCommittee, signingRoot common.Hash, bitmask [params.SyncCommitteeBitmaskSize]byte) (sig [params.BLSSignatureSize]byte) {
- for i, b := range committee[:] {
- sig[i] = b ^ signingRoot[i]
- }
- copy(sig[32:], bitmask[:])
- return
-}
diff --git a/beacon/types/committee.go b/beacon/types/committee.go
index 5f89c27554..5c434066df 100644
--- a/beacon/types/committee.go
+++ b/beacon/types/committee.go
@@ -129,9 +129,9 @@ func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) {
return nil, err
}
if i < params.SyncCommitteeSize {
- sc.keys[i] = key
+ sc.Keys[i] = key
} else {
- sc.aggregate = key
+ sc.Aggregate = key
}
}
return sc, nil
@@ -142,8 +142,8 @@ func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) {
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type SyncCommittee struct {
- keys [params.SyncCommitteeSize]*bls.Pubkey
- aggregate *bls.Pubkey
+ Keys [params.SyncCommitteeSize]*bls.Pubkey
+ Aggregate *bls.Pubkey
}
// VerifySignature returns true if the given sync aggregate is a valid signature
@@ -156,7 +156,7 @@ func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *Syn
if err := sig.Deserialize(&signature.Signature); err != nil {
return false
}
- for i, key := range sc.keys {
+ for i, key := range sc.Keys {
if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 {
keys = append(keys, key)
}
diff --git a/beacon/types/config.go b/beacon/types/config.go
deleted file mode 100644
index 8cb8808b6f..0000000000
--- a/beacon/types/config.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2022 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package types
-
-import (
- "crypto/sha256"
- "fmt"
- "os"
- "sort"
- "strconv"
- "strings"
-
- "github.com/ethereum/go-ethereum/beacon/merkle"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "gopkg.in/yaml.v3"
-)
-
-// syncCommitteeDomain specifies the signatures specific use to avoid clashes
-// across signing different data structures.
-const syncCommitteeDomain = 7
-
-// Fork describes a single beacon chain fork and also stores the calculated
-// signature domain used after this fork.
-type Fork struct {
- // Name of the fork in the chain config (config.yaml) file{
- Name string
-
- // Epoch when given fork version is activated
- Epoch uint64
-
- // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
- Version []byte
-
- // calculated by computeDomain, based on fork version and genesis validators root
- domain merkle.Value
-}
-
-// computeDomain returns the signature domain based on the given fork version
-// and genesis validator set root.
-func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
- var (
- hasher = sha256.New()
- forkVersion32 merkle.Value
- forkDataRoot merkle.Value
- )
- copy(forkVersion32[:], f.Version)
- hasher.Write(forkVersion32[:])
- hasher.Write(genesisValidatorsRoot[:])
- hasher.Sum(forkDataRoot[:0])
-
- f.domain[0] = syncCommitteeDomain
- copy(f.domain[4:], forkDataRoot[:28])
-}
-
-// Forks is the list of all beacon chain forks in the chain configuration.
-type Forks []*Fork
-
-// domain returns the signature domain for the given epoch (assumes that domains
-// have already been calculated).
-func (f Forks) domain(epoch uint64) (merkle.Value, error) {
- for i := len(f) - 1; i >= 0; i-- {
- if epoch >= f[i].Epoch {
- return f[i].domain, nil
- }
- }
- return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
-}
-
-// SigningRoot calculates the signing root of the given header.
-func (f Forks) SigningRoot(header Header) (common.Hash, error) {
- domain, err := f.domain(header.Epoch())
- if err != nil {
- return common.Hash{}, err
- }
- var (
- signingRoot common.Hash
- headerHash = header.Hash()
- hasher = sha256.New()
- )
- hasher.Write(headerHash[:])
- hasher.Write(domain[:])
- hasher.Sum(signingRoot[:0])
-
- return signingRoot, nil
-}
-
-func (f Forks) Len() int { return len(f) }
-func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch }
-
-// ChainConfig contains the beacon chain configuration.
-type ChainConfig struct {
- GenesisTime uint64 // Unix timestamp of slot 0
- GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation
- Forks Forks
-}
-
-// AddFork adds a new item to the list of forks.
-func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
- fork := &Fork{
- Name: name,
- Epoch: epoch,
- Version: version,
- }
- fork.computeDomain(c.GenesisValidatorsRoot)
-
- c.Forks = append(c.Forks, fork)
- sort.Sort(c.Forks)
-
- return c
-}
-
-// LoadForks parses the beacon chain configuration file (config.yaml) and extracts
-// the list of forks.
-func (c *ChainConfig) LoadForks(path string) error {
- file, err := os.ReadFile(path)
- if err != nil {
- return fmt.Errorf("failed to read beacon chain config file: %v", err)
- }
- config := make(map[string]string)
- if err := yaml.Unmarshal(file, &config); err != nil {
- return fmt.Errorf("failed to parse beacon chain config file: %v", err)
- }
- var (
- versions = make(map[string][]byte)
- epochs = make(map[string]uint64)
- )
- epochs["GENESIS"] = 0
-
- for key, value := range config {
- if strings.HasSuffix(key, "_FORK_VERSION") {
- name := key[:len(key)-len("_FORK_VERSION")]
- if v, err := hexutil.Decode(value); err == nil {
- versions[name] = v
- } else {
- return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err)
- }
- }
- if strings.HasSuffix(key, "_FORK_EPOCH") {
- name := key[:len(key)-len("_FORK_EPOCH")]
- if v, err := strconv.ParseUint(value, 10, 64); err == nil {
- epochs[name] = v
- } else {
- return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err)
- }
- }
- }
- for name, epoch := range epochs {
- if version, ok := versions[name]; ok {
- delete(versions, name)
- c.AddFork(name, epoch, version)
- } else {
- return fmt.Errorf("fork id missing for %q in beacon chain config file", name)
- }
- }
- for name := range versions {
- return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name)
- }
- sort.Sort(c.Forks)
- return nil
-}
diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go
deleted file mode 100644
index 3284081e4d..0000000000
--- a/beacon/types/light_sync.go
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2022 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package types
-
-import (
- "errors"
- "fmt"
-
- "github.com/ethereum/go-ethereum/beacon/merkle"
- "github.com/ethereum/go-ethereum/beacon/params"
- "github.com/ethereum/go-ethereum/common"
-)
-
-// BootstrapData contains a sync committee where light sync can be started,
-// together with a proof through a beacon header and corresponding state.
-// Note: BootstrapData is fetched from a server based on a known checkpoint hash.
-type BootstrapData struct {
- Header Header
- CommitteeRoot common.Hash
- Committee *SerializedSyncCommittee `rlp:"-"`
- CommitteeBranch merkle.Values
-}
-
-// Validate verifies the proof included in BootstrapData.
-func (c *BootstrapData) Validate() error {
- if c.CommitteeRoot != c.Committee.Root() {
- return errors.New("wrong committee root")
- }
- return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot))
-}
-
-// LightClientUpdate is a proof of the next sync committee root based on a header
-// signed by the sync committee of the given period. Optionally, the update can
-// prove quasi-finality by the signed header referring to a previous, finalized
-// header from the same period, and the finalized header referring to the next
-// sync committee root.
-//
-// See data structure definition here:
-// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
-type LightClientUpdate struct {
- AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee
- NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one
- NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
-
- FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality
- FinalityBranch merkle.Values // Proof for the announced finality
-
- score *UpdateScore // Weight of the update to compare between competing ones
-}
-
-// Validate verifies the validity of the update.
-func (update *LightClientUpdate) Validate() error {
- period := update.AttestedHeader.Header.SyncPeriod()
- if SyncPeriod(update.AttestedHeader.SignatureSlot) != period {
- return errors.New("signature slot and signed header are from different periods")
- }
- if update.FinalizedHeader != nil {
- if update.FinalizedHeader.SyncPeriod() != period {
- return errors.New("finalized header is from different period")
- }
- if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
- return fmt.Errorf("invalid finalized header proof: %w", err)
- }
- }
- if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
- return fmt.Errorf("invalid next sync committee proof: %w", err)
- }
- return nil
-}
-
-// Score returns the UpdateScore describing the proof strength of the update
-// Note: thread safety can be ensured by always calling Score on a newly received
-// or decoded update before making it potentially available for other threads
-func (update *LightClientUpdate) Score() UpdateScore {
- if update.score == nil {
- update.score = &UpdateScore{
- SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()),
- SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff),
- FinalizedHeader: update.FinalizedHeader != nil,
- }
- }
- return *update.score
-}
-
-// UpdateScore allows the comparison between updates at the same period in order
-// to find the best update chain that provides the strongest proof of being canonical.
-//
-// UpdateScores have a tightly packed binary encoding format for efficient p2p
-// protocol transmission. Each UpdateScore is encoded in 3 bytes.
-// When interpreted as a 24 bit little indian unsigned integer:
-// - the lowest 10 bits contain the number of signers in the header signature aggregate
-// - the next 13 bits contain the "sub-period index" which is he signed header's
-// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being
-// re-orged before the previous period boundary in case of non-finalized updates)
-// - the highest bit is set when the update is finalized (meaning that the finality
-// header referenced by the signed header is in the same period as the signed
-// header, making reorgs before the period boundary impossible
-type UpdateScore struct {
- SignerCount uint32 // number of signers in the header signature aggregate
- SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength
- FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures
-}
-
-// finalized returns true if the update has a header signed by at least 2/3 of
-// the committee, referring to a finalized header that refers to the next sync
-// committee. This condition is a close approximation of the actual finality
-// condition that can only be verified by full beacon nodes.
-func (u *UpdateScore) finalized() bool {
- return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority
-}
-
-// BetterThan returns true if update u is considered better than w.
-func (u UpdateScore) BetterThan(w UpdateScore) bool {
- var (
- uFinalized = u.finalized()
- wFinalized = w.finalized()
- )
- if uFinalized != wFinalized {
- return uFinalized
- }
- return u.SignerCount > w.SignerCount
-}
diff --git a/cmd/blsync/api.go b/cmd/blsync/api.go
new file mode 100644
index 0000000000..0de379f03d
--- /dev/null
+++ b/cmd/blsync/api.go
@@ -0,0 +1,140 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+
+ eth2client "github.com/attestantio/go-eth2-client"
+ eth2api "github.com/attestantio/go-eth2-client/api"
+ eth2http "github.com/attestantio/go-eth2-client/http"
+ eth2spec "github.com/attestantio/go-eth2-client/spec"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/rs/zerolog"
+)
+
+var (
+ beaconLightClientBootstrap = "eth/v1/beacon/light_client/bootstrap"
+ beaconLightClientUpdate = "eth/v1/beacon/light_client/updates"
+ beaconLightClientOptimisticUpdate = "eth/v1/beacon/light_client/optimistic_update"
+ beaconLightClientFinalityUpdate = "eth/v1/beacon/light_client/finality_update"
+)
+
+type BeaconClient struct {
+ ctx context.Context
+ url string
+ client eth2client.Service
+}
+
+func NewBeaconClient(ctx context.Context, server string) (*BeaconClient, error) {
+ client, err := eth2http.New(
+ ctx,
+ eth2http.WithAddress(server),
+ eth2http.WithLogLevel(zerolog.WarnLevel),
+ eth2http.WithEnforceJSON(true),
+ )
+ if err != nil {
+ return nil, err
+ }
+ return &BeaconClient{
+ ctx: ctx,
+ url: server,
+ client: client,
+ }, nil
+}
+
+func (c *BeaconClient) Bootstrap(root common.Hash) (*Bootstrap, error) {
+ resp, err := http.Get(fmt.Sprintf("%s/%s/%s", c.url, beaconLightClientBootstrap, root.String()))
+ if err != nil {
+ return nil, fmt.Errorf("failed http request: %w", err)
+ }
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %w", err)
+ }
+ var bs Bootstrap
+ if err := json.Unmarshal(b, &bs); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal data: %v", err)
+ }
+ return &bs, nil
+}
+
+func (c *BeaconClient) GetRangeUpdate(start, count int) ([]*LightClientUpdate, error) {
+ resp, err := http.Get(fmt.Sprintf("%s/%s?start_period=%d&count=%d", c.url, beaconLightClientUpdate, start, count))
+ if err != nil {
+ return nil, fmt.Errorf("failed http request: %w", err)
+ }
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %w", err)
+ }
+ var u []*LightClientUpdate
+ if err := json.Unmarshal(b, &u); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal data: %v", err)
+ }
+ return u, nil
+
+}
+
+func (c *BeaconClient) GetOptimisticUpdate() (*LightClientUpdate, error) {
+ resp, err := http.Get(fmt.Sprintf("%s/%s", c.url, beaconLightClientOptimisticUpdate))
+ if err != nil {
+ return nil, fmt.Errorf("failed http request: %w", err)
+ }
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %w", err)
+ }
+ var u LightClientUpdate
+ if err := json.Unmarshal(b, &u); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal data: %v", err)
+ }
+ return &u, nil
+}
+
+func (c *BeaconClient) GetFinalityUpdate() (*LightClientUpdate, error) {
+ resp, err := http.Get(fmt.Sprintf("%s/%s", c.url, beaconLightClientFinalityUpdate))
+ if err != nil {
+ return nil, fmt.Errorf("failed http request: %w", err)
+ }
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %w", err)
+ }
+ var u LightClientUpdate
+ if err := json.Unmarshal(b, &u); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal data: %v", err)
+ }
+ return &u, nil
+
+}
+
+func (c *BeaconClient) GetBlock(root common.Hash) (*eth2spec.VersionedSignedBeaconBlock, error) {
+ provider, ok := c.client.(eth2client.SignedBeaconBlockProvider)
+ if !ok {
+ return nil, fmt.Errorf("beacon server does not support retrieving blocks")
+ }
+ resp, err := provider.SignedBeaconBlock(c.ctx, ð2api.SignedBeaconBlockOpts{Block: root.String()})
+ if err != nil {
+ return nil, fmt.Errorf("failed http request: %w", err)
+ }
+ return resp.Data, nil
+}
diff --git a/cmd/blsync/beacon.go b/cmd/blsync/beacon.go
new file mode 100644
index 0000000000..a7a73f45a0
--- /dev/null
+++ b/cmd/blsync/beacon.go
@@ -0,0 +1,52 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "crypto/sha256"
+
+ "github.com/ethereum/go-ethereum/common"
+)
+
+const (
+ MinSyncCommitteeParticipants = 1
+ SecondsPerSlot = 12
+ SlotsPerEpoch = 32
+ EpochsPerSyncCommitteePeriod = 256
+)
+
+// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_fork_data_root
+func computeForkDataRoot(version []byte, genesisValidatorsRoot common.Hash) common.Hash {
+ var padded common.Hash
+ copy(padded[:], version)
+ return hash(padded.Bytes(), genesisValidatorsRoot.Bytes())
+}
+
+func computeSigningRoot(root, domain common.Hash) common.Hash {
+ return hash(root.Bytes(), domain.Bytes())
+}
+
+func hash(left, right []byte) common.Hash {
+ var (
+ hasher = sha256.New()
+ sum common.Hash
+ )
+ hasher.Write(left)
+ hasher.Write(right)
+ hasher.Sum(sum[:0])
+ return sum
+}
diff --git a/cmd/blsync/chain.go b/cmd/blsync/chain.go
new file mode 100644
index 0000000000..7aaee9ffb5
--- /dev/null
+++ b/cmd/blsync/chain.go
@@ -0,0 +1,156 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/ethereum/go-ethereum/beacon/engine"
+ "github.com/ethereum/go-ethereum/beacon/types"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+// LightClient tracks the head of the chain using the light client protocol,
+// which assumes the majority of beacon chain sync committe is honest.
+type LightClient struct {
+ beacon *BeaconClient
+ store *store
+
+ chainHeadFeed event.Feed
+}
+
+// bootstrap retrieves a light client bootstrap and authenticates it against the
+// provided trusted root.
+func bootstrap(ctx context.Context, server string, root common.Hash) (*LightClient, error) {
+ api, err := NewBeaconClient(ctx, server)
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to beacon server: %w", err)
+ }
+ bs, err := api.Bootstrap(root)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get bootstrap data: %w", err)
+ }
+ if err := bs.Valid(); err != nil {
+ return nil, fmt.Errorf("failed to validate bootstrap data: %w", err)
+ }
+ current, err := bs.Committee.Deserialize()
+ if err != nil {
+ return nil, fmt.Errorf("failed to deserialize committee")
+ }
+ return &LightClient{
+ beacon: api,
+ store: &store{
+ config: SepoliaChainConfig,
+ current: current,
+ optimistic: &bs.Header.Header,
+ finalized: &bs.Header.Header,
+ },
+ }, nil
+}
+
+// ChainHeadEvent returns an authenticated execution payload associated with the
+// latest accepted head of the beacon chain.
+type ChainHeadEvent struct {
+ Data *engine.ExecutableData
+}
+
+// SubscribeChainHeadEvent allows callers to subscribe a provided channel to new
+// head updates.
+func (c *LightClient) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription {
+ return c.chainHeadFeed.Subscribe(ch)
+}
+
+// Finalized returns the latest finalized head known to the light client.
+func (c *LightClient) Finalized() *types.Header {
+ return c.store.finalized
+}
+
+// Start executes the main active loop of the light client which drives the
+// underlying light client store.
+func (c *LightClient) Start() {
+ log.Info("beacon light client starting")
+ ticker := time.NewTicker(SecondsPerSlot * time.Second)
+ for ; ; <-ticker.C {
+ if c.store.next == nil {
+ log.Debug("fetching committee update", "period", c.store.finalizedPeriod())
+ updates, err := c.beacon.GetRangeUpdate(c.store.finalizedPeriod(), 1)
+ if err != nil {
+ log.Error("failed to fetch next committee", "err", err)
+ } else {
+ for _, update := range updates {
+ if err := c.store.Insert(update); err != nil {
+ log.Error("failed to insert committee update", "err", err)
+ break
+ }
+ }
+ }
+ }
+
+ var (
+ update *LightClientUpdate
+ err error
+ )
+ if c.store.optimistic.Slot%SlotsPerEpoch == 0 {
+ log.Debug("fetching finality update")
+ update, err = c.beacon.GetFinalityUpdate()
+ } else {
+ log.Debug("fetching optimistic update")
+ update, err = c.beacon.GetOptimisticUpdate()
+ }
+ if err != nil {
+ log.Error("failed to retrieve update", "err", err)
+ continue
+ }
+ if err := c.store.Insert(update); err != nil {
+ log.Error("failed to insert update", "err", err)
+ continue
+ }
+ head := update.AttestedHeader
+ log.Info("updated head", "slot", head.Slot, "root", head.Hash(), "finalized", c.Finalized().Hash(), "signers", update.SyncAggregate.SignerCount())
+
+ // Fetch full execution payload from beacon provider and send to head feed.
+ data, err := c.getExecutableData(head.Hash())
+ if err != nil {
+ log.Error("failed to insert update", "err", err)
+ continue
+ }
+ c.chainHeadFeed.Send(ChainHeadEvent{Data: data})
+ }
+}
+
+// getExecutableData retrieves the full beacon block associated with the beacon
+// block root and returns the inner execution payload.
+func (c *LightClient) getExecutableData(head common.Hash) (*engine.ExecutableData, error) {
+ block, err := c.beacon.GetBlock(head)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get execution payload: %w", err)
+ }
+ // Compute the root of the block and verify it matches the root the sync
+ // committee signed.
+ root, err := block.Root()
+ if err != nil {
+ return nil, fmt.Errorf("failed to compute root for beacon block: %w", err)
+ }
+ if common.Hash(root) != head {
+ return nil, fmt.Errorf("unable to verify block body against sync committee update")
+ }
+ return versionedBlockToExecutableData(block), nil
+}
diff --git a/cmd/blsync/chain_test.go b/cmd/blsync/chain_test.go
new file mode 100644
index 0000000000..9cc52d40fe
--- /dev/null
+++ b/cmd/blsync/chain_test.go
@@ -0,0 +1,428 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "bytes"
+ "crypto/rand"
+ "crypto/sha256"
+ "errors"
+ "math/bits"
+ mrand "math/rand"
+ "sort"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/beacon/merkle"
+ "github.com/ethereum/go-ethereum/beacon/params"
+ "github.com/ethereum/go-ethereum/beacon/types"
+ "github.com/ethereum/go-ethereum/common"
+ bls "github.com/protolambda/bls12-381-util"
+)
+
+func TestStore(t *testing.T) {
+ var (
+ current = newSyncCommitteeSigner()
+ _ = newSyncCommitteeSigner()
+ base = store{
+ config: SepoliaChainConfig,
+ finalized: &types.Header{},
+ optimistic: &types.Header{},
+ current: current.committee(),
+ next: nil,
+ }
+ )
+ tests := []*test{
+ { // Accept basic updates with various supermajority quorums.
+ store: base.copy(),
+ generators: []updateGen{
+ &single{
+ quorum: 1,
+ signer: current,
+ },
+ &single{
+ quorum: .9,
+ signer: current,
+ },
+ &single{
+ quorum: .8,
+ signer: current,
+ },
+ },
+ },
+ { // Reject if no sync committee members sign.
+ store: base.copy(),
+ generators: []updateGen{
+ &single{
+ quorum: 0,
+ signer: current,
+ err: &errNotEnoughParticipants,
+ },
+ },
+ },
+ { // Accept update with new finalized header and next sync committee.
+ store: base.copy(),
+ generators: []updateGen{
+ &single{
+ quorum: .75,
+ signer: current,
+ finalized: makeHeader(base.optimistic),
+ next: newSyncCommitteeSigner().serialized(),
+ },
+ },
+ },
+ }
+ for i, tt := range tests {
+ runTest(t, tt, i)
+ }
+}
+
+func TestHashTreeRoot(t *testing.T) {
+ for i, tt := range []struct {
+ input []common.Hash
+ root common.Hash
+ }{
+ {
+ input: []common.Hash{{0x42}, {0x00}},
+ root: hash(common.Hash{0x42}.Bytes(), common.Hash{0x00}.Bytes()),
+ },
+ {
+ input: []common.Hash{{0x42}, {0x13, 0x37}, {0x11}},
+ root: hash(
+ hash(common.Hash{0x42}.Bytes(), common.Hash{0x13, 0x37}.Bytes()).Bytes(),
+ hash(common.Hash{0x11}.Bytes(), common.Hash{0x00}.Bytes()).Bytes(),
+ ),
+ },
+ } {
+ got := hashTreeRoot(tt.input)
+ if got != tt.root {
+ t.Fatalf("test %d: mismatched hash tree root: got %s, want %s", i, got, tt.root)
+ }
+ }
+}
+
+func TestFakeStateRoot(t *testing.T) {
+ root, fb, nb := fakeStateRoot(common.Hash{42}, common.Hash{13, 37})
+ if err := merkle.VerifyProof(root, params.StateIndexFinalBlock, fb, merkle.Value{42}); err != nil {
+ t.Fatalf("failed to verify branch2: %v", err)
+ }
+ if err := merkle.VerifyProof(root, params.StateIndexNextSyncCommittee, nb, merkle.Value{13, 37}); err != nil {
+ t.Fatalf("failed to verify branch2: %v", err)
+ }
+}
+
+// syncCommitteeSigner represents a SyncCommittee and allows for signing
+// functionality on behalf of the committee.
+type syncCommitteeSigner struct {
+ config *ChainConfig
+ members []*bls.SecretKey
+}
+
+func newSyncCommitteeSigner() *syncCommitteeSigner {
+ c := &syncCommitteeSigner{config: SepoliaChainConfig}
+ for i := 0; i < params.SyncCommitteeSize; i++ {
+ var sk bls.SecretKey
+ if err := sk.Deserialize(rand32()); err != nil {
+ panic(err)
+ }
+ c.members = append(c.members, &sk)
+ }
+ return c
+}
+
+func (c *syncCommitteeSigner) shuffledCommittee() ([]int, []*bls.SecretKey) {
+ var (
+ shuffled []*bls.SecretKey
+ indexes []int
+ )
+ for i, m := range c.members {
+ shuffled = append(shuffled, m)
+ indexes = append(indexes, i)
+ }
+ mrand.Shuffle(len(shuffled), func(i, j int) {
+ shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
+ indexes[i], indexes[j] = indexes[j], indexes[i]
+ })
+ return indexes, shuffled
+}
+
+func (c *syncCommitteeSigner) signHeader(header *types.Header, quorum float32) types.SyncAggregate {
+ var (
+ count = int(quorum * float32(params.SyncCommitteeSize))
+ indexes []int
+ )
+ // Random draw of committee indices.
+ for i := 0; i < params.SyncCommitteeSize; i++ {
+ indexes = append(indexes, i)
+ }
+ mrand.Shuffle(len(indexes), func(i, j int) { indexes[i], indexes[j] = indexes[j], indexes[i] })
+ sort.Ints(indexes)
+ indexes = indexes[:count]
+
+ // Compute aggregate signature.
+ var (
+ domain = c.config.Domain(SyncCommitteeDomain, header.Slot)
+ root = computeSigningRoot(header.Hash(), domain)
+ sigs = make([]*bls.Signature, count)
+ keys = make([]*bls.Pubkey, count)
+ signers [params.SyncCommitteeBitmaskSize]byte
+ )
+ for i, j := range indexes {
+ sigs[i] = bls.Sign(c.members[j], root[:])
+ keys[i], _ = bls.SkToPk(c.members[j])
+ setBit(signers[:], j)
+ }
+ var agg bls.Signature
+ if len(sigs) != 0 {
+ sig, err := bls.Aggregate(sigs)
+ if err != nil {
+ panic(err)
+ }
+ agg = *sig
+ }
+ return types.SyncAggregate{
+ Signers: signers,
+ Signature: agg.Serialize(),
+ }
+}
+
+func (c *syncCommitteeSigner) serialized() *types.SerializedSyncCommittee {
+ var keys [params.SyncCommitteeSize]*bls.Pubkey
+ for i := range keys {
+ pk, err := bls.SkToPk(c.members[i])
+ if err != nil {
+ panic(err)
+ }
+ keys[i] = pk
+ }
+ agg, err := bls.AggregatePubkeys(keys[:])
+ if err != nil {
+ panic(err)
+ }
+ var out types.SerializedSyncCommittee
+ for i, key := range keys {
+ tmp := key.Serialize()
+ copy(out[i*48:], tmp[:])
+ }
+ tmp := agg.Serialize()
+ copy(out[len(out)-48:], tmp[:])
+ return &out
+}
+
+func (c *syncCommitteeSigner) committee() *types.SyncCommittee {
+ committee, _ := c.serialized().Deserialize()
+ return committee
+}
+
+func makeHeader(parent *types.Header) *types.Header {
+ h := &types.Header{
+ Slot: parent.Slot + 1,
+ ProposerIndex: 42,
+ ParentRoot: parent.Hash(),
+ StateRoot: common.Hash{},
+ BodyRoot: common.Hash{},
+ }
+ return h
+}
+
+// updateGen is an interface representing different test generators.
+type updateGen interface {
+ gen(*types.Header) []*LightClientUpdate
+ error() *error
+}
+
+// single is test generator which can generate a single custom LightClientUpdate.
+type single struct {
+ header *types.Header
+ quorum float32
+ signer *syncCommitteeSigner
+ finalized *types.Header
+ next *types.SerializedSyncCommittee
+ err *error
+}
+
+// gen generates a single LightClientUpdate given the generation parameters.
+func (u *single) gen(parent *types.Header) []*LightClientUpdate {
+ if u.header == nil {
+ u.header = makeHeader(parent)
+ }
+ var (
+ finalizedHeader *LightClientHeader
+ finalizedBranch *merkle.Values
+ next *types.SerializedSyncCommittee
+ nextBranch *merkle.Values
+ )
+ if u.finalized != nil || u.next != nil {
+ if u.finalized == nil || u.next == nil {
+ panic("must provide both finalized and next")
+ }
+ root, fb, nb := fakeStateRoot(u.finalized.Hash(), u.next.Root())
+ u.header.StateRoot = root
+ finalizedHeader = &LightClientHeader{Header: *u.finalized}
+ finalizedBranch = &fb
+ next = u.next
+ nextBranch = &nb
+ }
+ return []*LightClientUpdate{
+ {
+ AttestedHeader: LightClientHeader{*u.header},
+ SyncAggregate: u.signer.signHeader(u.header, u.quorum),
+ SignatureSlot: u.header.Slot,
+ FinalizedHeader: finalizedHeader,
+ FinalityBranch: finalizedBranch,
+ NextSyncCommittee: next,
+ NextSyncCommitteeBranch: nextBranch,
+ },
+ }
+}
+
+func (u *single) error() *error {
+ return u.err
+}
+
+type test struct {
+ store *store
+ generators []updateGen
+}
+
+// runTest executes a test case against the light client store and verifies the
+// resulting state of the store.
+func runTest(t *testing.T, tt *test, i int) {
+ parent := tt.store.optimistic
+ for _, g := range tt.generators {
+ updates := g.gen(parent)
+
+ // Send all updates to store.
+ for _, update := range updates {
+ err := tt.store.Insert(update)
+ if g.error() != nil && !errors.Is(err, *g.error()) {
+ t.Fatalf("test %d: mismatch errors: got %v, want %v", i, err, *g.error())
+ }
+ if g.error() == nil && err != nil {
+ t.Fatalf("test %d: unexpected error: %v", i, err)
+ }
+
+ // No error, verify update was successfully accepted.
+ if err == nil {
+ header := &update.AttestedHeader.Header
+ if tt.store.optimistic.Hash() != header.Hash() {
+ t.Fatalf("test %d: expected optimistic head to be updated: have %d, want %d", i, tt.store.optimistic.Slot, header.Slot)
+ }
+ if update.FinalizedHeader != nil && tt.store.finalized.Hash() != update.FinalizedHeader.Hash() {
+ t.Fatalf("test %d: expected finalized to be updated: have %d, want %d", i, tt.store.finalized.Slot, update.FinalizedHeader.Slot)
+ }
+ if update.NextSyncCommittee != nil {
+ if tt.store.next == nil {
+ t.Fatalf("test %d: expected next sync committe set, but found nil", i)
+ }
+ var (
+ have = tt.store.next.Aggregate.Serialize()
+ want = update.NextSyncCommittee[types.SerializedSyncCommitteeSize-48:]
+ )
+ if !bytes.Equal(have[:], want) {
+ t.Fatalf("test %d: mismatched next sync committee: have %s, want %s", i, common.Bytes2Hex(have[:]), common.Bytes2Hex(want))
+ }
+ }
+ parent = header
+ }
+ }
+ }
+}
+
+func setBit(bits []byte, pos int) {
+ bits[pos/8] |= 1 << (pos % 8)
+}
+
+func rand32() *[32]byte {
+ var b [32]byte
+ _, err := rand.Reader.Read(b[:])
+ if err != nil {
+ panic(err)
+ }
+ return &b
+}
+
+func hashTreeRoot(leaves []common.Hash) common.Hash {
+ var (
+ size = nextPowerOfTwo(len(leaves))
+ hasher = sha256.New()
+ )
+ leaves = append(leaves, make([]common.Hash, size-len(leaves))...)
+ for i := 0; i < bits.Len(uint(size)); i++ {
+ size = size >> 1
+ for j := 0; j < size; j++ {
+ hasher.Write(leaves[2*j][:])
+ hasher.Write(leaves[2*j+1][:])
+ hasher.Sum(leaves[j][:0])
+ hasher.Reset()
+ }
+ }
+ return leaves[0]
+}
+
+func nextPowerOfTwo(x int) int {
+ if x&(x-1) == 0 {
+ return x
+ }
+ return 1 << (bits.Len(uint(x)))
+}
+
+func fakeStateRoot(finalized, next common.Hash) (common.Hash, merkle.Values, merkle.Values) {
+ var (
+ hasher = sha256.New()
+ buf = make([]common.Hash, 32)
+ finalizedIdx = params.StateIndexFinalBlock
+ finalizedBranch merkle.Values
+ nextIdx = params.StateIndexNextSyncCommittee
+ nextBranch merkle.Values
+ )
+ // Compute root for Checkpoint structure and begin branch.
+ hasher.Write(common.Hash{}.Bytes())
+ hasher.Write(finalized.Bytes())
+ hasher.Sum(buf[20][:0])
+ finalizedBranch = append(finalizedBranch, merkle.Value{})
+ finalizedIdx >>= 1
+
+ // Write sync committee root in to correct location.
+ buf[23] = next
+
+ // Compute the root for the state object.
+ for i := 32; i > 1; i /= 2 {
+ for j := 0; j < i; j += 2 {
+ hasher.Reset()
+ if i+j == finalizedIdx || i+j+1 == finalizedIdx {
+ if finalizedIdx&1 == 0 {
+ finalizedBranch = append(finalizedBranch, merkle.Value(buf[j+1]))
+ } else {
+ finalizedBranch = append(finalizedBranch, merkle.Value(buf[j]))
+ }
+ finalizedIdx >>= 1
+ }
+ if i+j == nextIdx || i+j+1 == nextIdx {
+ if nextIdx&1 == 0 {
+ nextBranch = append(nextBranch, merkle.Value(buf[j+1]))
+ } else {
+ nextBranch = append(nextBranch, merkle.Value(buf[j]))
+ }
+ nextIdx >>= 1
+ }
+ hasher.Write(buf[j].Bytes())
+ hasher.Write(buf[j+1].Bytes())
+ hasher.Sum(buf[j/2][:0])
+ }
+ }
+ return buf[0], finalizedBranch, nextBranch
+}
diff --git a/cmd/blsync/config.go b/cmd/blsync/config.go
new file mode 100644
index 0000000000..a6a8a989d9
--- /dev/null
+++ b/cmd/blsync/config.go
@@ -0,0 +1,76 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
+
+// SyncCommitteeDomain is the signature type for sync committee signatures.
+var SyncCommitteeDomain = []byte{7, 0, 0, 0}
+
+// SepoliaChainConfig is the fork schedule and genesis info for the Sepolia beacon chain.
+var SepoliaChainConfig = &ChainConfig{
+ Genesis: &ForkConfig{0, []byte{144, 0, 0, 105}},
+ Altair: &ForkConfig{50, []byte{144, 0, 0, 112}},
+ Bellatrix: &ForkConfig{100, []byte{144, 0, 0, 113}},
+ Capella: &ForkConfig{56832, []byte{144, 0, 0, 114}},
+ GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
+}
+
+// Fork config encodes the epoch at which a certain fork must activate and the
+// version bytes to be used for signatures.
+type ForkConfig struct {
+ Epoch uint64
+ Version []byte
+}
+
+// ChainConfig represents the fork schedule for a certain chain.
+type ChainConfig struct {
+ GenesisValidatorsRoot common.Hash
+
+ Genesis *ForkConfig
+ Altair *ForkConfig
+ Bellatrix *ForkConfig
+ Capella *ForkConfig
+}
+
+// Version returns the active version for a given slot.
+func (c *ChainConfig) Version(slot uint64) []byte {
+ epoch := slot / SlotsPerEpoch
+ switch {
+ case c.Capella.Epoch <= epoch:
+ return c.Capella.Version
+ case c.Bellatrix.Epoch <= epoch:
+ return c.Bellatrix.Version
+ case c.Altair.Epoch <= epoch:
+ return c.Altair.Version
+ default:
+ return c.Genesis.Version
+ }
+}
+
+// Domain returns the domain for a given slot.
+func (c *ChainConfig) Domain(typ []byte, slot uint64) common.Hash {
+ var (
+ forkData = computeForkDataRoot(c.Version(slot), c.GenesisValidatorsRoot)
+ domain common.Hash
+ )
+ copy(domain[0:4], typ[:])
+ copy(domain[4:], forkData[0:28])
+ return domain
+}
diff --git a/cmd/blsync/errors.go b/cmd/blsync/errors.go
new file mode 100644
index 0000000000..35fd0494e0
--- /dev/null
+++ b/cmd/blsync/errors.go
@@ -0,0 +1,28 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import "errors"
+
+var (
+ errNotEnoughParticipants = errors.New("not enough sync committee participants")
+ errWrongPeriod = errors.New("update not from active period")
+ errUselessUpdate = errors.New("useless update")
+ errInvalidFinalityBranch = errors.New("invalid finality branch")
+ errInvalidNextSyncCommitteeBranch = errors.New("invalid next sync committee branch")
+ errInvalidSyncCommitteeSignature = errors.New("invalid sync committee signature")
+)
diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go
new file mode 100644
index 0000000000..e24db35074
--- /dev/null
+++ b/cmd/blsync/main.go
@@ -0,0 +1,184 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "time"
+
+ "github.com/ethereum/go-ethereum/beacon/engine"
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/internal/flags"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/mattn/go-colorable"
+ "github.com/mattn/go-isatty"
+ "github.com/urfave/cli/v2"
+)
+
+var app = &cli.App{
+ Usage: "go-ethereum beacon light sync tool",
+ Action: run,
+}
+
+var (
+ EngineApiFlag = &cli.StringFlag{
+ Name: "engine",
+ Usage: "url to execution client engine api",
+ }
+ JwtSecretFlag = &cli.StringFlag{
+ Name: "jwtsecret",
+ Usage: "path to jwt secret used to communicate with execution client",
+ }
+ LightClientServerFlag = &cli.StringFlag{
+ Name: "server",
+ Usage: "server which provides the beacon light client apis",
+ }
+ TrustedBlockRootFlag = &cli.StringFlag{
+ Name: "trusted-root",
+ Usage: "root of trusted block within the weak-subjectivity window",
+ }
+ VerbosityFlag = &cli.IntFlag{
+ Name: "verbosity",
+ Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
+ Value: 3,
+ }
+)
+
+func init() {
+ app.Flags = flags.Merge([]cli.Flag{
+ EngineApiFlag,
+ JwtSecretFlag,
+ LightClientServerFlag,
+ TrustedBlockRootFlag,
+ VerbosityFlag,
+ })
+}
+
+func main() {
+ if err := app.Run(os.Args); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
+
+func run(ctx *cli.Context) error {
+ // Setup logger.
+ var (
+ usecolor = (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
+ output = io.Writer(os.Stdout)
+ verbosity = log.FromLegacyLevel(ctx.Int(VerbosityFlag.Name))
+ )
+ if usecolor {
+ output = colorable.NewColorable(os.Stdout)
+ }
+ log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
+
+ // Start light client.
+ var (
+ root = ctx.String(TrustedBlockRootFlag.Name)
+ engine = makeRPCClient(ctx)
+ server = ctx.String(LightClientServerFlag.Name)
+ )
+ chain, err := bootstrap(context.Background(), server, common.HexToHash(root))
+ if err != nil {
+ return fmt.Errorf("failed to bootstrap: %v", err)
+ }
+ go chain.Start()
+
+ headCh := make(chan ChainHeadEvent)
+ chain.SubscribeChainHeadEvent(headCh)
+
+ // Send new head events to engine api.
+ for {
+ select {
+ case head := <-headCh:
+ if err := sendUpdate(engine, head.Data, chain.Finalized().Hash()); err != nil {
+ log.Error("unable to send update to execution client", "err", err)
+ }
+ }
+ }
+}
+
+// sendUpdate passes the execution payload to execution client and affirms it
+// with a forck choice updated.
+func sendUpdate(engine *rpc.Client, ep *engine.ExecutableData, finalized common.Hash) error {
+ if _, err := callNewPayloadV2(engine, ep); err != nil {
+ return fmt.Errorf("failed to send new payload: %w", err)
+ }
+ if _, err := callForkchoiceUpdatedV1(engine, ep.BlockHash, finalized); err != nil {
+ return fmt.Errorf("failed to send forkchoice updated: %w", err)
+ }
+ return nil
+}
+
+func makeRPCClient(ctx *cli.Context) *rpc.Client {
+ if !ctx.IsSet(EngineApiFlag.Name) {
+ log.Warn("No engine API target specified, performing a dry run")
+ return nil
+ }
+ if !ctx.IsSet(JwtSecretFlag.Name) {
+ exit(fmt.Errorf("JWT secret parameter missing")) // TODO use default if datadir is specified
+ }
+ engineApiUrl, jwtFileName := ctx.String(EngineApiFlag.Name), ctx.String(JwtSecretFlag.Name)
+ var jwtSecret [32]byte
+ if jwt, err := os.ReadFile(jwtFileName); err != nil {
+ utils.Fatalf("Error loading or generating JWT secret: %v", err)
+ } else {
+ copy(jwtSecret[:], common.FromHex(string(jwt)))
+ }
+ auth := node.NewJWTAuth(jwtSecret)
+ cl, err := rpc.DialOptions(context.Background(), engineApiUrl, rpc.WithHTTPAuth(auth))
+ if err != nil {
+ utils.Fatalf("Could not create RPC client: %v", err)
+ }
+ return cl
+}
+
+func callNewPayloadV2(client *rpc.Client, ep *engine.ExecutableData) (string, error) {
+ var resp engine.PayloadStatusV1
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ err := client.CallContext(ctx, &resp, "engine_newPayloadV2", ep)
+ cancel()
+ return resp.Status, err
+}
+
+func callForkchoiceUpdatedV1(client *rpc.Client, headHash, finalizedHash common.Hash) (string, error) {
+ var resp engine.ForkChoiceResponse
+ update := engine.ForkchoiceStateV1{
+ HeadBlockHash: headHash,
+ SafeBlockHash: common.Hash{},
+ FinalizedBlockHash: common.Hash{},
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ err := client.CallContext(ctx, &resp, "engine_forkchoiceUpdatedV1", update, nil)
+ cancel()
+ return resp.PayloadStatus.Status, err
+}
+
+func exit(err interface{}) {
+ if err == nil {
+ os.Exit(0)
+ }
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+}
diff --git a/cmd/blsync/store.go b/cmd/blsync/store.go
new file mode 100644
index 0000000000..6041b33649
--- /dev/null
+++ b/cmd/blsync/store.go
@@ -0,0 +1,183 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/beacon/merkle"
+ "github.com/ethereum/go-ethereum/beacon/params"
+ "github.com/ethereum/go-ethereum/beacon/types"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+// store implements the light client state machine LightClientStore from the
+// light client specification.
+//
+// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientstore
+type store struct {
+ config *ChainConfig
+
+ finalized *types.Header
+ optimistic *types.Header
+
+ current *types.SyncCommittee
+ next *types.SyncCommittee
+
+ best *LightClientUpdate
+
+ prevActive uint64
+ currActive uint64
+}
+
+func (s *store) copy() *store {
+ shallow := s
+ return shallow
+}
+
+func (s *store) validate(update *LightClientUpdate) error {
+ if update.SyncAggregate.SignerCount() <= MinSyncCommitteeParticipants {
+ return errNotEnoughParticipants
+ }
+ var (
+ updatePeriod = types.SyncPeriod(update.SignatureSlot)
+ storedPeriod = types.SyncPeriod(s.finalized.Slot)
+ )
+ // Verify update does not skip a sync committee.
+ if updatePeriod != storedPeriod && (s.next == nil || updatePeriod != storedPeriod+1) {
+ log.Error("update not from current or next sync committee", "stored", storedPeriod, "update", updatePeriod)
+ return errWrongPeriod
+ }
+ if !(update.AttestedHeader.Slot > s.finalized.Slot || update.NextSyncCommittee != nil) {
+ return errUselessUpdate
+ }
+
+ // Verify finalized header update, if it exists.
+ if update.FinalizedHeader != nil && update.FinalityBranch != nil {
+ finalized := merkle.Value{}
+ if update.FinalizedHeader.Slot != 0 {
+ finalized = merkle.Value(update.FinalizedHeader.Hash())
+ }
+ if err := merkle.VerifyProof(update.AttestedHeader.StateRoot, params.StateIndexFinalBlock, *update.FinalityBranch, finalized); err != nil {
+ return errInvalidFinalityBranch
+ }
+ }
+
+ // Validate sync committee update, if it exsits.
+ if update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch != nil {
+ if types.SyncPeriod(update.AttestedHeader.Slot) == storedPeriod && s.next != nil {
+ // TODO: maybe check if current next equals this update's next?
+ } else if err := merkle.VerifyProof(
+ update.AttestedHeader.StateRoot,
+ params.StateIndexNextSyncCommittee,
+ *update.NextSyncCommitteeBranch,
+ merkle.Value(update.NextSyncCommittee.Root()),
+ ); err != nil {
+ return errInvalidNextSyncCommitteeBranch
+ }
+ }
+
+ // Validate sync committee signature.
+ var (
+ domain = s.config.Domain(SyncCommitteeDomain, update.SignatureSlot)
+ signingRoot = computeSigningRoot(update.AttestedHeader.Hash(), domain)
+ )
+ committee := s.current
+ if updatePeriod == storedPeriod+1 {
+ committee = s.next
+ }
+ if !committee.VerifySignature(signingRoot, &update.SyncAggregate) {
+ return errInvalidSyncCommitteeSignature
+ }
+
+ return nil
+}
+
+func (s *store) safetyThreshold() int {
+ return int(max(s.currActive, s.prevActive) / 2)
+}
+
+func (s *store) finalizedPeriod() int {
+ return int(types.SyncPeriod(s.finalized.Slot))
+}
+
+func (s *store) Insert(update *LightClientUpdate) error {
+ if err := s.validate(update); err != nil {
+ return err
+ }
+ if err := s.best.Compare(update); err == nil {
+ s.best = update
+ }
+ s.currActive = max(s.currActive, uint64(update.SyncAggregate.SignerCount()))
+
+ if update.SyncAggregate.SignerCount() > s.safetyThreshold() &&
+ update.AttestedHeader.Slot > s.optimistic.Slot {
+ s.optimistic = &update.AttestedHeader.Header
+ }
+
+ // Process sync committee update.
+ if update.NextSyncCommittee != nil {
+ var (
+ storedPeriod = types.SyncPeriod(s.finalized.Slot)
+ updatePeriod = types.SyncPeriod(update.FinalizedHeader.Slot)
+ )
+ if s.next == nil && storedPeriod == updatePeriod {
+ committee, err := update.NextSyncCommittee.Deserialize()
+ if err != nil {
+ return fmt.Errorf("failed to deserialize next sync committee: %w", err)
+ }
+ s.next = committee
+ } else if updatePeriod == storedPeriod+1 {
+ committee, err := update.NextSyncCommittee.Deserialize()
+ if err != nil {
+ return fmt.Errorf("failed to deserialize next sync committee: %w", err)
+ }
+ s.current = s.next
+ s.next = committee
+ s.prevActive = s.currActive
+ s.currActive = 0
+ }
+ }
+
+ // Process finalized header update.
+ if update.FinalizedHeader != nil {
+ if update.FinalizedHeader.Header.Slot > s.finalized.Slot {
+ s.finalized = &update.FinalizedHeader.Header
+ var (
+ storedPeriod = types.SyncPeriod(s.finalized.Slot)
+ updatePeriod = types.SyncPeriod(update.FinalizedHeader.Slot)
+ )
+ // Shift over sync committee and active ratio when a finalized update
+ // moves into a new period.
+ if updatePeriod == storedPeriod+1 {
+ s.current = s.next
+ s.next = nil
+ s.prevActive = s.currActive
+ s.currActive = 0
+ }
+ }
+ }
+
+ return nil
+}
+
+func max(x, y uint64) uint64 {
+ if x < y {
+ return y
+ }
+ return x
+}
diff --git a/cmd/blsync/types.go b/cmd/blsync/types.go
new file mode 100644
index 0000000000..5e9a828981
--- /dev/null
+++ b/cmd/blsync/types.go
@@ -0,0 +1,306 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+
+ eth2spec "github.com/attestantio/go-eth2-client/spec"
+ "github.com/ethereum/go-ethereum/beacon/engine"
+ "github.com/ethereum/go-ethereum/beacon/merkle"
+ "github.com/ethereum/go-ethereum/beacon/params"
+ "github.com/ethereum/go-ethereum/beacon/types"
+ "github.com/ethereum/go-ethereum/common"
+ ctypes "github.com/ethereum/go-ethereum/core/types"
+)
+
+// LightClientHeader is a wrapper around a beacon header with special, nested
+// marshalling.
+type LightClientHeader struct {
+ types.Header
+}
+
+type lightClientHeaderMarshaling struct {
+ Beacon types.Header `json:"beacon"`
+}
+
+// MarshalJSON marshals as JSON.
+func (h LightClientHeader) MarshalJSON() ([]byte, error) {
+ var enc lightClientHeaderMarshaling
+ enc.Beacon = h.Header
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (h *LightClientHeader) UnmarshalJSON(input []byte) error {
+ var dec lightClientHeaderMarshaling
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ *h = LightClientHeader{dec.Beacon}
+ return nil
+}
+
+// Boostrap is response to the bootstap endpoint in the beacon API.
+type Bootstrap struct {
+ Header LightClientHeader `json:"header"`
+ Committee *types.SerializedSyncCommittee `json:"current_sync_committee"`
+ CommitteeBranch merkle.Values `json:"current_sync_committee_branch"`
+}
+
+// Valid verifies the current committee root is correctly encoded in the beacon
+// state of the weak-subjectivity checkpoint.
+func (b *Bootstrap) Valid() error {
+ root := merkle.Value(b.Committee.Root())
+ if err := merkle.VerifyProof(b.Header.StateRoot, params.StateIndexSyncCommittee, b.CommitteeBranch, root); err != nil {
+ return err
+ }
+ return nil
+}
+
+type bootstrapMarshaling struct {
+ Data struct {
+ Header LightClientHeader `json:"header"`
+ Committee *types.SerializedSyncCommittee `json:"current_sync_committee"`
+ CommitteeBranch merkle.Values `json:"current_sync_committee_branch"`
+ } `json:"data"`
+}
+
+// MarshalJSON marshals as JSON.
+func (b Bootstrap) MarshalJSON() ([]byte, error) {
+ var enc bootstrapMarshaling
+ enc.Data.Header = b.Header
+ enc.Data.Committee = b.Committee
+ enc.Data.CommitteeBranch = b.CommitteeBranch
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (b *Bootstrap) UnmarshalJSON(input []byte) error {
+ var dec bootstrapMarshaling
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ b.Header = dec.Data.Header
+ b.Committee = dec.Data.Committee
+ b.CommitteeBranch = dec.Data.CommitteeBranch
+ return nil
+}
+
+// LightClientUpdate represents the possible light client updates the beacon api
+// may respond with.
+type LightClientUpdate struct {
+ AttestedHeader LightClientHeader // Arbitrary header out of the period signed by the sync committee
+ SyncAggregate types.SyncAggregate // BLS aggregate signature from sync committee
+ SignatureSlot uint64 // Slot at which the signature is computed
+ NextSyncCommittee *types.SerializedSyncCommittee // Sync committee of the next period advertised in the current one
+ NextSyncCommitteeBranch *merkle.Values // Proof for the next period's sync committee
+ FinalizedHeader *LightClientHeader // Optional header to announce a point of finality
+ FinalityBranch *merkle.Values // Proof for the announced finality
+}
+
+type lightClientUpdateMarshaling struct {
+ Data struct {
+ AttestedHeader LightClientHeader `json:"attested_header"`
+ SyncAggregate types.SyncAggregate `json:"sync_aggregate"`
+ SignatureSlot common.Decimal `json:"signature_slot"`
+ NextSyncCommittee *types.SerializedSyncCommittee `json:"next_sync_committee"`
+ NextSyncCommitteeBranch *merkle.Values `json:"next_sync_committee_branch"`
+ FinalizedHeader *LightClientHeader `json:"finalized_header"`
+ FinalityBranch *merkle.Values `json:"finality_branch"`
+ } `json:"data"`
+}
+
+// MarshalJSON marshals to JSON.
+func (u LightClientUpdate) MarshalJSON() ([]byte, error) {
+ var enc lightClientUpdateMarshaling
+ enc.Data.AttestedHeader = u.AttestedHeader
+ enc.Data.SyncAggregate = u.SyncAggregate
+ enc.Data.SignatureSlot = common.Decimal(u.SignatureSlot)
+ enc.Data.NextSyncCommittee = u.NextSyncCommittee
+ enc.Data.NextSyncCommitteeBranch = u.NextSyncCommitteeBranch
+ enc.Data.FinalizedHeader = u.FinalizedHeader
+ enc.Data.FinalityBranch = u.FinalityBranch
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (u *LightClientUpdate) UnmarshalJSON(input []byte) error {
+ var dec lightClientUpdateMarshaling
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ u.AttestedHeader = dec.Data.AttestedHeader
+ u.SyncAggregate = dec.Data.SyncAggregate
+ u.SignatureSlot = uint64(dec.Data.SignatureSlot)
+ u.NextSyncCommittee = dec.Data.NextSyncCommittee
+ u.NextSyncCommitteeBranch = dec.Data.NextSyncCommitteeBranch
+ u.FinalizedHeader = dec.Data.FinalizedHeader
+ u.FinalityBranch = dec.Data.FinalityBranch
+ return nil
+}
+
+// Compare will compare two light client updates and determine the better one.
+// If next is not better than curr, it will error.
+func (curr *LightClientUpdate) Compare(next *LightClientUpdate) error {
+ if curr == nil {
+ // Nothing to compare.
+ return nil
+ }
+ var (
+ maxActiveParticipants = params.SyncCommitteeSize
+ newNumActiveParticipants = next.SyncAggregate.SignerCount()
+ oldNumActiveParticipants = curr.SyncAggregate.SignerCount()
+ newHasSupermajority = newNumActiveParticipants*3 >= maxActiveParticipants*2
+ oldHasSupermajority = oldNumActiveParticipants*3 >= maxActiveParticipants*2
+ )
+ if newHasSupermajority && !oldHasSupermajority {
+ return nil
+ } else if !newHasSupermajority && oldHasSupermajority {
+ return fmt.Errorf("new update does not have supermajority while old does")
+ }
+ if !newHasSupermajority && newNumActiveParticipants > oldNumActiveParticipants {
+ return nil
+ } else if !newHasSupermajority && newNumActiveParticipants <= oldNumActiveParticipants {
+ return fmt.Errorf("more active participants in old update")
+ }
+
+ // TODO: implement all tie breakers from spec
+ // var (
+ // sigPeriod = slotToSyncCommitteePeriod(next.SignatureSlot)
+ // newHasRelevantSyncCommitteeUpdate = next.NextSyncCommittee != nil && (slotToSyncCommitteePeriod(next.AttestedHeader.Slot) == sigPeriod)
+ // oldHasRelevantSyncCommitteeUpdate = curr.NextSyncCommittee != nil && (slotToSyncCommitteePeriod(curr.AttestedHeader.Slot) == sigPeriod)
+ // )
+ // if !newHasRelevantSyncCommitteeUpdate && oldHasRelevantSyncCommitteeUpdate {
+ // return fmt.Errorf("old update also includes sync committee update")
+ // }
+
+ return nil
+}
+
+// versionedBlockToExecutableData parses versioned blocks and returns a generic
+// execution payload object.
+func versionedBlockToExecutableData(block *eth2spec.VersionedSignedBeaconBlock) *engine.ExecutableData {
+ var ep *engine.ExecutableData
+ switch block.Version {
+ case eth2spec.DataVersionPhase0:
+ panic("phase0 block has no execution payload to send")
+ case eth2spec.DataVersionAltair:
+ panic("altair block has no execution payload to send")
+ case eth2spec.DataVersionBellatrix:
+ p := block.Bellatrix.Message.Body.ExecutionPayload
+ ep = &engine.ExecutableData{
+ ParentHash: common.Hash(p.ParentHash),
+ FeeRecipient: common.Address(p.FeeRecipient),
+ StateRoot: p.StateRoot,
+ ReceiptsRoot: p.ReceiptsRoot,
+ LogsBloom: p.LogsBloom[:],
+ Random: p.PrevRandao,
+ Number: p.BlockNumber,
+ GasLimit: p.GasLimit,
+ GasUsed: p.GasUsed,
+ Timestamp: p.Timestamp,
+ ExtraData: p.ExtraData,
+ BaseFeePerGas: new(big.Int).SetBytes(reverse(p.BaseFeePerGas[:])),
+ BlockHash: common.Hash(p.BlockHash),
+ Transactions: [][]byte{},
+ Withdrawals: nil,
+ BlobGasUsed: nil,
+ ExcessBlobGas: nil,
+ }
+ for _, tx := range p.Transactions {
+ ep.Transactions = append(ep.Transactions, tx)
+ }
+ case eth2spec.DataVersionCapella:
+ p := block.Capella.Message.Body.ExecutionPayload
+ ep = &engine.ExecutableData{
+ ParentHash: common.Hash(p.ParentHash),
+ FeeRecipient: common.Address(p.FeeRecipient),
+ StateRoot: p.StateRoot,
+ ReceiptsRoot: p.ReceiptsRoot,
+ LogsBloom: p.LogsBloom[:],
+ Random: p.PrevRandao,
+ Number: p.BlockNumber,
+ GasLimit: p.GasLimit,
+ GasUsed: p.GasUsed,
+ Timestamp: p.Timestamp,
+ ExtraData: p.ExtraData,
+ BaseFeePerGas: new(big.Int).SetBytes(reverse(p.BaseFeePerGas[:])),
+ BlockHash: common.Hash(p.BlockHash),
+ Transactions: [][]byte{},
+ Withdrawals: nil,
+ BlobGasUsed: nil,
+ ExcessBlobGas: nil,
+ }
+ for _, tx := range p.Transactions {
+ ep.Transactions = append(ep.Transactions, tx)
+ }
+ for _, wx := range p.Withdrawals {
+ ep.Withdrawals = append(ep.Withdrawals, &ctypes.Withdrawal{
+ Index: uint64(wx.Index),
+ Validator: uint64(wx.ValidatorIndex),
+ Address: common.Address(wx.Address),
+ Amount: uint64(wx.Amount),
+ })
+ }
+ case eth2spec.DataVersionDeneb:
+ p := block.Deneb.Message.Body.ExecutionPayload
+ ep = &engine.ExecutableData{
+ ParentHash: common.Hash(p.ParentHash),
+ FeeRecipient: common.Address(p.FeeRecipient),
+ StateRoot: common.Hash(p.StateRoot),
+ ReceiptsRoot: common.Hash(p.ReceiptsRoot),
+ LogsBloom: p.LogsBloom[:],
+ Random: p.PrevRandao,
+ Number: p.BlockNumber,
+ GasLimit: p.GasLimit,
+ GasUsed: p.GasUsed,
+ Timestamp: p.Timestamp,
+ ExtraData: p.ExtraData,
+ BaseFeePerGas: nil, // TODO: convert this []uint64 correctly to big.Int
+ BlockHash: common.Hash(p.BlockHash),
+ Transactions: [][]byte{},
+ Withdrawals: nil,
+ BlobGasUsed: &p.BlobGasUsed,
+ ExcessBlobGas: &p.ExcessBlobGas,
+ }
+ for _, tx := range p.Transactions {
+ ep.Transactions = append(ep.Transactions, tx)
+ }
+ for _, wx := range p.Withdrawals {
+ ep.Withdrawals = append(ep.Withdrawals, &ctypes.Withdrawal{
+ Index: uint64(wx.Index),
+ Validator: uint64(wx.ValidatorIndex),
+ Address: common.Address(wx.Address),
+ Amount: uint64(wx.Amount),
+ })
+ }
+ default:
+ panic("unknown beacon block version")
+ }
+ return ep
+}
+
+func reverse(b []byte) []byte {
+ for i := 0; i < len(b)/2; i++ {
+ j := len(b) - i - 1
+ b[i], b[j] = b[j], b[i]
+ }
+ return b
+}
diff --git a/go.mod b/go.mod
index b4d077fc47..ff02a3b1d9 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
github.com/Microsoft/go-winio v0.6.1
github.com/VictoriaMetrics/fastcache v1.12.1
+ github.com/attestantio/go-eth2-client v0.19.5
github.com/aws/aws-sdk-go-v2 v1.21.2
github.com/aws/aws-sdk-go-v2/config v1.18.45
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
@@ -54,6 +55,7 @@ require (
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/rs/cors v1.7.0
+ github.com/rs/zerolog v1.29.1
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.4
@@ -100,24 +102,30 @@ require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/deepmap/oapi-codegen v1.6.0 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
+ github.com/ferranbt/fastssz v0.1.3 // indirect
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/goccy/go-json v0.10.2 // indirect
+ github.com/goccy/go-yaml v1.9.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
+ github.com/huandu/go-clone v1.6.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kilic/bls12-381 v0.1.0 // indirect
github.com/klauspost/compress v1.15.15 // indirect
+ github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mitchellh/pointerstructure v1.2.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
@@ -125,19 +133,26 @@ require (
github.com/opentracing/opentracing-go v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_golang v1.12.0 // indirect
- github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
- github.com/prometheus/common v0.32.1 // indirect
- github.com/prometheus/procfs v0.7.3 // indirect
+ github.com/prometheus/client_golang v1.16.0 // indirect
+ github.com/prometheus/client_model v0.3.0 // indirect
+ github.com/prometheus/common v0.42.0 // indirect
+ github.com/prometheus/procfs v0.10.1 // indirect
+ github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect
+ github.com/r3labs/sse/v2 v2.10.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
- github.com/rogpeppe/go-internal v1.9.0 // indirect
+ github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
+ go.opentelemetry.io/otel v1.16.0 // indirect
+ go.opentelemetry.io/otel/metric v1.16.0 // indirect
+ go.opentelemetry.io/otel/trace v1.16.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.18.0 // indirect
- google.golang.org/protobuf v1.27.1 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
+ gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
diff --git a/go.sum b/go.sum
index bab51b1345..678e87bd21 100644
--- a/go.sum
+++ b/go.sum
@@ -1,36 +1,4 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
@@ -43,7 +11,6 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgx
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
@@ -58,14 +25,11 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/attestantio/go-eth2-client v0.19.5 h1:4V+vhXsCYji5jWrlONbr03GV7qoLRdzq96dLgXaqmek=
+github.com/attestantio/go-eth2-client v0.19.5/go.mod h1:mZve1kV9Ctj0I1HH9gdg+MnI8lZ+Cb2EktEtOYrBlsM=
github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA=
github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM=
github.com/aws/aws-sdk-go-v2/config v1.18.45 h1:Aka9bI7n8ysuwPeFdm77nfbyHCAKQ3z9ghB3S/38zes=
@@ -93,8 +57,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsP
github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8=
github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
@@ -105,15 +67,10 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOF
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M=
@@ -142,6 +99,7 @@ github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5U
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -177,16 +135,18 @@ github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
+github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
@@ -211,32 +171,36 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
+github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w=
+github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -245,32 +209,19 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -278,44 +229,24 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXi
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@@ -332,8 +263,6 @@ github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXc
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw=
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
@@ -342,10 +271,14 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
+github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
+github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc=
+github.com/huandu/go-clone v1.6.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE=
+github.com/huandu/go-clone/generic v1.6.0 h1:Wgmt/fUZ28r16F2Y3APotFD59sHk1p78K0XLdbUYN5U=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -367,18 +300,11 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
@@ -398,9 +324,9 @@ github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@@ -416,6 +342,8 @@ github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvf
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -424,6 +352,7 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -439,12 +368,13 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
-github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
+github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
+github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
@@ -454,14 +384,9 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
@@ -490,46 +415,38 @@ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
-github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
-github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
-github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
-github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
-github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
+github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
+github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c=
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY=
+github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=
+github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
+github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
+github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
+github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -539,9 +456,6 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -553,7 +467,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -573,6 +486,7 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
@@ -591,23 +505,19 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
+go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
+go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
+go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
+go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
+go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -617,35 +527,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -654,118 +540,63 @@ golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -779,9 +610,7 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -790,9 +619,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@@ -803,45 +629,12 @@ golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
@@ -851,86 +644,28 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
+gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -945,10 +680,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
@@ -957,14 +690,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=