From 97f0d599aeeb06e366522787ff7bdb6914e638d6 Mon Sep 17 00:00:00 2001 From: lightclient Date: Sat, 18 Nov 2023 14:09:19 +0300 Subject: [PATCH] cmd/blsync: support syncing geth with a beacon light client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: lightclient Co-authored-by: Zsolt Felföldi --- beacon/light/canonical.go | 125 ------- beacon/light/committee_chain.go | 514 --------------------------- beacon/light/committee_chain_test.go | 356 ------------------- beacon/light/range.go | 78 ---- beacon/light/test_helpers.go | 152 -------- beacon/types/committee.go | 10 +- beacon/types/config.go | 176 --------- beacon/types/light_sync.go | 136 ------- cmd/blsync/api.go | 140 ++++++++ cmd/blsync/beacon.go | 52 +++ cmd/blsync/chain.go | 156 ++++++++ cmd/blsync/chain_test.go | 428 ++++++++++++++++++++++ cmd/blsync/config.go | 76 ++++ cmd/blsync/errors.go | 28 ++ cmd/blsync/main.go | 184 ++++++++++ cmd/blsync/store.go | 183 ++++++++++ cmd/blsync/types.go | 306 ++++++++++++++++ go.mod | 31 +- go.sum | 407 ++++----------------- 19 files changed, 1647 insertions(+), 1891 deletions(-) delete mode 100644 beacon/light/canonical.go delete mode 100644 beacon/light/committee_chain.go delete mode 100644 beacon/light/committee_chain_test.go delete mode 100644 beacon/light/range.go delete mode 100644 beacon/light/test_helpers.go delete mode 100644 beacon/types/config.go delete mode 100644 beacon/types/light_sync.go create mode 100644 cmd/blsync/api.go create mode 100644 cmd/blsync/beacon.go create mode 100644 cmd/blsync/chain.go create mode 100644 cmd/blsync/chain_test.go create mode 100644 cmd/blsync/config.go create mode 100644 cmd/blsync/errors.go create mode 100644 cmd/blsync/main.go create mode 100644 cmd/blsync/store.go create mode 100644 cmd/blsync/types.go 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=