diff --git a/simulators/eth2/common/chain_generators/main.go b/simulators/eth2/common/chain_generators/main.go
new file mode 100644
index 0000000000..ce131287d6
--- /dev/null
+++ b/simulators/eth2/common/chain_generators/main.go
@@ -0,0 +1,10 @@
+package chaingenerators
+
+import (
+ "github.com/ethereum/go-ethereum/core/types"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+)
+
+type ChainGenerator interface {
+ Generate(*el.ExecutionGenesis) ([]*types.Block, error)
+}
diff --git a/simulators/eth2/engine/chain_generators.go b/simulators/eth2/common/chain_generators/pow/pow.go
similarity index 59%
rename from simulators/eth2/engine/chain_generators.go
rename to simulators/eth2/common/chain_generators/pow/pow.go
index 4288082a86..d167d4d28f 100644
--- a/simulators/eth2/engine/chain_generators.go
+++ b/simulators/eth2/common/chain_generators/pow/pow.go
@@ -1,28 +1,22 @@
-package main
+package pow
import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
-
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
+ execution_config "github.com/ethereum/hive/simulators/eth2/common/config/execution"
)
-type ChainGenerator interface {
- Generate(*setup.Eth1Genesis) ([]*types.Block, error)
-}
-
-var PoWChainGeneratorDefaults = ethash.Config{
+var Defaults = ethash.Config{
PowMode: ethash.ModeNormal,
CachesInMem: 2,
DatasetsOnDisk: 2,
DatasetDir: "/ethash",
}
-type PoWChainGenerator struct {
+type ChainGenerator struct {
BlockCount int
ethash.Config
GenFunction func(int, *core.BlockGen)
@@ -35,8 +29,24 @@ type instaSeal struct{ consensus.Engine }
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and uncle rewards,
// setting the final state and assembling the block.
-func (e instaSeal) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
- block, err := e.Engine.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
+func (e instaSeal) FinalizeAndAssemble(
+ chain consensus.ChainHeaderReader,
+ header *types.Header,
+ state *state.StateDB,
+ txs []*types.Transaction,
+ uncles []*types.Header,
+ receipts []*types.Receipt,
+ withdrawals []*types.Withdrawal,
+) (*types.Block, error) {
+ block, err := e.Engine.FinalizeAndAssemble(
+ chain,
+ header,
+ state,
+ txs,
+ uncles,
+ receipts,
+ withdrawals,
+ )
if err != nil {
return nil, err
}
@@ -47,26 +57,31 @@ func (e instaSeal) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header
return <-sealedBlock, nil
}
-func (p *PoWChainGenerator) Generate(genesis *setup.Eth1Genesis) ([]*types.Block, error) {
+func (p *ChainGenerator) Generate(
+ genesis *execution_config.ExecutionGenesis,
+) ([]*types.Block, error) {
// We generate a new chain only if the generator had not generated one already.
// This is done because the chain generators can be reused on different clients to ensure
// they start with the same chain.
if p.blocks != nil {
return p.blocks, nil
}
- db := rawdb.NewMemoryDatabase()
engine := ethash.New(p.Config, nil, false)
insta := instaSeal{engine}
- genesisBlock := genesis.Genesis.ToBlock()
- p.blocks, _ = core.GenerateChain(genesis.Genesis.Config, genesisBlock, insta, db, p.BlockCount, p.GenFunction)
+ _, p.blocks, _ = core.GenerateChainWithGenesis(
+ genesis.Genesis,
+ insta,
+ p.BlockCount,
+ p.GenFunction,
+ )
return p.blocks, nil
}
-func (p *PoWChainGenerator) Blocks() []*types.Block {
+func (p *ChainGenerator) Blocks() []*types.Block {
return p.blocks
}
-func (p *PoWChainGenerator) Head() *types.Block {
+func (p *ChainGenerator) Head() *types.Block {
if p.blocks == nil || len(p.blocks) == 0 {
return nil
}
diff --git a/simulators/eth2/common/clients/beacon.go b/simulators/eth2/common/clients/beacon.go
new file mode 100644
index 0000000000..f99e952729
--- /dev/null
+++ b/simulators/eth2/common/clients/beacon.go
@@ -0,0 +1,896 @@
+package clients
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ api "github.com/ethereum/go-ethereum/core/beacon"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/utils"
+ "github.com/holiman/uint256"
+ "github.com/protolambda/eth2api"
+ "github.com/protolambda/eth2api/client/beaconapi"
+ "github.com/protolambda/eth2api/client/debugapi"
+ "github.com/protolambda/eth2api/client/nodeapi"
+ "github.com/protolambda/zrnt/eth2/beacon/altair"
+ "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
+ "github.com/protolambda/zrnt/eth2/beacon/capella"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/zrnt/eth2/beacon/phase0"
+ "github.com/protolambda/ztyp/tree"
+)
+
+const (
+ PortBeaconTCP = 9000
+ PortBeaconUDP = 9000
+ PortBeaconAPI = 4000
+ PortBeaconGRPC = 4001
+ PortMetrics = 8080
+ PortValidatorAPI = 5000
+)
+
+type BeaconClient struct {
+ T *hivesim.T
+ HiveClient *hivesim.Client
+ ClientType string
+ OptionsGenerator func() ([]hivesim.StartOption, error)
+ API *eth2api.Eth2HttpClient
+ genesisTime common.Timestamp
+ spec *common.Spec
+ index int
+ genesisValidatorsRoot tree.Root
+}
+
+func NewBeaconClient(
+ t *hivesim.T,
+ beaconDef *hivesim.ClientDefinition,
+ optionsGenerator func() ([]hivesim.StartOption, error),
+ genesisTime common.Timestamp,
+ spec *common.Spec,
+ index int,
+ genesisValidatorsRoot tree.Root,
+) *BeaconClient {
+ return &BeaconClient{
+ T: t,
+ ClientType: beaconDef.Name,
+ OptionsGenerator: optionsGenerator,
+ genesisTime: genesisTime,
+ spec: spec,
+ index: index,
+ genesisValidatorsRoot: genesisValidatorsRoot,
+ }
+}
+
+func (bn *BeaconClient) Start(extraOptions ...hivesim.StartOption) error {
+ if bn.HiveClient != nil {
+ return fmt.Errorf("client already started")
+ }
+ bn.T.Logf("Starting client %s", bn.ClientType)
+ opts, err := bn.OptionsGenerator()
+ if err != nil {
+ return fmt.Errorf("unable to get start options: %v", err)
+ }
+ opts = append(opts, extraOptions...)
+
+ bn.HiveClient = bn.T.StartClient(bn.ClientType, opts...)
+ bn.API = ð2api.Eth2HttpClient{
+ Addr: fmt.Sprintf("http://%s:%d", bn.HiveClient.IP, PortBeaconAPI),
+ Cli: &http.Client{},
+ Codec: eth2api.JSONCodec{},
+ }
+ return nil
+}
+
+func (bn *BeaconClient) Shutdown() error {
+ if err := bn.T.Sim.StopClient(bn.T.SuiteID, bn.T.TestID, bn.HiveClient.Container); err != nil {
+ return err
+ }
+ bn.HiveClient = nil
+ return nil
+}
+
+func (bn *BeaconClient) IsRunning() bool {
+ return bn.HiveClient != nil
+}
+
+func (bn *BeaconClient) ENR(parentCtx context.Context) (string, error) {
+ ctx, cancel := context.WithTimeout(parentCtx, time.Second*10)
+ defer cancel()
+ var out eth2api.NetworkIdentity
+ if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
+ return "", err
+ }
+ fmt.Printf("p2p addrs: %v\n", out.P2PAddresses)
+ fmt.Printf("peer id: %s\n", out.PeerID)
+ return out.ENR, nil
+}
+
+func (bn *BeaconClient) P2PAddr(parentCtx context.Context) (string, error) {
+ ctx, cancel := context.WithTimeout(parentCtx, time.Second*10)
+ defer cancel()
+ var out eth2api.NetworkIdentity
+ if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
+ return "", err
+ }
+ return out.P2PAddresses[0], nil
+}
+
+func (bn *BeaconClient) EnodeURL() (string, error) {
+ return "", errors.New(
+ "beacon node does not have an discv4 Enode URL, use ENR or multi-address instead",
+ )
+}
+
+func (bn *BeaconClient) ClientName() string {
+ name := bn.ClientType
+ if len(name) > 3 && name[len(name)-3:] == "-bn" {
+ name = name[:len(name)-3]
+ }
+ return name
+}
+
+// Beacon API wrappers
+type VersionedSignedBeaconBlock struct {
+ *eth2api.VersionedSignedBeaconBlock
+}
+
+func (versionedBlock *VersionedSignedBeaconBlock) ContainsExecutionPayload() bool {
+ return versionedBlock.Version == "bellatrix" ||
+ versionedBlock.Version == "capella"
+}
+
+func (versionedBlock *VersionedSignedBeaconBlock) ExecutionPayload() (api.ExecutableData, error) {
+ result := api.ExecutableData{}
+ switch v := versionedBlock.Data.(type) {
+ case *bellatrix.SignedBeaconBlock:
+ execPayload := v.Message.Body.ExecutionPayload
+ copy(result.ParentHash[:], execPayload.ParentHash[:])
+ copy(result.FeeRecipient[:], execPayload.FeeRecipient[:])
+ copy(result.StateRoot[:], execPayload.StateRoot[:])
+ copy(result.ReceiptsRoot[:], execPayload.ReceiptsRoot[:])
+ copy(result.LogsBloom[:], execPayload.LogsBloom[:])
+ copy(result.Random[:], execPayload.PrevRandao[:])
+ result.Number = uint64(execPayload.BlockNumber)
+ result.GasLimit = uint64(execPayload.GasLimit)
+ result.GasUsed = uint64(execPayload.GasUsed)
+ result.Timestamp = uint64(execPayload.Timestamp)
+ copy(result.ExtraData[:], execPayload.ExtraData[:])
+ result.BaseFeePerGas = (*uint256.Int)(&execPayload.BaseFeePerGas).ToBig()
+ copy(result.BlockHash[:], execPayload.BlockHash[:])
+ result.Transactions = make([][]byte, 0)
+ for _, t := range execPayload.Transactions {
+ result.Transactions = append(result.Transactions, t)
+ }
+ case *capella.SignedBeaconBlock:
+ execPayload := v.Message.Body.ExecutionPayload
+ copy(result.ParentHash[:], execPayload.ParentHash[:])
+ copy(result.FeeRecipient[:], execPayload.FeeRecipient[:])
+ copy(result.StateRoot[:], execPayload.StateRoot[:])
+ copy(result.ReceiptsRoot[:], execPayload.ReceiptsRoot[:])
+ copy(result.LogsBloom[:], execPayload.LogsBloom[:])
+ copy(result.Random[:], execPayload.PrevRandao[:])
+ result.Number = uint64(execPayload.BlockNumber)
+ result.GasLimit = uint64(execPayload.GasLimit)
+ result.GasUsed = uint64(execPayload.GasUsed)
+ result.Timestamp = uint64(execPayload.Timestamp)
+ copy(result.ExtraData[:], execPayload.ExtraData[:])
+ result.BaseFeePerGas = (*uint256.Int)(&execPayload.BaseFeePerGas).ToBig()
+ copy(result.BlockHash[:], execPayload.BlockHash[:])
+ result.Transactions = make([][]byte, 0)
+ for _, t := range execPayload.Transactions {
+ result.Transactions = append(result.Transactions, t)
+ }
+ result.Withdrawals = make([]*types.Withdrawal, 0)
+ for _, w := range execPayload.Withdrawals {
+ withdrawal := new(types.Withdrawal)
+ withdrawal.Index = uint64(w.Index)
+ withdrawal.Validator = uint64(w.ValidatorIndex)
+ copy(withdrawal.Address[:], w.Address[:])
+ withdrawal.Amount = uint64(w.Amount)
+ result.Withdrawals = append(result.Withdrawals, withdrawal)
+ }
+ default:
+ return result, fmt.Errorf(
+ "beacon block version can't contain execution payload",
+ )
+ }
+ return result, nil
+}
+
+func (b *VersionedSignedBeaconBlock) StateRoot() tree.Root {
+ switch v := b.Data.(type) {
+ case *phase0.SignedBeaconBlock:
+ return v.Message.StateRoot
+ case *altair.SignedBeaconBlock:
+ return v.Message.StateRoot
+ case *bellatrix.SignedBeaconBlock:
+ return v.Message.StateRoot
+ case *capella.SignedBeaconBlock:
+ return v.Message.StateRoot
+ }
+ panic("badly formatted beacon block")
+}
+
+func (b *VersionedSignedBeaconBlock) Slot() common.Slot {
+ switch v := b.Data.(type) {
+ case *phase0.SignedBeaconBlock:
+ return v.Message.Slot
+ case *altair.SignedBeaconBlock:
+ return v.Message.Slot
+ case *bellatrix.SignedBeaconBlock:
+ return v.Message.Slot
+ case *capella.SignedBeaconBlock:
+ return v.Message.Slot
+ }
+ panic("badly formatted beacon block")
+}
+
+func (b *VersionedSignedBeaconBlock) ProposerIndex() common.ValidatorIndex {
+ switch v := b.Data.(type) {
+ case *phase0.SignedBeaconBlock:
+ return v.Message.ProposerIndex
+ case *altair.SignedBeaconBlock:
+ return v.Message.ProposerIndex
+ case *bellatrix.SignedBeaconBlock:
+ return v.Message.ProposerIndex
+ case *capella.SignedBeaconBlock:
+ return v.Message.ProposerIndex
+ }
+ panic("badly formatted beacon block")
+}
+
+func (bn *BeaconClient) BlockV2(
+ parentCtx context.Context,
+ blockId eth2api.BlockId,
+) (*VersionedSignedBeaconBlock, error) {
+ var (
+ versionedBlock = new(eth2api.VersionedSignedBeaconBlock)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.BlockV2(ctx, bn.API, blockId, versionedBlock)
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return &VersionedSignedBeaconBlock{
+ VersionedSignedBeaconBlock: versionedBlock,
+ }, err
+}
+
+type BlockV2OptimisticResponse struct {
+ Version string `json:"version"`
+ ExecutionOptimistic bool `json:"execution_optimistic"`
+}
+
+func (bn *BeaconClient) BlockIsOptimistic(
+ parentCtx context.Context,
+ blockId eth2api.BlockId,
+) (bool, error) {
+ var (
+ blockOptResp = new(BlockV2OptimisticResponse)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = eth2api.SimpleRequest(
+ ctx,
+ bn.API,
+ eth2api.FmtGET("/eth/v2/beacon/blocks/%s", blockId.BlockId()),
+ blockOptResp,
+ )
+ if !exists {
+ return false, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return blockOptResp.ExecutionOptimistic, err
+}
+
+func (bn *BeaconClient) BlockHeader(
+ parentCtx context.Context,
+ blockId eth2api.BlockId,
+) (*eth2api.BeaconBlockHeaderAndInfo, error) {
+ var (
+ headInfo = new(eth2api.BeaconBlockHeaderAndInfo)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.BlockHeader(ctx, bn.API, blockId, headInfo)
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return headInfo, err
+}
+
+func (bn *BeaconClient) StateValidator(
+ parentCtx context.Context,
+ stateId eth2api.StateId,
+ validatorId eth2api.ValidatorId,
+) (*eth2api.ValidatorResponse, error) {
+ var (
+ stateValidatorResponse = new(eth2api.ValidatorResponse)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.StateValidator(
+ ctx,
+ bn.API,
+ stateId,
+ validatorId,
+ stateValidatorResponse,
+ )
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return stateValidatorResponse, err
+}
+
+func (bn *BeaconClient) StateFinalityCheckpoints(
+ parentCtx context.Context,
+ stateId eth2api.StateId,
+) (*eth2api.FinalityCheckpoints, error) {
+ var (
+ finalityCheckpointsResponse = new(eth2api.FinalityCheckpoints)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.FinalityCheckpoints(
+ ctx,
+ bn.API,
+ stateId,
+ finalityCheckpointsResponse,
+ )
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return finalityCheckpointsResponse, err
+}
+
+func (bn *BeaconClient) BlockFinalityCheckpoints(
+ parentCtx context.Context,
+ blockId eth2api.BlockId,
+) (*eth2api.FinalityCheckpoints, error) {
+ var (
+ headInfo *eth2api.BeaconBlockHeaderAndInfo
+ finalityCheckpointsResponse *eth2api.FinalityCheckpoints
+ err error
+ )
+ headInfo, err = bn.BlockHeader(parentCtx, blockId)
+ if err != nil {
+ return nil, err
+ }
+ finalityCheckpointsResponse, err = bn.StateFinalityCheckpoints(
+ parentCtx,
+ eth2api.StateIdRoot(headInfo.Header.Message.StateRoot),
+ )
+ if err != nil {
+ // Try again using slot number
+ return bn.StateFinalityCheckpoints(
+ parentCtx,
+ eth2api.StateIdSlot(headInfo.Header.Message.Slot),
+ )
+ }
+ return finalityCheckpointsResponse, err
+}
+
+type VersionedBeaconStateResponse struct {
+ *eth2api.VersionedBeaconState
+}
+
+func (vbs *VersionedBeaconStateResponse) CurrentVersion() common.Version {
+ switch state := vbs.Data.(type) {
+ case *phase0.BeaconState:
+ return state.Fork.CurrentVersion
+ case *altair.BeaconState:
+ return state.Fork.CurrentVersion
+ case *bellatrix.BeaconState:
+ return state.Fork.CurrentVersion
+ case *capella.BeaconState:
+ return state.Fork.CurrentVersion
+ }
+ panic("badly formatted beacon state")
+}
+
+func (vbs *VersionedBeaconStateResponse) PreviousVersion() common.Version {
+ switch state := vbs.Data.(type) {
+ case *phase0.BeaconState:
+ return state.Fork.PreviousVersion
+ case *altair.BeaconState:
+ return state.Fork.PreviousVersion
+ case *bellatrix.BeaconState:
+ return state.Fork.PreviousVersion
+ case *capella.BeaconState:
+ return state.Fork.PreviousVersion
+ }
+ panic("badly formatted beacon state")
+}
+
+func (vbs *VersionedBeaconStateResponse) CurrentEpochParticipation() altair.ParticipationRegistry {
+ switch state := vbs.Data.(type) {
+ case *altair.BeaconState:
+ return state.CurrentEpochParticipation
+ case *bellatrix.BeaconState:
+ return state.CurrentEpochParticipation
+ case *capella.BeaconState:
+ return state.CurrentEpochParticipation
+ }
+ return nil
+}
+
+func (vbs *VersionedBeaconStateResponse) Balances() phase0.Balances {
+ switch state := vbs.Data.(type) {
+ case *phase0.BeaconState:
+ return state.Balances
+ case *altair.BeaconState:
+ return state.Balances
+ case *bellatrix.BeaconState:
+ return state.Balances
+ case *capella.BeaconState:
+ return state.Balances
+ }
+ panic("badly formatted beacon state")
+}
+
+func (vbs *VersionedBeaconStateResponse) Validators() phase0.ValidatorRegistry {
+ switch state := vbs.Data.(type) {
+ case *phase0.BeaconState:
+ return state.Validators
+ case *altair.BeaconState:
+ return state.Validators
+ case *bellatrix.BeaconState:
+ return state.Validators
+ case *capella.BeaconState:
+ return state.Validators
+ }
+ panic("badly formatted beacon state")
+}
+
+func (bn *BeaconClient) BeaconStateV2(
+ parentCtx context.Context,
+ stateId eth2api.StateId,
+) (*VersionedBeaconStateResponse, error) {
+ var (
+ versionedBeaconStateResponse = new(eth2api.VersionedBeaconState)
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = debugapi.BeaconStateV2(
+ ctx,
+ bn.API,
+ stateId,
+ versionedBeaconStateResponse,
+ )
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return &VersionedBeaconStateResponse{
+ VersionedBeaconState: versionedBeaconStateResponse,
+ }, err
+}
+
+func (bn *BeaconClient) BeaconStateV2ByBlock(
+ parentCtx context.Context,
+ blockId eth2api.BlockId,
+) (*VersionedBeaconStateResponse, error) {
+ var (
+ headInfo *eth2api.BeaconBlockHeaderAndInfo
+ err error
+ )
+ headInfo, err = bn.BlockHeader(parentCtx, blockId)
+ if err != nil {
+ return nil, err
+ }
+ return bn.BeaconStateV2(
+ parentCtx,
+ eth2api.StateIdRoot(headInfo.Header.Message.StateRoot),
+ )
+}
+
+func (bn *BeaconClient) StateValidators(
+ parentCtx context.Context,
+ stateId eth2api.StateId,
+ validatorIds []eth2api.ValidatorId,
+ statusFilter []eth2api.ValidatorStatus,
+) ([]eth2api.ValidatorResponse, error) {
+ var (
+ stateValidatorResponse = make(
+ []eth2api.ValidatorResponse,
+ 0,
+ )
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.StateValidators(
+ ctx,
+ bn.API,
+ stateId,
+ validatorIds,
+ statusFilter,
+ &stateValidatorResponse,
+ )
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return stateValidatorResponse, err
+}
+
+func (bn *BeaconClient) StateValidatorBalances(
+ parentCtx context.Context,
+ stateId eth2api.StateId,
+ validatorIds []eth2api.ValidatorId,
+) ([]eth2api.ValidatorBalanceResponse, error) {
+ var (
+ stateValidatorBalanceResponse = make(
+ []eth2api.ValidatorBalanceResponse,
+ 0,
+ )
+ exists bool
+ err error
+ )
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ exists, err = beaconapi.StateValidatorBalances(
+ ctx,
+ bn.API,
+ stateId,
+ validatorIds,
+ &stateValidatorBalanceResponse,
+ )
+ if !exists {
+ return nil, fmt.Errorf("endpoint not found on beacon client")
+ }
+ return stateValidatorBalanceResponse, err
+}
+
+func (bn *BeaconClient) ComputeDomain(
+ ctx context.Context,
+ typ common.BLSDomainType,
+ version *common.Version,
+) (common.BLSDomain, error) {
+ if version != nil {
+ return common.ComputeDomain(
+ typ,
+ *version,
+ bn.genesisValidatorsRoot,
+ ), nil
+ }
+ // We need to request for head state to know current active version
+ state, err := bn.BeaconStateV2ByBlock(ctx, eth2api.BlockHead)
+ if err != nil {
+ return common.BLSDomain{}, err
+ }
+ return common.ComputeDomain(
+ typ,
+ state.CurrentVersion(),
+ bn.genesisValidatorsRoot,
+ ), nil
+}
+
+func (bn *BeaconClient) SubmitPoolBLSToExecutionChange(
+ parentCtx context.Context,
+ l common.SignedBLSToExecutionChanges,
+) error {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return beaconapi.SubmitBLSToExecutionChanges(ctx, bn.API, l)
+}
+
+func (bn *BeaconClient) SubmitVoluntaryExit(
+ parentCtx context.Context,
+ exit *phase0.SignedVoluntaryExit,
+) error {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return beaconapi.SubmitVoluntaryExit(ctx, bn.API, exit)
+}
+
+func (b *BeaconClient) WaitForExecutionPayload(
+ ctx context.Context,
+) (ethcommon.Hash, error) {
+ fmt.Printf(
+ "Waiting for execution payload on beacon %d (%s)\n",
+ b.index,
+ b.ClientName(),
+ )
+ slotDuration := time.Duration(b.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+
+ for {
+ select {
+ case <-ctx.Done():
+ return ethcommon.Hash{}, ctx.Err()
+ case <-timer.C:
+ realTimeSlot := b.spec.TimeToSlot(
+ common.Timestamp(time.Now().Unix()),
+ b.genesisTime,
+ )
+ var (
+ headInfo *eth2api.BeaconBlockHeaderAndInfo
+ err error
+ execution ethcommon.Hash
+ )
+ if headInfo, err = b.BlockHeader(ctx, eth2api.BlockHead); err != nil {
+ return ethcommon.Hash{}, err
+ }
+ if !headInfo.Canonical {
+ continue
+ }
+
+ if versionedBlock, err := b.BlockV2(ctx, eth2api.BlockIdRoot(headInfo.Root)); err != nil {
+ continue
+ } else if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ copy(
+ execution[:],
+ executionPayload.BlockHash[:],
+ )
+ }
+ zero := ethcommon.Hash{}
+ fmt.Printf(
+ "WaitForExecutionPayload: beacon %d (%s): slot=%d, realTimeSlot=%d, head=%s, exec=%s\n",
+ b.index,
+ b.ClientName(),
+ headInfo.Header.Message.Slot,
+ realTimeSlot,
+ utils.Shorten(headInfo.Root.String()),
+ utils.Shorten(execution.Hex()),
+ )
+ if !bytes.Equal(execution[:], zero[:]) {
+ return execution, nil
+ }
+ }
+ }
+}
+
+func (b *BeaconClient) WaitForOptimisticState(
+ ctx context.Context,
+ blockID eth2api.BlockId,
+ optimistic bool,
+) (*eth2api.BeaconBlockHeaderAndInfo, error) {
+ fmt.Printf("Waiting for optimistic sync on beacon %d (%s)\n",
+ b.index,
+ b.ClientName(),
+ )
+ slotDuration := time.Duration(b.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case <-timer.C:
+ var headOptStatus BlockV2OptimisticResponse
+ if exists, err := eth2api.SimpleRequest(ctx, b.API, eth2api.FmtGET("/eth/v2/beacon/blocks/%s", blockID.BlockId()), &headOptStatus); err != nil {
+ // Block still not synced
+ continue
+ } else if !exists {
+ // Block still not synced
+ continue
+ }
+ if headOptStatus.ExecutionOptimistic != optimistic {
+ continue
+ }
+ // Return the block
+ var blockInfo eth2api.BeaconBlockHeaderAndInfo
+ if exists, err := beaconapi.BlockHeader(ctx, b.API, blockID, &blockInfo); err != nil {
+ return nil, fmt.Errorf(
+ "WaitForExecutionPayload: failed to poll block: %v",
+ err,
+ )
+ } else if !exists {
+ return nil, fmt.Errorf("WaitForExecutionPayload: failed to poll block: !exists")
+ }
+ return &blockInfo, nil
+ }
+ }
+}
+
+func (bn *BeaconClient) GetLatestExecutionBeaconBlock(
+ parentCtx context.Context,
+) (*VersionedSignedBeaconBlock, error) {
+ headInfo, err := bn.BlockHeader(parentCtx, eth2api.BlockHead)
+ if err != nil {
+ return nil, fmt.Errorf("failed to poll head: %v", err)
+ }
+ for slot := headInfo.Header.Message.Slot; slot > 0; slot-- {
+ versionedBlock, err := bn.BlockV2(parentCtx, eth2api.BlockIdSlot(slot))
+ if err != nil {
+ return nil, fmt.Errorf("failed to retrieve block: %v", err)
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ emptyRoot := tree.Root{}
+ if !bytes.Equal(executionPayload.BlockHash[:], emptyRoot[:]) {
+ return versionedBlock, nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+func (bn *BeaconClient) GetFirstExecutionBeaconBlock(
+ parentCtx context.Context,
+) (*VersionedSignedBeaconBlock, error) {
+ lastSlot := bn.spec.TimeToSlot(
+ common.Timestamp(time.Now().Unix()),
+ bn.genesisTime,
+ )
+ for slot := common.Slot(0); slot <= lastSlot; slot++ {
+ versionedBlock, err := bn.BlockV2(parentCtx, eth2api.BlockIdSlot(slot))
+ if err != nil {
+ continue
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ emptyRoot := tree.Root{}
+ if !bytes.Equal(executionPayload.BlockHash[:], emptyRoot[:]) {
+ return versionedBlock, nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+func (bn *BeaconClient) GetBeaconBlockByExecutionHash(
+ parentCtx context.Context,
+ hash ethcommon.Hash,
+) (*VersionedSignedBeaconBlock, error) {
+ headInfo, err := bn.BlockHeader(parentCtx, eth2api.BlockHead)
+ if err != nil {
+ return nil, fmt.Errorf("failed to poll head: %v", err)
+ }
+ for slot := int(headInfo.Header.Message.Slot); slot > 0; slot -= 1 {
+ versionedBlock, err := bn.BlockV2(parentCtx, eth2api.BlockIdSlot(slot))
+ if err != nil {
+ continue
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ if !bytes.Equal(executionPayload.BlockHash[:], hash[:]) {
+ return versionedBlock, nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+type BeaconClients []*BeaconClient
+
+// Return subset of clients that are currently running
+func (all BeaconClients) Running() BeaconClients {
+ res := make(BeaconClients, 0)
+ for _, bc := range all {
+ if bc.IsRunning() {
+ res = append(res, bc)
+ }
+ }
+ return res
+}
+
+// Returns comma-separated ENRs of all running beacon nodes
+func (beacons BeaconClients) ENRs(parentCtx context.Context) (string, error) {
+ if len(beacons) == 0 {
+ return "", nil
+ }
+ enrs := make([]string, 0)
+ for _, bn := range beacons {
+ if bn.IsRunning() {
+ enr, err := bn.ENR(parentCtx)
+ if err != nil {
+ return "", err
+ }
+ enrs = append(enrs, enr)
+ }
+ }
+ return strings.Join(enrs, ","), nil
+}
+
+// Returns comma-separated P2PAddr of all running beacon nodes
+func (beacons BeaconClients) P2PAddrs(
+ parentCtx context.Context,
+) (string, error) {
+ if len(beacons) == 0 {
+ return "", nil
+ }
+ staticPeers := make([]string, 0)
+ for _, bn := range beacons {
+ if bn.IsRunning() {
+ p2p, err := bn.P2PAddr(parentCtx)
+ if err != nil {
+ return "", err
+ }
+ staticPeers = append(staticPeers, p2p)
+ }
+ }
+ return strings.Join(staticPeers, ","), nil
+}
+
+func (b BeaconClients) GetBeaconBlockByExecutionHash(
+ parentCtx context.Context,
+ hash ethcommon.Hash,
+) (*VersionedSignedBeaconBlock, error) {
+ for _, bn := range b {
+ block, err := bn.GetBeaconBlockByExecutionHash(parentCtx, hash)
+ if err != nil || block != nil {
+ return block, err
+ }
+ }
+ return nil, nil
+}
+
+func (runningBeacons BeaconClients) PrintStatus(
+ ctx context.Context,
+ l utils.Logging,
+) {
+ for i, b := range runningBeacons {
+ var (
+ slot common.Slot
+ version string
+ head string
+ justified string
+ finalized string
+ execution = "0x0000..0000"
+ )
+
+ if headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead); err == nil {
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+ }
+ checkpoints, err := b.BlockFinalityCheckpoints(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err == nil {
+ justified = utils.Shorten(
+ checkpoints.CurrentJustified.String(),
+ )
+ finalized = utils.Shorten(checkpoints.Finalized.String())
+ }
+ if versionedBlock, err := b.BlockV2(ctx, eth2api.BlockHead); err == nil {
+ version = versionedBlock.Version
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = utils.Shorten(
+ executionPayload.BlockHash.String(),
+ )
+ }
+ }
+
+ l.Logf(
+ "beacon %d (%s): fork=%s, slot=%d, head=%s, exec_payload=%s, justified=%s, finalized=%s",
+ i,
+ b.ClientName(),
+ version,
+ slot,
+ head,
+ execution,
+ justified,
+ finalized,
+ )
+ }
+}
+
+func (all BeaconClients) SubmitPoolBLSToExecutionChange(
+ parentCtx context.Context,
+ l common.SignedBLSToExecutionChanges,
+) error {
+ for _, b := range all {
+ if err := b.SubmitPoolBLSToExecutionChange(parentCtx, l); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/simulators/eth2/common/clients/execution.go b/simulators/eth2/common/clients/execution.go
new file mode 100644
index 0000000000..6da6d23796
--- /dev/null
+++ b/simulators/eth2/common/clients/execution.go
@@ -0,0 +1,502 @@
+package clients
+
+import (
+ "context"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "net"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ api "github.com/ethereum/go-ethereum/core/beacon"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/spoofing/proxy"
+ "github.com/ethereum/hive/simulators/eth2/common/utils"
+ "github.com/golang-jwt/jwt/v4"
+)
+
+const (
+ PortUserRPC = 8545
+ PortEngineRPC = 8551
+)
+
+type ExecutionClient struct {
+ T *hivesim.T
+ HiveClient *hivesim.Client
+ ClientType string
+ OptionsGenerator func() ([]hivesim.StartOption, error)
+ proxy **proxy.Proxy
+ proxyPort int
+ subnet string
+ ttd *big.Int
+
+ engineRpcClient *rpc.Client
+ ethRpcClient *rpc.Client
+ eth *ethclient.Client
+}
+
+func NewExecutionClient(
+ t *hivesim.T,
+ eth1Def *hivesim.ClientDefinition,
+ optionsGenerator func() ([]hivesim.StartOption, error),
+ proxyPort int,
+ subnet string,
+ ttd *big.Int,
+) *ExecutionClient {
+ return &ExecutionClient{
+ T: t,
+ ClientType: eth1Def.Name,
+ OptionsGenerator: optionsGenerator,
+ proxyPort: proxyPort,
+ proxy: new(*proxy.Proxy),
+ subnet: subnet,
+ ttd: ttd,
+ }
+}
+
+func (en *ExecutionClient) UserRPCAddress() (string, error) {
+ return fmt.Sprintf("http://%v:%d", en.HiveClient.IP, PortUserRPC), nil
+}
+
+func (en *ExecutionClient) EngineRPCAddress() (string, error) {
+ // TODO what will the default port be?
+ return fmt.Sprintf("http://%v:%d", en.HiveClient.IP, PortEngineRPC), nil
+}
+
+func (en *ExecutionClient) MustGetEnode() string {
+ addr, err := en.HiveClient.EnodeURL()
+ if err != nil {
+ panic(err)
+ }
+ return addr
+}
+
+func (en *ExecutionClient) ConfiguredTTD() *big.Int {
+ return en.ttd
+}
+
+func (en *ExecutionClient) Start(extraOptions ...hivesim.StartOption) error {
+ if en.HiveClient != nil {
+ return fmt.Errorf("client already started")
+ }
+ en.T.Logf("Starting client %s", en.ClientType)
+ opts, err := en.OptionsGenerator()
+ if err != nil {
+ return fmt.Errorf("unable to get start options: %v", err)
+ }
+ opts = append(opts, extraOptions...)
+
+ en.HiveClient = en.T.StartClient(en.ClientType, opts...)
+
+ // Prepare Eth/Engine RPCs
+ engineRPCAddress, err := en.EngineRPCAddress()
+ if err != nil {
+ return err
+ }
+ client := &http.Client{}
+ // Prepare HTTP Client
+ en.engineRpcClient, err = rpc.DialHTTPWithClient(engineRPCAddress, client)
+ if err != nil {
+ return err
+ }
+
+ // Prepare ETH Client
+ client = &http.Client{}
+
+ userRPCAddress, err := en.UserRPCAddress()
+ if err != nil {
+ return err
+ }
+ en.ethRpcClient, err = rpc.DialHTTPWithClient(userRPCAddress, client)
+ if err != nil {
+ return err
+ }
+ en.eth = ethclient.NewClient(en.ethRpcClient)
+
+ // Prepare proxy
+ dest, err := en.EngineRPCAddress()
+ if err != nil {
+ return err
+ }
+
+ secret, err := hex.DecodeString(
+ "7365637265747365637265747365637265747365637265747365637265747365",
+ )
+ if err != nil {
+ panic(err)
+ }
+ simIP, err := en.T.Sim.ContainerNetworkIP(
+ en.T.SuiteID,
+ "bridge",
+ "simulation",
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ *en.proxy = proxy.NewProxy(
+ net.ParseIP(simIP),
+ en.proxyPort,
+ dest,
+ secret,
+ )
+ return nil
+}
+
+func (en *ExecutionClient) Shutdown() error {
+ if err := en.T.Sim.StopClient(en.T.SuiteID, en.T.TestID, en.HiveClient.Container); err != nil {
+ return err
+ }
+ en.HiveClient = nil
+ return nil
+}
+
+func (en *ExecutionClient) IsRunning() bool {
+ return en.HiveClient != nil
+}
+
+func (en *ExecutionClient) Proxy() *proxy.Proxy {
+ if en.proxy != nil && *en.proxy != nil {
+ return *en.proxy
+ }
+ return nil
+}
+
+// Engine API
+
+// JWT Tokens
+func GetNewToken(jwtSecretBytes []byte, iat time.Time) (string, error) {
+ newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
+ "iat": iat.Unix(),
+ })
+ tokenString, err := newToken.SignedString(jwtSecretBytes)
+ if err != nil {
+ return "", err
+ }
+ return tokenString, nil
+}
+
+func (en *ExecutionClient) PrepareAuthCallToken(
+ jwtSecretBytes []byte,
+ iat time.Time,
+) error {
+ newTokenString, err := GetNewToken(jwtSecretBytes, iat)
+ if err != nil {
+ return err
+ }
+ en.engineRpcClient.SetHeader(
+ "Authorization",
+ fmt.Sprintf("Bearer %s", newTokenString),
+ )
+ return nil
+}
+
+func (en *ExecutionClient) PrepareDefaultAuthCallToken() error {
+ secret, _ := hex.DecodeString(
+ "7365637265747365637265747365637265747365637265747365637265747365",
+ )
+ en.PrepareAuthCallToken(secret, time.Now())
+ return nil
+}
+
+func (en *ExecutionClient) EngineForkchoiceUpdated(
+ parentCtx context.Context,
+ fcState *api.ForkchoiceStateV1,
+ pAttributes *api.PayloadAttributes,
+ version int,
+) (*api.ForkChoiceResponse, error) {
+ var result api.ForkChoiceResponse
+ if err := en.PrepareDefaultAuthCallToken(); err != nil {
+ return nil, err
+ }
+ request := fmt.Sprintf("engine_forkchoiceUpdatedV%d", version)
+ ctx, cancel := context.WithTimeout(parentCtx, time.Second*10)
+ defer cancel()
+ err := en.engineRpcClient.CallContext(
+ ctx,
+ &result,
+ request,
+ fcState,
+ pAttributes,
+ )
+ return &result, err
+}
+
+func (en *ExecutionClient) EngineGetPayload(
+ parentCtx context.Context,
+ payloadID *api.PayloadID,
+ version int,
+) (*api.ExecutableData, error) {
+ var result api.ExecutableData
+ if err := en.PrepareDefaultAuthCallToken(); err != nil {
+ return nil, err
+ }
+ request := fmt.Sprintf("engine_getPayload%d", version)
+ ctx, cancel := context.WithTimeout(parentCtx, time.Second*10)
+ defer cancel()
+ err := en.engineRpcClient.CallContext(ctx, &result, request, payloadID)
+ return &result, err
+}
+
+func (en *ExecutionClient) EngineNewPayload(
+ parentCtx context.Context,
+ payload *api.ExecutableData,
+ version int,
+) (*api.PayloadStatusV1, error) {
+ var result api.PayloadStatusV1
+ if err := en.PrepareDefaultAuthCallToken(); err != nil {
+ return nil, err
+ }
+ request := fmt.Sprintf("engine_newPayload%d", version)
+ ctx, cancel := context.WithTimeout(parentCtx, time.Second*10)
+ defer cancel()
+ err := en.engineRpcClient.CallContext(ctx, &result, request, payload)
+ return &result, err
+}
+
+// Eth RPC
+// Helper structs to fetch the TotalDifficulty
+type TD struct {
+ TotalDifficulty *hexutil.Big `json:"totalDifficulty"`
+}
+type TotalDifficultyHeader struct {
+ types.Header
+ TD
+}
+
+func (tdh *TotalDifficultyHeader) UnmarshalJSON(data []byte) error {
+ if err := json.Unmarshal(data, &tdh.Header); err != nil {
+ return err
+ }
+ if err := json.Unmarshal(data, &tdh.TD); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (en *ExecutionClient) TotalDifficultyByNumber(
+ parentCtx context.Context,
+ blockNumber *big.Int,
+) (*big.Int, error) {
+ var td *TotalDifficultyHeader
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ var blockId string
+ if blockNumber == nil {
+ blockId = "latest"
+ } else {
+ blockId = fmt.Sprintf("%d", blockNumber)
+ }
+ if err := en.ethRpcClient.CallContext(ctx, &td, "eth_getBlockByNumber", blockId, false); err == nil {
+ return td.TotalDifficulty.ToInt(), nil
+ } else {
+ return nil, err
+ }
+}
+
+func (en *ExecutionClient) TotalDifficultyByHash(
+ parentCtx context.Context,
+ blockHash common.Hash,
+) (*big.Int, error) {
+ var td *TotalDifficultyHeader
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ if err := en.ethRpcClient.CallContext(ctx, &td, "eth_getBlockByHash", fmt.Sprintf("%s", blockHash), false); err == nil {
+ return td.TotalDifficulty.ToInt(), nil
+ } else {
+ return nil, err
+ }
+}
+
+func (ec *ExecutionClient) CheckTTD(parentCtx context.Context) (bool, error) {
+ td, err := ec.TotalDifficultyByNumber(parentCtx, nil)
+ if err != nil {
+ return false, err
+ }
+ if td.Cmp(ec.ttd) >= 0 {
+ return true, nil
+ }
+ return false, nil
+}
+
+func (ec *ExecutionClient) WaitForTerminalTotalDifficulty(
+ parentCtx context.Context,
+) error {
+ for {
+ select {
+ case <-time.After(time.Second):
+ reached, err := ec.CheckTTD(parentCtx)
+ if err != nil {
+ return err
+ }
+ if reached {
+ return nil
+ }
+ case <-parentCtx.Done():
+ return parentCtx.Err()
+ }
+ }
+}
+
+func (ec *ExecutionClient) HeaderByHash(
+ parentCtx context.Context,
+ h common.Hash,
+) (*types.Header, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return ec.eth.HeaderByHash(ctx, h)
+}
+
+func (ec *ExecutionClient) HeaderByNumber(
+ parentCtx context.Context,
+ n *big.Int,
+) (*types.Header, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return ec.eth.HeaderByNumber(ctx, n)
+}
+
+func (ec *ExecutionClient) HeaderByLabel(
+ parentCtx context.Context,
+ l string,
+) (*types.Header, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ h := new(types.Header)
+ err := ec.ethRpcClient.CallContext(
+ ctx,
+ h,
+ "eth_getBlockByNumber",
+ l,
+ false,
+ )
+ return h, err
+}
+
+func (ec *ExecutionClient) BlockByHash(
+ parentCtx context.Context,
+ h common.Hash,
+) (*types.Block, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return ec.eth.BlockByHash(ctx, h)
+}
+
+func (ec *ExecutionClient) BlockByNumber(
+ parentCtx context.Context,
+ n *big.Int,
+) (*types.Block, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return ec.eth.BlockByNumber(ctx, n)
+}
+
+func (ec *ExecutionClient) BalanceAt(
+ parentCtx context.Context,
+ account common.Address,
+ n *big.Int,
+) (*big.Int, error) {
+ ctx, cancel := utils.ContextTimeoutRPC(parentCtx)
+ defer cancel()
+ return ec.eth.BalanceAt(ctx, account, n)
+}
+
+type ExecutionClients []*ExecutionClient
+
+// Return subset of clients that are currently running
+func (all ExecutionClients) Running() ExecutionClients {
+ res := make(ExecutionClients, 0)
+ for _, ec := range all {
+ if ec.IsRunning() {
+ res = append(res, ec)
+ }
+ }
+ return res
+}
+
+// Return subset of clients that are part of an specific subnet
+func (all ExecutionClients) Subnet(subnet string) ExecutionClients {
+ if subnet == "" {
+ return all
+ }
+ res := make(ExecutionClients, 0)
+ for _, ec := range all {
+ if ec.subnet == subnet {
+ res = append(res, ec)
+ }
+ }
+ return res
+}
+
+// Returns comma-separated Bootnodes of all running execution nodes
+func (all ExecutionClients) Enodes() (string, error) {
+ if len(all) == 0 {
+ return "", nil
+ }
+ enodes := make([]string, 0)
+ for _, en := range all {
+ if en.IsRunning() {
+ enode, err := en.HiveClient.EnodeURL()
+ if err != nil {
+ return "", err
+ }
+ enodes = append(enodes, enode)
+ }
+ }
+ return strings.Join(enodes, ","), nil
+}
+
+// Returns true if all head hashes match
+func (all ExecutionClients) CheckHeads(
+ l utils.Logging,
+ parentCtx context.Context,
+) (bool, error) {
+ if len(all) <= 1 {
+ return false, fmt.Errorf(
+ "attempted to check the heads of a single or zero clients matched",
+ )
+ }
+
+ header, err := all[0].HeaderByNumber(parentCtx, nil)
+ if err != nil || header == nil {
+ return false, err
+ }
+ baseHash := header.Hash()
+
+ for _, en := range all[1:] {
+ header, err = en.HeaderByNumber(parentCtx, nil)
+ if err != nil || header == nil {
+ return false, err
+ }
+ h := header.Hash()
+ if h != baseHash {
+ if l != nil {
+ l.Logf("Hash mismatch between heads: %s != %s\n", h, baseHash)
+ }
+ return false, nil
+ } else if l != nil {
+ l.Logf("Hash match between heads: %s == %s\n", h, baseHash)
+ }
+ }
+ return true, nil
+}
+
+type Proxies []**proxy.Proxy
+
+func (all Proxies) Running() []*proxy.Proxy {
+ res := make([]*proxy.Proxy, 0)
+ for _, p := range all {
+ if p != nil && *p != nil {
+ res = append(res, *p)
+ }
+ }
+ return res
+}
diff --git a/simulators/eth2/common/clients/node.go b/simulators/eth2/common/clients/node.go
new file mode 100644
index 0000000000..e9c6a54850
--- /dev/null
+++ b/simulators/eth2/common/clients/node.go
@@ -0,0 +1,406 @@
+package clients
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "golang.org/x/exp/slices"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/hive/hivesim"
+ cg "github.com/ethereum/hive/simulators/eth2/common/chain_generators"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/zrnt/eth2/beacon/phase0"
+)
+
+// Describe a node setup, which consists of:
+// - Execution Client
+// - Beacon Client
+// - Validator Client
+type NodeDefinition struct {
+ ExecutionClient string
+ ConsensusClient string
+ ValidatorClient string
+ ValidatorShares uint64
+ ExecutionClientTTD *big.Int
+ BeaconNodeTTD *big.Int
+ TestVerificationNode bool
+ DisableStartup bool
+ ChainGenerator cg.ChainGenerator
+ Chain []*types.Block
+ ExecutionSubnet string
+}
+
+func (n *NodeDefinition) String() string {
+ return fmt.Sprintf("%s-%s", n.ConsensusClient, n.ExecutionClient)
+}
+
+func (n *NodeDefinition) ExecutionClientName() string {
+ return n.ExecutionClient
+}
+
+func (n *NodeDefinition) ConsensusClientName() string {
+ return fmt.Sprintf("%s-bn", n.ConsensusClient)
+}
+
+func (n *NodeDefinition) ValidatorClientName() string {
+ if n.ValidatorClient == "" {
+ return fmt.Sprintf("%s-vc", n.ConsensusClient)
+ }
+ return fmt.Sprintf("%s-vc", n.ValidatorClient)
+}
+
+type NodeDefinitions []NodeDefinition
+
+func (nodes NodeDefinitions) ClientTypes() []string {
+ types := make([]string, 0)
+ for _, n := range nodes {
+ if !slices.Contains(types, n.ExecutionClient) {
+ types = append(types, n.ExecutionClient)
+ }
+ if !slices.Contains(types, n.ConsensusClient) {
+ types = append(types, n.ConsensusClient)
+ }
+ }
+ return types
+}
+
+func (nodes NodeDefinitions) Shares() []uint64 {
+ shares := make([]uint64, len(nodes))
+ for i, n := range nodes {
+ shares[i] = n.ValidatorShares
+ }
+ return shares
+}
+
+func (all NodeDefinitions) FilterByCL(filter []string) NodeDefinitions {
+ ret := make(NodeDefinitions, 0)
+ for _, n := range all {
+ if slices.Contains(filter, n.ConsensusClient) {
+ ret = append(ret, n)
+ }
+ }
+ return ret
+}
+
+func (all NodeDefinitions) FilterByEL(filter []string) NodeDefinitions {
+ ret := make(NodeDefinitions, 0)
+ for _, n := range all {
+ if slices.Contains(filter, n.ExecutionClient) {
+ ret = append(ret, n)
+ }
+ }
+ return ret
+}
+
+// A node bundles together:
+// - Running Execution client
+// - Running Beacon client
+// - Running Validator client
+// Contains a flag that marks a node that can be used to query
+// test verification information.
+type Node struct {
+ T *hivesim.T
+ Index int
+ ExecutionClient *ExecutionClient
+ BeaconClient *BeaconClient
+ ValidatorClient *ValidatorClient
+ Verification bool
+}
+
+// Starts all clients included in the bundle
+func (n *Node) Start(extraOptions ...hivesim.StartOption) error {
+ n.T.Logf("Starting validator client bundle %d", n.Index)
+ if n.ExecutionClient != nil {
+ if err := n.ExecutionClient.Start(extraOptions...); err != nil {
+ return err
+ }
+ } else {
+ n.T.Logf("No execution client started")
+ }
+ if n.BeaconClient != nil {
+ if err := n.BeaconClient.Start(extraOptions...); err != nil {
+ return err
+ }
+ } else {
+ n.T.Logf("No beacon client started")
+ }
+ if n.ValidatorClient != nil {
+ if err := n.ValidatorClient.Start(extraOptions...); err != nil {
+ return err
+ }
+ } else {
+ n.T.Logf("No validator client started")
+ }
+ return nil
+}
+
+func (n *Node) Shutdown() error {
+ if err := n.ExecutionClient.Shutdown(); err != nil {
+ return err
+ }
+ if err := n.BeaconClient.Shutdown(); err != nil {
+ return err
+ }
+ if err := n.ValidatorClient.Shutdown(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (n *Node) ClientNames() string {
+ var name string
+ if n.ExecutionClient != nil {
+ name = n.ExecutionClient.ClientType
+ }
+ if n.BeaconClient != nil {
+ name = fmt.Sprintf("%s/%s", name, n.BeaconClient.ClientName())
+ }
+ return name
+}
+
+func (n *Node) IsRunning() bool {
+ return n.ExecutionClient.IsRunning() && n.BeaconClient.IsRunning()
+}
+
+// Validator operations
+func (n *Node) SignBLSToExecutionChange(
+ ctx context.Context,
+ blsToExecutionChangeInfo BLSToExecutionChangeInfo,
+) (*common.SignedBLSToExecutionChange, error) {
+ vc, bn := n.ValidatorClient, n.BeaconClient
+ if !vc.ContainsValidatorIndex(blsToExecutionChangeInfo.ValidatorIndex) {
+ return nil, fmt.Errorf(
+ "validator does not contain specified validator index %d",
+ blsToExecutionChangeInfo.ValidatorIndex,
+ )
+ }
+ if domain, err := bn.ComputeDomain(
+ ctx,
+ common.DOMAIN_BLS_TO_EXECUTION_CHANGE,
+ &bn.spec.GENESIS_FORK_VERSION,
+ ); err != nil {
+ return nil, err
+ } else {
+ return vc.SignBLSToExecutionChange(domain, blsToExecutionChangeInfo)
+ }
+}
+
+func (n *Node) SignSubmitBLSToExecutionChanges(
+ ctx context.Context,
+ blsToExecutionChangesInfo []BLSToExecutionChangeInfo,
+) error {
+ l := make(common.SignedBLSToExecutionChanges, 0)
+ for _, c := range blsToExecutionChangesInfo {
+ blsToExecChange, err := n.SignBLSToExecutionChange(
+ ctx,
+ c,
+ )
+ if err != nil {
+ return err
+ }
+ l = append(l, *blsToExecChange)
+ }
+
+ return n.BeaconClient.SubmitPoolBLSToExecutionChange(ctx, l)
+}
+
+func (n *Node) SignVoluntaryExit(
+ ctx context.Context,
+ epoch common.Epoch,
+ validatorIndex common.ValidatorIndex,
+) (*phase0.SignedVoluntaryExit, error) {
+ vc, bn := n.ValidatorClient, n.BeaconClient
+ if !vc.ContainsValidatorIndex(validatorIndex) {
+ return nil, fmt.Errorf(
+ "validator does not contain specified validator index %d",
+ validatorIndex,
+ )
+ }
+ if domain, err := bn.ComputeDomain(
+ ctx,
+ common.DOMAIN_VOLUNTARY_EXIT,
+ nil,
+ ); err != nil {
+ return nil, err
+ } else {
+ return vc.SignVoluntaryExit(domain, epoch, validatorIndex)
+ }
+}
+
+func (n *Node) SignSubmitVoluntaryExit(
+ ctx context.Context,
+ epoch common.Epoch,
+ validatorIndex common.ValidatorIndex,
+) error {
+ exit, err := n.SignVoluntaryExit(ctx, epoch, validatorIndex)
+ if err != nil {
+ return err
+ }
+ return n.BeaconClient.SubmitVoluntaryExit(ctx, exit)
+}
+
+// Node cluster operations
+type Nodes []*Node
+
+// Return all execution clients, even the ones not currently running
+func (all Nodes) ExecutionClients() ExecutionClients {
+ en := make(ExecutionClients, 0)
+ for _, n := range all {
+ if n.ExecutionClient != nil {
+ en = append(en, n.ExecutionClient)
+ }
+ }
+ return en
+}
+
+// Return all proxy pointers, even the ones not currently running
+func (all Nodes) Proxies() Proxies {
+ ps := make(Proxies, 0)
+ for _, n := range all {
+ if n.ExecutionClient != nil {
+ ps = append(ps, n.ExecutionClient.proxy)
+ }
+ }
+ return ps
+}
+
+// Return all beacon clients, even the ones not currently running
+func (all Nodes) BeaconClients() BeaconClients {
+ bn := make(BeaconClients, 0)
+ for _, n := range all {
+ if n.BeaconClient != nil {
+ bn = append(bn, n.BeaconClient)
+ }
+ }
+ return bn
+}
+
+// Return all validator clients, even the ones not currently running
+func (all Nodes) ValidatorClients() ValidatorClients {
+ vc := make(ValidatorClients, 0)
+ for _, n := range all {
+ if n.ValidatorClient != nil {
+ vc = append(vc, n.ValidatorClient)
+ }
+ }
+ return vc
+}
+
+// Return subset of nodes which are marked as verification nodes
+func (all Nodes) VerificationNodes() Nodes {
+ // If none is set as verification, then all are verification nodes
+ var any bool
+ for _, n := range all {
+ if n.Verification {
+ any = true
+ break
+ }
+ }
+ if !any {
+ return all
+ }
+
+ res := make(Nodes, 0)
+ for _, n := range all {
+ if n.Verification {
+ res = append(res, n)
+ }
+ }
+ return res
+}
+
+// Return subset of nodes that are currently running
+func (all Nodes) Running() Nodes {
+ res := make(Nodes, 0)
+ for _, n := range all {
+ if n.IsRunning() {
+ res = append(res, n)
+ }
+ }
+ return res
+}
+
+func (all Nodes) FilterByCL(filter []string) Nodes {
+ ret := make(Nodes, 0)
+ for _, n := range all {
+ if slices.Contains(filter, n.BeaconClient.ClientName()) {
+ ret = append(ret, n)
+ }
+ }
+ return ret
+}
+
+func (all Nodes) FilterByEL(filter []string) Nodes {
+ ret := make(Nodes, 0)
+ for _, n := range all {
+ if slices.Contains(filter, n.ExecutionClient.ClientType) {
+ ret = append(ret, n)
+ }
+ }
+ return ret
+}
+
+func (all Nodes) RemoveNodeAsVerifier(id int) error {
+ if id >= len(all) {
+ return fmt.Errorf("node %d does not exist", id)
+ }
+ var any bool
+ for _, n := range all {
+ if n.Verification {
+ any = true
+ break
+ }
+ }
+ if any {
+ all[id].Verification = false
+ } else {
+ // If no node is set as verifier, we will set all other nodes as verifiers then
+ for i := range all {
+ all[i].Verification = (i != id)
+ }
+ }
+ return nil
+}
+
+func (all Nodes) ByValidatorIndex(validatorIndex common.ValidatorIndex) *Node {
+ for _, n := range all {
+ if n.ValidatorClient.ContainsValidatorIndex(validatorIndex) {
+ return n
+ }
+ }
+ return nil
+}
+
+func (all Nodes) SignSubmitBLSToExecutionChanges(
+ ctx context.Context,
+ blsToExecutionChanges []BLSToExecutionChangeInfo,
+) error {
+ // First gather all signed changes
+ l := make(common.SignedBLSToExecutionChanges, 0)
+ for _, c := range blsToExecutionChanges {
+ n := all.ByValidatorIndex(c.ValidatorIndex)
+ if n == nil {
+ return fmt.Errorf(
+ "validator index %d not found",
+ c.ValidatorIndex,
+ )
+ }
+ blsToExecChange, err := n.SignBLSToExecutionChange(
+ ctx,
+ c,
+ )
+ if err != nil {
+ return err
+ }
+ l = append(l, *blsToExecChange)
+ }
+ // Then send the signed changes
+ for _, n := range all {
+ if err := n.BeaconClient.SubmitPoolBLSToExecutionChange(ctx, l); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/simulators/eth2/testnet/roles.go b/simulators/eth2/common/clients/roles.go
similarity index 64%
rename from simulators/eth2/testnet/roles.go
rename to simulators/eth2/common/clients/roles.go
index 0aac41645f..fa557a7154 100644
--- a/simulators/eth2/testnet/roles.go
+++ b/simulators/eth2/common/clients/roles.go
@@ -1,4 +1,4 @@
-package main
+package clients
import "github.com/ethereum/hive/hivesim"
@@ -9,7 +9,9 @@ type ClientDefinitionsByRole struct {
Other []*hivesim.ClientDefinition `json:"Other"`
}
-func ClientsByRole(available []*hivesim.ClientDefinition) *ClientDefinitionsByRole {
+func ClientsByRole(
+ available []*hivesim.ClientDefinition,
+) *ClientDefinitionsByRole {
var out ClientDefinitionsByRole
for _, client := range available {
if client.HasRole("beacon") {
@@ -25,7 +27,9 @@ func ClientsByRole(available []*hivesim.ClientDefinition) *ClientDefinitionsByRo
return &out
}
-func (c *ClientDefinitionsByRole) ClientByNameAndRole(name, role string) *hivesim.ClientDefinition {
+func (c *ClientDefinitionsByRole) ClientByNameAndRole(
+ name, role string,
+) *hivesim.ClientDefinition {
switch role {
case "beacon":
return byName(c.Beacon, name)
@@ -37,7 +41,10 @@ func (c *ClientDefinitionsByRole) ClientByNameAndRole(name, role string) *hivesi
return nil
}
-func byName(clients []*hivesim.ClientDefinition, name string) *hivesim.ClientDefinition {
+func byName(
+ clients []*hivesim.ClientDefinition,
+ name string,
+) *hivesim.ClientDefinition {
for _, client := range clients {
if client.Name == name {
return client
@@ -46,11 +53,17 @@ func byName(clients []*hivesim.ClientDefinition, name string) *hivesim.ClientDef
return nil
}
-func (c *ClientDefinitionsByRole) Combinations() []node {
- var nodes []node
+func (c *ClientDefinitionsByRole) Combinations() NodeDefinitions {
+ var nodes NodeDefinitions
for _, beacon := range c.Beacon {
for _, eth1 := range c.Eth1 {
- nodes = append(nodes, node{eth1.Name, beacon.Name[:len(beacon.Name)-3]})
+ nodes = append(
+ nodes,
+ NodeDefinition{
+ ExecutionClient: eth1.Name,
+ ConsensusClient: beacon.Name[:len(beacon.Name)-3],
+ },
+ )
}
}
return nodes
diff --git a/simulators/eth2/common/clients/validator.go b/simulators/eth2/common/clients/validator.go
new file mode 100644
index 0000000000..2d29edc050
--- /dev/null
+++ b/simulators/eth2/common/clients/validator.go
@@ -0,0 +1,195 @@
+package clients
+
+import (
+ "fmt"
+
+ "github.com/ethereum/hive/hivesim"
+ consensus_config "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ blsu "github.com/protolambda/bls12-381-util"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/zrnt/eth2/beacon/phase0"
+ "github.com/protolambda/ztyp/tree"
+)
+
+type ValidatorClient struct {
+ T *hivesim.T
+ HiveClient *hivesim.Client
+ ClientType string
+ OptionsGenerator func(map[common.ValidatorIndex]*consensus_config.KeyDetails) ([]hivesim.StartOption, error)
+ Keys map[common.ValidatorIndex]*consensus_config.KeyDetails
+}
+
+func NewValidatorClient(
+ t *hivesim.T,
+ validatorDef *hivesim.ClientDefinition,
+ optionsGenerator func(map[common.ValidatorIndex]*consensus_config.KeyDetails) ([]hivesim.StartOption, error),
+ keys map[common.ValidatorIndex]*consensus_config.KeyDetails,
+) *ValidatorClient {
+ return &ValidatorClient{
+ T: t,
+ ClientType: validatorDef.Name,
+ OptionsGenerator: optionsGenerator,
+ Keys: keys,
+ }
+}
+
+func (vc *ValidatorClient) Start(extraOptions ...hivesim.StartOption) error {
+ if vc.HiveClient != nil {
+ return fmt.Errorf("client already started")
+ }
+ if len(vc.Keys) == 0 {
+ vc.T.Logf("Skipping validator because it has 0 validator keys")
+ return nil
+ }
+ vc.T.Logf("Starting client %s", vc.ClientType)
+ opts, err := vc.OptionsGenerator(vc.Keys)
+ if err != nil {
+ return fmt.Errorf("unable to get start options: %v", err)
+ }
+ opts = append(opts, extraOptions...)
+
+ vc.HiveClient = vc.T.StartClient(vc.ClientType, opts...)
+ return nil
+}
+
+func (vc *ValidatorClient) Shutdown() error {
+ if err := vc.T.Sim.StopClient(vc.T.SuiteID, vc.T.TestID, vc.HiveClient.Container); err != nil {
+ return err
+ }
+ vc.HiveClient = nil
+ return nil
+}
+
+func (vc *ValidatorClient) IsRunning() bool {
+ return vc.HiveClient != nil
+}
+
+func (v *ValidatorClient) ContainsKey(pk [48]byte) bool {
+ for _, k := range v.Keys {
+ if k.ValidatorPubkey == pk {
+ return true
+ }
+ }
+ return false
+}
+
+func (v *ValidatorClient) ContainsValidatorIndex(
+ index common.ValidatorIndex,
+) bool {
+ _, ok := v.Keys[index]
+ return ok
+}
+
+type BLSToExecutionChangeInfo struct {
+ common.ValidatorIndex
+ common.Eth1Address
+}
+
+func (v *ValidatorClient) SignBLSToExecutionChange(
+ domain common.BLSDomain,
+ c BLSToExecutionChangeInfo,
+) (*common.SignedBLSToExecutionChange, error) {
+ kd, ok := v.Keys[c.ValidatorIndex]
+ if !ok {
+ return nil, fmt.Errorf(
+ "validator client does not contain validator index %d",
+ c.ValidatorIndex,
+ )
+ }
+ if len(c.Eth1Address) != 20 {
+ return nil, fmt.Errorf("invalid length for execution address")
+ }
+ kdPubKey := common.BLSPubkey{}
+ copy(kdPubKey[:], kd.WithdrawalPubkey[:])
+ blsToExecChange := common.BLSToExecutionChange{
+ ValidatorIndex: c.ValidatorIndex,
+ FromBLSPubKey: kdPubKey,
+ ToExecutionAddress: c.Eth1Address,
+ }
+ sigRoot := common.ComputeSigningRoot(
+ blsToExecChange.HashTreeRoot(tree.GetHashFn()),
+ domain,
+ )
+
+ sk := new(blsu.SecretKey)
+ sk.Deserialize(&kd.WithdrawalSecretKey)
+ signature := blsu.Sign(sk, sigRoot[:]).Serialize()
+ return &common.SignedBLSToExecutionChange{
+ BLSToExecutionChange: blsToExecChange,
+ Signature: common.BLSSignature(signature),
+ }, nil
+}
+
+func (v *ValidatorClient) SignVoluntaryExit(
+ domain common.BLSDomain,
+ epoch common.Epoch,
+ validatorIndex common.ValidatorIndex,
+) (*phase0.SignedVoluntaryExit, error) {
+ kd, ok := v.Keys[validatorIndex]
+ if !ok {
+ return nil, fmt.Errorf(
+ "validator client does not contain validator index %d",
+ validatorIndex,
+ )
+ }
+ kdPubKey := common.BLSPubkey{}
+ copy(kdPubKey[:], kd.ValidatorPubkey[:])
+ voluntaryExit := phase0.VoluntaryExit{
+ Epoch: epoch,
+ ValidatorIndex: validatorIndex,
+ }
+ sigRoot := common.ComputeSigningRoot(
+ voluntaryExit.HashTreeRoot(tree.GetHashFn()),
+ domain,
+ )
+
+ sk := new(blsu.SecretKey)
+ sk.Deserialize(&kd.ValidatorSecretKey)
+ signature := blsu.Sign(sk, sigRoot[:]).Serialize()
+ return &phase0.SignedVoluntaryExit{
+ Message: voluntaryExit,
+ Signature: common.BLSSignature(signature),
+ }, nil
+}
+
+type ValidatorClients []*ValidatorClient
+
+// Return subset of clients that are currently running
+func (all ValidatorClients) Running() ValidatorClients {
+ res := make(ValidatorClients, 0)
+ for _, vc := range all {
+ if vc.IsRunning() {
+ res = append(res, vc)
+ }
+ }
+ return res
+}
+
+// Returns the validator that contains specified validator index
+func (all ValidatorClients) ByValidatorIndex(
+ validatorIndex common.ValidatorIndex,
+) *ValidatorClient {
+ for _, v := range all {
+ if v.ContainsValidatorIndex(validatorIndex) {
+ return v
+ }
+ }
+ return nil
+}
+
+func (all ValidatorClients) SignBLSToExecutionChange(
+ domain common.BLSDomain,
+ c BLSToExecutionChangeInfo,
+) (*common.SignedBLSToExecutionChange, error) {
+ if v := all.ByValidatorIndex(c.ValidatorIndex); v == nil {
+ return nil, fmt.Errorf(
+ "validator index %d not found",
+ c.ValidatorIndex,
+ )
+ } else {
+ return v.SignBLSToExecutionChange(
+ domain,
+ c,
+ )
+ }
+}
diff --git a/simulators/eth2/common/config/config.go b/simulators/eth2/common/config/config.go
new file mode 100644
index 0000000000..8e24dc2321
--- /dev/null
+++ b/simulators/eth2/common/config/config.go
@@ -0,0 +1,13 @@
+package config
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+)
+
+func BytesSource(data []byte) func() (io.ReadCloser, error) {
+ return func() (io.ReadCloser, error) {
+ return ioutil.NopCloser(bytes.NewReader(data)), nil
+ }
+}
diff --git a/simulators/eth2/common/config/consensus/consensus_config.go b/simulators/eth2/common/config/consensus/consensus_config.go
new file mode 100644
index 0000000000..46b14d3297
--- /dev/null
+++ b/simulators/eth2/common/config/consensus/consensus_config.go
@@ -0,0 +1,77 @@
+package consensus_config
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/config"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/ztyp/codec"
+ "gopkg.in/yaml.v2"
+)
+
+func StateBundle(state common.BeaconState) (hivesim.StartOption, error) {
+ var stateBytes bytes.Buffer
+ if err := state.Serialize(codec.NewEncodingWriter(&stateBytes)); err != nil {
+ return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
+ }
+ return hivesim.WithDynamicFile(
+ "/hive/input/genesis.ssz",
+ config.BytesSource(stateBytes.Bytes()),
+ ), nil
+}
+
+func ConsensusConfigsBundle(
+ spec *common.Spec,
+ genesis *core.Genesis,
+ valCount uint64,
+) (hivesim.StartOption, error) {
+ specConfig, err := yaml.Marshal(spec.Config)
+ if err != nil {
+ return nil, err
+ }
+ phase0Preset, err := yaml.Marshal(spec.Phase0Preset)
+ if err != nil {
+ return nil, err
+ }
+ altairPreset, err := yaml.Marshal(spec.AltairPreset)
+ if err != nil {
+ return nil, err
+ }
+ bellatrixPreset, err := yaml.Marshal(spec.BellatrixPreset)
+ if err != nil {
+ return nil, err
+ }
+ capellaPreset, err := yaml.Marshal(spec.CapellaPreset)
+ if err != nil {
+ return nil, err
+ }
+ genesisHash := genesis.ToBlock().Hash()
+ return hivesim.Bundle(
+ hivesim.WithDynamicFile(
+ "/hive/input/config.yaml",
+ config.BytesSource(specConfig),
+ ),
+ hivesim.WithDynamicFile(
+ "/hive/input/preset_phase0.yaml",
+ config.BytesSource(phase0Preset),
+ ),
+ hivesim.WithDynamicFile(
+ "/hive/input/preset_altair.yaml",
+ config.BytesSource(altairPreset),
+ ),
+ hivesim.WithDynamicFile(
+ "/hive/input/preset_bellatrix.yaml",
+ config.BytesSource(bellatrixPreset),
+ ),
+ hivesim.WithDynamicFile(
+ "/hive/input/preset_capella.yaml",
+ config.BytesSource(capellaPreset),
+ ),
+ hivesim.Params{
+ "HIVE_ETH2_ETH1_GENESIS_HASH": genesisHash.String(),
+ },
+ ), nil
+}
diff --git a/simulators/eth2/testnet/setup/genesis.go b/simulators/eth2/common/config/consensus/genesis.go
similarity index 67%
rename from simulators/eth2/testnet/setup/genesis.go
rename to simulators/eth2/common/config/consensus/genesis.go
index fd3d16538c..1cb752bd12 100644
--- a/simulators/eth2/testnet/setup/genesis.go
+++ b/simulators/eth2/common/config/consensus/genesis.go
@@ -1,7 +1,6 @@
-package setup
+package consensus_config
import (
- "crypto/sha256"
"fmt"
"github.com/ethereum/go-ethereum/core"
@@ -9,6 +8,7 @@ import (
"github.com/holiman/uint256"
"github.com/protolambda/zrnt/eth2/beacon/altair"
"github.com/protolambda/zrnt/eth2/beacon/bellatrix"
+ "github.com/protolambda/zrnt/eth2/beacon/capella"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/zrnt/eth2/beacon/phase0"
"github.com/protolambda/zrnt/eth2/configs"
@@ -16,13 +16,22 @@ import (
"github.com/protolambda/ztyp/view"
)
-func genesisPayloadHeader(eth1GenesisBlock *types.Block, spec *common.Spec) (*common.ExecutionPayloadHeader, error) {
+func genesisPayloadHeader(
+ eth1GenesisBlock *types.Block,
+ spec *common.Spec,
+) (*bellatrix.ExecutionPayloadHeader, error) {
extra := eth1GenesisBlock.Extra()
if len(extra) > common.MAX_EXTRA_DATA_BYTES {
- return nil, fmt.Errorf("extra data is %d bytes, max is %d", len(extra), common.MAX_EXTRA_DATA_BYTES)
+ return nil, fmt.Errorf(
+ "extra data is %d bytes, max is %d",
+ len(extra),
+ common.MAX_EXTRA_DATA_BYTES,
+ )
}
if len(eth1GenesisBlock.Transactions()) != 0 {
- return nil, fmt.Errorf("expected no transactions in genesis execution payload")
+ return nil, fmt.Errorf(
+ "expected no transactions in genesis execution payload",
+ )
}
baseFee, overflow := uint256.FromBig(eth1GenesisBlock.BaseFee())
@@ -30,7 +39,7 @@ func genesisPayloadHeader(eth1GenesisBlock *types.Block, spec *common.Spec) (*co
return nil, fmt.Errorf("basefee larger than 2^256-1")
}
- return &common.ExecutionPayloadHeader{
+ return &bellatrix.ExecutionPayloadHeader{
ParentHash: common.Root(eth1GenesisBlock.ParentHash()),
FeeRecipient: common.Eth1Address(eth1GenesisBlock.Coinbase()),
StateRoot: common.Bytes32(eth1GenesisBlock.Root()),
@@ -45,26 +54,22 @@ func genesisPayloadHeader(eth1GenesisBlock *types.Block, spec *common.Spec) (*co
BaseFeePerGas: view.Uint256View(*baseFee),
BlockHash: common.Root(eth1GenesisBlock.Hash()),
// empty transactions root
- TransactionsRoot: common.PayloadTransactionsType(spec).DefaultNode().MerkleRoot(tree.GetHashFn()),
+ TransactionsRoot: common.PayloadTransactionsType(spec).
+ DefaultNode().
+ MerkleRoot(tree.GetHashFn()),
}, nil
}
-func createValidators(spec *common.Spec, keys []*KeyDetails) []phase0.KickstartValidatorData {
+func createValidators(
+ spec *common.Spec,
+ keys []*KeyDetails,
+) []phase0.KickstartValidatorData {
validators := make([]phase0.KickstartValidatorData, 0, len(keys))
- hasher := sha256.New()
- withdrawalCred := func(k common.BLSPubkey) (out common.Root) {
- hasher.Reset()
- hasher.Write(k[:])
- dat := hasher.Sum(nil)
- copy(out[:], dat)
- out[0] = common.BLS_WITHDRAWAL_PREFIX
- return
- }
for _, key := range keys {
validators = append(validators, phase0.KickstartValidatorData{
Pubkey: key.ValidatorPubkey,
- WithdrawalCredentials: withdrawalCred(key.WithdrawalPubkey),
- Balance: spec.MAX_EFFECTIVE_BALANCE,
+ WithdrawalCredentials: key.WithdrawalCredentials(),
+ Balance: spec.MAX_EFFECTIVE_BALANCE + key.ExtraInitialBalance,
})
}
return validators
@@ -74,10 +79,18 @@ func createValidators(spec *common.Spec, keys []*KeyDetails) []phase0.KickstartV
// The deposit contract will be recognized as an empty tree, ready for new deposits, thus skipping any transactions for pre-mined validators.
//
// TODO: instead of providing a eth1 genesis, provide an eth1 chain, so we can simulate a merge genesis state that embeds an existing eth1 chain.
-func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisTime common.Timestamp, keys []*KeyDetails) (common.BeaconState, error) {
+func BuildBeaconState(
+ spec *common.Spec,
+ eth1Genesis *core.Genesis,
+ eth2GenesisTime common.Timestamp,
+ keys []*KeyDetails,
+) (common.BeaconState, error) {
if uint64(len(keys)) < uint64(spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) {
- return nil, fmt.Errorf("WARNING: not enough validator keys for genesis. Got %d, but need at least %d.\n",
- len(keys), spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT)
+ return nil, fmt.Errorf(
+ "not enough validator keys for genesis. Got %d, but need at least %d",
+ len(keys),
+ spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT,
+ )
}
eth1GenesisBlock := eth1Genesis.ToBlock()
@@ -90,18 +103,33 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
var state common.BeaconState
var forkVersion common.Version
var emptyBodyRoot common.Root
- if spec.BELLATRIX_FORK_EPOCH == 0 {
- state = bellatrix.NewBeaconStateView(spec)
+ if spec.CAPELLA_FORK_EPOCH == 0 {
+ stateView := capella.NewBeaconStateView(spec)
+ forkVersion = spec.CAPELLA_FORK_VERSION
+ emptyBodyRoot = capella.BeaconBlockBodyType(configs.Mainnet).
+ New().
+ HashTreeRoot(hFn)
+ // TODO: Check if we need to add execution payload to the state
+ state = stateView
+ } else if spec.BELLATRIX_FORK_EPOCH == 0 {
+ stateView := bellatrix.NewBeaconStateView(spec)
forkVersion = spec.BELLATRIX_FORK_VERSION
- emptyBodyRoot = bellatrix.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
+ emptyBodyRoot = bellatrix.BeaconBlockBodyType(configs.Mainnet).
+ New().
+ HashTreeRoot(hFn)
+ state = stateView
} else if spec.ALTAIR_FORK_EPOCH == 0 {
state = bellatrix.NewBeaconStateView(spec)
forkVersion = spec.ALTAIR_FORK_VERSION
- emptyBodyRoot = altair.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
+ emptyBodyRoot = altair.BeaconBlockBodyType(configs.Mainnet).
+ New().
+ HashTreeRoot(hFn)
} else {
state = phase0.NewBeaconStateView(spec)
forkVersion = spec.GENESIS_FORK_VERSION
- emptyBodyRoot = phase0.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
+ emptyBodyRoot = phase0.BeaconBlockBodyType(configs.Mainnet).
+ New().
+ HashTreeRoot(hFn)
}
if err := state.SetGenesisTime(eth2GenesisTime); err != nil {
@@ -117,7 +145,8 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
}
// Empty deposit-tree
eth1Dat := common.Eth1Data{
- DepositRoot: phase0.NewDepositRootsView().HashTreeRoot(tree.GetHashFn()),
+ DepositRoot: phase0.NewDepositRootsView().
+ HashTreeRoot(tree.GetHashFn()),
DepositCount: 0,
BlockHash: eth1BlockHash,
}
@@ -147,7 +176,7 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
if err != nil {
return nil, err
}
- // Process activations
+ // Process activations and exits
for i := 0; i < len(validators); i++ {
val, err := vals.Validator(common.ValidatorIndex(i))
if err != nil {
@@ -165,7 +194,32 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
return nil, err
}
}
+ // Process exits/slashings
+ slashings, err := state.Slashings()
+ if err != nil {
+ return nil, err
+ }
+ if keys[i].Exited || keys[i].Slashed {
+ exit_epoch := common.GENESIS_EPOCH
+ val.SetExitEpoch(exit_epoch)
+ val.SetWithdrawableEpoch(
+ exit_epoch + spec.MIN_VALIDATOR_WITHDRAWABILITY_DELAY,
+ )
+ if keys[i].Slashed {
+ val.MakeSlashed()
+
+ bal, err := val.EffectiveBalance()
+ if err != nil {
+ return nil, err
+ }
+
+ if err := slashings.AddSlashing(exit_epoch, bal); err != nil {
+ return nil, err
+ }
+ }
+ }
}
+
if err := state.SetGenesisValidatorsRoot(vals.HashTreeRoot(tree.GetHashFn())); err != nil {
return nil, err
}
@@ -175,9 +229,17 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
return nil, err
}
active := common.ActiveIndices(indicesBounded, common.GENESIS_EPOCH)
- indices, err := common.ComputeSyncCommitteeIndices(spec, state, common.GENESIS_EPOCH, active)
+ indices, err := common.ComputeSyncCommitteeIndices(
+ spec,
+ state,
+ common.GENESIS_EPOCH,
+ active,
+ )
if err != nil {
- return nil, fmt.Errorf("failed to compute sync committee indices: %v", err)
+ return nil, fmt.Errorf(
+ "failed to compute sync committee indices: %v",
+ err,
+ )
}
pubs, err := common.NewPubkeyCache(vals)
if err != nil {
@@ -205,13 +267,19 @@ func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisT
tdd := uint256.Int(spec.TERMINAL_TOTAL_DIFFICULTY)
embedExecAtGenesis := tdd.ToBig().Cmp(eth1Genesis.Difficulty) < 0
- var execPayloadHeader *common.ExecutionPayloadHeader
+ var execPayloadHeader *bellatrix.ExecutionPayloadHeader
if embedExecAtGenesis {
- execPayloadHeader, err = genesisPayloadHeader(eth1GenesisBlock, spec)
+ execPayloadHeader, err = genesisPayloadHeader(
+ eth1GenesisBlock,
+ spec,
+ )
+ if err != nil {
+ return nil, err
+ }
} else {
// we didn't build any on the eth1 chain though,
// so we just put the genesis hash here (it could be any block from eth1 chain before TTD that is not ahead of eth2)
- execPayloadHeader = new(common.ExecutionPayloadHeader)
+ execPayloadHeader = new(bellatrix.ExecutionPayloadHeader)
}
if err := st.SetLatestExecutionPayloadHeader(execPayloadHeader); err != nil {
diff --git a/simulators/eth2/engine/setup/validator_keys.go b/simulators/eth2/common/config/consensus/validator_keys.go
similarity index 62%
rename from simulators/eth2/engine/setup/validator_keys.go
rename to simulators/eth2/common/config/consensus/validator_keys.go
index b39365f5c4..1d2842cc22 100644
--- a/simulators/eth2/engine/setup/validator_keys.go
+++ b/simulators/eth2/common/config/consensus/validator_keys.go
@@ -1,7 +1,8 @@
-package setup
+package consensus_config
import (
"crypto/rand"
+ "crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
@@ -9,10 +10,13 @@ import (
blsu "github.com/protolambda/bls12-381-util"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/config"
"github.com/google/uuid"
hbls "github.com/herumi/bls-eth-go-binary/bls"
"github.com/pkg/errors"
"github.com/protolambda/go-keystorev4"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/tyler-smith/go-bip39"
util "github.com/wealdtech/go-eth2-util"
)
@@ -37,10 +41,34 @@ type KeyDetails struct {
ValidatorSecretKey [32]byte
// ValidatorSecretKey is the serialized pubkey derived from ValidatorSecretKey
ValidatorPubkey [48]byte
+ // Withdrawal credential type: can be 0, BLS, or 1, execution
+ WithdrawalCredentialType int
// WithdrawalSecretKey is the serialized secret key for withdrawing stake
WithdrawalSecretKey [32]byte
// WithdrawalPubkey is the serialized pubkey derived from WithdrawalSecretKey
WithdrawalPubkey [48]byte
+ // Withdrawal Execution Address
+ WithdrawalExecAddress [20]byte
+ // Extra initial balance
+ ExtraInitialBalance common.Gwei
+ // Validator starts in exit state
+ Exited bool
+ // Validator starts in slashed state
+ Slashed bool
+}
+
+func (kd *KeyDetails) WithdrawalCredentials() (out common.Root) {
+ if kd.WithdrawalCredentialType == common.BLS_WITHDRAWAL_PREFIX {
+ hasher := sha256.New()
+ hasher.Write(kd.WithdrawalPubkey[:])
+ dat := hasher.Sum(nil)
+ copy(out[:], dat)
+ out[0] = common.BLS_WITHDRAWAL_PREFIX
+ } else if kd.WithdrawalCredentialType == common.ETH1_ADDRESS_WITHDRAWAL_PREFIX {
+ copy(out[12:], kd.WithdrawalExecAddress[:])
+ out[0] = common.ETH1_ADDRESS_WITHDRAWAL_PREFIX
+ }
+ return
}
// MnemonicsKeySource creates a range of BLS validator and withdrawal keys.
@@ -55,6 +83,8 @@ type MnemonicsKeySource struct {
Validator string `yaml:"validator"`
// Withdrawal mnemonic
Withdrawal string `yaml:"withdrawal"`
+ // Withdrawal type
+ WithdrawalCredentialType int
// cache loaded validator details
cache []*KeyDetails `yaml:"-"`
@@ -68,7 +98,12 @@ func mnemonicToSeed(mnemonic string) (seed []byte, err error) {
return bip39.NewSeed(mnemonic, ""), nil
}
-func weakKeystore(secret []byte, pub []byte, passphrase []byte, path string) (*keystorev4.Keystore, error) {
+func weakKeystore(
+ secret []byte,
+ pub []byte,
+ passphrase []byte,
+ path string,
+) (*keystorev4.Keystore, error) {
var salt [32]byte
if _, err := rand.Read(salt[:]); err != nil {
return nil, err
@@ -83,7 +118,13 @@ func weakKeystore(secret []byte, pub []byte, passphrase []byte, path string) (*k
if err != nil {
return nil, fmt.Errorf("failed to create AES128CTR params: %w", err)
}
- crypto, err := keystorev4.Encrypt(secret, passphrase, kdfParams, keystorev4.Sha256ChecksumParams, cipherParams)
+ crypto, err := keystorev4.Encrypt(
+ secret,
+ passphrase,
+ kdfParams,
+ keystorev4.Sha256ChecksumParams,
+ cipherParams,
+ )
if err != nil {
return nil, fmt.Errorf("failed to encrypt secret: %w", err)
}
@@ -103,7 +144,12 @@ func weakKeystore(secret []byte, pub []byte, passphrase []byte, path string) (*k
// Same crypto, but not secure, for testing only!
// Just generate weak keystores, so encryption and decryption doesn't take as long during testing.
-func marshalWeakKeystoreJSON(priv []byte, pub []byte, normedPass []byte, path string) ([]byte, error) {
+func marshalWeakKeystoreJSON(
+ priv []byte,
+ pub []byte,
+ normedPass []byte,
+ path string,
+) ([]byte, error) {
store, err := weakKeystore(priv, pub, normedPass, path)
if err != nil {
return nil, fmt.Errorf("failed to encrypt keystore: %v", err)
@@ -124,44 +170,82 @@ func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) {
return nil, fmt.Errorf("bad validator seed: %w", err)
}
if k.From > k.To {
- return nil, fmt.Errorf("invalid key range: from %d > to %d", k.From, k.To)
+ return nil, fmt.Errorf(
+ "invalid key range: from %d > to %d",
+ k.From,
+ k.To,
+ )
}
out := make([]*KeyDetails, 0, k.To-k.From)
for i := k.From; i < k.To; i++ {
valpath := fmt.Sprintf("m/12381/3600/%d/0/0", i)
valPrivateKey, err := util.PrivateKeyFromSeedAndPath(valSeed, valpath)
if err != nil {
- return nil, errors.Wrapf(err, "failed to create validator private key for path %q", valpath)
+ return nil, errors.Wrapf(
+ err,
+ "failed to create validator private key for path %q",
+ valpath,
+ )
}
path := fmt.Sprintf("m/12381/3600/%d/0", i)
- withdrPrivateKey, err := util.PrivateKeyFromSeedAndPath(withdrSeed, path)
+ withdrPrivateKey, err := util.PrivateKeyFromSeedAndPath(
+ withdrSeed,
+ path,
+ )
if err != nil {
- return nil, errors.Wrapf(err, "failed to create withdrawal private key for path %q", path)
+ return nil, errors.Wrapf(
+ err,
+ "failed to create withdrawal private key for path %q",
+ path,
+ )
}
var passRandomness [32]byte
_, err = rand.Read(passRandomness[:])
if err != nil {
- return nil, fmt.Errorf("failed to generate keystore password: %w", err)
+ return nil, fmt.Errorf(
+ "failed to generate keystore password: %w",
+ err,
+ )
}
priv := valPrivateKey.Marshal()
if len(priv) != 32 {
- return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs.
+ return nil, fmt.Errorf(
+ "expected priv key of 32 bytes, got: %x",
+ priv,
+ ) // testing, we can log privs.
}
pub := valPrivateKey.PublicKey().Marshal()
if len(pub) != 48 {
- return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs.
+ return nil, fmt.Errorf(
+ "expected pub key of 48 bytes, got: %x",
+ pub,
+ ) // testing, we can log privs.
}
wPriv := withdrPrivateKey.Marshal()
if len(priv) != 32 {
- return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs.
+ return nil, fmt.Errorf(
+ "expected priv key of 32 bytes, got: %x",
+ priv,
+ ) // testing, we can log privs.
}
wPub := withdrPrivateKey.PublicKey().Marshal()
if len(pub) != 48 {
- return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs.
+ return nil, fmt.Errorf(
+ "expected pub key of 48 bytes, got: %x",
+ pub,
+ ) // testing, we can log privs.
}
// We don't have fancy password norming, just use a base64 pass instead.
passphrase := base64.URLEncoding.EncodeToString(passRandomness[:])
- jsonData, err := marshalWeakKeystoreJSON(priv, pub, []byte(passphrase), valpath)
+ jsonData, err := marshalWeakKeystoreJSON(
+ priv,
+ pub,
+ []byte(passphrase),
+ valpath,
+ )
+ if err != nil {
+ return nil, err
+ }
k := &KeyDetails{
ValidatorKeystoreJSON: jsonData,
ValidatorKeystorePass: passphrase,
@@ -211,16 +295,47 @@ func (shares Shares) ValidatorSplits(validatorTotalCount uint64) []uint64 {
return validators
}
-func KeyTranches(keys []*KeyDetails, shares Shares) [][]*KeyDetails {
- tranches := make([][]*KeyDetails, 0, len(shares))
+func KeyTranches(
+ keys []*KeyDetails,
+ shares Shares,
+) []map[common.ValidatorIndex]*KeyDetails {
+ tranches := make([]map[common.ValidatorIndex]*KeyDetails, 0, len(shares))
i := uint64(0)
for _, c := range shares.ValidatorSplits(uint64(len(keys))) {
- if c > 0 {
- tranches = append(tranches, keys[i:i+c])
- } else {
- tranches = append(tranches, make([]*KeyDetails, 0))
+ tranche := make(map[common.ValidatorIndex]*KeyDetails)
+ for j := i; j < (i + c); j++ {
+ tranche[common.ValidatorIndex(j)] = keys[j]
}
+ tranches = append(tranches, tranche)
i += c
}
return tranches
}
+
+func KeysBundle(
+ keys map[common.ValidatorIndex]*KeyDetails,
+) hivesim.StartOption {
+ opts := make([]hivesim.StartOption, 0, len(keys)*2)
+ for _, k := range keys {
+ p := fmt.Sprintf(
+ "/hive/input/keystores/0x%x/keystore.json",
+ k.ValidatorPubkey[:],
+ )
+ opts = append(
+ opts,
+ hivesim.WithDynamicFile(
+ p,
+ config.BytesSource(k.ValidatorKeystoreJSON),
+ ),
+ )
+ p = fmt.Sprintf("/hive/input/secrets/0x%x", k.ValidatorPubkey[:])
+ opts = append(
+ opts,
+ hivesim.WithDynamicFile(
+ p,
+ config.BytesSource([]byte(k.ValidatorKeystorePass)),
+ ),
+ )
+ }
+ return hivesim.Bundle(opts...)
+}
diff --git a/simulators/eth2/engine/setup/eth1config.go b/simulators/eth2/common/config/execution/execution_config.go
similarity index 87%
rename from simulators/eth2/engine/setup/eth1config.go
rename to simulators/eth2/common/config/execution/execution_config.go
index df4bf294c7..17479f3bc1 100644
--- a/simulators/eth2/engine/setup/eth1config.go
+++ b/simulators/eth2/common/config/execution/execution_config.go
@@ -1,14 +1,17 @@
-package setup
+package execution_config
import (
+ "bytes"
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/config"
)
// The runtime deposit contract code, along with the storage that would otherwise have been initialized
@@ -61,24 +64,24 @@ var (
DEFAULT_ETHASH_MINER_ADDRESS = "1212121212121212121212121212121212121212"
)
-type Eth1Consensus interface {
- Configure(*Eth1Genesis) error
+type ExecutionConsensus interface {
+ Configure(*ExecutionGenesis) error
HiveParams(int) hivesim.Params
DifficultyPerBlock() *big.Int
SecondsPerBlock() uint64
}
-type Eth1EthashConsensus struct {
+type ExecutionEthashConsensus struct {
MinerAddress string
MiningNodes int
}
-func (c Eth1EthashConsensus) Configure(*Eth1Genesis) error {
+func (c ExecutionEthashConsensus) Configure(*ExecutionGenesis) error {
// Nothing to do here...
return nil
}
-func (c Eth1EthashConsensus) HiveParams(node int) hivesim.Params {
+func (c ExecutionEthashConsensus) HiveParams(node int) hivesim.Params {
if c.MinerAddress == "" {
c.MinerAddress = DEFAULT_ETHASH_MINER_ADDRESS
}
@@ -92,56 +95,61 @@ func (c Eth1EthashConsensus) HiveParams(node int) hivesim.Params {
return hivesim.Params{}
}
-func (c Eth1EthashConsensus) DifficultyPerBlock() *big.Int {
+func (c ExecutionEthashConsensus) DifficultyPerBlock() *big.Int {
// Approximately 0x20000
return big.NewInt(131072)
}
-func (c Eth1EthashConsensus) SecondsPerBlock() uint64 {
+func (c ExecutionEthashConsensus) SecondsPerBlock() uint64 {
// It is really hard to approxmate this value
return 10
}
// A pre-existing chain is imported by the client, and it is not
// expected that the client mines or produces any blocks.
-type Eth1PreChain struct{}
+type ExecutionPreChain struct{}
-func (c Eth1PreChain) Configure(*Eth1Genesis) error {
+func (c ExecutionPreChain) Configure(*ExecutionGenesis) error {
return nil
}
-func (c Eth1PreChain) HiveParams(node int) hivesim.Params {
+func (c ExecutionPreChain) HiveParams(node int) hivesim.Params {
return hivesim.Params{}
}
-func (c Eth1PreChain) DifficultyPerBlock() *big.Int {
+func (c ExecutionPreChain) DifficultyPerBlock() *big.Int {
// Approximately 0x20000
return big.NewInt(131072)
}
-func (c Eth1PreChain) SecondsPerBlock() uint64 {
+func (c ExecutionPreChain) SecondsPerBlock() uint64 {
return 1
}
-type Eth1CliqueConsensus struct {
+type ExecutionCliqueConsensus struct {
CliquePeriod uint64
PrivateKey string
MinerAddress string
}
-func (c Eth1CliqueConsensus) Configure(genesis *Eth1Genesis) error {
+func (c ExecutionCliqueConsensus) Configure(genesis *ExecutionGenesis) error {
if c.CliquePeriod == 0 {
c.CliquePeriod = CLIQUE_PERIOD_DEFAULT
}
if c.MinerAddress == "" {
c.MinerAddress = DEFAULT_CLIQUE_MINER_ADDRESS
}
- genesis.Genesis.Config.Clique = ¶ms.CliqueConfig{Period: c.CliquePeriod, Epoch: 0}
- genesis.Genesis.ExtraData = common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000000" + c.MinerAddress + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
+ genesis.Genesis.Config.Clique = ¶ms.CliqueConfig{
+ Period: c.CliquePeriod,
+ Epoch: 0,
+ }
+ genesis.Genesis.ExtraData = common.FromHex(
+ "0x0000000000000000000000000000000000000000000000000000000000000000" + c.MinerAddress + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ )
return nil
}
-func (c Eth1CliqueConsensus) HiveParams(node int) hivesim.Params {
+func (c ExecutionCliqueConsensus) HiveParams(node int) hivesim.Params {
if node > 0 {
return hivesim.Params{}
}
@@ -157,30 +165,37 @@ func (c Eth1CliqueConsensus) HiveParams(node int) hivesim.Params {
}
}
-func (c Eth1CliqueConsensus) DifficultyPerBlock() *big.Int {
+func (c ExecutionCliqueConsensus) DifficultyPerBlock() *big.Int {
return big.NewInt(2)
}
-func (c Eth1CliqueConsensus) SecondsPerBlock() uint64 {
+func (c ExecutionCliqueConsensus) SecondsPerBlock() uint64 {
if c.CliquePeriod == 0 {
return CLIQUE_PERIOD_DEFAULT
}
return c.CliquePeriod
}
-type Eth1Genesis struct {
+type ExecutionGenesis struct {
Genesis *core.Genesis
DepositAddress common.Address
NetworkID uint64
}
-func BuildEth1Genesis(ttd *big.Int, genesisTime uint64, consensus Eth1Consensus) *Eth1Genesis {
- depositContractAddr := common.HexToAddress("0x4242424242424242424242424242424242424242")
+func BuildExecutionGenesis(
+ ttd *big.Int,
+ genesisTime uint64,
+ consensus ExecutionConsensus,
+ forkConfig *params.ChainConfig,
+) *ExecutionGenesis {
+ depositContractAddr := common.HexToAddress(
+ "0x4242424242424242424242424242424242424242",
+ )
var depositContractAcc core.GenesisAccount
if err := json.Unmarshal([]byte(embeddedDepositContract), &depositContractAcc); err != nil {
panic(err)
}
- genesis := Eth1Genesis{
+ genesis := ExecutionGenesis{
Genesis: &core.Genesis{
Config: ¶ms.ChainConfig{
ChainID: big.NewInt(7),
@@ -218,6 +233,11 @@ func BuildEth1Genesis(ttd *big.Int, genesisTime uint64, consensus Eth1Consensus)
NetworkID: 7,
}
+ // Configure post-merge forks
+ if forkConfig.ShanghaiTime != nil {
+ genesis.Genesis.Config.ShanghaiTime = forkConfig.ShanghaiTime
+ }
+
// Configure consensus
if err := consensus.Configure(&genesis); err != nil {
panic(err)
@@ -226,12 +246,15 @@ func BuildEth1Genesis(ttd *big.Int, genesisTime uint64, consensus Eth1Consensus)
return &genesis
}
-func (conf *Eth1Genesis) ToParams(depositAddress [20]byte) hivesim.Params {
+func (conf *ExecutionGenesis) ToParams(
+ depositAddress [20]byte,
+) hivesim.Params {
params := hivesim.Params{
- "HIVE_DEPOSIT_CONTRACT_ADDRESS": common.Address(depositAddress).String(),
- "HIVE_NETWORK_ID": fmt.Sprintf("%d", conf.NetworkID),
- "HIVE_CHAIN_ID": conf.Genesis.Config.ChainID.String(),
- "HIVE_FORK_HOMESTEAD": conf.Genesis.Config.HomesteadBlock.String(),
+ "HIVE_DEPOSIT_CONTRACT_ADDRESS": common.Address(depositAddress).
+ String(),
+ "HIVE_NETWORK_ID": fmt.Sprintf("%d", conf.NetworkID),
+ "HIVE_CHAIN_ID": conf.Genesis.Config.ChainID.String(),
+ "HIVE_FORK_HOMESTEAD": conf.Genesis.Config.HomesteadBlock.String(),
//"HIVE_FORK_DAO_BLOCK": conf.Genesis.Config.DAOForkBlock.String(), // nil error, not used anyway
"HIVE_FORK_TANGERINE": conf.Genesis.Config.EIP150Block.String(),
"HIVE_FORK_SPURIOUS": conf.Genesis.Config.EIP155Block.String(), // also eip558
@@ -245,9 +268,46 @@ func (conf *Eth1Genesis) ToParams(depositAddress [20]byte) hivesim.Params {
"HIVE_FORK_ARROWGLACIER": conf.Genesis.Config.ArrowGlacierBlock.String(),
"HIVE_MERGE_BLOCK_ID": conf.Genesis.Config.MergeNetsplitBlock.String(),
"HIVE_TERMINAL_TOTAL_DIFFICULTY": conf.Genesis.Config.TerminalTotalDifficulty.String(),
+ "HIVE_SHANGHAI_TIMESTAMP": conf.Genesis.Config.ShanghaiTime.String(),
+ }
+ if conf.Genesis.Config.ShanghaiTime != nil {
+ params = params.Set(
+ "HIVE_SHANGHAI_TIMESTAMP",
+ conf.Genesis.Config.ShanghaiTime.String(),
+ )
}
if conf.Genesis.Config.Clique != nil {
- params["HIVE_CLIQUE_PERIOD"] = fmt.Sprint(conf.Genesis.Config.Clique.Period)
+ params["HIVE_CLIQUE_PERIOD"] = fmt.Sprint(
+ conf.Genesis.Config.Clique.Period,
+ )
}
return params
}
+
+func IsEth1GenesisPostMerge(genesis *core.Genesis) bool {
+ return genesis.Config.TerminalTotalDifficulty.Cmp(genesis.Difficulty) <= 0
+}
+
+func ExecutionBundle(genesis *core.Genesis) (hivesim.StartOption, error) {
+ out, err := json.Marshal(genesis)
+ if err != nil {
+ return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
+ }
+ return hivesim.WithDynamicFile(
+ "genesis.json",
+ config.BytesSource(out),
+ ), nil
+}
+
+func ChainBundle(chain []*types.Block) (hivesim.StartOption, error) {
+ var buf bytes.Buffer
+ for _, block := range chain {
+ if err := block.EncodeRLP(&buf); err != nil {
+ return nil, err
+ }
+ }
+ return hivesim.WithDynamicFile(
+ "/chain.rlp",
+ config.BytesSource(buf.Bytes()),
+ ), nil
+}
diff --git a/simulators/eth2/common/debug/debug.go b/simulators/eth2/common/debug/debug.go
new file mode 100644
index 0000000000..08edee619d
--- /dev/null
+++ b/simulators/eth2/common/debug/debug.go
@@ -0,0 +1,214 @@
+package debug
+
+import (
+ "context"
+ "fmt"
+ "sort"
+
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ "github.com/ethereum/hive/simulators/eth2/common/utils"
+ "github.com/protolambda/eth2api"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/ztyp/tree"
+)
+
+// Helper debugging functions
+func PrintAllBeaconBlocks(
+ parentCtx context.Context,
+ l utils.Logging,
+ b *clients.BeaconClient,
+) error {
+ headInfo, err := b.BlockHeader(parentCtx, eth2api.BlockHead)
+
+ if err != nil {
+ return fmt.Errorf("PrintAllBeaconBlocks: failed to poll head: %v", err)
+ }
+ l.Logf(
+ "PrintAllBeaconBlocks: Printing beacon chain from %s\n",
+ b.HiveClient.Container,
+ )
+ l.Logf(
+ "PrintAllBeaconBlocks: Head, slot %d, root %v\n",
+ headInfo.Header.Message.Slot,
+ headInfo.Root,
+ )
+ for i := 1; i <= int(headInfo.Header.Message.Slot); i++ {
+ bHeader, err := b.BlockHeader(parentCtx, eth2api.BlockIdSlot(i))
+ if err != nil {
+ l.Logf("PrintAllBeaconBlocks: Slot %d, not found\n", i)
+ continue
+ }
+ var (
+ root = bHeader.Root
+ execution = "0x0000..0000"
+ )
+
+ if versionedBlock, err := b.BlockV2(parentCtx, eth2api.BlockIdRoot(root)); err == nil {
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = utils.Shorten(executionPayload.BlockHash.Hex())
+ }
+ }
+
+ l.Logf(
+ "PrintAllBeaconBlocks: Slot=%d, root=%v, exec=%s\n",
+ i,
+ root,
+ execution,
+ )
+ }
+ return nil
+}
+
+type BeaconBlockInfo struct {
+ Root tree.Root
+ Parent tree.Root
+ Execution ethcommon.Hash
+ Nodes []int
+}
+
+type BeaconBlockList []*BeaconBlockInfo
+
+func (bl BeaconBlockList) Add(
+ root tree.Root,
+ parent tree.Root,
+ execution ethcommon.Hash,
+ nodeId int,
+) (BeaconBlockList, error) {
+ for _, b := range bl {
+ if root == b.Root {
+ if parent != b.Parent {
+ return bl, fmt.Errorf(
+ "roots equal (%s), parent root mismatch: %s != %s",
+ root.String(),
+ parent.String(),
+ b.Parent.String(),
+ )
+ }
+ if execution != b.Execution {
+ return bl, fmt.Errorf(
+ "roots equal (%s), exec hash mismatch: %s != %s",
+ root.String(),
+ execution.String(),
+ b.Execution.String(),
+ )
+ }
+ for _, n := range b.Nodes {
+ if nodeId == n {
+ return bl, nil
+ }
+ }
+ b.Nodes = append(b.Nodes, nodeId)
+ return bl, nil
+ }
+ }
+ return append(bl, &BeaconBlockInfo{
+ Root: root,
+ Parent: parent,
+ Execution: execution,
+ Nodes: []int{nodeId},
+ }), nil
+}
+
+type BeaconBlockMap map[common.Slot]BeaconBlockList
+
+func (bm BeaconBlockMap) Add(
+ slot common.Slot,
+ root tree.Root,
+ parent tree.Root,
+ execution ethcommon.Hash,
+ nodeId int,
+) error {
+ if _, found := bm[slot]; !found {
+ bm[slot] = make(BeaconBlockList, 0)
+ }
+ var err error
+ bm[slot], err = bm[slot].Add(root, parent, execution, nodeId)
+ if err != nil {
+ return fmt.Errorf("conflicting block on slot %d: %v", slot, err)
+ }
+ return nil
+}
+func (bm BeaconBlockMap) Print(l utils.Logging) error {
+ slots := make([]int, 0, len(bm))
+ for s := range bm {
+ slots = append(slots, int(s))
+ }
+ sort.Ints(slots)
+ for _, s := range slots {
+ l.Logf("- Slot=%d\n", s)
+ for i, b := range bm[common.Slot(s)] {
+ l.Logf(
+ " Fork %d: root=%v, parent=%v, exec=%s, nodes=%v \n",
+ i,
+ utils.Shorten(b.Root.String()),
+ utils.Shorten(b.Parent.String()),
+ utils.Shorten(b.Execution.String()),
+ b.Nodes,
+ )
+ }
+ }
+ return nil
+}
+
+func PrintAllTestnetBeaconBlocks(
+ parentCtx context.Context,
+ l utils.Logging,
+ runningBeacons clients.BeaconClients,
+) error {
+ beaconTree := make(BeaconBlockMap)
+
+ for nodeId, beaconNode := range runningBeacons {
+
+ var (
+ nextBlock eth2api.BlockId
+ )
+
+ nextBlock = eth2api.BlockHead
+
+ for {
+ if nextBlock.BlockId() == eth2api.BlockIdRoot(tree.Root{}).
+ BlockId() {
+ break
+ }
+ // Get block header
+ bHeader, err := beaconNode.BlockHeader(parentCtx, nextBlock)
+ if err != nil {
+ l.Logf(
+ "Error fetching block (%s) from beacon node %d: %v",
+ nextBlock.BlockId(),
+ nodeId,
+ err,
+ )
+ break
+ }
+
+ var (
+ root = bHeader.Root
+ parent = bHeader.Header.Message.ParentRoot
+ execution = ethcommon.Hash{}
+ )
+
+ if versionedBlock, err := beaconNode.BlockV2(parentCtx, eth2api.BlockIdRoot(root)); err == nil {
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = executionPayload.BlockHash
+ l.Logf(
+ "Node %d: Execution payload: hash=%s",
+ nodeId,
+ utils.Shorten(execution.String()),
+ )
+ }
+ } else if err != nil {
+ l.Logf("Error getting versioned block=%s node=%d: %v", nextBlock.BlockId(), nodeId, err)
+ break
+ }
+ if err := beaconTree.Add(bHeader.Header.Message.Slot, root, parent, execution, nodeId); err != nil {
+ return err
+ }
+ nextBlock = eth2api.BlockIdRoot(parent)
+ }
+
+ }
+ beaconTree.Print(l)
+ return nil
+}
diff --git a/simulators/eth2/common/go.mod b/simulators/eth2/common/go.mod
new file mode 100644
index 0000000000..e8ee981f7a
--- /dev/null
+++ b/simulators/eth2/common/go.mod
@@ -0,0 +1,70 @@
+module github.com/ethereum/hive/simulators/eth2/common
+
+go 1.18
+
+require (
+ github.com/ethereum/go-ethereum v1.10.26
+ github.com/ethereum/hive v0.0.0-20221214152536-bfabd993ae7b
+ github.com/golang-jwt/jwt/v4 v4.3.0
+ github.com/google/uuid v1.3.0
+ github.com/herumi/bls-eth-go-binary v1.28.1
+ github.com/holiman/uint256 v1.2.1
+ github.com/pkg/errors v0.9.1
+ github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e
+ github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0
+ github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564
+ github.com/protolambda/zrnt v0.30.0
+ github.com/protolambda/ztyp v0.2.2
+ github.com/rauljordan/engine-proxy v0.0.0-20220517190449-e62b2e2f6e27
+ github.com/tyler-smith/go-bip39 v1.1.0
+ github.com/wealdtech/go-eth2-util v1.8.0
+ golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a
+ gopkg.in/yaml.v2 v2.4.0
+)
+
+require (
+ github.com/VictoriaMetrics/fastcache v1.12.0 // indirect
+ github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/deckarep/golang-set/v2 v2.1.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
+ github.com/edsrzf/mmap-go v1.1.0 // indirect
+ github.com/ferranbt/fastssz v0.1.2 // indirect
+ github.com/go-kit/kit v0.12.0 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/go-stack/stack v1.8.1 // indirect
+ github.com/golang/snappy v0.0.4 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect
+ github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
+ github.com/julienschmidt/httprouter v1.3.0 // indirect
+ github.com/kilic/bls12-381 v0.1.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.1 // indirect
+ github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/minio/sha256-simd v1.0.0 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/prometheus/tsdb v0.10.0 // indirect
+ github.com/rivo/uniseg v0.4.3 // indirect
+ github.com/rogpeppe/go-internal v1.8.1 // indirect
+ github.com/rs/cors v1.8.2 // indirect
+ github.com/shirou/gopsutil v3.21.11+incompatible // indirect
+ github.com/sirupsen/logrus v1.9.0 // indirect
+ github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
+ github.com/tklauser/go-sysconf v0.3.11 // indirect
+ github.com/tklauser/numcpus v0.6.0 // indirect
+ github.com/wealdtech/go-bytesutil v1.2.0 // indirect
+ github.com/wealdtech/go-eth2-types/v2 v2.8.0 // indirect
+ github.com/yusufpapurcu/wmi v1.2.2 // indirect
+ golang.org/x/crypto v0.4.0 // indirect
+ golang.org/x/sys v0.3.0 // indirect
+ golang.org/x/text v0.5.0 // indirect
+ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+replace github.com/rauljordan/engine-proxy => github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea
+
+replace github.com/ethereum/go-ethereum v1.10.26 => github.com/lightclient/go-ethereum v1.10.10-0.20230116085521-6ab6d738866f
+
+replace github.com/protolambda/eth2api => github.com/marioevz/eth2api v0.0.0-20230110222620-e349e704f20c
diff --git a/simulators/eth2/common/go.sum b/simulators/eth2/common/go.sum
new file mode 100644
index 0000000000..e07f472bc4
--- /dev/null
+++ b/simulators/eth2/common/go.sum
@@ -0,0 +1,316 @@
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
+github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
+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/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+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/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
+github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
+github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
+github.com/ethereum/hive v0.0.0-20221214152536-bfabd993ae7b h1:T8hIVTXQfUI5EwOsmOo4vMRkaBzm6E6rY826YTVt0jI=
+github.com/ethereum/hive v0.0.0-20221214152536-bfabd993ae7b/go.mod h1:pqToex2uV+Tg7bhBla/uvB3APKZ6FogJMMpow33nUIA=
+github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
+github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
+github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
+github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
+github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
+github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
+github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+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.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.2/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/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+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.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
+github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA=
+github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
+github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=
+github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU=
+github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
+github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
+github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
+github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+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/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
+github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
+github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
+github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/lightclient/go-ethereum v1.10.10-0.20230116085521-6ab6d738866f h1:Pox2oxBYKWVEw2JUCyiEybqEIurSkq8VHjRp6s9jdf8=
+github.com/lightclient/go-ethereum v1.10.10-0.20230116085521-6ab6d738866f/go.mod h1:n7VlOgCwYheLB/mi+V8ni2yf8K2qM3N9WAmalxkhk+c=
+github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea h1:9ahHMPkNvYf9Nn3+U072ZKMDm05gaXfRESAmwP07Q+M=
+github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+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/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+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.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/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_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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+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/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
+github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
+github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e h1:ugvwIKDzqL6ODJciRPMm+9xFQ5AlOYHeMpCOeEuP7LA=
+github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w=
+github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0 h1:/0Dm3GrX4sk0aAYdrjtFvJigvPZ8HcAQ3ZT7kW+da7M=
+github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0/go.mod h1:dzegbgrVD+2MQZ86RHWQvgWfnFxEjlDNkzf69afaSnA=
+github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564 h1:yCXGkFjrZ8EggxW+Y7ueRZesNcBk0avLU0mVU/I2KtU=
+github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564/go.mod h1:Xda3KO8+DMyWaTr+LwUUpVRTB5SdFzoKu0ivXNI6p1s=
+github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M=
+github.com/protolambda/zrnt v0.29.0 h1:pHCagNwM1KJztMnXXCZ6RAvQL4nVTCJ1v1tTyl/nP0o=
+github.com/protolambda/zrnt v0.29.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
+github.com/protolambda/zrnt v0.30.0 h1:pHEn69ZgaDFGpLGGYG1oD7DvYI7RDirbMBPfbC+8p4g=
+github.com/protolambda/zrnt v0.30.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
+github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY=
+github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
+github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
+github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
+github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
+github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
+github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
+github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
+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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
+github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
+github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
+github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
+github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
+github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
+github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
+github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
+github.com/wealdtech/go-bytesutil v1.2.0 h1:GEIzvAZEIgqOoRfnEAaMRNL73gl8e+YlQzqxhFyR30Y=
+github.com/wealdtech/go-bytesutil v1.2.0/go.mod h1:FHQSlwhzfSZGffu1osaUGdnNtl5C8tBKwmqvPdB66pM=
+github.com/wealdtech/go-eth2-types/v2 v2.8.0 h1:Cts9J78ryXVp8jwotdSSVU75S+QWJrgVCArXreD2X8A=
+github.com/wealdtech/go-eth2-types/v2 v2.8.0/go.mod h1:tJazo9o28kdQs3V/U4VafQ4neG+/sL3OBozQ8J3CWmo=
+github.com/wealdtech/go-eth2-util v1.8.0 h1:hhs3h2y3Ldty18lppFdpe46nZpdDAMbY7QqiHO5BvE0=
+github.com/wealdtech/go-eth2-util v1.8.0/go.mod h1:rSuE0v5zX+uyZrqW/iUmXOxeDpB7lTvhcZvAVh0KlMU=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
+github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
+golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a h1:tlXy25amD5A7gOfbXdqCGN5k8ESEed/Ee1E5RcrYnqU=
+golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+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-20190423024810-112230192c58/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-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
+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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-20191005200804-aed5e4c7ecf9/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-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+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=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1 h1:iiHuQZCNgYPmFQxd3BBN/Nc5+dAwzZuq5y40s20oQw0=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/simulators/eth2/common/main.go b/simulators/eth2/common/main.go
new file mode 100644
index 0000000000..805d0c79aa
--- /dev/null
+++ b/simulators/eth2/common/main.go
@@ -0,0 +1 @@
+package common
diff --git a/simulators/eth2/common/spoofing/payload/payload_spoofing.go b/simulators/eth2/common/spoofing/payload/payload_spoofing.go
new file mode 100644
index 0000000000..2370bad07f
--- /dev/null
+++ b/simulators/eth2/common/spoofing/payload/payload_spoofing.go
@@ -0,0 +1,817 @@
+package payload
+
+import (
+ "crypto/rand"
+ "fmt"
+ "math/big"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ api "github.com/ethereum/go-ethereum/core/beacon"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/trie"
+ "github.com/ethereum/hive/simulators/eth2/common/spoofing/proxy"
+ spoof "github.com/rauljordan/engine-proxy/proxy"
+)
+
+// API call names
+const (
+ EngineForkchoiceUpdatedV1 = "engine_forkchoiceUpdatedV1"
+ EngineGetPayloadV1 = "engine_getPayloadV1"
+ EngineNewPayloadV1 = "engine_newPayloadV1"
+ EthGetBlockByHash = "eth_getBlockByHash"
+ EthGetBlockByNumber = "eth_getBlockByNumber"
+)
+
+// Engine API Types
+
+type PayloadStatus string
+
+const (
+ Unknown = ""
+ Valid = "VALID"
+ Invalid = "INVALID"
+ Accepted = "ACCEPTED"
+ Syncing = "SYNCING"
+ InvalidBlockHash = "INVALID_BLOCK_HASH"
+)
+
+// Payload helper methods
+type SignatureValues struct {
+ V *big.Int
+ R *big.Int
+ S *big.Int
+}
+
+func SignatureValuesFromRaw(
+ v *big.Int,
+ r *big.Int,
+ s *big.Int,
+) SignatureValues {
+ return SignatureValues{
+ V: v,
+ R: r,
+ S: s,
+ }
+}
+
+type CustomTransactionData struct {
+ Nonce *uint64
+ GasPrice *big.Int
+ Gas *uint64
+ To *common.Address
+ Value *big.Int
+ Data *[]byte
+ Signature *SignatureValues
+}
+
+type SignerWithKey interface {
+ SignTx(*types.Transaction) (*types.Transaction, error)
+}
+
+func CustomizeTransaction(
+ baseTransaction *types.Transaction,
+ customData *CustomTransactionData,
+ signer SignerWithKey,
+) (*types.Transaction, error) {
+ // Create a modified transaction base, from the base transaction and customData mix
+ modifiedTxBase := &types.LegacyTx{}
+
+ if customData.Nonce != nil {
+ modifiedTxBase.Nonce = *customData.Nonce
+ } else {
+ modifiedTxBase.Nonce = baseTransaction.Nonce()
+ }
+ if customData.GasPrice != nil {
+ modifiedTxBase.GasPrice = customData.GasPrice
+ } else {
+ modifiedTxBase.GasPrice = baseTransaction.GasPrice()
+ }
+ if customData.Gas != nil {
+ modifiedTxBase.Gas = *customData.Gas
+ } else {
+ modifiedTxBase.Gas = baseTransaction.Gas()
+ }
+ if customData.To != nil {
+ modifiedTxBase.To = customData.To
+ } else {
+ modifiedTxBase.To = baseTransaction.To()
+ }
+ if customData.Value != nil {
+ modifiedTxBase.Value = customData.Value
+ } else {
+ modifiedTxBase.Value = baseTransaction.Value()
+ }
+ if customData.Data != nil {
+ modifiedTxBase.Data = *customData.Data
+ } else {
+ modifiedTxBase.Data = baseTransaction.Data()
+ }
+
+ if customData.Signature != nil {
+ modifiedTxBase.V = customData.Signature.V
+ modifiedTxBase.R = customData.Signature.R
+ modifiedTxBase.S = customData.Signature.S
+ return types.NewTx(modifiedTxBase), nil
+ } else {
+ // If a custom signature was not specified, simply sign the transaction again
+ if signer == nil {
+ return nil, fmt.Errorf("custom tx needs to be signed but no signer provided")
+ }
+ return signer.SignTx(types.NewTx(modifiedTxBase))
+ }
+}
+
+type CustomPayloadData struct {
+ ParentHash *common.Hash
+ FeeRecipient *common.Address
+ StateRoot *common.Hash
+ ReceiptsRoot *common.Hash
+ LogsBloom *[]byte
+ PrevRandao *common.Hash
+ Number *uint64
+ GasLimit *uint64
+ GasUsed *uint64
+ Timestamp *uint64
+ ExtraData *[]byte
+ BaseFeePerGas *big.Int
+ BlockHash *common.Hash
+ Transactions *[][]byte
+}
+
+func calcTxsHash(txsBytes [][]byte) (common.Hash, error) {
+ txs := make([]*types.Transaction, len(txsBytes))
+ for i, bytesTx := range txsBytes {
+ var currentTx types.Transaction
+ err := currentTx.UnmarshalBinary(bytesTx)
+ if err != nil {
+ return common.Hash{}, err
+ }
+ txs[i] = ¤tTx
+ }
+ return types.DeriveSha(
+ types.Transactions(txs),
+ trie.NewStackTrie(nil),
+ ), nil
+}
+
+// Construct a customized payload by taking an existing payload as base and mixing it CustomPayloadData
+// BlockHash is calculated automatically.
+func CustomizePayloadSpoof(
+ method string,
+ basePayload *api.ExecutableData,
+ customData *CustomPayloadData,
+) (common.Hash, *spoof.Spoof, error) {
+ fields := make(map[string]interface{})
+
+ txs := basePayload.Transactions
+ if customData.Transactions != nil {
+ txs = *customData.Transactions
+ }
+ txsHash, err := calcTxsHash(txs)
+ if err != nil {
+ return common.Hash{}, nil, err
+ }
+ // Start by filling the header with the basePayload information
+ customPayloadHeader := types.Header{
+ ParentHash: basePayload.ParentHash,
+ UncleHash: types.EmptyUncleHash, // Could be overwritten
+ Coinbase: basePayload.FeeRecipient,
+ Root: basePayload.StateRoot,
+ TxHash: txsHash,
+ ReceiptHash: basePayload.ReceiptsRoot,
+ Bloom: types.BytesToBloom(basePayload.LogsBloom),
+ Difficulty: big.NewInt(0), // could be overwritten
+ Number: big.NewInt(int64(basePayload.Number)),
+ GasLimit: basePayload.GasLimit,
+ GasUsed: basePayload.GasUsed,
+ Time: basePayload.Timestamp,
+ Extra: basePayload.ExtraData,
+ MixDigest: basePayload.Random,
+ Nonce: types.BlockNonce{0}, // could be overwritten
+ BaseFee: basePayload.BaseFeePerGas,
+ }
+
+ // Overwrite custom information
+ if customData.ParentHash != nil {
+ customPayloadHeader.ParentHash = *customData.ParentHash
+ fields["parentHash"] = customPayloadHeader.ParentHash
+ }
+ if customData.FeeRecipient != nil {
+ customPayloadHeader.Coinbase = *customData.FeeRecipient
+ fields["feeRecipient"] = customPayloadHeader.Coinbase
+ }
+ if customData.StateRoot != nil {
+ customPayloadHeader.Root = *customData.StateRoot
+ fields["stateRoot"] = customPayloadHeader.Root
+ }
+ if customData.ReceiptsRoot != nil {
+ customPayloadHeader.ReceiptHash = *customData.ReceiptsRoot
+ fields["receiptsRoot"] = customPayloadHeader.ReceiptHash
+ }
+ if customData.LogsBloom != nil {
+ customPayloadHeader.Bloom = types.BytesToBloom(*customData.LogsBloom)
+ fields["logsBloom"] = hexutil.Bytes(*customData.LogsBloom)
+ }
+ if customData.PrevRandao != nil {
+ customPayloadHeader.MixDigest = *customData.PrevRandao
+ fields["prevRandao"] = customPayloadHeader.MixDigest
+ }
+ if customData.Number != nil {
+ customPayloadHeader.Number = big.NewInt(int64(*customData.Number))
+ fields["blockNumber"] = hexutil.Uint64(*customData.Number)
+ }
+ if customData.GasLimit != nil {
+ customPayloadHeader.GasLimit = *customData.GasLimit
+ fields["gasLimit"] = hexutil.Uint64(customPayloadHeader.GasLimit)
+ }
+ if customData.GasUsed != nil {
+ customPayloadHeader.GasUsed = *customData.GasUsed
+ fields["gasUsed"] = hexutil.Uint64(customPayloadHeader.GasUsed)
+ }
+ if customData.Timestamp != nil {
+ customPayloadHeader.Time = *customData.Timestamp
+ fields["timestamp"] = hexutil.Uint64(customPayloadHeader.Time)
+ }
+ if customData.ExtraData != nil {
+ customPayloadHeader.Extra = *customData.ExtraData
+ fields["extraData"] = hexutil.Bytes(customPayloadHeader.Extra)
+ }
+ if customData.BaseFeePerGas != nil {
+ customPayloadHeader.BaseFee = customData.BaseFeePerGas
+ fields["baseFeePerGas"] = (*hexutil.Big)(customPayloadHeader.BaseFee)
+ }
+
+ var payloadHash common.Hash
+ if customData.BlockHash != nil {
+ payloadHash = *customData.BlockHash
+ } else {
+ payloadHash = customPayloadHeader.Hash()
+ }
+ fields["blockHash"] = payloadHash
+
+ // Return the new payload
+ return payloadHash, &spoof.Spoof{
+ Method: method,
+ Fields: fields,
+ }, nil
+}
+
+func (customData *CustomPayloadData) String() string {
+ customFieldsList := make([]string, 0)
+ if customData.ParentHash != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("ParentHash=%s", customData.ParentHash.String()),
+ )
+ }
+ if customData.FeeRecipient != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("Coinbase=%s", customData.FeeRecipient.String()),
+ )
+ }
+ if customData.StateRoot != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("StateRoot=%s", customData.StateRoot.String()),
+ )
+ }
+ if customData.ReceiptsRoot != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("ReceiptsRoot=%s", customData.ReceiptsRoot.String()),
+ )
+ }
+ if customData.LogsBloom != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf(
+ "LogsBloom=%v",
+ types.BytesToBloom(*customData.LogsBloom),
+ ),
+ )
+ }
+ if customData.PrevRandao != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("PrevRandao=%s", customData.PrevRandao.String()),
+ )
+ }
+ if customData.Number != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("Number=%d", *customData.Number),
+ )
+ }
+ if customData.GasLimit != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("GasLimit=%d", *customData.GasLimit),
+ )
+ }
+ if customData.GasUsed != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("GasUsed=%d", *customData.GasUsed),
+ )
+ }
+ if customData.Timestamp != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("Timestamp=%d", *customData.Timestamp),
+ )
+ }
+ if customData.ExtraData != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("ExtraData=%v", *customData.ExtraData),
+ )
+ }
+ if customData.BaseFeePerGas != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("BaseFeePerGas=%s", customData.BaseFeePerGas.String()),
+ )
+ }
+ if customData.Transactions != nil {
+ customFieldsList = append(
+ customFieldsList,
+ fmt.Sprintf("Transactions=%v", customData.Transactions),
+ )
+ }
+ return strings.Join(customFieldsList, ", ")
+}
+
+type InvalidPayloadField string
+
+const (
+ InvalidParentHash = "ParentHash"
+ InvalidStateRoot = "StateRoot"
+ InvalidReceiptsRoot = "ReceiptsRoot"
+ InvalidNumber = "Number"
+ InvalidGasLimit = "GasLimit"
+ InvalidGasUsed = "GasUsed"
+ InvalidTimestamp = "Timestamp"
+ InvalidPrevRandao = "PrevRandao"
+ RemoveTransaction = "Incomplete Transactions"
+ InvalidTransactionSignature = "Transaction Signature"
+ InvalidTransactionNonce = "Transaction Nonce"
+ InvalidTransactionGas = "Transaction Gas"
+ InvalidTransactionGasPrice = "Transaction GasPrice"
+ InvalidTransactionValue = "Transaction Value"
+)
+
+// This function generates an invalid payload by taking a base payload and modifying the specified field such that it ends up being invalid.
+// One small consideration is that the payload needs to contain transactions and specially transactions using the PREVRANDAO opcode for all the fields to be compatible with this function.
+func GenerateInvalidPayloadSpoof(
+ method string,
+ basePayload *api.ExecutableData,
+ payloadField InvalidPayloadField,
+ signer SignerWithKey,
+) (common.Hash, *spoof.Spoof, error) {
+ var customPayloadMod *CustomPayloadData
+ switch payloadField {
+ case InvalidParentHash:
+ var randomParentHash common.Hash
+ rand.Read(randomParentHash[:])
+ customPayloadMod = &CustomPayloadData{
+ ParentHash: &randomParentHash,
+ }
+ case InvalidStateRoot:
+ modStateRoot := basePayload.StateRoot
+ modStateRoot[common.HashLength-1] = byte(
+ 255 - modStateRoot[common.HashLength-1],
+ )
+ customPayloadMod = &CustomPayloadData{
+ StateRoot: &modStateRoot,
+ }
+ case InvalidReceiptsRoot:
+ modReceiptsRoot := basePayload.ReceiptsRoot
+ modReceiptsRoot[common.HashLength-1] = byte(
+ 255 - modReceiptsRoot[common.HashLength-1],
+ )
+ customPayloadMod = &CustomPayloadData{
+ ReceiptsRoot: &modReceiptsRoot,
+ }
+ case InvalidNumber:
+ modNumber := basePayload.Number - 1
+ customPayloadMod = &CustomPayloadData{
+ Number: &modNumber,
+ }
+ case InvalidGasLimit:
+ modGasLimit := basePayload.GasLimit * 2
+ customPayloadMod = &CustomPayloadData{
+ GasLimit: &modGasLimit,
+ }
+ case InvalidGasUsed:
+ modGasUsed := basePayload.GasUsed - 1
+ customPayloadMod = &CustomPayloadData{
+ GasUsed: &modGasUsed,
+ }
+ case InvalidTimestamp:
+ modTimestamp := basePayload.Timestamp - 1
+ customPayloadMod = &CustomPayloadData{
+ Timestamp: &modTimestamp,
+ }
+ case InvalidPrevRandao:
+ // This option potentially requires a transaction that uses the PREVRANDAO opcode.
+ // Otherwise the payload will still be valid.
+ modPrevRandao := common.Hash{}
+ rand.Read(modPrevRandao[:])
+ customPayloadMod = &CustomPayloadData{
+ PrevRandao: &modPrevRandao,
+ }
+ case RemoveTransaction:
+ emptyTxs := make([][]byte, 0)
+ customPayloadMod = &CustomPayloadData{
+ Transactions: &emptyTxs,
+ }
+ case InvalidTransactionSignature,
+ InvalidTransactionNonce,
+ InvalidTransactionGas,
+ InvalidTransactionGasPrice,
+ InvalidTransactionValue:
+
+ if len(basePayload.Transactions) == 0 {
+ return common.Hash{}, nil, fmt.Errorf(
+ "no transactions available for modification",
+ )
+ }
+ var baseTx types.Transaction
+ if err := baseTx.UnmarshalBinary(basePayload.Transactions[0]); err != nil {
+ return common.Hash{}, nil, err
+ }
+ var customTxData CustomTransactionData
+ switch payloadField {
+ case InvalidTransactionSignature:
+ modifiedSignature := SignatureValuesFromRaw(
+ baseTx.RawSignatureValues(),
+ )
+ modifiedSignature.R = modifiedSignature.R.Sub(
+ modifiedSignature.R,
+ big.NewInt(1),
+ )
+ customTxData = CustomTransactionData{
+ Signature: &modifiedSignature,
+ }
+ case InvalidTransactionNonce:
+ customNonce := baseTx.Nonce() - 1
+ customTxData = CustomTransactionData{
+ Nonce: &customNonce,
+ }
+ case InvalidTransactionGas:
+ customGas := uint64(0)
+ customTxData = CustomTransactionData{
+ Gas: &customGas,
+ }
+ case InvalidTransactionGasPrice:
+ customTxData = CustomTransactionData{
+ GasPrice: big.NewInt(0),
+ }
+ case InvalidTransactionValue:
+ // Vault account initially has 0x123450000000000000000, so this value should overflow
+ customValue, err := hexutil.DecodeBig("0x123450000000000000001")
+ if err != nil {
+ return common.Hash{}, nil, err
+ }
+ customTxData = CustomTransactionData{
+ Value: customValue,
+ }
+ }
+
+ modifiedTx, err := CustomizeTransaction(
+ &baseTx,
+ &customTxData,
+ signer,
+ )
+ if err != nil {
+ return common.Hash{}, nil, err
+ }
+
+ modifiedTxBytes, err := modifiedTx.MarshalBinary()
+ if err != nil {
+ return common.Hash{}, nil, err
+ }
+ modifiedTransactions := [][]byte{
+ modifiedTxBytes,
+ }
+ customPayloadMod = &CustomPayloadData{
+ Transactions: &modifiedTransactions,
+ }
+ }
+
+ if customPayloadMod == nil {
+ return common.Hash{}, nil, fmt.Errorf(
+ "invalid payload field to corrupt: %s",
+ payloadField,
+ )
+ }
+
+ return CustomizePayloadSpoof(method, basePayload, customPayloadMod)
+}
+
+// Generate a payload status spoof
+func PayloadStatusSpoof(
+ method string,
+ status *api.PayloadStatusV1,
+) (*spoof.Spoof, error) {
+ fields := make(map[string]interface{})
+ fields["status"] = status.Status
+ fields["latestValidHash"] = status.LatestValidHash
+ fields["validationError"] = status.ValidationError
+
+ // Return the new payload status spoof
+ return &spoof.Spoof{
+ Method: method,
+ Fields: fields,
+ }, nil
+}
+
+// Generate a payload status spoof
+func ForkchoiceResponseSpoof(
+ method string,
+ status api.PayloadStatusV1,
+ payloadID *api.PayloadID,
+) (*spoof.Spoof, error) {
+ fields := make(map[string]interface{})
+ fields["payloadStatus"] = status
+ fields["payloadId"] = payloadID
+
+ // Return the new payload status spoof
+ return &spoof.Spoof{
+ Method: method,
+ Fields: fields,
+ }, nil
+}
+
+type EngineResponseHash struct {
+ Response *api.PayloadStatusV1
+ Hash common.Hash
+}
+
+type EngineResponseMocker struct {
+ Lock sync.Mutex
+ DefaultResponse *api.PayloadStatusV1
+ HashToResponse map[common.Hash]*api.PayloadStatusV1
+ HashPassthrough map[common.Hash]bool
+ NewPayloadCalled chan EngineResponseHash
+ ForkchoiceUpdatedCalled chan EngineResponseHash
+ Mocking bool
+}
+
+func NewEngineResponseMocker(
+ defaultResponse *api.PayloadStatusV1,
+ perHashResponses ...*EngineResponseHash,
+) *EngineResponseMocker {
+ e := &EngineResponseMocker{
+ DefaultResponse: defaultResponse,
+ HashToResponse: make(map[common.Hash]*api.PayloadStatusV1),
+ HashPassthrough: make(map[common.Hash]bool),
+ NewPayloadCalled: make(chan EngineResponseHash),
+ ForkchoiceUpdatedCalled: make(chan EngineResponseHash),
+ Mocking: true,
+ }
+ for _, r := range perHashResponses {
+ e.AddResponse(r.Hash, r.Response)
+ }
+ return e
+}
+
+func (e *EngineResponseMocker) AddResponse(
+ h common.Hash,
+ r *api.PayloadStatusV1,
+) {
+ e.Lock.Lock()
+ defer e.Lock.Unlock()
+ if e.HashToResponse == nil {
+ e.HashToResponse = make(map[common.Hash]*api.PayloadStatusV1)
+ }
+ e.HashToResponse[h] = r
+}
+
+func (e *EngineResponseMocker) AddPassthrough(h common.Hash, pass bool) {
+ e.Lock.Lock()
+ defer e.Lock.Unlock()
+ e.HashPassthrough[h] = pass
+}
+
+func (e *EngineResponseMocker) CanPassthrough(h common.Hash) bool {
+ e.Lock.Lock()
+ defer e.Lock.Unlock()
+ if pass, ok := e.HashPassthrough[h]; ok && pass {
+ return true
+ }
+ return false
+}
+
+func (e *EngineResponseMocker) GetResponse(
+ h common.Hash,
+) *api.PayloadStatusV1 {
+ e.Lock.Lock()
+ defer e.Lock.Unlock()
+ if e.HashToResponse != nil {
+ if r, ok := e.HashToResponse[h]; ok {
+ return r
+ }
+ }
+ return e.DefaultResponse
+}
+
+func (e *EngineResponseMocker) SetDefaultResponse(r *api.PayloadStatusV1) {
+ e.Lock.Lock()
+ defer e.Lock.Unlock()
+ e.DefaultResponse = r
+}
+
+func (e *EngineResponseMocker) AddGetPayloadPassthroughToProxy(
+ p *proxy.Proxy,
+) {
+ p.AddResponseCallback(
+ EngineGetPayloadV1,
+ func(res []byte, req []byte) *spoof.Spoof {
+ // Hash of the payload built is being added to the passthrough list
+ var (
+ payload api.ExecutableData // ExecutableDataV1
+ )
+ err := proxy.UnmarshalFromJsonRPCResponse(res, &payload)
+ if err != nil {
+ panic(err)
+ }
+ e.AddPassthrough(payload.BlockHash, true)
+ return nil
+ },
+ )
+}
+
+func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy(p *proxy.Proxy) {
+ p.AddResponseCallback(
+ EngineNewPayloadV1,
+ func(res []byte, req []byte) *spoof.Spoof {
+ var (
+ payload api.ExecutableData
+ status api.PayloadStatusV1
+ spoof *spoof.Spoof
+ err error
+ )
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &payload)
+ if err != nil {
+ panic(err)
+ }
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &status)
+ if err != nil {
+ panic(err)
+ }
+ if r := e.GetResponse(payload.BlockHash); e.Mocking &&
+ !e.CanPassthrough(payload.BlockHash) &&
+ r != nil {
+ // We are mocking this specific response, either with a hash specific response, or the default response
+ spoof, err = PayloadStatusSpoof(
+ EngineNewPayloadV1,
+ &api.PayloadStatusV1{
+ Status: r.Status,
+ LatestValidHash: r.LatestValidHash,
+ ValidationError: nil,
+ },
+ )
+ if err != nil {
+ panic(err)
+ }
+ select {
+ case e.NewPayloadCalled <- EngineResponseHash{
+ Response: r,
+ Hash: payload.BlockHash,
+ }:
+ default:
+ }
+ return spoof
+ } else {
+ select {
+ case e.NewPayloadCalled <- EngineResponseHash{
+ Response: &status,
+ Hash: payload.BlockHash,
+ }:
+ default:
+ }
+ }
+ return nil
+ },
+ )
+}
+
+func (e *EngineResponseMocker) AddForkchoiceUpdatedCallbackToProxy(
+ p *proxy.Proxy,
+) {
+ p.AddResponseCallback(
+ EngineForkchoiceUpdatedV1,
+ func(res []byte, req []byte) *spoof.Spoof {
+ var (
+ fcState api.ForkchoiceStateV1
+ pAttr api.PayloadAttributes
+ fResp api.ForkChoiceResponse
+ spoof *spoof.Spoof
+ err error
+ )
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
+ if err != nil {
+ panic(err)
+ }
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &fResp)
+ if err != nil {
+ panic(err)
+ }
+
+ if r := e.GetResponse(fcState.HeadBlockHash); e.Mocking &&
+ !e.CanPassthrough(fcState.HeadBlockHash) &&
+ r != nil {
+ // We are mocking this specific response, either with a hash specific response, or the default response
+ spoof, err = ForkchoiceResponseSpoof(
+ EngineForkchoiceUpdatedV1,
+ api.PayloadStatusV1{
+ Status: r.Status,
+ LatestValidHash: r.LatestValidHash,
+ ValidationError: nil,
+ },
+ nil,
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ select {
+ case e.ForkchoiceUpdatedCalled <- EngineResponseHash{
+ Response: r,
+ Hash: fcState.HeadBlockHash,
+ }:
+ default:
+ }
+ return spoof
+ } else {
+ // Let the original response pass through
+ select {
+ case e.ForkchoiceUpdatedCalled <- EngineResponseHash{
+ Response: &fResp.PayloadStatus,
+ Hash: fcState.HeadBlockHash,
+ }:
+ default:
+ }
+ }
+ return nil
+ },
+ )
+}
+
+func (e *EngineResponseMocker) AddCallbacksToProxy(p *proxy.Proxy) {
+ e.AddForkchoiceUpdatedCallbackToProxy(p)
+ e.AddNewPayloadCallbackToProxy(p)
+}
+
+// Generates a callback that detects when a ForkchoiceUpdated with Payload Attributes fails.
+// Requires a lock in case two clients receive the fcU with payload attributes at the same time.
+// Requires chan(error) to return the final outcome of the callbacks.
+// Requires the maximum number of fcU+attr calls to check.
+func CheckErrorOnForkchoiceUpdatedPayloadAttributes(
+ fcuLock *sync.Mutex,
+ fcUCountLimit int,
+ fcUAttrCount *int,
+ fcudone chan<- error,
+) func(res []byte, req []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
+ var (
+ fcS api.ForkchoiceStateV1
+ pA *api.PayloadAttributes
+ )
+ if err := proxy.UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil {
+ panic(
+ fmt.Errorf(
+ "unable to parse ForkchoiceUpdated request: %v",
+ err,
+ ),
+ )
+ }
+ if pA != nil {
+ fcuLock.Lock()
+ defer fcuLock.Unlock()
+ (*fcUAttrCount)++
+ // The CL requested a payload, it should have not produced an error
+ var (
+ fcResponse api.ForkChoiceResponse
+ )
+ err := proxy.UnmarshalFromJsonRPCResponse(res, &fcResponse)
+ if err == nil && fcResponse.PayloadID == nil {
+ err = fmt.Errorf(
+ "PayloadID null on ForkchoiceUpdated with attributes",
+ )
+ }
+ if err != nil || (*fcUAttrCount) > fcUCountLimit {
+ select {
+ case fcudone <- err:
+ default:
+ }
+ }
+ }
+ return nil
+ }
+}
diff --git a/simulators/eth2/engine/proxies.go b/simulators/eth2/common/spoofing/proxy/proxy.go
similarity index 53%
rename from simulators/eth2/engine/proxies.go
rename to simulators/eth2/common/spoofing/proxy/proxy.go
index df393552d8..c728540e10 100644
--- a/simulators/eth2/engine/proxies.go
+++ b/simulators/eth2/common/spoofing/proxy/proxy.go
@@ -1,7 +1,8 @@
-package main
+package proxy
import (
"context"
+ "encoding/json"
"fmt"
"net"
"sync"
@@ -25,7 +26,12 @@ type Proxy struct {
mu sync.Mutex
}
-func NewProxy(hostIP net.IP, port int, destination string, jwtSecret []byte) *Proxy {
+func NewProxy(
+ hostIP net.IP,
+ port int,
+ destination string,
+ jwtSecret []byte,
+) *Proxy {
host := "0.0.0.0"
config := proxy.SpoofingConfig{}
callbacks := proxy.SpoofingCallbacks{
@@ -52,9 +58,22 @@ func NewProxy(hostIP net.IP, port int, destination string, jwtSecret []byte) *Pr
}()
time.Sleep(100 * time.Millisecond)
log.Info("Starting new proxy", "host", host, "port", port)
- return &Proxy{IP: hostIP, port: port, proxy: proxy, config: &config, callbacks: &callbacks, cancel: cancel}
+ return &Proxy{
+ IP: hostIP,
+ port: port,
+ proxy: proxy,
+ config: &config,
+ callbacks: &callbacks,
+ cancel: cancel,
+ }
}
+func (p *Proxy) Cancel() error {
+ if p.cancel != nil {
+ p.cancel()
+ }
+ return nil
+}
func (p *Proxy) UserRPCAddress() (string, error) {
return fmt.Sprintf("http://%v:%d", p.IP, p.port), nil
}
@@ -63,7 +82,10 @@ func (p *Proxy) EngineRPCAddress() (string, error) {
return fmt.Sprintf("http://%v:%d", p.IP, p.port), nil
}
-func (p *Proxy) AddRequestCallback(method string, callback func([]byte) *proxy.Spoof) {
+func (p *Proxy) AddRequestCallback(
+ method string,
+ callback func([]byte) *proxy.Spoof,
+) {
log.Info("Adding request spoof callback", "method", method)
requestCallbacks := p.callbacks.RequestCallbacks
requestCallbacks[method] = callback
@@ -77,7 +99,10 @@ func (p *Proxy) AddRequest(spoof *proxy.Spoof) {
p.proxy.UpdateSpoofingConfig(p.config)
}
-func (p *Proxy) AddResponseCallback(method string, callback func([]byte, []byte) *proxy.Spoof) {
+func (p *Proxy) AddResponseCallback(
+ method string,
+ callback func([]byte, []byte) *proxy.Spoof,
+) {
log.Info("Adding response spoof callback", "method", method)
responseCallbacks := p.callbacks.ResponseCallbacks
responseCallbacks[method] = callback
@@ -99,3 +124,74 @@ func (p *Proxy) RPC() *rpc.Client {
}
return p.rpc
}
+
+func Combine(a, b *proxy.Spoof) *proxy.Spoof {
+ if a == nil {
+ return b
+ }
+ if b == nil {
+ return a
+ }
+ if a.Method != b.Method {
+ panic(
+ fmt.Errorf(
+ "spoof methods don't match: %s != %s",
+ a.Method,
+ b.Method,
+ ),
+ )
+ }
+ for k, v := range b.Fields {
+ a.Fields[k] = v
+ }
+ return a
+}
+
+// Json helpers
+// A value of this type can a JSON-RPC request, notification, successful response or
+// error response. Which one it is depends on the fields.
+type jsonError struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data interface{} `json:"data,omitempty"`
+}
+
+func (err *jsonError) Error() string {
+ if err.Message == "" {
+ return fmt.Sprintf("json-rpc error %d", err.Code)
+ }
+ return err.Message
+}
+
+type jsonrpcMessage struct {
+ Version string `json:"jsonrpc,omitempty"`
+ ID json.RawMessage `json:"id,omitempty"`
+ Method string `json:"method,omitempty"`
+ Params json.RawMessage `json:"params,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Result json.RawMessage `json:"result,omitempty"`
+}
+
+func UnmarshalFromJsonRPCResponse(b []byte, result interface{}) error {
+ var rpcMessage jsonrpcMessage
+ err := json.Unmarshal(b, &rpcMessage)
+ if err != nil {
+ return err
+ }
+ if rpcMessage.Error != nil {
+ return rpcMessage.Error
+ }
+ return json.Unmarshal(rpcMessage.Result, &result)
+}
+
+func UnmarshalFromJsonRPCRequest(b []byte, params ...interface{}) error {
+ var rpcMessage jsonrpcMessage
+ err := json.Unmarshal(b, &rpcMessage)
+ if err != nil {
+ return err
+ }
+ if rpcMessage.Error != nil {
+ return rpcMessage.Error
+ }
+ return json.Unmarshal(rpcMessage.Params, ¶ms)
+}
diff --git a/simulators/eth2/common/testnet/config.go b/simulators/eth2/common/testnet/config.go
new file mode 100644
index 0000000000..59fd990ddb
--- /dev/null
+++ b/simulators/eth2/common/testnet/config.go
@@ -0,0 +1,99 @@
+package testnet
+
+import (
+ "math/big"
+
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ execution_config "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+)
+
+var (
+ Big0 = big.NewInt(0)
+ Big1 = big.NewInt(1)
+)
+
+type Config struct {
+ AltairForkEpoch *big.Int
+ BellatrixForkEpoch *big.Int
+ CapellaForkEpoch *big.Int
+ ValidatorCount *big.Int
+ KeyTranches *big.Int
+ SlotTime *big.Int
+ TerminalTotalDifficulty *big.Int
+ SafeSlotsToImportOptimistically *big.Int
+ ExtraShares *big.Int
+
+ // Node configurations to launch. Each node as a proportional share of
+ // validators.
+ NodeDefinitions clients.NodeDefinitions
+ Eth1Consensus execution_config.ExecutionConsensus
+
+ // Execution Layer specific config
+ InitialBaseFeePerGas *big.Int
+}
+
+// Choose a configuration value. `b` takes precedence
+func choose(a, b *big.Int) *big.Int {
+ if b != nil {
+ return new(big.Int).Set(b)
+ }
+ if a != nil {
+ return new(big.Int).Set(a)
+ }
+ return nil
+}
+
+// Join two configurations. `b` takes precedence
+func (a *Config) Join(b *Config) *Config {
+ c := Config{}
+ // Forks
+ c.AltairForkEpoch = choose(a.AltairForkEpoch, b.AltairForkEpoch)
+ c.BellatrixForkEpoch = choose(a.BellatrixForkEpoch, b.BellatrixForkEpoch)
+ c.CapellaForkEpoch = choose(a.CapellaForkEpoch, b.CapellaForkEpoch)
+
+ // Testnet config
+ c.ValidatorCount = choose(a.ValidatorCount, b.ValidatorCount)
+ c.KeyTranches = choose(a.KeyTranches, b.KeyTranches)
+ c.SlotTime = choose(a.SlotTime, b.SlotTime)
+ c.TerminalTotalDifficulty = choose(
+ a.TerminalTotalDifficulty,
+ b.TerminalTotalDifficulty,
+ )
+ c.SafeSlotsToImportOptimistically = choose(
+ a.SafeSlotsToImportOptimistically,
+ b.SafeSlotsToImportOptimistically,
+ )
+ c.ExtraShares = choose(a.ExtraShares, b.ExtraShares)
+
+ // EL config
+ c.InitialBaseFeePerGas = choose(
+ a.InitialBaseFeePerGas,
+ b.InitialBaseFeePerGas,
+ )
+
+ if b.NodeDefinitions != nil {
+ c.NodeDefinitions = b.NodeDefinitions
+ } else {
+ c.NodeDefinitions = a.NodeDefinitions
+ }
+
+ if b.Eth1Consensus != nil {
+ c.Eth1Consensus = b.Eth1Consensus
+ } else {
+ c.Eth1Consensus = a.Eth1Consensus
+ }
+
+ return &c
+}
+
+func (c *Config) activeFork() string {
+ if c.CapellaForkEpoch != nil && c.CapellaForkEpoch.Cmp(Big0) == 0 {
+ return "capella"
+ } else if c.BellatrixForkEpoch != nil && c.BellatrixForkEpoch.Cmp(Big0) == 0 {
+ return "bellatrix"
+ } else if c.AltairForkEpoch != nil && c.AltairForkEpoch.Cmp(Big0) == 0 {
+ return "altair"
+ } else {
+ return "phase0"
+ }
+}
diff --git a/simulators/eth2/common/testnet/environment.go b/simulators/eth2/common/testnet/environment.go
new file mode 100644
index 0000000000..9049ac7da3
--- /dev/null
+++ b/simulators/eth2/common/testnet/environment.go
@@ -0,0 +1,13 @@
+package testnet
+
+import (
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ consensus_config "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ blsu "github.com/protolambda/bls12-381-util"
+)
+
+type Environment struct {
+ Clients *clients.ClientDefinitionsByRole
+ Keys []*consensus_config.KeyDetails
+ Secrets *[]blsu.SecretKey
+}
diff --git a/simulators/eth2/engine/prepared_testnet.go b/simulators/eth2/common/testnet/prepared_testnet.go
similarity index 52%
rename from simulators/eth2/engine/prepared_testnet.go
rename to simulators/eth2/common/testnet/prepared_testnet.go
index df31ec6c9c..530865d1d0 100644
--- a/simulators/eth2/engine/prepared_testnet.go
+++ b/simulators/eth2/common/testnet/prepared_testnet.go
@@ -1,6 +1,7 @@
-package main
+package testnet
import (
+ "context"
"encoding/json"
"fmt"
"math/big"
@@ -10,14 +11,18 @@ import (
"github.com/holiman/uint256"
blsu "github.com/protolambda/bls12-381-util"
+ "github.com/protolambda/ztyp/tree"
"github.com/protolambda/ztyp/view"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/params"
"github.com/protolambda/zrnt/eth2/beacon/common"
"github.com/protolambda/zrnt/eth2/configs"
"github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ cl "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
)
var (
@@ -26,7 +31,9 @@ var (
)
func init() {
- _ = depositAddress.UnmarshalText([]byte("0x4242424242424242424242424242424242424242"))
+ _ = depositAddress.UnmarshalText(
+ []byte("0x4242424242424242424242424242424242424242"),
+ )
}
// PreparedTestnet has all the options for starting nodes, ready to build the network.
@@ -35,7 +42,7 @@ type PreparedTestnet struct {
spec *common.Spec
// Execution chain configuration and genesis info
- eth1Genesis *setup.Eth1Genesis
+ eth1Genesis *el.ExecutionGenesis
// Consensus genesis state
eth2Genesis common.BeaconState
// Secret keys of validators, to fabricate extra signed test messages with during testnet/
@@ -48,21 +55,47 @@ type PreparedTestnet struct {
beaconOpts hivesim.StartOption
// A tranche is a group of validator keys to run on 1 node
- keyTranches [][]*setup.KeyDetails
+ keyTranches []map[common.ValidatorIndex]*cl.KeyDetails
+}
+
+// Prepares the fork timestamps of post-merge forks based on the
+// consensus layer genesis time and the fork epochs
+func prepareExecutionForkConfig(
+ eth2GenesisTime common.Timestamp,
+ config *Config,
+) *params.ChainConfig {
+ chainConfig := params.ChainConfig{}
+ if config.CapellaForkEpoch != nil {
+ if config.CapellaForkEpoch.Uint64() == 0 {
+ chainConfig.ShanghaiTime = big.NewInt(int64(eth2GenesisTime))
+ } else {
+ chainConfig.ShanghaiTime = big.NewInt(int64(eth2GenesisTime) + config.SlotTime.Int64()*32)
+ }
+ }
+ return &chainConfig
}
// Build all artifacts require to start a testnet.
-func prepareTestnet(t *hivesim.T, env *testEnv, config *Config) *PreparedTestnet {
+func prepareTestnet(
+ t *hivesim.T,
+ env *Environment,
+ config *Config,
+) *PreparedTestnet {
eth1GenesisTime := common.Timestamp(time.Now().Unix())
eth2GenesisTime := eth1GenesisTime + 30
// Generate genesis for execution clients
- eth1Genesis := setup.BuildEth1Genesis(config.TerminalTotalDifficulty, uint64(eth1GenesisTime), config.Eth1Consensus)
+ eth1Genesis := el.BuildExecutionGenesis(
+ config.TerminalTotalDifficulty,
+ uint64(eth1GenesisTime),
+ config.Eth1Consensus,
+ prepareExecutionForkConfig(eth2GenesisTime, config),
+ )
if config.InitialBaseFeePerGas != nil {
eth1Genesis.Genesis.BaseFee = config.InitialBaseFeePerGas
}
eth1ConfigOpt := eth1Genesis.ToParams(depositAddress)
- eth1Bundle, err := setup.Eth1Bundle(eth1Genesis.Genesis)
+ eth1Bundle, err := el.ExecutionBundle(eth1Genesis.Genesis)
if err != nil {
t.Fatal(err)
}
@@ -71,17 +104,24 @@ func prepareTestnet(t *hivesim.T, env *testEnv, config *Config) *PreparedTestnet
"HIVE_NODETYPE": "full",
}
jwtSecret := hivesim.Params{"HIVE_JWTSECRET": "true"}
- executionOpts := hivesim.Bundle(eth1ConfigOpt, eth1Bundle, execNodeOpts, jwtSecret)
+ executionOpts := hivesim.Bundle(
+ eth1ConfigOpt,
+ eth1Bundle,
+ execNodeOpts,
+ jwtSecret,
+ )
// Pre-generate PoW chains for clients that require it
- for i := 0; i < len(config.Nodes); i++ {
- if config.Nodes[i].ChainGenerator != nil {
- config.Nodes[i].Chain, err = config.Nodes[i].ChainGenerator.Generate(eth1Genesis)
+ for i := 0; i < len(config.NodeDefinitions); i++ {
+ if config.NodeDefinitions[i].ChainGenerator != nil {
+ config.NodeDefinitions[i].Chain, err = config.NodeDefinitions[i].ChainGenerator.Generate(
+ eth1Genesis,
+ )
if err != nil {
t.Fatal(err)
}
fmt.Printf("Generated chain for node %d:\n", i+1)
- for j, b := range config.Nodes[i].Chain {
+ for j, b := range config.NodeDefinitions[i].Chain {
js, _ := json.MarshalIndent(b.Header(), "", " ")
fmt.Printf("Block %d: %s\n", j, js)
}
@@ -95,48 +135,75 @@ func prepareTestnet(t *hivesim.T, env *testEnv, config *Config) *PreparedTestnet
specCpy := *configs.Mainnet
spec := &specCpy
spec.Config.DEPOSIT_CONTRACT_ADDRESS = depositAddress
- spec.Config.DEPOSIT_CHAIN_ID = view.Uint64View(eth1Genesis.Genesis.Config.ChainID.Uint64())
+ spec.Config.DEPOSIT_CHAIN_ID = view.Uint64View(
+ eth1Genesis.Genesis.Config.ChainID.Uint64(),
+ )
spec.Config.DEPOSIT_NETWORK_ID = view.Uint64View(eth1Genesis.NetworkID)
spec.Config.ETH1_FOLLOW_DISTANCE = 1
// Alter versions to avoid conflicts with mainnet values
spec.Config.GENESIS_FORK_VERSION = common.Version{0x00, 0x00, 0x00, 0x0a}
if config.AltairForkEpoch != nil {
- spec.Config.ALTAIR_FORK_EPOCH = common.Epoch(config.AltairForkEpoch.Uint64())
+ spec.Config.ALTAIR_FORK_EPOCH = common.Epoch(
+ config.AltairForkEpoch.Uint64(),
+ )
}
spec.Config.ALTAIR_FORK_VERSION = common.Version{0x01, 0x00, 0x00, 0x0a}
- if config.MergeForkEpoch != nil {
- spec.Config.BELLATRIX_FORK_EPOCH = common.Epoch(config.MergeForkEpoch.Uint64())
+ if config.BellatrixForkEpoch != nil {
+ spec.Config.BELLATRIX_FORK_EPOCH = common.Epoch(
+ config.BellatrixForkEpoch.Uint64(),
+ )
}
spec.Config.BELLATRIX_FORK_VERSION = common.Version{0x02, 0x00, 0x00, 0x0a}
- // TODO: Requires https://github.com/protolambda/zrnt/pull/38
- /*
- if config.CapellaForkEpoch != nil {
- spec.Config.CAPELLA_FORK_EPOCH = common.Epoch(config.CapellaForkEpoch.Uint64())
- }
- spec.Config.CAPELLA_FORK_VERSION = common.Version{0x03, 0x00, 0x00, 0x0a}
- */
- spec.Config.SHARDING_FORK_VERSION = common.Version{0x04, 0x00, 0x00, 0x0a}
+ if config.CapellaForkEpoch != nil {
+ spec.Config.CAPELLA_FORK_EPOCH = common.Epoch(
+ config.CapellaForkEpoch.Uint64(),
+ )
+ }
+ spec.Config.CAPELLA_FORK_VERSION = common.Version{0x03, 0x00, 0x00, 0x0a}
+ spec.Config.DENEB_FORK_VERSION = common.Version{0x04, 0x00, 0x00, 0x0a}
if config.ValidatorCount == nil {
t.Fatal(fmt.Errorf("ValidatorCount was not configured"))
}
- spec.Config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT = view.Uint64View(config.ValidatorCount.Uint64())
+ spec.Config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT = view.Uint64View(
+ config.ValidatorCount.Uint64(),
+ )
if config.SlotTime != nil {
- spec.Config.SECONDS_PER_SLOT = common.Timestamp(config.SlotTime.Uint64())
+ spec.Config.SECONDS_PER_SLOT = common.Timestamp(
+ config.SlotTime.Uint64(),
+ )
}
tdd, _ := uint256.FromBig(config.TerminalTotalDifficulty)
spec.Config.TERMINAL_TOTAL_DIFFICULTY = view.Uint256View(*tdd)
+ if el.IsEth1GenesisPostMerge(eth1Genesis.Genesis) {
+ genesisBlock := eth1Genesis.Genesis.ToBlock()
+ spec.Config.TERMINAL_BLOCK_HASH = tree.Root(
+ genesisBlock.Hash(),
+ )
+ spec.Config.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH = common.Timestamp(0)
+ }
+
+ // Validators can exit immediately
+ spec.Config.SHARD_COMMITTEE_PERIOD = 0
+ spec.Config.CHURN_LIMIT_QUOTIENT = 2
+
+ // Validators can withdraw immediately
+ spec.Config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 0
// Generate keys opts for validators
- shares := config.Nodes.Shares()
+ shares := config.NodeDefinitions.Shares()
// ExtraShares defines an extra set of keys that none of the nodes will have.
// E.g. to produce an environment where none of the nodes has 50%+ of the keys.
if config.ExtraShares != nil {
shares = append(shares, config.ExtraShares.Uint64())
}
- keyTranches := setup.KeyTranches(env.Keys, shares)
+ keyTranches := cl.KeyTranches(env.Keys, shares)
- consensusConfigOpts, err := setup.ConsensusConfigsBundle(spec, eth1Genesis.Genesis, config.ValidatorCount.Uint64())
+ consensusConfigOpts, err := cl.ConsensusConfigsBundle(
+ spec,
+ eth1Genesis.Genesis,
+ config.ValidatorCount.Uint64(),
+ )
if err != nil {
t.Fatal(err)
}
@@ -145,34 +212,57 @@ func prepareTestnet(t *hivesim.T, env *testEnv, config *Config) *PreparedTestnet
if config.SafeSlotsToImportOptimistically == nil {
config.SafeSlotsToImportOptimistically = DEFAULT_SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
}
- optimisticSync = optimisticSync.Set("HIVE_ETH2_SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY", fmt.Sprintf("%d", config.SafeSlotsToImportOptimistically))
+ optimisticSync = optimisticSync.Set(
+ "HIVE_ETH2_SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY",
+ fmt.Sprintf("%d", config.SafeSlotsToImportOptimistically),
+ )
// prepare genesis beacon state, with all the validators in it.
- state, err := setup.BuildBeaconState(spec, eth1Genesis.Genesis, eth2GenesisTime, env.Keys)
+ state, err := cl.BuildBeaconState(
+ spec,
+ eth1Genesis.Genesis,
+ eth2GenesisTime,
+ env.Keys,
+ )
if err != nil {
t.Fatal(err)
}
// Write info so that the genesis state can be generated by the client
- stateOpt, err := setup.StateBundle(state)
+ stateOpt, err := cl.StateBundle(state)
if err != nil {
t.Fatal(err)
}
// Define additional start options for beacon chain
commonOpts := hivesim.Params{
- "HIVE_ETH2_BN_API_PORT": fmt.Sprintf("%d", PortBeaconAPI),
- "HIVE_ETH2_BN_GRPC_PORT": fmt.Sprintf("%d", PortBeaconGRPC),
- "HIVE_ETH2_METRICS_PORT": fmt.Sprintf("%d", PortMetrics),
+ "HIVE_ETH2_BN_API_PORT": fmt.Sprintf(
+ "%d",
+ clients.PortBeaconAPI,
+ ),
+ "HIVE_ETH2_BN_GRPC_PORT": fmt.Sprintf(
+ "%d",
+ clients.PortBeaconGRPC,
+ ),
+ "HIVE_ETH2_METRICS_PORT": fmt.Sprintf(
+ "%d",
+ clients.PortMetrics,
+ ),
"HIVE_ETH2_CONFIG_DEPOSIT_CONTRACT_ADDRESS": depositAddress.String(),
}
beaconOpts := hivesim.Bundle(
commonOpts,
hivesim.Params{
- "HIVE_CHECK_LIVE_PORT": fmt.Sprintf("%d", PortBeaconAPI),
- "HIVE_ETH2_MERGE_ENABLED": "1",
- "HIVE_ETH2_ETH1_GENESIS_TIME": fmt.Sprintf("%d", eth1Genesis.Genesis.Timestamp),
- "HIVE_ETH2_GENESIS_FORK": config.activeFork(),
+ "HIVE_CHECK_LIVE_PORT": fmt.Sprintf(
+ "%d",
+ clients.PortBeaconAPI,
+ ),
+ "HIVE_ETH2_MERGE_ENABLED": "1",
+ "HIVE_ETH2_ETH1_GENESIS_TIME": fmt.Sprintf(
+ "%d",
+ eth1Genesis.Genesis.Timestamp,
+ ),
+ "HIVE_ETH2_GENESIS_FORK": config.activeFork(),
},
stateOpt,
consensusConfigOpts,
@@ -208,13 +298,27 @@ func (p *PreparedTestnet) createTestnet(t *hivesim.T) *Testnet {
genesisValidatorsRoot: genesisValidatorsRoot,
spec: p.spec,
eth1Genesis: p.eth1Genesis,
+ eth2GenesisState: p.eth2Genesis,
}
}
// Prepares an execution client object with all the necessary information
// to start
-func (p *PreparedTestnet) prepareExecutionNode(testnet *Testnet, eth1Def *hivesim.ClientDefinition, consensus setup.Eth1Consensus, ttd *big.Int, executionIndex int, chain []*types.Block, subnet string) *ExecutionClient {
- testnet.Logf("Preparing execution node: %s (%s)", eth1Def.Name, eth1Def.Version)
+func (p *PreparedTestnet) prepareExecutionNode(
+ parentCtx context.Context,
+ testnet *Testnet,
+ eth1Def *hivesim.ClientDefinition,
+ consensus el.ExecutionConsensus,
+ ttd *big.Int,
+ executionIndex int,
+ chain []*types.Block,
+ subnet string,
+) *clients.ExecutionClient {
+ testnet.Logf(
+ "Preparing execution node: %s (%s)",
+ eth1Def.Name,
+ eth1Def.Version,
+ )
// This method will return the options used to run the client.
// Requires a method that returns the rest of the currently running
@@ -223,7 +327,9 @@ func (p *PreparedTestnet) prepareExecutionNode(testnet *Testnet, eth1Def *hivesi
opts := []hivesim.StartOption{p.executionOpts}
opts = append(opts, consensus.HiveParams(executionIndex))
- currentlyRunningEcs := testnet.ExecutionClients().Running().Subnet(subnet)
+ currentlyRunningEcs := testnet.ExecutionClients().
+ Running().
+ Subnet(subnet)
if len(currentlyRunningEcs) > 0 {
bootnode, err := currentlyRunningEcs.Enodes()
if err != nil {
@@ -234,11 +340,43 @@ func (p *PreparedTestnet) prepareExecutionNode(testnet *Testnet, eth1Def *hivesi
opts = append(opts, hivesim.Params{"HIVE_BOOTNODE": bootnode})
}
if ttd != nil {
- opts = append(opts, hivesim.Params{"HIVE_TERMINAL_TOTAL_DIFFICULTY": fmt.Sprintf("%d", ttd.Int64())})
+ opts = append(
+ opts,
+ hivesim.Params{
+ "HIVE_TERMINAL_TOTAL_DIFFICULTY": fmt.Sprintf(
+ "%d",
+ ttd.Int64(),
+ ),
+ },
+ )
+ } else {
+ genesis := testnet.ExecutionGenesis()
+ genesisBlock := genesis.ToBlock()
+ if genesis.Config.TerminalTotalDifficulty.Cmp(genesisBlock.Difficulty()) <= 0 {
+ opts = append(
+ opts,
+ hivesim.Params{
+ "HIVE_TERMINAL_BLOCK_HASH": fmt.Sprintf(
+ "%s",
+ genesisBlock.Hash(),
+ ),
+ },
+ )
+ opts = append(
+ opts,
+ hivesim.Params{
+ "HIVE_TERMINAL_BLOCK_NUMBER": fmt.Sprintf(
+ "%d",
+ genesisBlock.NumberU64(),
+ ),
+ },
+ )
+ }
}
- if chain != nil && len(chain) > 0 {
+
+ if len(chain) > 0 {
// Bundle the chain into the container
- chainParam, err := setup.ChainBundle(chain)
+ chainParam, err := el.ChainBundle(chain)
if err != nil {
return nil, err
}
@@ -246,19 +384,36 @@ func (p *PreparedTestnet) prepareExecutionNode(testnet *Testnet, eth1Def *hivesi
}
return opts, nil
}
- return NewExecutionClient(testnet.T, eth1Def, optionsGenerator, PortEngineRPC+executionIndex, subnet)
+ return clients.NewExecutionClient(
+ testnet.T,
+ eth1Def,
+ optionsGenerator,
+ clients.PortEngineRPC+executionIndex,
+ subnet,
+ ttd,
+ )
}
// Prepares a beacon client object with all the necessary information
// to start
-func (p *PreparedTestnet) prepareBeaconNode(testnet *Testnet, beaconDef *hivesim.ClientDefinition, ttd *big.Int, beaconIndex int, eth1Endpoints ...*ExecutionClient) *BeaconClient {
- testnet.Logf("Preparing beacon node: %s (%s)", beaconDef.Name, beaconDef.Version)
+func (p *PreparedTestnet) prepareBeaconNode(
+ parentCtx context.Context,
+ testnet *Testnet,
+ beaconDef *hivesim.ClientDefinition,
+ ttd *big.Int,
+ beaconIndex int,
+ eth1Endpoints ...*clients.ExecutionClient,
+) *clients.BeaconClient {
+ testnet.Logf(
+ "Preparing beacon node: %s (%s)",
+ beaconDef.Name,
+ beaconDef.Version,
+ )
// This method will return the options used to run the client.
// Requires a method that returns the rest of the currently running
// beacon clients on the network at startup.
optionsGenerator := func() ([]hivesim.StartOption, error) {
-
opts := []hivesim.StartOption{p.beaconOpts}
// Hook up beacon node to (maybe multiple) eth1 nodes
@@ -266,17 +421,25 @@ func (p *PreparedTestnet) prepareBeaconNode(testnet *Testnet, beaconDef *hivesim
var engineAddrs []string
for _, en := range eth1Endpoints {
if !en.IsRunning() || en.Proxy() == nil {
- return nil, fmt.Errorf("Attempted to start beacon node when the execution client is not yet running")
+ return nil, fmt.Errorf(
+ "attempted to start beacon node when the execution client is not yet running",
+ )
}
execNode := en.Proxy()
userRPC, err := execNode.UserRPCAddress()
if err != nil {
- return nil, fmt.Errorf("eth1 node used for beacon without available RPC: %v", err)
+ return nil, fmt.Errorf(
+ "eth1 node used for beacon without available RPC: %v",
+ err,
+ )
}
addrs = append(addrs, userRPC)
engineRPC, err := execNode.EngineRPCAddress()
if err != nil {
- return nil, fmt.Errorf("eth1 node used for beacon without available RPC: %v", err)
+ return nil, fmt.Errorf(
+ "eth1 node used for beacon without available RPC: %v",
+ err,
+ )
}
engineAddrs = append(engineAddrs, engineRPC)
}
@@ -286,20 +449,31 @@ func (p *PreparedTestnet) prepareBeaconNode(testnet *Testnet, beaconDef *hivesim
"HIVE_ETH2_BEACON_NODE_INDEX": fmt.Sprintf("%d", beaconIndex),
})
- if bootnodeENRs, err := testnet.BeaconClients().Running().ENRs(); err != nil {
- return nil, fmt.Errorf("failed to get ENR as bootnode for every beacon node: %v", err)
+ if bootnodeENRs, err := testnet.BeaconClients().Running().ENRs(parentCtx); err != nil {
+ return nil, fmt.Errorf(
+ "failed to get ENR as bootnode for every beacon node: %v",
+ err,
+ )
} else if bootnodeENRs != "" {
opts = append(opts, hivesim.Params{"HIVE_ETH2_BOOTNODE_ENRS": bootnodeENRs})
}
- if staticPeers, err := testnet.BeaconClients().Running().P2PAddrs(); err != nil {
- return nil, fmt.Errorf("failed to get p2paddr for every beacon node: %v", err)
+ if staticPeers, err := testnet.BeaconClients().Running().P2PAddrs(parentCtx); err != nil {
+ return nil, fmt.Errorf(
+ "failed to get p2paddr for every beacon node: %v",
+ err,
+ )
} else if staticPeers != "" {
opts = append(opts, hivesim.Params{"HIVE_ETH2_STATIC_PEERS": staticPeers})
}
if ttd != nil {
- opts = append(opts, hivesim.Params{"HIVE_TERMINAL_TOTAL_DIFFICULTY": fmt.Sprintf("%d", ttd)})
+ opts = append(
+ opts,
+ hivesim.Params{
+ "HIVE_TERMINAL_TOTAL_DIFFICULTY": fmt.Sprintf("%d", ttd),
+ },
+ )
}
return opts, nil
}
@@ -308,27 +482,51 @@ func (p *PreparedTestnet) prepareBeaconNode(testnet *Testnet, beaconDef *hivesim
//if p.configName != "mainnet" && hasBuildTarget(beaconDef, p.configName) {
// opts = append(opts, hivesim.WithBuildTarget(p.configName))
//}
- return NewBeaconClient(testnet.T, beaconDef, optionsGenerator, testnet.genesisTime, testnet.spec, beaconIndex)
+ return clients.NewBeaconClient(
+ testnet.T,
+ beaconDef,
+ optionsGenerator,
+ testnet.genesisTime,
+ testnet.spec,
+ beaconIndex,
+ testnet.genesisValidatorsRoot,
+ )
}
// Prepares a validator client object with all the necessary information
// to eventually start the client.
-func (p *PreparedTestnet) prepareValidatorClient(testnet *Testnet, validatorDef *hivesim.ClientDefinition, bn *BeaconClient, keyIndex int) *ValidatorClient {
- testnet.Logf("Preparing validator client: %s (%s)", validatorDef.Name, validatorDef.Version)
+func (p *PreparedTestnet) prepareValidatorClient(
+ parentCtx context.Context,
+ testnet *Testnet,
+ validatorDef *hivesim.ClientDefinition,
+ bn *clients.BeaconClient,
+ keyIndex int,
+) *clients.ValidatorClient {
+ testnet.Logf(
+ "Preparing validator client: %s (%s)",
+ validatorDef.Name,
+ validatorDef.Version,
+ )
if keyIndex >= len(p.keyTranches) {
- testnet.Fatalf("only have %d key tranches, cannot find index %d for VC", len(p.keyTranches), keyIndex)
+ testnet.Fatalf(
+ "only have %d key tranches, cannot find index %d for VC",
+ len(p.keyTranches),
+ keyIndex,
+ )
}
// This method will return the options used to run the client.
// Requires the beacon client object to which to connect.
- optionsGenerator := func(validatorKeys []*setup.KeyDetails) ([]hivesim.StartOption, error) {
+ optionsGenerator := func(validatorKeys map[common.ValidatorIndex]*cl.KeyDetails) ([]hivesim.StartOption, error) {
if !bn.IsRunning() {
- return nil, fmt.Errorf("Attempted to start a validator when the beacon node is not running")
+ return nil, fmt.Errorf(
+ "attempted to start a validator when the beacon node is not running",
+ )
}
// Hook up validator to beacon node
bnAPIOpt := hivesim.Params{
"HIVE_ETH2_BN_API_IP": bn.HiveClient.IP.String(),
}
- keysOpt := setup.KeysBundle(validatorKeys)
+ keysOpt := cl.KeysBundle(validatorKeys)
opts := []hivesim.StartOption{p.validatorOpts, keysOpt, bnAPIOpt}
// TODO
//if p.configName != "mainnet" && hasBuildTarget(validatorDef, p.configName) {
@@ -336,5 +534,10 @@ func (p *PreparedTestnet) prepareValidatorClient(testnet *Testnet, validatorDef
//}
return opts, nil
}
- return NewValidatorClient(testnet.T, validatorDef, optionsGenerator, p.keyTranches[keyIndex])
+ return clients.NewValidatorClient(
+ testnet.T,
+ validatorDef,
+ optionsGenerator,
+ p.keyTranches[keyIndex],
+ )
}
diff --git a/simulators/eth2/common/testnet/running_testnet.go b/simulators/eth2/common/testnet/running_testnet.go
new file mode 100644
index 0000000000..4c85268e56
--- /dev/null
+++ b/simulators/eth2/common/testnet/running_testnet.go
@@ -0,0 +1,1129 @@
+package testnet
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+
+ "github.com/protolambda/eth2api"
+ "github.com/protolambda/zrnt/eth2/beacon/altair"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/zrnt/eth2/beacon/phase0"
+ "github.com/protolambda/zrnt/eth2/util/math"
+
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ execution_config "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+ "github.com/ethereum/hive/simulators/eth2/common/utils"
+)
+
+var MAX_PARTICIPATION_SCORE = 7
+
+type Testnet struct {
+ *hivesim.T
+ clients.Nodes
+
+ genesisTime common.Timestamp
+ genesisValidatorsRoot common.Root
+
+ // Consensus chain configuration
+ spec *common.Spec
+ // Execution chain configuration and genesis info
+ eth1Genesis *execution_config.ExecutionGenesis
+ // Consensus genesis state
+ eth2GenesisState common.BeaconState
+}
+
+type ActiveSpec struct {
+ *common.Spec
+}
+
+func (spec *ActiveSpec) EpochTimeoutContext(
+ parent context.Context,
+ epochs common.Epoch,
+) (context.Context, context.CancelFunc) {
+ return context.WithTimeout(
+ parent,
+ time.Duration(
+ uint64(spec.SLOTS_PER_EPOCH*common.Slot(epochs))*
+ uint64(spec.SECONDS_PER_SLOT),
+ )*time.Second,
+ )
+}
+
+func (spec *ActiveSpec) SlotTimeoutContext(
+ parent context.Context,
+ slots common.Slot,
+) (context.Context, context.CancelFunc) {
+ return context.WithTimeout(
+ parent,
+ time.Duration(
+ uint64(slots)*
+ uint64(spec.SECONDS_PER_SLOT))*time.Second,
+ )
+}
+
+func (spec *ActiveSpec) EpochsTimeout(epochs common.Epoch) <-chan time.Time {
+ return time.After(
+ time.Duration(
+ uint64(
+ spec.SLOTS_PER_EPOCH*common.Slot(epochs),
+ )*uint64(
+ spec.SECONDS_PER_SLOT,
+ ),
+ ) * time.Second,
+ )
+}
+
+func (spec *ActiveSpec) SlotsTimeout(slots common.Slot) <-chan time.Time {
+ return time.After(
+ time.Duration(
+ uint64(slots)*uint64(spec.SECONDS_PER_SLOT),
+ ) * time.Second,
+ )
+}
+
+func (t *Testnet) Spec() *ActiveSpec {
+ return &ActiveSpec{
+ Spec: t.spec,
+ }
+}
+
+func (t *Testnet) GenesisTime() common.Timestamp {
+ // return time.Unix(int64(t.genesisTime), 0)
+ return t.genesisTime
+}
+
+func (t *Testnet) GenesisTimeUnix() time.Time {
+ return time.Unix(int64(t.genesisTime), 0)
+}
+
+func (t *Testnet) GenesisBeaconState() common.BeaconState {
+ return t.eth2GenesisState
+}
+
+func (t *Testnet) GenesisValidatorsRoot() common.Root {
+ return t.genesisValidatorsRoot
+}
+
+func (t *Testnet) ExecutionGenesis() *core.Genesis {
+ return t.eth1Genesis.Genesis
+}
+
+func StartTestnet(
+ parentCtx context.Context,
+ t *hivesim.T,
+ env *Environment,
+ config *Config,
+) *Testnet {
+ prep := prepareTestnet(t, env, config)
+ testnet := prep.createTestnet(t)
+ genesisTime := testnet.GenesisTimeUnix()
+ countdown := time.Until(genesisTime)
+ t.Logf(
+ "Created new testnet, genesis at %s (%s from now)",
+ genesisTime,
+ countdown,
+ )
+
+ testnet.Nodes = make(clients.Nodes, len(config.NodeDefinitions))
+
+ // Init all client bundles
+ for nodeIndex := range testnet.Nodes {
+ testnet.Nodes[nodeIndex] = new(clients.Node)
+ }
+
+ // For each key partition, we start a client bundle that consists of:
+ // - 1 execution client
+ // - 1 beacon client
+ // - 1 validator client,
+ for nodeIndex, node := range config.NodeDefinitions {
+ // Prepare clients for this node
+ var (
+ nodeClient = testnet.Nodes[nodeIndex]
+
+ executionDef = env.Clients.ClientByNameAndRole(
+ node.ExecutionClientName(),
+ "eth1",
+ )
+ beaconDef = env.Clients.ClientByNameAndRole(
+ node.ConsensusClientName(),
+ "beacon",
+ )
+ validatorDef = env.Clients.ClientByNameAndRole(
+ node.ValidatorClientName(),
+ "validator",
+ )
+ )
+
+ if executionDef == nil || beaconDef == nil || validatorDef == nil {
+ t.Fatalf("FAIL: Unable to get client")
+ }
+
+ // Prepare the client objects with all the information necessary to
+ // eventually start
+ nodeClient.ExecutionClient = prep.prepareExecutionNode(
+ parentCtx,
+ testnet,
+ executionDef,
+ config.Eth1Consensus,
+ node.ExecutionClientTTD,
+ nodeIndex,
+ node.Chain,
+ node.ExecutionSubnet,
+ )
+
+ if node.ConsensusClient != "" {
+ nodeClient.BeaconClient = prep.prepareBeaconNode(
+ parentCtx,
+ testnet,
+ beaconDef,
+ node.BeaconNodeTTD,
+ nodeIndex,
+ nodeClient.ExecutionClient,
+ )
+
+ nodeClient.ValidatorClient = prep.prepareValidatorClient(
+ parentCtx,
+ testnet,
+ validatorDef,
+ nodeClient.BeaconClient,
+ nodeIndex,
+ )
+ }
+
+ // Add rest of properties
+ nodeClient.T = t
+ nodeClient.Index = nodeIndex
+ nodeClient.Verification = node.TestVerificationNode
+
+ // Start the node clients if specified so
+ if !node.DisableStartup {
+ nodeClient.Start()
+ }
+ }
+
+ return testnet
+}
+
+func (t *Testnet) Stop() {
+ for _, p := range t.Proxies().Running() {
+ p.Cancel()
+ }
+}
+
+func (t *Testnet) ValidatorClientIndex(pk [48]byte) (int, error) {
+ for i, v := range t.ValidatorClients() {
+ if v.ContainsKey(pk) {
+ return i, nil
+ }
+ }
+ return 0, fmt.Errorf("key not found in any validator client")
+}
+
+// Wait until the beacon chain genesis happens.
+func (t *Testnet) WaitForGenesis(ctx context.Context) {
+ genesis := t.GenesisTimeUnix()
+ select {
+ case <-ctx.Done():
+ case <-time.After(time.Until(genesis)):
+ }
+}
+
+// Wait a certain amount of slots while printing the current status.
+func (t *Testnet) WaitSlots(ctx context.Context, slots common.Slot) error {
+ for s := common.Slot(0); s < slots; s++ {
+ t.BeaconClients().Running().PrintStatus(ctx, t)
+ select {
+ case <-time.After(time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second):
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+ }
+ return nil
+}
+
+// WaitForFork blocks until a beacon client reaches specified fork,
+// or context finalizes, whichever happens first.
+func (t *Testnet) WaitForFork(ctx context.Context, fork string) error {
+ genesis := t.GenesisTimeUnix()
+ slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+ runningNodes := t.VerificationNodes().Running()
+ done := make(chan error, len(runningNodes))
+ for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case err := <-done:
+ return err
+ case tim := <-timer.C:
+ // start polling after first slot of genesis
+ if tim.Before(genesis.Add(slotDuration)) {
+ t.Logf("Time till genesis: %s", genesis.Sub(tim))
+ continue
+ }
+
+ // new slot, log and check status of all beacon nodes
+ type res struct {
+ idx int
+ msg string
+ err error
+ }
+ var (
+ wg sync.WaitGroup
+ ch = make(chan res, len(runningNodes))
+ )
+ for i, n := range runningNodes {
+ wg.Add(1)
+ go func(
+ ctx context.Context,
+ i int,
+ n *clients.Node,
+ ch chan res,
+ ) {
+ defer wg.Done()
+
+ var (
+ b = n.BeaconClient
+ slot common.Slot
+ head string
+ justified string
+ finalized string
+ execution = "0x0000..0000"
+ )
+
+ headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s): failed to poll head: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+
+ checkpoints, err := b.BlockFinalityCheckpoints(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ ch <- res{err: fmt.Errorf("node %d (%s) failed to poll finality checkpoint: %v", i, n.ClientNames(), err)}
+ return
+ }
+
+ versionedBlock, err := b.BlockV2(
+ ctx,
+ eth2api.BlockIdRoot(headInfo.Root),
+ )
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to retrieve block: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = utils.Shorten(
+ executionPayload.BlockHash.String(),
+ )
+ }
+
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+ justified = utils.Shorten(
+ checkpoints.CurrentJustified.String(),
+ )
+ finalized = utils.Shorten(checkpoints.Finalized.String())
+
+ ch <- res{
+ i,
+ fmt.Sprintf(
+ "node %d (%s) fork=%s, slot=%d, head=%s, exec_payload=%s, justified=%s, finalized=%s",
+ i,
+ n.ClientNames(),
+ versionedBlock.Version,
+ slot,
+ head,
+ execution,
+ justified,
+ finalized,
+ ),
+ nil,
+ }
+
+ if versionedBlock.Version == fork {
+ done <- nil
+ }
+ }(ctx, i, n, ch)
+ }
+ wg.Wait()
+ close(ch)
+
+ // print out logs in ascending idx order
+ sorted := make([]string, len(runningNodes))
+ for out := range ch {
+ if out.err != nil {
+ return out.err
+ }
+ sorted[out.idx] = out.msg
+ }
+ for _, msg := range sorted {
+ t.Logf(msg)
+ }
+ }
+ }
+}
+
+// WaitForFinality blocks until a beacon client reaches finality,
+// or timeoutSlots have passed, whichever happens first.
+func (t *Testnet) WaitForFinality(ctx context.Context) (
+ common.Checkpoint, error,
+) {
+ genesis := t.GenesisTimeUnix()
+ slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+ runningNodes := t.VerificationNodes().Running()
+ done := make(chan common.Checkpoint, len(runningNodes))
+ for {
+ select {
+ case <-ctx.Done():
+ return common.Checkpoint{}, ctx.Err()
+ case finalized := <-done:
+ return finalized, nil
+ case tim := <-timer.C:
+ // start polling after first slot of genesis
+ if tim.Before(genesis.Add(slotDuration)) {
+ t.Logf("Time till genesis: %s", genesis.Sub(tim))
+ continue
+ }
+
+ // new slot, log and check status of all beacon nodes
+ type res struct {
+ idx int
+ msg string
+ err error
+ }
+ var (
+ wg sync.WaitGroup
+ ch = make(chan res, len(runningNodes))
+ )
+ for i, n := range runningNodes {
+ wg.Add(1)
+ go func(
+ ctx context.Context,
+ i int,
+ n *clients.Node,
+ ch chan res,
+ ) {
+ defer wg.Done()
+
+ var (
+ b = n.BeaconClient
+ slot common.Slot
+ head string
+ justified string
+ finalized string
+ health float64
+ execution = "0x0000..0000"
+ )
+
+ headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll head: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+
+ checkpoints, err := b.BlockFinalityCheckpoints(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll finality checkpoint: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+
+ versionedBlock, err := b.BlockV2(
+ ctx,
+ eth2api.BlockIdRoot(headInfo.Root),
+ )
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to retrieve block: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = utils.Shorten(
+ executionPayload.BlockHash.String(),
+ )
+ }
+
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+ justified = utils.Shorten(
+ checkpoints.CurrentJustified.String(),
+ )
+ finalized = utils.Shorten(checkpoints.Finalized.String())
+ health, err = GetHealth(ctx, b, t.spec, slot)
+ if err != nil {
+ // warning is printed here instead because some clients
+ // don't support the required REST endpoint.
+ fmt.Printf(
+ "WARN: node %d (%s) %s\n",
+ i,
+ n.ClientNames(),
+ err,
+ )
+ }
+
+ ep := t.spec.SlotToEpoch(slot)
+ if ep > 4 && ep > checkpoints.Finalized.Epoch+2 {
+ ch <- res{
+ err: fmt.Errorf(
+ "failed to finalize, head slot %d (epoch %d) "+
+ "is more than 2 ahead of finality checkpoint %d",
+ slot,
+ ep,
+ checkpoints.Finalized.Epoch,
+ ),
+ }
+ } else {
+ ch <- res{
+ i,
+ fmt.Sprintf(
+ "node %d (%s) fork=%s, slot=%d, head=%s, "+
+ "health=%.2f, exec_payload=%s, justified=%s, "+
+ "finalized=%s",
+ i,
+ n.ClientNames(),
+ versionedBlock.Version,
+ slot,
+ head,
+ health,
+ execution,
+ justified,
+ finalized,
+ ),
+ nil,
+ }
+ }
+
+ if (checkpoints.Finalized != common.Checkpoint{}) {
+ done <- checkpoints.Finalized
+ }
+ }(ctx, i, n, ch)
+ }
+ wg.Wait()
+ close(ch)
+
+ // print out logs in ascending idx order
+ sorted := make([]string, len(runningNodes))
+ for out := range ch {
+ if out.err != nil {
+ return common.Checkpoint{}, out.err
+ }
+ sorted[out.idx] = out.msg
+ }
+ for _, msg := range sorted {
+ t.Logf(msg)
+ }
+ }
+ }
+}
+
+// WaitForExecutionFinality blocks until a beacon client reaches finality
+// and the finality checkpoint contains an execution payload,
+// or timeoutSlots have passed, whichever happens first.
+func (t *Testnet) WaitForExecutionFinality(
+ ctx context.Context,
+) (common.Checkpoint, error) {
+ genesis := t.GenesisTimeUnix()
+ slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+ runningNodes := t.VerificationNodes().Running()
+ done := make(chan common.Checkpoint, len(runningNodes))
+ for {
+ select {
+ case <-ctx.Done():
+ return common.Checkpoint{}, ctx.Err()
+ case finalized := <-done:
+ return finalized, nil
+ case tim := <-timer.C:
+ // start polling after first slot of genesis
+ if tim.Before(genesis.Add(slotDuration)) {
+ t.Logf("Time till genesis: %s", genesis.Sub(tim))
+ continue
+ }
+
+ // new slot, log and check status of all beacon nodes
+ type res struct {
+ idx int
+ msg string
+ err error
+ }
+ var (
+ wg sync.WaitGroup
+ ch = make(chan res, len(runningNodes))
+ )
+ for i, n := range runningNodes {
+ wg.Add(1)
+ go func(ctx context.Context, i int, n *clients.Node, ch chan res) {
+ defer wg.Done()
+ var (
+ b = n.BeaconClient
+ slot common.Slot
+ version string
+ head string
+ justified string
+ finalized string
+ )
+
+ headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll head: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+
+ checkpoints, err := b.BlockFinalityCheckpoints(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll finality checkpoint: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ justified = utils.Shorten(
+ checkpoints.CurrentJustified.String(),
+ )
+ finalized = utils.Shorten(checkpoints.Finalized.String())
+
+ var (
+ execution ethcommon.Hash
+ executionStr = "0x0000..0000"
+ )
+
+ if (checkpoints.Finalized != common.Checkpoint{}) {
+ if versionedBlock, err := b.BlockV2(
+ ctx,
+ eth2api.BlockIdRoot(checkpoints.Finalized.Root),
+ ); err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to retrieve block: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ } else {
+ version = versionedBlock.Version
+ if exeuctionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ execution = exeuctionPayload.BlockHash
+ executionStr = utils.Shorten(execution.Hex())
+ }
+ }
+ }
+
+ ch <- res{
+ i,
+ fmt.Sprintf("node %d (%s) fork=%s, slot=%d, head=%s, "+"finalized_exec_payload=%s, justified=%s, finalized=%s",
+ i,
+ n.ClientNames(),
+ version,
+ slot,
+ head,
+ executionStr,
+ justified,
+ finalized,
+ ),
+ nil,
+ }
+ emptyHash := ethcommon.Hash{}
+ if !bytes.Equal(execution[:], emptyHash[:]) {
+ done <- checkpoints.Finalized
+ }
+ }(
+ ctx,
+ i,
+ n,
+ ch,
+ )
+ }
+ wg.Wait()
+ close(ch)
+
+ // print out logs in ascending idx order
+ sorted := make([]string, len(runningNodes))
+ for out := range ch {
+ if out.err != nil {
+ return common.Checkpoint{}, out.err
+ }
+ sorted[out.idx] = out.msg
+ }
+ for _, msg := range sorted {
+ t.Logf(msg)
+ }
+ }
+ }
+}
+
+// Waits for the current epoch to be finalized, or timeoutSlots have passed, whichever happens first.
+func (t *Testnet) WaitForCurrentEpochFinalization(
+ ctx context.Context,
+) (common.Checkpoint, error) {
+ genesis := t.GenesisTimeUnix()
+ slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+ runningNodes := t.VerificationNodes().Running()
+ done := make(chan common.Checkpoint, len(runningNodes))
+
+ // Get the current head root which must be finalized
+ headInfo, err := runningNodes[0].BeaconClient.BlockHeader(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ return common.Checkpoint{}, fmt.Errorf("failed to poll head: %v", err)
+ }
+ epochToBeFinalized := t.spec.SlotToEpoch(headInfo.Header.Message.Slot)
+
+ for {
+ select {
+ case <-ctx.Done():
+ return common.Checkpoint{}, ctx.Err()
+ case finalized := <-done:
+ return finalized, nil
+ case tim := <-timer.C:
+ // start polling after first slot of genesis
+ if tim.Before(genesis.Add(slotDuration)) {
+ t.Logf("Time till genesis: %s", genesis.Sub(tim))
+ continue
+ }
+
+ // new slot, log and check status of all beacon nodes
+ type res struct {
+ idx int
+ msg string
+ err error
+ }
+ var (
+ wg sync.WaitGroup
+ ch = make(chan res, len(runningNodes))
+ )
+ for i, n := range runningNodes {
+ wg.Add(1)
+ go func(ctx context.Context, i int, n *clients.Node, ch chan res) {
+ defer wg.Done()
+
+ var (
+ b = n.BeaconClient
+ slot common.Slot
+ head string
+ justified string
+ finalized string
+ )
+
+ headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll head: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+
+ checkpoints, err := b.BlockFinalityCheckpoints(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s) failed to poll finality checkpoint: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ justified = utils.Shorten(
+ checkpoints.CurrentJustified.String(),
+ )
+ finalized = utils.Shorten(checkpoints.Finalized.String())
+
+ ch <- res{
+ i,
+ fmt.Sprintf(
+ "node %d (%s) slot=%d, head=%s justified=%s, "+
+ "finalized=%s, epoch_to_finalize=%d",
+ i,
+ n.ClientNames(),
+ slot,
+ head,
+ justified,
+ finalized,
+ epochToBeFinalized,
+ ),
+ nil,
+ }
+
+ if checkpoints.Finalized != (common.Checkpoint{}) &&
+ checkpoints.Finalized.Epoch >= epochToBeFinalized {
+ done <- checkpoints.Finalized
+ }
+ }(
+ ctx,
+ i,
+ n,
+ ch,
+ )
+ }
+ wg.Wait()
+ close(ch)
+
+ // print out logs in ascending idx order
+ sorted := make([]string, len(runningNodes))
+ for out := range ch {
+ if out.err != nil {
+ return common.Checkpoint{}, out.err
+ }
+ sorted[out.idx] = out.msg
+ }
+ for _, msg := range sorted {
+ t.Logf(msg)
+ }
+ }
+ }
+}
+
+// Waits for any execution payload to be available included in a beacon block (merge),
+// or timeoutSlots have passed, whichever happens first.
+func (t *Testnet) WaitForExecutionPayload(
+ ctx context.Context,
+) (ethcommon.Hash, error) {
+ genesis := t.GenesisTimeUnix()
+ slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
+ timer := time.NewTicker(slotDuration)
+ runningNodes := t.VerificationNodes().Running()
+ done := make(chan ethcommon.Hash, len(runningNodes))
+ executionClient := runningNodes[0].ExecutionClient
+ ttdReached := false
+
+ for {
+ select {
+ case <-ctx.Done():
+ return ethcommon.Hash{}, ctx.Err()
+ case result := <-done:
+ return result, nil
+ case tim := <-timer.C:
+ // start polling after first slot of genesis
+ if tim.Before(genesis.Add(slotDuration)) {
+ t.Logf("Time till genesis: %s", genesis.Sub(tim))
+ continue
+ }
+
+ if !ttdReached {
+ // Check if TTD has been reached
+ if td, err := executionClient.TotalDifficultyByNumber(ctx, nil); err == nil &&
+ td.Cmp(t.eth1Genesis.Genesis.Config.TerminalTotalDifficulty) >= 0 {
+ ttdReached = true
+ } else {
+ t.Logf("Error querying eth1 for TTD: %v", err)
+ }
+ }
+
+ // new slot, log and check status of all beacon nodes
+ type res struct {
+ idx int
+ msg string
+ err error
+ }
+
+ var (
+ wg sync.WaitGroup
+ ch = make(chan res, len(runningNodes))
+ )
+ for i, n := range runningNodes {
+ wg.Add(1)
+ go func(ctx context.Context, i int, n *clients.Node, ch chan res) {
+ defer wg.Done()
+
+ var (
+ b = n.BeaconClient
+ slot common.Slot
+ version string
+ head string
+ health float64
+ )
+
+ headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s): failed to poll head: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ }
+ slot = headInfo.Header.Message.Slot
+ head = utils.Shorten(headInfo.Root.String())
+
+ if versionedBlock, err := b.BlockV2(
+ ctx,
+ eth2api.BlockIdRoot(headInfo.Root),
+ ); err != nil {
+ ch <- res{
+ err: fmt.Errorf(
+ "node %d (%s): failed to retrieve block: %v",
+ i,
+ n.ClientNames(),
+ err,
+ ),
+ }
+ return
+ } else {
+ version = versionedBlock.Version
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil {
+ emptyHash := ethcommon.Hash{}
+ if !bytes.Equal(executionPayload.BlockHash[:], emptyHash[:]) {
+ ch <- res{
+ i,
+ fmt.Sprintf(
+ "node %d (%s): fork=%s, slot=%d, "+
+ "head=%s, health=%.2f, exec_payload=%s",
+ i,
+ n.ClientNames(),
+ version,
+ slot,
+ head,
+ health,
+ utils.Shorten(executionPayload.BlockHash.Hex()),
+ ),
+ nil,
+ }
+ done <- executionPayload.BlockHash
+ }
+ }
+ }
+
+ health, err = GetHealth(ctx, b, t.spec, slot)
+ if err != nil {
+ // warning is printed here instead because some clients
+ // don't support the required REST endpoint.
+ fmt.Printf(
+ "WARN: node %d (%s): %s\n",
+ i,
+ n.ClientNames(),
+ err,
+ )
+ }
+
+ ch <- res{
+ i,
+ fmt.Sprintf(
+ "node %d (%s): fork=%s, slot=%d, head=%s, "+
+ "health=%.2f, exec_payload=0x000..000",
+ i,
+ n.ClientNames(),
+ version,
+ slot,
+ head,
+ health,
+ ),
+ nil,
+ }
+ }(
+ ctx,
+ i,
+ n,
+ ch,
+ )
+ }
+ wg.Wait()
+ close(ch)
+
+ // print out logs in ascending idx order
+ sorted := make([]string, len(runningNodes))
+ for out := range ch {
+ if out.err != nil {
+ return ethcommon.Hash{}, out.err
+ }
+ sorted[out.idx] = out.msg
+ }
+ for _, msg := range sorted {
+ t.Logf(msg)
+ }
+
+ }
+ }
+}
+
+func GetHealth(
+ parentCtx context.Context,
+ bn *clients.BeaconClient,
+ spec *common.Spec,
+ slot common.Slot,
+) (float64, error) {
+ var health float64
+ stateInfo, err := bn.BeaconStateV2(parentCtx, eth2api.StateIdSlot(slot))
+ if err != nil {
+ return 0, fmt.Errorf("failed to retrieve state: %v", err)
+ }
+ currentEpochParticipation := stateInfo.CurrentEpochParticipation()
+ if currentEpochParticipation != nil {
+ // Altair and after
+ health = calcHealth(currentEpochParticipation)
+ } else {
+ if stateInfo.Version != "phase0" {
+ return 0, fmt.Errorf("calculate participation")
+ }
+ state := stateInfo.Data.(*phase0.BeaconState)
+ epoch := spec.SlotToEpoch(slot)
+ validatorIds := make([]eth2api.ValidatorId, 0, len(state.Validators))
+ for id, validator := range state.Validators {
+ if epoch >= validator.ActivationEligibilityEpoch &&
+ epoch < validator.ExitEpoch &&
+ !validator.Slashed {
+ validatorIds = append(
+ validatorIds,
+ eth2api.ValidatorIdIndex(id),
+ )
+ }
+ }
+ var (
+ beforeEpoch = 0
+ afterEpoch = spec.SlotToEpoch(slot)
+ )
+
+ // If it's genesis, keep before also set to 0.
+ if afterEpoch != 0 {
+ beforeEpoch = int(spec.SlotToEpoch(slot)) - 1
+ }
+ balancesBefore, err := bn.StateValidatorBalances(
+ parentCtx,
+ eth2api.StateIdSlot(beforeEpoch*int(spec.SLOTS_PER_EPOCH)),
+ validatorIds,
+ )
+ if err != nil {
+ return 0, fmt.Errorf(
+ "failed to retrieve validator balances: %v",
+ err,
+ )
+ }
+ balancesAfter, err := bn.StateValidatorBalances(
+ parentCtx,
+ eth2api.StateIdSlot(int(afterEpoch)*int(spec.SLOTS_PER_EPOCH)),
+ validatorIds,
+ )
+ if err != nil {
+ return 0, fmt.Errorf(
+ "failed to retrieve validator balances: %v",
+ err,
+ )
+ }
+ health = legacyCalcHealth(spec, balancesBefore, balancesAfter)
+ }
+ return health, nil
+}
+
+func calcHealth(p altair.ParticipationRegistry) float64 {
+ sum := 0
+ for _, p := range p {
+ sum += int(p)
+ }
+ avg := float64(sum) / float64(len(p))
+ return avg / float64(MAX_PARTICIPATION_SCORE)
+}
+
+// legacyCalcHealth calculates the health of the network based on balances at
+// the beginning of an epoch versus the balances at the end.
+//
+// NOTE: this isn't strictly the most correct way of doing things, but it is
+// quite accurate and doesn't require implementing the attestation processing
+// logic here.
+func legacyCalcHealth(
+ spec *common.Spec,
+ before, after []eth2api.ValidatorBalanceResponse,
+) float64 {
+ sum_before := big.NewInt(0)
+ sum_after := big.NewInt(0)
+ for i := range before {
+ sum_before.Add(sum_before, big.NewInt(int64(before[i].Balance)))
+ sum_after.Add(sum_after, big.NewInt(int64(after[i].Balance)))
+ }
+ count := big.NewInt(int64(len(before)))
+ avg_before := big.NewInt(0).Div(sum_before, count).Uint64()
+ avg_after := sum_after.Div(sum_after, count).Uint64()
+ reward := avg_before * uint64(
+ spec.BASE_REWARD_FACTOR,
+ ) / math.IntegerSquareRootPrysm(
+ sum_before.Uint64(),
+ ) / uint64(
+ spec.HYSTERESIS_QUOTIENT,
+ )
+ return float64(
+ avg_after-avg_before,
+ ) / float64(
+ reward*common.BASE_REWARDS_PER_EPOCH,
+ )
+}
diff --git a/simulators/eth2/common/testnet/verification.go b/simulators/eth2/common/testnet/verification.go
new file mode 100644
index 0000000000..356cb77eb1
--- /dev/null
+++ b/simulators/eth2/common/testnet/verification.go
@@ -0,0 +1,387 @@
+package testnet
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "math/big"
+ "time"
+
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ "github.com/ethereum/hive/simulators/eth2/common/utils"
+ "github.com/protolambda/eth2api"
+ "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/ztyp/tree"
+)
+
+// Interface to specify on which slot the verification will be performed
+type VerificationSlot interface {
+ Slot(
+ ctx context.Context,
+ t *Testnet,
+ bn *clients.BeaconClient,
+ ) (common.Slot, error)
+}
+
+// Return the slot at the start of the checkpoint's following epoch
+type FirstSlotAfterCheckpoint struct {
+ *common.Checkpoint
+}
+
+func (c FirstSlotAfterCheckpoint) Slot(
+ ctx context.Context,
+ t *Testnet,
+ _ *clients.BeaconClient,
+) (common.Slot, error) {
+ return t.Spec().EpochStartSlot(c.Checkpoint.Epoch + 1)
+}
+
+// Return the slot at the end of a checkpoint
+type LastSlotAtCheckpoint struct {
+ *common.Checkpoint
+}
+
+func (c LastSlotAtCheckpoint) Slot(
+ ctx context.Context,
+ t *Testnet,
+ _ *clients.BeaconClient,
+) (common.Slot, error) {
+ return t.Spec().SLOTS_PER_EPOCH * common.Slot(c.Checkpoint.Epoch), nil
+}
+
+// Get last slot according to current time
+type LastestSlotByTime struct{}
+
+func (l LastestSlotByTime) Slot(
+ ctx context.Context,
+ t *Testnet,
+ _ *clients.BeaconClient,
+) (common.Slot, error) {
+ return t.Spec().
+ TimeToSlot(common.Timestamp(time.Now().Unix()), t.GenesisTime()),
+ nil
+}
+
+// Get last slot according to current head of a beacon node
+type LastestSlotByHead struct{}
+
+func (l LastestSlotByHead) Slot(
+ ctx context.Context,
+ t *Testnet,
+ bn *clients.BeaconClient,
+) (common.Slot, error) {
+ headInfo, err := bn.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
+ return common.Slot(0), fmt.Errorf("failed to poll head: %v", err)
+ }
+ return headInfo.Header.Message.Slot, nil
+}
+
+// VerifyParticipation ensures that the participation of the finialized epoch
+// of a given checkpoint is above the expected threshold.
+func (t *Testnet) VerifyParticipation(
+ parentCtx context.Context,
+ vs VerificationSlot,
+ expected float64,
+) error {
+ runningNodes := t.VerificationNodes().Running()
+ slot, err := vs.Slot(parentCtx, t, runningNodes[0].BeaconClient)
+ if err != nil {
+ return err
+ }
+ if t.Spec().BELLATRIX_FORK_EPOCH <= t.Spec().SlotToEpoch(slot) {
+ // slot-1 to target last slot in finalized epoch
+ slot = slot - 1
+ }
+ for i, n := range runningNodes {
+ health, err := GetHealth(
+ parentCtx,
+ n.BeaconClient,
+ t.Spec().Spec,
+ slot,
+ )
+ if err != nil {
+ return err
+ }
+ if health < expected {
+ return fmt.Errorf(
+ "node %d (%s): participation not healthy (got:%.2f, want:%.2f)",
+ i,
+ n.ClientNames(),
+ health,
+ expected,
+ )
+ }
+ t.Logf(
+ "node %d (%s): epoch=%d participation=%.2f",
+ i,
+ n.ClientNames(),
+ t.Spec().SlotToEpoch(slot),
+ health,
+ )
+ }
+ return nil
+}
+
+// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the
+// finalized block and verifies that is in the execution client's canonical
+// chain.
+func (t *Testnet) VerifyExecutionPayloadIsCanonical(
+ parentCtx context.Context,
+ vs VerificationSlot,
+) error {
+ runningNodes := t.VerificationNodes().Running()
+ b := runningNodes[0].BeaconClient
+ slot, err := vs.Slot(parentCtx, t, b)
+ if err != nil {
+ return err
+ }
+
+ versionedBlock, err := b.BlockV2(
+ parentCtx,
+ eth2api.BlockIdSlot(slot),
+ )
+ if err != nil {
+ return fmt.Errorf(
+ "node %d (%s): failed to retrieve block: %v",
+ 0,
+ runningNodes[0].ClientNames(),
+ err,
+ )
+ }
+
+ payload, err := versionedBlock.ExecutionPayload()
+ if err != nil {
+ return err
+ }
+
+ for i, n := range runningNodes {
+ ec := n.ExecutionClient
+ if block, err := ec.BlockByNumber(
+ parentCtx,
+ big.NewInt(int64(payload.Number)),
+ ); err != nil {
+ return fmt.Errorf("eth1 %d: %s", 0, err)
+ } else {
+ blockHash := block.Hash()
+ if !bytes.Equal(blockHash[:], payload.BlockHash[:]) {
+ return fmt.Errorf(
+ "node %d (%s): execution blocks don't match (got=%s, expected=%s)",
+ i,
+ n.ClientNames(),
+ utils.Shorten(blockHash.String()),
+ utils.Shorten(payload.BlockHash.String()),
+ )
+ }
+ }
+ }
+ return nil
+}
+
+// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the
+// finalized block and verifies that is in the execution client's canonical
+// chain.
+func (t *Testnet) VerifyExecutionPayloadHashInclusion(
+ parentCtx context.Context,
+ vs VerificationSlot,
+ hash ethcommon.Hash,
+) (*clients.VersionedSignedBeaconBlock, error) {
+ for _, bn := range t.VerificationNodes().BeaconClients().Running() {
+ b, err := t.VerifyExecutionPayloadHashInclusionNode(
+ parentCtx,
+ vs,
+ bn,
+ hash,
+ )
+ if err != nil || b != nil {
+ return b, err
+ }
+ }
+ return nil, nil
+}
+
+func (t *Testnet) VerifyExecutionPayloadHashInclusionNode(
+ parentCtx context.Context,
+ vs VerificationSlot,
+ bn *clients.BeaconClient,
+ hash ethcommon.Hash,
+) (*clients.VersionedSignedBeaconBlock, error) {
+ lastSlot, err := vs.Slot(parentCtx, t, bn)
+ if err != nil {
+ return nil, err
+ }
+ for slot := lastSlot; slot > 0; slot -= 1 {
+ versionedBlock, err := bn.BlockV2(parentCtx, eth2api.BlockIdSlot(slot))
+ if err != nil {
+ continue
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err != nil {
+ // Block can't contain an executable payload
+ break
+ } else if bytes.Equal(executionPayload.BlockHash[:], hash[:]) {
+ return versionedBlock, nil
+ }
+
+ }
+ return nil, nil
+}
+
+// VerifyProposers checks that all validator clients have proposed a block on
+// the finalized beacon chain that includes an execution payload.
+func (t *Testnet) VerifyProposers(
+ parentCtx context.Context,
+ vs VerificationSlot,
+ allow_empty_blocks bool,
+) error {
+ runningNodes := t.VerificationNodes().Running()
+ bn := runningNodes[0].BeaconClient
+ lastSlot, err := vs.Slot(parentCtx, t, bn)
+ if err != nil {
+ return err
+ }
+ proposers := make([]bool, len(runningNodes))
+ for slot := common.Slot(0); slot <= lastSlot; slot += 1 {
+ versionedBlock, err := bn.BlockV2(parentCtx, eth2api.BlockIdSlot(slot))
+ if err != nil {
+ if allow_empty_blocks {
+ continue
+ }
+ return fmt.Errorf(
+ "node %d (%s): failed to retrieve beacon block: %v",
+ 0,
+ runningNodes[0].ClientNames(),
+ err,
+ )
+ }
+
+ validator, err := bn.StateValidator(
+ parentCtx,
+ eth2api.StateIdSlot(slot),
+ eth2api.ValidatorIdIndex(versionedBlock.ProposerIndex()),
+ )
+ if err != nil {
+ return fmt.Errorf(
+ "node %d (%s): failed to retrieve validator: %v",
+ 0,
+ runningNodes[0].ClientNames(),
+ err,
+ )
+ }
+ idx, err := t.ValidatorClientIndex(
+ [48]byte(validator.Validator.Pubkey),
+ )
+ if err != nil {
+ return fmt.Errorf("pub key not found on any validator client")
+ }
+ proposers[idx] = true
+ }
+ for i, proposed := range proposers {
+ if !proposed {
+ return fmt.Errorf(
+ "node %d (%s): did not propose a block",
+ i,
+ runningNodes[i].ClientNames(),
+ )
+ }
+ }
+ return nil
+}
+
+func (t *Testnet) VerifyELBlockLabels(parentCtx context.Context) error {
+ runningNodes := t.VerificationNodes().Running()
+ for i := 0; i < len(runningNodes); i++ {
+ n := runningNodes[i]
+ el := n.ExecutionClient
+ bn := n.BeaconClient
+ // Get the head
+ headInfo, err := bn.BlockHeader(parentCtx, eth2api.BlockHead)
+ if err != nil {
+ return err
+ }
+
+ // Get the checkpoints, first try querying state root, then slot number
+ checkpoints, err := bn.BlockFinalityCheckpoints(
+ parentCtx,
+ eth2api.BlockHead,
+ )
+ if err != nil {
+ return err
+ }
+ blockLabels := map[string]tree.Root{
+ "latest": headInfo.Root,
+ "finalized": checkpoints.Finalized.Root,
+ "safe": checkpoints.CurrentJustified.Root,
+ }
+
+ for label, root := range blockLabels {
+ // Get the beacon block
+ versionedBlock, err := bn.BlockV2(
+ parentCtx,
+ eth2api.BlockIdRoot(root),
+ )
+ if err != nil {
+ return err
+ }
+ if executionPayload, err := versionedBlock.ExecutionPayload(); err != nil {
+ // Get the el block and compare
+ h, err := el.HeaderByLabel(parentCtx, label)
+ if err != nil {
+ if executionPayload.BlockHash != (ethcommon.Hash{}) {
+ return err
+ }
+ } else {
+ if h.Hash() != executionPayload.BlockHash {
+ return fmt.Errorf(
+ "node %d (%s): Execution hash found in checkpoint block "+
+ "(%s) does not match what the el returns: %v != %v",
+ i,
+ n.ClientNames(),
+ label,
+ executionPayload.BlockHash,
+ h.Hash(),
+ )
+ }
+ fmt.Printf(
+ "node %d (%s): Execution hash matches beacon "+
+ "checkpoint block (%s) information: %v\n",
+ i,
+ n.ClientNames(),
+ label,
+ h.Hash(),
+ )
+ }
+ }
+
+ }
+ }
+ return nil
+}
+
+func (t *Testnet) VerifyELHeads(
+ parentCtx context.Context,
+) error {
+ runningExecution := t.VerificationNodes().ExecutionClients().Running()
+ head, err := runningExecution[0].HeaderByNumber(parentCtx, nil)
+ if err != nil {
+ return err
+ }
+
+ t.Logf("Verifying EL heads at %v", head.Hash())
+ for i, node := range runningExecution {
+ head2, err := node.HeaderByNumber(parentCtx, nil)
+ if err != nil {
+ return err
+ }
+ if head.Hash() != head2.Hash() {
+ return fmt.Errorf(
+ "different heads: %v: %v %v: %v",
+ 0,
+ head,
+ i,
+ head2,
+ )
+ }
+ }
+ return nil
+}
diff --git a/simulators/eth2/common/utils/context.go b/simulators/eth2/common/utils/context.go
new file mode 100644
index 0000000000..787e95eaf6
--- /dev/null
+++ b/simulators/eth2/common/utils/context.go
@@ -0,0 +1,18 @@
+package utils
+
+import (
+ "context"
+ "time"
+)
+
+// Maximum seconds to wait on an RPC request
+var rpcTimeoutSeconds = 5
+
+func ContextTimeoutRPC(
+ parent context.Context,
+) (context.Context, context.CancelFunc) {
+ return context.WithTimeout(
+ parent,
+ time.Second*time.Duration(rpcTimeoutSeconds),
+ )
+}
diff --git a/simulators/eth2/common/utils/log.go b/simulators/eth2/common/utils/log.go
new file mode 100644
index 0000000000..f2ea5d0a9a
--- /dev/null
+++ b/simulators/eth2/common/utils/log.go
@@ -0,0 +1,13 @@
+package utils
+
+import "fmt"
+
+func Shorten(s string) string {
+ start := s[0:6]
+ end := s[62:]
+ return fmt.Sprintf("%s..%s", start, end)
+}
+
+type Logging interface {
+ Logf(format string, values ...interface{})
+}
diff --git a/simulators/eth2/engine/Dockerfile b/simulators/eth2/engine/Dockerfile
index c8b1a4a40d..7f58423b7c 100644
--- a/simulators/eth2/engine/Dockerfile
+++ b/simulators/eth2/engine/Dockerfile
@@ -8,14 +8,19 @@ RUN \
# Build the simulator binary
FROM golang:1-alpine AS builder
RUN apk --no-cache add gcc musl-dev linux-headers cmake make clang build-base clang-static clang-dev
+
+# Prepare workspace.
+# Note: the build context of this simulator image is the parent directory!
ADD . /source
-WORKDIR /source
+
+# Build within simulator folder
+WORKDIR /source/engine
RUN go build -o ./sim .
# Build the runner container.
FROM alpine:latest
ADD . /
-COPY --from=builder /source/sim /
+COPY --from=builder /source/engine/sim /
COPY --from=geth /ethash /ethash
ENTRYPOINT ["./sim"]
diff --git a/simulators/eth2/engine/engineapi.go b/simulators/eth2/engine/engineapi.go
deleted file mode 100644
index 0de0ef5bc1..0000000000
--- a/simulators/eth2/engine/engineapi.go
+++ /dev/null
@@ -1,365 +0,0 @@
-package main
-
-import (
- "context"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "math/big"
- "net"
- "net/http"
- "time"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/hive/hivesim"
- "github.com/golang-jwt/jwt/v4"
-)
-
-// https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.7/src/engine/specification.md
-var EthPortHTTP = 8545
-var EnginePortHTTP = 8551
-
-// API call names
-const (
- EngineForkchoiceUpdatedV1 string = "engine_forkchoiceUpdatedV1"
- EngineGetPayloadV1 = "engine_getPayloadV1"
- EngineNewPayloadV1 = "engine_newPayloadV1"
- EthGetBlockByHash = "eth_getBlockByHash"
- EthGetBlockByNumber = "eth_getBlockByNumber"
-)
-
-// EngineClient wrapper for Ethereum Engine RPC for testing purposes.
-type EngineClient struct {
- *hivesim.T
- *hivesim.Client
- c *rpc.Client
- Eth *ethclient.Client
- cEth *rpc.Client
- IP net.IP
- TerminalTotalDifficulty *big.Int
-
- // This holds most recent context created by the Ctx method.
- // Every time Ctx is called, it creates a new context with the default
- // timeout and cancels the previous one.
- lastCtx context.Context
- lastCancel context.CancelFunc
-}
-
-// NewClient creates a engine client that uses the given RPC client.
-func NewEngineClient(t *hivesim.T, n *ExecutionClient, ttd *big.Int) *EngineClient {
- engineRPCAddress, err := n.EngineRPCAddress()
- if err != nil {
- panic(err)
- }
-
- client := &http.Client{}
- // Prepare HTTP Client
- rpcHttpClient, _ := rpc.DialHTTPWithClient(engineRPCAddress, client)
-
- // Prepare ETH Client
- client = &http.Client{}
-
- userRPCAddress, err := n.UserRPCAddress()
- if err != nil {
- panic(err)
- }
- rpcClient, _ := rpc.DialHTTPWithClient(userRPCAddress, client)
- eth := ethclient.NewClient(rpcClient)
- return &EngineClient{
- T: t,
- c: rpcHttpClient,
- Eth: eth,
- cEth: rpcClient,
- TerminalTotalDifficulty: ttd,
- lastCtx: nil,
- lastCancel: nil,
- }
-}
-
-func (ec *EngineClient) Close() {
- ec.c.Close()
- ec.Eth.Close()
- if ec.lastCtx != nil {
- ec.lastCancel()
- }
-}
-
-func (ec *EngineClient) Ctx() context.Context {
- if ec.lastCtx != nil {
- ec.lastCancel()
- }
- ec.lastCtx, ec.lastCancel = context.WithTimeout(context.Background(), 10*time.Second)
- return ec.lastCtx
-}
-
-// Helper structs to fetch the TotalDifficulty
-type TD struct {
- TotalDifficulty *hexutil.Big `json:"totalDifficulty"`
-}
-type TotalDifficultyHeader struct {
- types.Header
- TD
-}
-
-func (tdh *TotalDifficultyHeader) UnmarshalJSON(data []byte) error {
- if err := json.Unmarshal(data, &tdh.Header); err != nil {
- return err
- }
- if err := json.Unmarshal(data, &tdh.TD); err != nil {
- return err
- }
- return nil
-}
-
-func (ec *EngineClient) checkTTD() (*types.Header, bool) {
- var td *TotalDifficultyHeader
- if err := ec.cEth.CallContext(ec.Ctx(), &td, "eth_getBlockByNumber", "latest", false); err != nil {
- panic(err)
- }
- if td.TotalDifficulty.ToInt().Cmp(ec.TerminalTotalDifficulty) >= 0 {
- return &td.Header, true
- }
- return nil, false
-}
-
-func (ec *EngineClient) waitForTTDWithTimeout(cliqueSeconds uint64, timeout <-chan time.Time) bool {
- for {
- select {
- case <-time.After(time.Duration(cliqueSeconds) * time.Second):
- _, ok := ec.checkTTD()
- if ok {
- return true
- }
- case <-timeout:
- return false
- }
- }
-}
-
-// Engine API Types
-type PayloadStatusV1 struct {
- Status PayloadStatus `json:"status"`
- LatestValidHash *common.Hash `json:"latestValidHash"`
- ValidationError *string `json:"validationError"`
-}
-type ForkChoiceResponse struct {
- PayloadStatus PayloadStatusV1 `json:"payloadStatus"`
- PayloadID *PayloadID `json:"payloadId"`
-}
-
-type PayloadStatus int
-
-const (
- Unknown PayloadStatus = iota
- Valid
- Invalid
- Accepted
- Syncing
- InvalidBlockHash
-)
-
-var PayloadStatuses = map[PayloadStatus]string{
- Valid: "VALID",
- Invalid: "INVALID",
- Accepted: "ACCEPTED",
- Syncing: "SYNCING",
- InvalidBlockHash: "INVALID_BLOCK_HASH",
-}
-
-func (b PayloadStatus) String() string {
- str, ok := PayloadStatuses[b]
- if !ok {
- return "UNKNOWN"
- }
- return str
-}
-
-func (b PayloadStatus) MarshalText() ([]byte, error) {
- str, ok := PayloadStatuses[b]
- if !ok {
- return nil, fmt.Errorf("invalid payload status")
- }
- return []byte(str), nil
-}
-
-func (b *PayloadStatus) UnmarshalText(input []byte) error {
- s := string(input)
- for p, status := range PayloadStatuses {
- if status == s {
- *b = p
- return nil
- }
- }
- return fmt.Errorf("invalid payload status: %s", s)
-}
-
-type PayloadID [8]byte
-
-func (b PayloadID) MarshalText() ([]byte, error) {
- return hexutil.Bytes(b[:]).MarshalText()
-}
-func (b *PayloadID) UnmarshalText(input []byte) error {
- err := hexutil.UnmarshalFixedText("PayloadID", input, b[:])
- if err != nil {
- return fmt.Errorf("invalid payload id %q: %w", input, err)
- }
- return nil
-}
-
-type ForkchoiceStateV1 struct {
- HeadBlockHash common.Hash `json:"headBlockHash"`
- SafeBlockHash common.Hash `json:"safeBlockHash"`
- FinalizedBlockHash common.Hash `json:"finalizedBlockHash"`
-}
-
-//go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go
-// ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/src/engine/specification.md
-type ExecutableDataV1 struct {
- ParentHash common.Hash `json:"parentHash" gencodec:"required"`
- FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
- StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
- ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
- LogsBloom []byte `json:"logsBloom" gencodec:"required"`
- PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
- Number uint64 `json:"blockNumber" gencodec:"required"`
- GasLimit uint64 `json:"gasLimit" gencodec:"required"`
- GasUsed uint64 `json:"gasUsed" gencodec:"required"`
- Timestamp uint64 `json:"timestamp" gencodec:"required"`
- ExtraData []byte `json:"extraData" gencodec:"required"`
- BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
- BlockHash common.Hash `json:"blockHash" gencodec:"required"`
- Transactions [][]byte `json:"transactions" gencodec:"required"`
-}
-
-// JSON type overrides for executableData.
-type executableDataMarshaling struct {
- Number hexutil.Uint64
- GasLimit hexutil.Uint64
- GasUsed hexutil.Uint64
- Timestamp hexutil.Uint64
- BaseFeePerGas *hexutil.Big
- ExtraData hexutil.Bytes
- LogsBloom hexutil.Bytes
- Transactions []hexutil.Bytes
-}
-
-//go:generate go run github.com/fjl/gencodec -type PayloadAttributesV1 -field-override payloadAttributesMarshaling -out gen_blockparams.go
-// PayloadAttributesV1 structure described at https://github.com/ethereum/execution-apis/pull/74
-type PayloadAttributesV1 struct {
- Timestamp uint64 `json:"timestamp" gencodec:"required"`
- PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
- SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
-}
-
-// JSON type overrides for PayloadAttributesV1.
-type payloadAttributesMarshaling struct {
- Timestamp hexutil.Uint64
-}
-
-// JWT Tokens
-func GetNewToken(jwtSecretBytes []byte, iat time.Time) (string, error) {
- newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
- "iat": iat.Unix(),
- })
- tokenString, err := newToken.SignedString(jwtSecretBytes)
- if err != nil {
- return "", err
- }
- return tokenString, nil
-}
-
-func (ec *EngineClient) PrepareAuthCallToken(jwtSecretBytes []byte, iat time.Time) error {
- newTokenString, err := GetNewToken(jwtSecretBytes, iat)
- if err != nil {
- return err
- }
- ec.c.SetHeader("Authorization", fmt.Sprintf("Bearer %s", newTokenString))
- return nil
-}
-
-func (ec *EngineClient) PrepareDefaultAuthCallToken() error {
- secret, _ := hex.DecodeString("7365637265747365637265747365637265747365637265747365637265747365")
- ec.PrepareAuthCallToken(secret, time.Now())
- return nil
-}
-
-// Engine API Call Methods
-func (ec *EngineClient) EngineForkchoiceUpdatedV1(fcState *ForkchoiceStateV1, pAttributes *PayloadAttributesV1) (ForkChoiceResponse, error) {
- var result ForkChoiceResponse
- if err := ec.PrepareDefaultAuthCallToken(); err != nil {
- return result, err
- }
- err := ec.c.CallContext(ec.Ctx(), &result, EngineForkchoiceUpdatedV1, fcState, pAttributes)
- return result, err
-}
-
-func (ec *EngineClient) EngineGetPayloadV1(payloadId *PayloadID) (ExecutableDataV1, error) {
- var result ExecutableDataV1
- if err := ec.PrepareDefaultAuthCallToken(); err != nil {
- return result, err
- }
- err := ec.c.CallContext(ec.Ctx(), &result, EngineGetPayloadV1, payloadId)
- return result, err
-}
-
-func (ec *EngineClient) EngineNewPayloadV1(payload *ExecutableDataV1) (PayloadStatusV1, error) {
- var result PayloadStatusV1
- if err := ec.PrepareDefaultAuthCallToken(); err != nil {
- return result, err
- }
- err := ec.c.CallContext(ec.Ctx(), &result, EngineNewPayloadV1, payload)
- return result, err
-}
-
-// Json helpers
-// A value of this type can a JSON-RPC request, notification, successful response or
-// error response. Which one it is depends on the fields.
-type jsonError struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data interface{} `json:"data,omitempty"`
-}
-
-func (err *jsonError) Error() string {
- if err.Message == "" {
- return fmt.Sprintf("json-rpc error %d", err.Code)
- }
- return err.Message
-}
-
-type jsonrpcMessage struct {
- Version string `json:"jsonrpc,omitempty"`
- ID json.RawMessage `json:"id,omitempty"`
- Method string `json:"method,omitempty"`
- Params json.RawMessage `json:"params,omitempty"`
- Error *jsonError `json:"error,omitempty"`
- Result json.RawMessage `json:"result,omitempty"`
-}
-
-func UnmarshalFromJsonRPCResponse(b []byte, result interface{}) error {
- var rpcMessage jsonrpcMessage
- err := json.Unmarshal(b, &rpcMessage)
- if err != nil {
- return err
- }
- if rpcMessage.Error != nil {
- return rpcMessage.Error
- }
- return json.Unmarshal(rpcMessage.Result, &result)
-}
-
-func UnmarshalFromJsonRPCRequest(b []byte, params ...interface{}) error {
- var rpcMessage jsonrpcMessage
- err := json.Unmarshal(b, &rpcMessage)
- if err != nil {
- return err
- }
- if rpcMessage.Error != nil {
- return rpcMessage.Error
- }
- return json.Unmarshal(rpcMessage.Params, ¶ms)
-}
diff --git a/simulators/eth2/engine/gen_blockparams.go b/simulators/eth2/engine/gen_blockparams.go
deleted file mode 100644
index 0e0e8db9bc..0000000000
--- a/simulators/eth2/engine/gen_blockparams.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
-
-package main
-
-import (
- "encoding/json"
- "errors"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
-)
-
-var _ = (*payloadAttributesMarshaling)(nil)
-
-// MarshalJSON marshals as JSON.
-func (p PayloadAttributesV1) MarshalJSON() ([]byte, error) {
- type PayloadAttributesV1 struct {
- Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
- SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
- }
- var enc PayloadAttributesV1
- enc.Timestamp = hexutil.Uint64(p.Timestamp)
- enc.PrevRandao = p.PrevRandao
- enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
- return json.Marshal(&enc)
-}
-
-// UnmarshalJSON unmarshals from JSON.
-func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error {
- type PayloadAttributesV1 struct {
- Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- PrevRandao *common.Hash `json:"prevRandao" gencodec:"required"`
- SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
- }
- var dec PayloadAttributesV1
- if err := json.Unmarshal(input, &dec); err != nil {
- return err
- }
- if dec.Timestamp == nil {
- return errors.New("missing required field 'timestamp' for PayloadAttributesV1")
- }
- p.Timestamp = uint64(*dec.Timestamp)
- if dec.PrevRandao == nil {
- return errors.New("missing required field 'prevRandao' for PayloadAttributesV1")
- }
- p.PrevRandao = *dec.PrevRandao
- if dec.SuggestedFeeRecipient == nil {
- return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributesV1")
- }
- p.SuggestedFeeRecipient = *dec.SuggestedFeeRecipient
- return nil
-}
diff --git a/simulators/eth2/engine/gen_ed.go b/simulators/eth2/engine/gen_ed.go
deleted file mode 100644
index ad40dccf09..0000000000
--- a/simulators/eth2/engine/gen_ed.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
-
-package main
-
-import (
- "encoding/json"
- "errors"
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
-)
-
-var _ = (*executableDataMarshaling)(nil)
-
-// MarshalJSON marshals as JSON.
-func (e ExecutableDataV1) MarshalJSON() ([]byte, error) {
- type ExecutableDataV1 struct {
- ParentHash common.Hash `json:"parentHash" gencodec:"required"`
- FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
- StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
- ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
- LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
- PrevRandao common.Hash `json:"prevRandao" gencodec:"required"`
- Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
- GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
- GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
- Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
- BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
- BlockHash common.Hash `json:"blockHash" gencodec:"required"`
- Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
- }
- var enc ExecutableDataV1
- enc.ParentHash = e.ParentHash
- enc.FeeRecipient = e.FeeRecipient
- enc.StateRoot = e.StateRoot
- enc.ReceiptsRoot = e.ReceiptsRoot
- enc.LogsBloom = e.LogsBloom
- enc.PrevRandao = e.PrevRandao
- enc.Number = hexutil.Uint64(e.Number)
- enc.GasLimit = hexutil.Uint64(e.GasLimit)
- enc.GasUsed = hexutil.Uint64(e.GasUsed)
- enc.Timestamp = hexutil.Uint64(e.Timestamp)
- enc.ExtraData = e.ExtraData
- enc.BaseFeePerGas = (*hexutil.Big)(e.BaseFeePerGas)
- enc.BlockHash = e.BlockHash
- if e.Transactions != nil {
- enc.Transactions = make([]hexutil.Bytes, len(e.Transactions))
- for k, v := range e.Transactions {
- enc.Transactions[k] = v
- }
- }
- return json.Marshal(&enc)
-}
-
-// UnmarshalJSON unmarshals from JSON.
-func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error {
- type ExecutableDataV1 struct {
- ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
- FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
- StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
- ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
- LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
- PrevRandao *common.Hash `json:"prevRandao" gencodec:"required"`
- Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
- GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
- GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
- Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
- ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
- BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
- BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
- Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
- }
- var dec ExecutableDataV1
- if err := json.Unmarshal(input, &dec); err != nil {
- return err
- }
- if dec.ParentHash == nil {
- return errors.New("missing required field 'parentHash' for ExecutableDataV1")
- }
- e.ParentHash = *dec.ParentHash
- if dec.FeeRecipient == nil {
- return errors.New("missing required field 'feeRecipient' for ExecutableDataV1")
- }
- e.FeeRecipient = *dec.FeeRecipient
- if dec.StateRoot == nil {
- return errors.New("missing required field 'stateRoot' for ExecutableDataV1")
- }
- e.StateRoot = *dec.StateRoot
- if dec.ReceiptsRoot == nil {
- return errors.New("missing required field 'receiptsRoot' for ExecutableDataV1")
- }
- e.ReceiptsRoot = *dec.ReceiptsRoot
- if dec.LogsBloom == nil {
- return errors.New("missing required field 'logsBloom' for ExecutableDataV1")
- }
- e.LogsBloom = *dec.LogsBloom
- if dec.PrevRandao == nil {
- return errors.New("missing required field 'prevRandao' for ExecutableDataV1")
- }
- e.PrevRandao = *dec.PrevRandao
- if dec.Number == nil {
- return errors.New("missing required field 'blockNumber' for ExecutableDataV1")
- }
- e.Number = uint64(*dec.Number)
- if dec.GasLimit == nil {
- return errors.New("missing required field 'gasLimit' for ExecutableDataV1")
- }
- e.GasLimit = uint64(*dec.GasLimit)
- if dec.GasUsed == nil {
- return errors.New("missing required field 'gasUsed' for ExecutableDataV1")
- }
- e.GasUsed = uint64(*dec.GasUsed)
- if dec.Timestamp == nil {
- return errors.New("missing required field 'timestamp' for ExecutableDataV1")
- }
- e.Timestamp = uint64(*dec.Timestamp)
- if dec.ExtraData == nil {
- return errors.New("missing required field 'extraData' for ExecutableDataV1")
- }
- e.ExtraData = *dec.ExtraData
- if dec.BaseFeePerGas == nil {
- return errors.New("missing required field 'baseFeePerGas' for ExecutableDataV1")
- }
- e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas)
- if dec.BlockHash == nil {
- return errors.New("missing required field 'blockHash' for ExecutableDataV1")
- }
- e.BlockHash = *dec.BlockHash
- if dec.Transactions == nil {
- return errors.New("missing required field 'transactions' for ExecutableDataV1")
- }
- e.Transactions = make([][]byte, len(dec.Transactions))
- for k, v := range dec.Transactions {
- e.Transactions[k] = v
- }
- return nil
-}
diff --git a/simulators/eth2/engine/go.sum b/simulators/eth2/engine/go.sum
index 6f49f5970d..bcae9b0376 100644
--- a/simulators/eth2/engine/go.sum
+++ b/simulators/eth2/engine/go.sum
@@ -1,23 +1,58 @@
+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=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
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/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+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/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -26,39 +61,65 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS3
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s=
github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b h1:uWfa1x0lA7o5O6XgFxENIxAlevy9W5U6nAp79naD7e4=
github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b/go.mod h1:G8XiiUErpj6++yb93r6y6T1nWBh4Bgoi3QFwUSbzt/U=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
+github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
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/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
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-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gogo/googleapis v1.1.0/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.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.3/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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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.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=
@@ -67,23 +128,59 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.2/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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+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.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY=
+github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+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/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA=
github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
@@ -92,71 +189,145 @@ github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25
github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
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/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.2 h1:xPMwiykqNK9VK0NYC3+jTMYv9I6Vl3YdjZgPZKG3zO0=
github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea h1:9ahHMPkNvYf9Nn3+U072ZKMDm05gaXfRESAmwP07Q+M=
github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
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/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
+github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w=
@@ -172,60 +343,127 @@ github.com/protolambda/zrnt v0.28.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax
github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY=
github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
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/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
+github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+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.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
+github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/wealdtech/go-bytesutil v1.2.0 h1:GEIzvAZEIgqOoRfnEAaMRNL73gl8e+YlQzqxhFyR30Y=
github.com/wealdtech/go-bytesutil v1.2.0/go.mod h1:FHQSlwhzfSZGffu1osaUGdnNtl5C8tBKwmqvPdB66pM=
github.com/wealdtech/go-eth2-types/v2 v2.8.0 h1:Cts9J78ryXVp8jwotdSSVU75S+QWJrgVCArXreD2X8A=
github.com/wealdtech/go-eth2-types/v2 v2.8.0/go.mod h1:tJazo9o28kdQs3V/U4VafQ4neG+/sL3OBozQ8J3CWmo=
github.com/wealdtech/go-eth2-util v1.8.0 h1:hhs3h2y3Ldty18lppFdpe46nZpdDAMbY7QqiHO5BvE0=
github.com/wealdtech/go-eth2-util v1.8.0/go.mod h1:rSuE0v5zX+uyZrqW/iUmXOxeDpB7lTvhcZvAVh0KlMU=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-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=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/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-20190404232315-eb5bcb51f2a3/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -233,23 +471,39 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+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/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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+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-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20181122145206-62eef0e2fa9b/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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/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-20191005200804-aed5e4c7ecf9/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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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=
@@ -263,26 +517,61 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.3.0/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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=
@@ -293,14 +582,21 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1 h1:iiHuQZCNgYPmFQxd3BBN/Nc5+dAwzZuq5y40s20oQw0=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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=
@@ -311,3 +607,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/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=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/simulators/eth2/engine/helper.go b/simulators/eth2/engine/helper.go
index c314bfa6b9..cfc498ec8a 100644
--- a/simulators/eth2/engine/helper.go
+++ b/simulators/eth2/engine/helper.go
@@ -3,844 +3,93 @@ package main
import (
"context"
"crypto/ecdsa"
- "crypto/rand"
"fmt"
"math/big"
- "net/http"
- "strings"
- "sync"
"time"
- "github.com/ethereum/go-ethereum/common"
- ethcommon "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
- blsu "github.com/protolambda/bls12-381-util"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
beacon "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/rauljordan/engine-proxy/proxy"
)
type testSpec struct {
Name string
About string
- Run func(*hivesim.T, *testEnv, node)
+ Run func(*hivesim.T, *testnet.Environment, clients.NodeDefinition)
}
-type testEnv struct {
- Clients *ClientDefinitionsByRole
- Keys []*setup.KeyDetails
- Secrets *[]blsu.SecretKey
-}
-
-type Logging interface {
- Logf(format string, values ...interface{})
-}
-
-type node struct {
- ExecutionClient string
- ConsensusClient string
- ValidatorShares uint64
- ExecutionClientTTD *big.Int
- BeaconNodeTTD *big.Int
- TestVerificationNode bool
- DisableStartup bool
- ChainGenerator ChainGenerator
- Chain []*types.Block
- ExecutionSubnet string
-}
-
-type Nodes []node
-
-func (n *node) String() string {
- return fmt.Sprintf("%s-%s", n.ConsensusClient, n.ExecutionClient)
-}
-
-func (nodes Nodes) Shares() []uint64 {
- shares := make([]uint64, len(nodes))
- for i, n := range nodes {
- shares[i] = n.ValidatorShares
- }
- return shares
-}
-
-type Config struct {
- AltairForkEpoch *big.Int
- MergeForkEpoch *big.Int
- CapellaForkEpoch *big.Int
- ValidatorCount *big.Int
- KeyTranches *big.Int
- SlotTime *big.Int
- TerminalTotalDifficulty *big.Int
- SafeSlotsToImportOptimistically *big.Int
- ExtraShares *big.Int
-
- // Node configurations to launch. Each node as a proportional share of
- // validators.
- Nodes Nodes
- Eth1Consensus setup.Eth1Consensus
-
- // Execution Layer specific config
- InitialBaseFeePerGas *big.Int
-}
-
-// Choose a configuration value. `b` takes precedence
-func choose(a, b *big.Int) *big.Int {
- if b != nil {
- return new(big.Int).Set(b)
- }
- if a != nil {
- return new(big.Int).Set(a)
- }
- return nil
-}
-
-// Join two configurations. `b` takes precedence
-func (a *Config) join(b *Config) *Config {
- c := Config{}
- // Forks
- c.AltairForkEpoch = choose(a.AltairForkEpoch, b.AltairForkEpoch)
- c.MergeForkEpoch = choose(a.MergeForkEpoch, b.MergeForkEpoch)
- c.CapellaForkEpoch = choose(a.CapellaForkEpoch, b.CapellaForkEpoch)
-
- // Testnet config
- c.ValidatorCount = choose(a.ValidatorCount, b.ValidatorCount)
- c.KeyTranches = choose(a.KeyTranches, b.KeyTranches)
- c.SlotTime = choose(a.SlotTime, b.SlotTime)
- c.TerminalTotalDifficulty = choose(a.TerminalTotalDifficulty, b.TerminalTotalDifficulty)
- c.SafeSlotsToImportOptimistically = choose(a.SafeSlotsToImportOptimistically, b.SafeSlotsToImportOptimistically)
- c.ExtraShares = choose(a.ExtraShares, b.ExtraShares)
-
- // EL config
- c.InitialBaseFeePerGas = choose(a.InitialBaseFeePerGas, b.InitialBaseFeePerGas)
-
- if b.Nodes != nil {
- c.Nodes = b.Nodes
- } else {
- c.Nodes = a.Nodes
- }
-
- if b.Eth1Consensus != nil {
- c.Eth1Consensus = b.Eth1Consensus
- } else {
- c.Eth1Consensus = a.Eth1Consensus
- }
-
- return &c
-}
-
-func (c *Config) activeFork() string {
- if c.MergeForkEpoch != nil && c.MergeForkEpoch.Cmp(common.Big0) == 0 {
- return "merge"
- } else if c.AltairForkEpoch != nil && c.AltairForkEpoch.Cmp(common.Big0) == 0 {
- return "altair"
- } else {
- return "phase0"
- }
-}
-
-func shorten(s string) string {
- start := s[0:6]
- end := s[62:]
- return fmt.Sprintf("%s..%s", start, end)
-}
-
-// Payload helper methods
-type SignatureValues struct {
- V *big.Int
- R *big.Int
- S *big.Int
-}
-
-func SignatureValuesFromRaw(v *big.Int, r *big.Int, s *big.Int) SignatureValues {
- return SignatureValues{
- V: v,
- R: r,
- S: s,
- }
-}
-
-type CustomTransactionData struct {
- Nonce *uint64
- GasPrice *big.Int
- Gas *uint64
- To *common.Address
- Value *big.Int
- Data *[]byte
- Signature *SignatureValues
-}
-
-func customizeTransaction(baseTransaction *types.Transaction, pk *ecdsa.PrivateKey, customData *CustomTransactionData) (*types.Transaction, error) {
- // Create a modified transaction base, from the base transaction and customData mix
- modifiedTxBase := &types.LegacyTx{}
-
- if customData.Nonce != nil {
- modifiedTxBase.Nonce = *customData.Nonce
- } else {
- modifiedTxBase.Nonce = baseTransaction.Nonce()
- }
- if customData.GasPrice != nil {
- modifiedTxBase.GasPrice = customData.GasPrice
- } else {
- modifiedTxBase.GasPrice = baseTransaction.GasPrice()
- }
- if customData.Gas != nil {
- modifiedTxBase.Gas = *customData.Gas
- } else {
- modifiedTxBase.Gas = baseTransaction.Gas()
- }
- if customData.To != nil {
- modifiedTxBase.To = customData.To
- } else {
- modifiedTxBase.To = baseTransaction.To()
- }
- if customData.Value != nil {
- modifiedTxBase.Value = customData.Value
- } else {
- modifiedTxBase.Value = baseTransaction.Value()
- }
- if customData.Data != nil {
- modifiedTxBase.Data = *customData.Data
- } else {
- modifiedTxBase.Data = baseTransaction.Data()
- }
- var modifiedTx *types.Transaction
- if customData.Signature != nil {
- modifiedTxBase.V = customData.Signature.V
- modifiedTxBase.R = customData.Signature.R
- modifiedTxBase.S = customData.Signature.S
- modifiedTx = types.NewTx(modifiedTxBase)
- } else {
- // If a custom signature was not specified, simply sign the transaction again
- signer := types.NewEIP155Signer(CHAIN_ID)
- var err error
- modifiedTx, err = types.SignTx(types.NewTx(modifiedTxBase), signer, pk)
- if err != nil {
- return nil, err
- }
- }
- return modifiedTx, nil
-}
-
-type CustomPayloadData struct {
- ParentHash *common.Hash
- FeeRecipient *common.Address
- StateRoot *common.Hash
- ReceiptsRoot *common.Hash
- LogsBloom *[]byte
- PrevRandao *common.Hash
- Number *uint64
- GasLimit *uint64
- GasUsed *uint64
- Timestamp *uint64
- ExtraData *[]byte
- BaseFeePerGas *big.Int
- BlockHash *common.Hash
- Transactions *[][]byte
-}
-
-func calcTxsHash(txsBytes [][]byte) (common.Hash, error) {
- txs := make([]*types.Transaction, len(txsBytes))
- for i, bytesTx := range txsBytes {
- var currentTx types.Transaction
- err := currentTx.UnmarshalBinary(bytesTx)
- if err != nil {
- return common.Hash{}, err
- }
- txs[i] = ¤tTx
- }
- return types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), nil
-}
-
-// Construct a customized payload by taking an existing payload as base and mixing it CustomPayloadData
-// BlockHash is calculated automatically.
-func customizePayloadSpoof(method string, basePayload *ExecutableDataV1, customData *CustomPayloadData) (common.Hash, *proxy.Spoof, error) {
- fields := make(map[string]interface{})
-
- txs := basePayload.Transactions
- if customData.Transactions != nil {
- txs = *customData.Transactions
- }
- txsHash, err := calcTxsHash(txs)
- if err != nil {
- return common.Hash{}, nil, err
- }
- // Start by filling the header with the basePayload information
- customPayloadHeader := types.Header{
- ParentHash: basePayload.ParentHash,
- UncleHash: types.EmptyUncleHash, // Could be overwritten
- Coinbase: basePayload.FeeRecipient,
- Root: basePayload.StateRoot,
- TxHash: txsHash,
- ReceiptHash: basePayload.ReceiptsRoot,
- Bloom: types.BytesToBloom(basePayload.LogsBloom),
- Difficulty: big.NewInt(0), // could be overwritten
- Number: big.NewInt(int64(basePayload.Number)),
- GasLimit: basePayload.GasLimit,
- GasUsed: basePayload.GasUsed,
- Time: basePayload.Timestamp,
- Extra: basePayload.ExtraData,
- MixDigest: basePayload.PrevRandao,
- Nonce: types.BlockNonce{0}, // could be overwritten
- BaseFee: basePayload.BaseFeePerGas,
- }
-
- // Overwrite custom information
- if customData.ParentHash != nil {
- customPayloadHeader.ParentHash = *customData.ParentHash
- fields["parentHash"] = customPayloadHeader.ParentHash
- }
- if customData.FeeRecipient != nil {
- customPayloadHeader.Coinbase = *customData.FeeRecipient
- fields["feeRecipient"] = customPayloadHeader.Coinbase
- }
- if customData.StateRoot != nil {
- customPayloadHeader.Root = *customData.StateRoot
- fields["stateRoot"] = customPayloadHeader.Root
- }
- if customData.ReceiptsRoot != nil {
- customPayloadHeader.ReceiptHash = *customData.ReceiptsRoot
- fields["receiptsRoot"] = customPayloadHeader.ReceiptHash
- }
- if customData.LogsBloom != nil {
- customPayloadHeader.Bloom = types.BytesToBloom(*customData.LogsBloom)
- fields["logsBloom"] = hexutil.Bytes(*customData.LogsBloom)
- }
- if customData.PrevRandao != nil {
- customPayloadHeader.MixDigest = *customData.PrevRandao
- fields["prevRandao"] = customPayloadHeader.MixDigest
- }
- if customData.Number != nil {
- customPayloadHeader.Number = big.NewInt(int64(*customData.Number))
- fields["blockNumber"] = hexutil.Uint64(*customData.Number)
- }
- if customData.GasLimit != nil {
- customPayloadHeader.GasLimit = *customData.GasLimit
- fields["gasLimit"] = hexutil.Uint64(customPayloadHeader.GasLimit)
- }
- if customData.GasUsed != nil {
- customPayloadHeader.GasUsed = *customData.GasUsed
- fields["gasUsed"] = hexutil.Uint64(customPayloadHeader.GasUsed)
- }
- if customData.Timestamp != nil {
- customPayloadHeader.Time = *customData.Timestamp
- fields["timestamp"] = hexutil.Uint64(customPayloadHeader.Time)
- }
- if customData.ExtraData != nil {
- customPayloadHeader.Extra = *customData.ExtraData
- fields["extraData"] = hexutil.Bytes(customPayloadHeader.Extra)
- }
- if customData.BaseFeePerGas != nil {
- customPayloadHeader.BaseFee = customData.BaseFeePerGas
- fields["baseFeePerGas"] = (*hexutil.Big)(customPayloadHeader.BaseFee)
- }
-
- var payloadHash common.Hash
- if customData.BlockHash != nil {
- payloadHash = *customData.BlockHash
- } else {
- payloadHash = customPayloadHeader.Hash()
- }
- fields["blockHash"] = payloadHash
-
- // Return the new payload
- return payloadHash, &proxy.Spoof{
- Method: method,
- Fields: fields,
- }, nil
-}
-
-func (customData *CustomPayloadData) String() string {
- customFieldsList := make([]string, 0)
- if customData.ParentHash != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("ParentHash=%s", customData.ParentHash.String()))
- }
- if customData.FeeRecipient != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("Coinbase=%s", customData.FeeRecipient.String()))
- }
- if customData.StateRoot != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("StateRoot=%s", customData.StateRoot.String()))
- }
- if customData.ReceiptsRoot != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("ReceiptsRoot=%s", customData.ReceiptsRoot.String()))
- }
- if customData.LogsBloom != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("LogsBloom=%v", types.BytesToBloom(*customData.LogsBloom)))
- }
- if customData.PrevRandao != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("PrevRandao=%s", customData.PrevRandao.String()))
- }
- if customData.Number != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("Number=%d", *customData.Number))
- }
- if customData.GasLimit != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("GasLimit=%d", *customData.GasLimit))
- }
- if customData.GasUsed != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("GasUsed=%d", *customData.GasUsed))
- }
- if customData.Timestamp != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("Timestamp=%d", *customData.Timestamp))
- }
- if customData.ExtraData != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("ExtraData=%v", *customData.ExtraData))
- }
- if customData.BaseFeePerGas != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("BaseFeePerGas=%s", customData.BaseFeePerGas.String()))
- }
- if customData.Transactions != nil {
- customFieldsList = append(customFieldsList, fmt.Sprintf("Transactions=%v", customData.Transactions))
- }
- return strings.Join(customFieldsList, ", ")
-}
-
-type InvalidPayloadField string
-
+// API call names
const (
- InvalidParentHash InvalidPayloadField = "ParentHash"
- InvalidStateRoot = "StateRoot"
- InvalidReceiptsRoot = "ReceiptsRoot"
- InvalidNumber = "Number"
- InvalidGasLimit = "GasLimit"
- InvalidGasUsed = "GasUsed"
- InvalidTimestamp = "Timestamp"
- InvalidPrevRandao = "PrevRandao"
- RemoveTransaction = "Incomplete Transactions"
- InvalidTransactionSignature = "Transaction Signature"
- InvalidTransactionNonce = "Transaction Nonce"
- InvalidTransactionGas = "Transaction Gas"
- InvalidTransactionGasPrice = "Transaction GasPrice"
- InvalidTransactionValue = "Transaction Value"
+ EngineForkchoiceUpdatedV1 = "engine_forkchoiceUpdatedV1"
+ EngineGetPayloadV1 = "engine_getPayloadV1"
+ EngineNewPayloadV1 = "engine_newPayloadV1"
+ EthGetBlockByHash = "eth_getBlockByHash"
+ EthGetBlockByNumber = "eth_getBlockByNumber"
)
-// This function generates an invalid payload by taking a base payload and modifying the specified field such that it ends up being invalid.
-// One small consideration is that the payload needs to contain transactions and specially transactions using the PREVRANDAO opcode for all the fields to be compatible with this function.
-func generateInvalidPayloadSpoof(method string, basePayload *ExecutableDataV1, payloadField InvalidPayloadField) (common.Hash, *proxy.Spoof, error) {
-
- var customPayloadMod *CustomPayloadData
- switch payloadField {
- case InvalidParentHash:
- var randomParentHash common.Hash
- rand.Read(randomParentHash[:])
- customPayloadMod = &CustomPayloadData{
- ParentHash: &randomParentHash,
- }
- case InvalidStateRoot:
- modStateRoot := basePayload.StateRoot
- modStateRoot[common.HashLength-1] = byte(255 - modStateRoot[common.HashLength-1])
- customPayloadMod = &CustomPayloadData{
- StateRoot: &modStateRoot,
- }
- case InvalidReceiptsRoot:
- modReceiptsRoot := basePayload.ReceiptsRoot
- modReceiptsRoot[common.HashLength-1] = byte(255 - modReceiptsRoot[common.HashLength-1])
- customPayloadMod = &CustomPayloadData{
- ReceiptsRoot: &modReceiptsRoot,
- }
- case InvalidNumber:
- modNumber := basePayload.Number - 1
- customPayloadMod = &CustomPayloadData{
- Number: &modNumber,
- }
- case InvalidGasLimit:
- modGasLimit := basePayload.GasLimit * 2
- customPayloadMod = &CustomPayloadData{
- GasLimit: &modGasLimit,
- }
- case InvalidGasUsed:
- modGasUsed := basePayload.GasUsed - 1
- customPayloadMod = &CustomPayloadData{
- GasUsed: &modGasUsed,
- }
- case InvalidTimestamp:
- modTimestamp := basePayload.Timestamp - 1
- customPayloadMod = &CustomPayloadData{
- Timestamp: &modTimestamp,
- }
- case InvalidPrevRandao:
- // This option potentially requires a transaction that uses the PREVRANDAO opcode.
- // Otherwise the payload will still be valid.
- modPrevRandao := common.Hash{}
- rand.Read(modPrevRandao[:])
- customPayloadMod = &CustomPayloadData{
- PrevRandao: &modPrevRandao,
- }
- case RemoveTransaction:
- emptyTxs := make([][]byte, 0)
- customPayloadMod = &CustomPayloadData{
- Transactions: &emptyTxs,
- }
- case InvalidTransactionSignature,
- InvalidTransactionNonce,
- InvalidTransactionGas,
- InvalidTransactionGasPrice,
- InvalidTransactionValue:
-
- if len(basePayload.Transactions) == 0 {
- return common.Hash{}, nil, fmt.Errorf("No transactions available for modification")
- }
- var baseTx types.Transaction
- if err := baseTx.UnmarshalBinary(basePayload.Transactions[0]); err != nil {
- return common.Hash{}, nil, err
- }
- var customTxData CustomTransactionData
- switch payloadField {
- case InvalidTransactionSignature:
- modifiedSignature := SignatureValuesFromRaw(baseTx.RawSignatureValues())
- modifiedSignature.R = modifiedSignature.R.Sub(modifiedSignature.R, big.NewInt(1))
- customTxData = CustomTransactionData{
- Signature: &modifiedSignature,
- }
- case InvalidTransactionNonce:
- customNonce := baseTx.Nonce() - 1
- customTxData = CustomTransactionData{
- Nonce: &customNonce,
- }
- case InvalidTransactionGas:
- customGas := uint64(0)
- customTxData = CustomTransactionData{
- Gas: &customGas,
- }
- case InvalidTransactionGasPrice:
- customTxData = CustomTransactionData{
- GasPrice: big.NewInt(0),
- }
- case InvalidTransactionValue:
- // Vault account initially has 0x123450000000000000000, so this value should overflow
- customValue, err := hexutil.DecodeBig("0x123450000000000000001")
- if err != nil {
- return common.Hash{}, nil, err
- }
- customTxData = CustomTransactionData{
- Value: customValue,
- }
- }
-
- modifiedTx, err := customizeTransaction(&baseTx, VAULT_KEY, &customTxData)
- if err != nil {
- return common.Hash{}, nil, err
- }
-
- modifiedTxBytes, err := modifiedTx.MarshalBinary()
- if err != nil {
- }
- modifiedTransactions := [][]byte{
- modifiedTxBytes,
- }
- customPayloadMod = &CustomPayloadData{
- Transactions: &modifiedTransactions,
- }
- }
-
- if customPayloadMod == nil {
- return common.Hash{}, nil, fmt.Errorf("Invalid payload field to corrupt: %s", payloadField)
- }
-
- return customizePayloadSpoof(method, basePayload, customPayloadMod)
-}
-
-// Generate a payload status spoof
-func payloadStatusSpoof(method string, status *PayloadStatusV1) (*proxy.Spoof, error) {
- fields := make(map[string]interface{})
- fields["status"] = status.Status
- fields["latestValidHash"] = status.LatestValidHash
- fields["validationError"] = status.ValidationError
+// Engine API Types
- // Return the new payload status spoof
- return &proxy.Spoof{
- Method: method,
- Fields: fields,
- }, nil
-}
-
-// Generate a payload status spoof
-func forkchoiceResponseSpoof(method string, status PayloadStatusV1, payloadID *PayloadID) (*proxy.Spoof, error) {
- fields := make(map[string]interface{})
- fields["payloadStatus"] = status
- fields["payloadId"] = payloadID
-
- // Return the new payload status spoof
- return &proxy.Spoof{
- Method: method,
- Fields: fields,
- }, nil
-}
-
-type EngineResponse struct {
- Status PayloadStatus
- LatestValidHash *common.Hash
-}
-
-type EngineResponseHash struct {
- Response *EngineResponse
- Hash common.Hash
-}
-
-//
-type EngineResponseMocker struct {
- Lock sync.Mutex
- DefaultResponse *EngineResponse
- HashToResponse map[common.Hash]*EngineResponse
- HashPassthrough map[common.Hash]bool
- NewPayloadCalled chan EngineResponseHash
- ForkchoiceUpdatedCalled chan EngineResponseHash
- Mocking bool
-}
-
-func NewEngineResponseMocker(defaultResponse *EngineResponse, perHashResponses ...*EngineResponseHash) *EngineResponseMocker {
- e := &EngineResponseMocker{
- DefaultResponse: defaultResponse,
- HashToResponse: make(map[common.Hash]*EngineResponse),
- HashPassthrough: make(map[common.Hash]bool),
- NewPayloadCalled: make(chan EngineResponseHash),
- ForkchoiceUpdatedCalled: make(chan EngineResponseHash),
- Mocking: true,
- }
- for _, r := range perHashResponses {
- e.AddResponse(r.Hash, r.Response)
- }
- return e
-}
+type PayloadStatus string
-func (e *EngineResponseMocker) AddResponse(h common.Hash, r *EngineResponse) {
- e.Lock.Lock()
- defer e.Lock.Unlock()
- if e.HashToResponse == nil {
- e.HashToResponse = make(map[common.Hash]*EngineResponse)
- }
- e.HashToResponse[h] = r
-}
-
-func (e *EngineResponseMocker) AddPassthrough(h common.Hash, pass bool) {
- e.Lock.Lock()
- defer e.Lock.Unlock()
- e.HashPassthrough[h] = pass
-}
-
-func (e *EngineResponseMocker) CanPassthrough(h common.Hash) bool {
- e.Lock.Lock()
- defer e.Lock.Unlock()
- if pass, ok := e.HashPassthrough[h]; ok && pass {
- return true
- }
- return false
-}
-
-func (e *EngineResponseMocker) GetResponse(h common.Hash) *EngineResponse {
- e.Lock.Lock()
- defer e.Lock.Unlock()
- if e.HashToResponse != nil {
- if r, ok := e.HashToResponse[h]; ok {
- return r
- }
- }
- return e.DefaultResponse
-}
-
-func (e *EngineResponseMocker) SetDefaultResponse(r *EngineResponse) {
- e.Lock.Lock()
- defer e.Lock.Unlock()
- e.DefaultResponse = r
-}
-
-func (e *EngineResponseMocker) AddGetPayloadPassthroughToProxy(p *Proxy) {
- p.AddResponseCallback(EngineGetPayloadV1, func(res []byte, req []byte) *proxy.Spoof {
- // Hash of the payload built is being added to the passthrough list
- var (
- payload ExecutableDataV1
- )
- err := UnmarshalFromJsonRPCResponse(res, &payload)
- if err != nil {
- panic(err)
- }
- e.AddPassthrough(payload.BlockHash, true)
- return nil
- })
-}
-
-func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy(p *Proxy) {
- p.AddResponseCallback(EngineNewPayloadV1, func(res []byte, req []byte) *proxy.Spoof {
- var (
- payload ExecutableDataV1
- status PayloadStatusV1
- spoof *proxy.Spoof
- err error
- )
- err = UnmarshalFromJsonRPCRequest(req, &payload)
- if err != nil {
- panic(err)
- }
- err = UnmarshalFromJsonRPCResponse(res, &status)
- if err != nil {
- panic(err)
- }
- if r := e.GetResponse(payload.BlockHash); e.Mocking && !e.CanPassthrough(payload.BlockHash) && r != nil {
- // We are mocking this specific response, either with a hash specific response, or the default response
- spoof, err = payloadStatusSpoof(EngineNewPayloadV1, &PayloadStatusV1{
- Status: r.Status,
- LatestValidHash: r.LatestValidHash,
- ValidationError: nil,
- })
- if err != nil {
- panic(err)
- }
- select {
- case e.NewPayloadCalled <- EngineResponseHash{
- Response: r,
- Hash: payload.BlockHash,
- }:
- default:
- }
- return spoof
- } else {
- select {
- case e.NewPayloadCalled <- EngineResponseHash{
- Response: &EngineResponse{
- Status: status.Status,
- LatestValidHash: status.LatestValidHash,
- },
- Hash: payload.BlockHash,
- }:
- default:
- }
- }
- return nil
- })
-}
-
-func (e *EngineResponseMocker) AddForkchoiceUpdatedCallbackToProxy(p *Proxy) {
- p.AddResponseCallback(EngineForkchoiceUpdatedV1, func(res []byte, req []byte) *proxy.Spoof {
- var (
- fcState ForkchoiceStateV1
- pAttr PayloadAttributesV1
- fResp ForkChoiceResponse
- spoof *proxy.Spoof
- err error
- )
- err = UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
- if err != nil {
- panic(err)
- }
- err = UnmarshalFromJsonRPCResponse(res, &fResp)
- if err != nil {
- panic(err)
- }
-
- if r := e.GetResponse(fcState.HeadBlockHash); e.Mocking && !e.CanPassthrough(fcState.HeadBlockHash) && r != nil {
- // We are mocking this specific response, either with a hash specific response, or the default response
- spoof, err = forkchoiceResponseSpoof(EngineForkchoiceUpdatedV1, PayloadStatusV1{
- Status: r.Status,
- LatestValidHash: r.LatestValidHash,
- ValidationError: nil,
- }, nil)
- if err != nil {
- panic(err)
- }
+const (
+ Unknown = ""
+ Valid = "VALID"
+ Invalid = "INVALID"
+ Accepted = "ACCEPTED"
+ Syncing = "SYNCING"
+ InvalidBlockHash = "INVALID_BLOCK_HASH"
+)
- select {
- case e.ForkchoiceUpdatedCalled <- EngineResponseHash{
- Response: r,
- Hash: fcState.HeadBlockHash,
- }:
- default:
- }
- return spoof
- } else {
- // Let the original response pass through
- select {
- case e.ForkchoiceUpdatedCalled <- EngineResponseHash{
- Response: &EngineResponse{
- Status: fResp.PayloadStatus.Status,
- LatestValidHash: fResp.PayloadStatus.LatestValidHash,
- },
- Hash: fcState.HeadBlockHash,
- }:
- default:
- }
- }
- return nil
- })
+// Signer for all txs
+type Signer struct {
+ ChainID *big.Int
+ PrivateKey *ecdsa.PrivateKey
}
-func (e *EngineResponseMocker) AddCallbacksToProxy(p *Proxy) {
- e.AddForkchoiceUpdatedCallbackToProxy(p)
- e.AddNewPayloadCallbackToProxy(p)
+func (vs Signer) SignTx(
+ baseTx *types.Transaction,
+) (*types.Transaction, error) {
+ signer := types.NewEIP155Signer(vs.ChainID)
+ return types.SignTx(baseTx, signer, vs.PrivateKey)
}
-// Generates a callback that detects when a ForkchoiceUpdated with Payload Attributes fails.
-// Requires a lock in case two clients receive the fcU with payload attributes at the same time.
-// Requires chan(error) to return the final outcome of the callbacks.
-// Requires the maximum number of fcU+attr calls to check.
-func CheckErrorOnForkchoiceUpdatedPayloadAttr(fcuLock *sync.Mutex, fcUCountLimit int, fcUAttrCount *int, fcudone chan<- error) func(res []byte, req []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
- var (
- fcS ForkchoiceStateV1
- pA *PayloadAttributesV1
- )
- if err := UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil {
- panic(fmt.Errorf("Unable to parse ForkchoiceUpdated request: %v", err))
- }
- if pA != nil {
- fcuLock.Lock()
- defer fcuLock.Unlock()
- (*fcUAttrCount)++
- // The CL requested a payload, it should have not produced an error
- var (
- fcResponse ForkChoiceResponse
- )
- err := UnmarshalFromJsonRPCResponse(res, &fcResponse)
- if err == nil && fcResponse.PayloadID == nil {
- err = fmt.Errorf("PayloadID null on ForkchoiceUpdated with attributes")
- }
- if err != nil || (*fcUAttrCount) > fcUCountLimit {
- select {
- case fcudone <- err:
- default:
- }
- }
- }
- return nil
- }
-}
-
-func combine(a, b *proxy.Spoof) *proxy.Spoof {
- if a == nil {
- return b
- }
- if b == nil {
- return a
- }
- if a.Method != b.Method {
- panic(fmt.Errorf("Spoof methods don't match: %s != %s", a.Method, b.Method))
- }
- for k, v := range b.Fields {
- a.Fields[k] = v
- }
- return a
-}
-
-func ContextWithSlotsTimeout(parent context.Context, t *Testnet, slots beacon.Slot) (context.Context, context.CancelFunc) {
- timeout := time.Duration(uint64(slots)*uint64(t.spec.SECONDS_PER_SLOT)) * time.Second
- return context.WithTimeout(parent, timeout)
+var VaultSigner = Signer{
+ ChainID: CHAIN_ID,
+ PrivateKey: VAULT_KEY,
}
// Try to approximate how much time until the merge based on current time, bellatrix fork epoch,
// TTD, execution clients' consensus mechanism, current total difficulty.
// This function is used to calculate timeouts, so it will always return a pessimistic value.
-func SlotsUntilMerge(t *Testnet, c *Config) beacon.Slot {
+func SlotsUntilMerge(
+ parentCtx context.Context,
+ t *testnet.Testnet,
+ c *testnet.Config,
+) beacon.Slot {
l := make([]beacon.Slot, 0)
- l = append(l, SlotsUntilBellatrix(t.genesisTime, t.spec))
-
- for i, e := range t.ExecutionClients().Running() {
- l = append(l, beacon.Slot(TimeUntilTerminalBlock(e, c.Eth1Consensus, c.TerminalTotalDifficulty, c.Nodes[i])/uint64(t.spec.SECONDS_PER_SLOT)))
+ l = append(l, SlotsUntilBellatrix(t.GenesisTime(), t.Spec().Spec))
+
+ for _, e := range t.ExecutionClients().Running() {
+ l = append(
+ l,
+ beacon.Slot(
+ TimeUntilTerminalBlock(
+ parentCtx,
+ e,
+ c.Eth1Consensus,
+ c.TerminalTotalDifficulty,
+ )/uint64(
+ t.Spec().SECONDS_PER_SLOT,
+ ),
+ ),
+ )
}
// Return the worst case
- var max = beacon.Slot(0)
+ max := beacon.Slot(0)
for _, s := range l {
if s > max {
max = s
@@ -853,88 +102,52 @@ func SlotsUntilMerge(t *Testnet, c *Config) beacon.Slot {
return max + 5
}
-func SlotsUntilBellatrix(genesisTime beacon.Timestamp, spec *beacon.Spec) beacon.Slot {
+func SlotsUntilBellatrix(
+ genesisTime beacon.Timestamp,
+ spec *beacon.Spec,
+) beacon.Slot {
currentTimestamp := beacon.Timestamp(time.Now().Unix())
- bellatrixTime, err := spec.TimeAtSlot(beacon.Slot(spec.BELLATRIX_FORK_EPOCH*beacon.Epoch(spec.SLOTS_PER_EPOCH)), genesisTime)
+ bellatrixTime, err := spec.TimeAtSlot(
+ beacon.Slot(
+ spec.BELLATRIX_FORK_EPOCH*beacon.Epoch(spec.SLOTS_PER_EPOCH),
+ ),
+ genesisTime,
+ )
if err != nil {
panic(err)
}
if currentTimestamp >= bellatrixTime {
return beacon.Slot(0)
}
- s := beacon.Slot((bellatrixTime-currentTimestamp)/spec.SECONDS_PER_SLOT) + 1
- fmt.Printf("INFO: bellatrixTime:%d, currentTimestamp:%d, slots=%d\n", bellatrixTime, currentTimestamp, s)
+ s := beacon.Slot(
+ (bellatrixTime-currentTimestamp)/spec.SECONDS_PER_SLOT,
+ ) + 1
+ fmt.Printf(
+ "INFO: bellatrixTime:%d, currentTimestamp:%d, slots=%d\n",
+ bellatrixTime,
+ currentTimestamp,
+ s,
+ )
return s
}
-func TimeUntilTerminalBlock(e *ExecutionClient, c setup.Eth1Consensus, defaultTTD *big.Int, n node) uint64 {
- var ttd = defaultTTD
- if n.ExecutionClientTTD != nil {
- ttd = n.ExecutionClientTTD
+func TimeUntilTerminalBlock(
+ parentCtx context.Context,
+ e *clients.ExecutionClient,
+ c el.ExecutionConsensus,
+ defaultTTD *big.Int,
+) uint64 {
+ ttd := defaultTTD
+ if e.ConfiguredTTD() != nil {
+ ttd = e.ConfiguredTTD()
}
- // Get the current total difficulty for node
- userRPCAddress, err := e.UserRPCAddress()
- if err != nil {
- panic(err)
- }
- client := &http.Client{}
- rpcClient, _ := rpc.DialHTTPWithClient(userRPCAddress, client)
- var tdh *TotalDifficultyHeader
- if err := rpcClient.CallContext(context.Background(), &tdh, "eth_getBlockByNumber", "latest", false); err != nil {
- panic(err)
- }
- td := tdh.TotalDifficulty.ToInt()
- if td.Cmp(ttd) >= 0 {
+ if td, err := e.TotalDifficultyByNumber(parentCtx, nil); err != nil ||
+ td.Cmp(ttd) >= 0 {
// TTD already reached
return 0
+ } else {
+ fmt.Printf("INFO: ttd:%d, td:%d, diffPerBlock:%d, secondsPerBlock:%d\n", ttd, td, c.DifficultyPerBlock(), c.SecondsPerBlock())
+ td.Sub(ttd, td).Div(td, c.DifficultyPerBlock()).Mul(td, big.NewInt(int64(c.SecondsPerBlock())))
+ return td.Uint64()
}
- fmt.Printf("INFO: ttd:%d, td:%d, diffPerBlock:%d, secondsPerBlock:%d\n", ttd, td, c.DifficultyPerBlock(), c.SecondsPerBlock())
- td.Sub(ttd, td).Div(td, c.DifficultyPerBlock()).Mul(td, big.NewInt(int64(c.SecondsPerBlock())))
- return td.Uint64()
-}
-
-func SlotsToDuration(slots beacon.Slot, spec *beacon.Spec) time.Duration {
- return time.Duration(slots) * time.Duration(spec.SECONDS_PER_SLOT) * time.Second
-}
-
-// Gets the head of the execution client
-func GetHead(ctx context.Context, en *ExecutionClient) (ethcommon.Hash, error) {
- ctx, cancel := context.WithCancel(ctx)
- defer cancel()
- userRPCAddress, err := en.UserRPCAddress()
- if err != nil {
- panic(err)
- }
- client := &http.Client{}
- rpcClient, _ := rpc.DialHTTPWithClient(userRPCAddress, client)
- eth := ethclient.NewClient(rpcClient)
- b, err := eth.BlockByNumber(ctx, nil)
- if err != nil {
- return ethcommon.Hash{}, err
- }
- return b.Hash(), nil
-}
-
-// Returns true if all head hashes match
-func CheckHeads(ctx context.Context, all ExecutionClients) (bool, error) {
- if len(all) <= 1 {
- return true, nil
- }
- var hash ethcommon.Hash
- for i, en := range all {
- h, err := GetHead(ctx, en)
- if err != nil {
- return false, err
- }
- if i == 0 {
- hash = h
- } else {
- if h != hash {
- fmt.Printf("Hash mismatch between heads: %s != %s\n", h, hash)
- return false, nil
- }
- fmt.Printf("Hash match between heads: %s == %s\n", h, hash)
- }
- }
- return true, nil
}
diff --git a/simulators/eth2/engine/hive_context.txt b/simulators/eth2/engine/hive_context.txt
new file mode 100644
index 0000000000..a96aa0ea9d
--- /dev/null
+++ b/simulators/eth2/engine/hive_context.txt
@@ -0,0 +1 @@
+..
\ No newline at end of file
diff --git a/simulators/eth2/engine/main.go b/simulators/eth2/engine/main.go
index b8ec3bad5f..949cc6f7ad 100644
--- a/simulators/eth2/engine/main.go
+++ b/simulators/eth2/engine/main.go
@@ -7,7 +7,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ consensus_config "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
)
var (
@@ -47,7 +49,6 @@ var transitionTests = []testSpec{
}
func main() {
-
// Create simulator that runs all tests
sim := hivesim.New()
// From the simulator we can get all client types provided
@@ -55,7 +56,7 @@ func main() {
if err != nil {
panic(err)
}
- c := ClientsByRole(clientTypes)
+ c := clients.ClientsByRole(clientTypes)
if len(c.Eth1) != 1 {
panic("choose 1 eth1 client type")
}
@@ -85,11 +86,11 @@ func main() {
hivesim.MustRunSuite(sim, transitionSuite)
}
-func addAllTests(suite *hivesim.Suite, c *ClientDefinitionsByRole, tests []testSpec) {
+func addAllTests(suite *hivesim.Suite, c *clients.ClientDefinitionsByRole, tests []testSpec) {
mnemonic := "couple kiwi radio river setup fortune hunt grief buddy forward perfect empty slim wear bounce drift execute nation tobacco dutch chapter festival ice fog"
// Generate validator keys to use for all tests.
- keySrc := &setup.MnemonicsKeySource{
+ keySrc := &consensus_config.MnemonicsKeySource{
From: 0,
To: 64,
Validator: mnemonic,
@@ -99,19 +100,23 @@ func addAllTests(suite *hivesim.Suite, c *ClientDefinitionsByRole, tests []testS
if err != nil {
panic(err)
}
- secrets, err := setup.SecretKeys(keys)
+ secrets, err := consensus_config.SecretKeys(keys)
if err != nil {
panic(err)
}
- for _, node := range c.Combinations() {
+ for _, nodeDefinition := range c.Combinations() {
for _, test := range tests {
test := test
suite.Add(hivesim.TestSpec{
- Name: fmt.Sprintf("%s-%s", test.Name, node.String()),
+ Name: fmt.Sprintf("%s-%s", test.Name, nodeDefinition.String()),
Description: test.About,
Run: func(t *hivesim.T) {
- env := &testEnv{c, keys, secrets}
- test.Run(t, env, node)
+ env := &testnet.Environment{
+ Clients: c,
+ Keys: keys,
+ Secrets: secrets,
+ }
+ test.Run(t, env, nodeDefinition)
},
},
)
diff --git a/simulators/eth2/engine/nodes.go b/simulators/eth2/engine/nodes.go
deleted file mode 100644
index 20e6bf980c..0000000000
--- a/simulators/eth2/engine/nodes.go
+++ /dev/null
@@ -1,718 +0,0 @@
-package main
-
-import (
- "bytes"
- "context"
- "encoding/hex"
- "errors"
- "fmt"
- "net"
- "net/http"
- "strings"
- "time"
-
- ethcommon "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
- "github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/beaconapi"
- "github.com/protolambda/eth2api/client/nodeapi"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
- "github.com/protolambda/zrnt/eth2/beacon/common"
-)
-
-const (
- PortUserRPC = 8545
- PortEngineRPC = 8551
- PortBeaconTCP = 9000
- PortBeaconUDP = 9000
- PortBeaconAPI = 4000
- PortBeaconGRPC = 4001
- PortMetrics = 8080
- PortValidatorAPI = 5000
-)
-
-// TODO: we assume the clients were configured with default ports.
-// Would be cleaner to run a script in the client to get the address without assumptions
-
-type ExecutionClient struct {
- T *hivesim.T
- HiveClient *hivesim.Client
- ClientType string
- OptionsGenerator func() ([]hivesim.StartOption, error)
- proxy **Proxy
- proxyPort int
- subnet string
-}
-
-func NewExecutionClient(t *hivesim.T, eth1Def *hivesim.ClientDefinition, optionsGenerator func() ([]hivesim.StartOption, error), proxyPort int, subnet string) *ExecutionClient {
- return &ExecutionClient{
- T: t,
- ClientType: eth1Def.Name,
- OptionsGenerator: optionsGenerator,
- proxyPort: proxyPort,
- proxy: new(*Proxy),
- subnet: subnet,
- }
-}
-
-func (en *ExecutionClient) UserRPCAddress() (string, error) {
- return fmt.Sprintf("http://%v:%d", en.HiveClient.IP, PortUserRPC), nil
-}
-
-func (en *ExecutionClient) EngineRPCAddress() (string, error) {
- // TODO what will the default port be?
- return fmt.Sprintf("http://%v:%d", en.HiveClient.IP, PortEngineRPC), nil
-}
-
-func (en *ExecutionClient) MustGetEnode() string {
- addr, err := en.HiveClient.EnodeURL()
- if err != nil {
- panic(err)
- }
- return addr
-}
-
-func (en *ExecutionClient) Start(extraOptions ...hivesim.StartOption) error {
- if en.HiveClient != nil {
- return fmt.Errorf("Client already started")
- }
- en.T.Logf("Starting client %s", en.ClientType)
- opts, err := en.OptionsGenerator()
- if err != nil {
- return fmt.Errorf("Unable to get start options: %v", err)
- }
- for _, opt := range extraOptions {
- opts = append(opts, opt)
- }
- en.HiveClient = en.T.StartClient(en.ClientType, opts...)
-
- // Prepare proxy
- dest, _ := en.EngineRPCAddress()
-
- secret, err := hex.DecodeString("7365637265747365637265747365637265747365637265747365637265747365")
- if err != nil {
- panic(err)
- }
- simIP, err := en.T.Sim.ContainerNetworkIP(en.T.SuiteID, "bridge", "simulation")
- if err != nil {
- panic(err)
- }
-
- *en.proxy = NewProxy(net.ParseIP(simIP), en.proxyPort, dest, secret)
- return nil
-}
-
-func (en *ExecutionClient) Shutdown() error {
- if err := en.T.Sim.StopClient(en.T.SuiteID, en.T.TestID, en.HiveClient.Container); err != nil {
- return err
- }
- en.HiveClient = nil
- return nil
-}
-
-func (en *ExecutionClient) IsRunning() bool {
- return en.HiveClient != nil
-}
-
-func (en *ExecutionClient) Proxy() *Proxy {
- if en.proxy != nil && *en.proxy != nil {
- return *en.proxy
- }
- return nil
-}
-
-type ExecutionClients []*ExecutionClient
-
-// Return subset of clients that are currently running
-func (all ExecutionClients) Running() ExecutionClients {
- res := make(ExecutionClients, 0)
- for _, ec := range all {
- if ec.IsRunning() {
- res = append(res, ec)
- }
- }
- return res
-}
-
-// Return subset of clients that are part of an specific subnet
-func (all ExecutionClients) Subnet(subnet string) ExecutionClients {
- if subnet == "" {
- return all
- }
- res := make(ExecutionClients, 0)
- for _, ec := range all {
- if ec.subnet == subnet {
- res = append(res, ec)
- }
- }
- return res
-}
-
-// Returns comma-separated Bootnodes of all running execution nodes
-func (ens ExecutionClients) Enodes() (string, error) {
- if len(ens) == 0 {
- return "", nil
- }
- enodes := make([]string, 0)
- for _, en := range ens {
- if en.IsRunning() {
- enode, err := en.HiveClient.EnodeURL()
- if err != nil {
- return "", err
- }
- enodes = append(enodes, enode)
- }
- }
- return strings.Join(enodes, ","), nil
-}
-
-type Proxies []**Proxy
-
-func (all Proxies) Running() []*Proxy {
- res := make([]*Proxy, 0)
- for _, p := range all {
- if p != nil && *p != nil {
- res = append(res, *p)
- }
- }
- return res
-}
-
-type BeaconClient struct {
- T *hivesim.T
- HiveClient *hivesim.Client
- ClientType string
- OptionsGenerator func() ([]hivesim.StartOption, error)
- API *eth2api.Eth2HttpClient
- genesisTime common.Timestamp
- spec *common.Spec
- index int
-}
-
-func NewBeaconClient(t *hivesim.T, beaconDef *hivesim.ClientDefinition, optionsGenerator func() ([]hivesim.StartOption, error), genesisTime common.Timestamp, spec *common.Spec, index int) *BeaconClient {
- return &BeaconClient{
- T: t,
- ClientType: beaconDef.Name,
- OptionsGenerator: optionsGenerator,
- genesisTime: genesisTime,
- spec: spec,
- index: index,
- }
-}
-
-func (bn *BeaconClient) Start(extraOptions ...hivesim.StartOption) error {
- if bn.HiveClient != nil {
- return fmt.Errorf("Client already started")
- }
- bn.T.Logf("Starting client %s", bn.ClientType)
- opts, err := bn.OptionsGenerator()
- if err != nil {
- return fmt.Errorf("Unable to get start options: %v", err)
- }
- for _, opt := range extraOptions {
- opts = append(opts, opt)
- }
- bn.HiveClient = bn.T.StartClient(bn.ClientType, opts...)
- bn.API = ð2api.Eth2HttpClient{
- Addr: fmt.Sprintf("http://%s:%d", bn.HiveClient.IP, PortBeaconAPI),
- Cli: &http.Client{},
- Codec: eth2api.JSONCodec{},
- }
- return nil
-}
-
-func (bn *BeaconClient) Shutdown() error {
- if err := bn.T.Sim.StopClient(bn.T.SuiteID, bn.T.TestID, bn.HiveClient.Container); err != nil {
- return err
- }
- bn.HiveClient = nil
- return nil
-}
-
-func (bn *BeaconClient) IsRunning() bool {
- return bn.HiveClient != nil
-}
-
-func (bn *BeaconClient) ENR() (string, error) {
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
- defer cancel()
- var out eth2api.NetworkIdentity
- if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
- return "", err
- }
- fmt.Printf("p2p addrs: %v\n", out.P2PAddresses)
- fmt.Printf("peer id: %s\n", out.PeerID)
- return out.ENR, nil
-}
-
-func (bn *BeaconClient) P2PAddr() (string, error) {
- ctx, _ := context.WithTimeout(context.Background(), time.Second*10)
- var out eth2api.NetworkIdentity
- if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
- return "", err
- }
- return out.P2PAddresses[0], nil
-}
-
-func (bn *BeaconClient) EnodeURL() (string, error) {
- return "", errors.New("beacon node does not have an discv4 Enode URL, use ENR or multi-address instead")
-}
-
-type BeaconClients []*BeaconClient
-
-// Return subset of clients that are currently running
-func (all BeaconClients) Running() BeaconClients {
- res := make(BeaconClients, 0)
- for _, bc := range all {
- if bc.IsRunning() {
- res = append(res, bc)
- }
- }
- return res
-}
-
-// Returns comma-separated ENRs of all running beacon nodes
-func (beacons BeaconClients) ENRs() (string, error) {
- if len(beacons) == 0 {
- return "", nil
- }
- enrs := make([]string, 0)
- for _, bn := range beacons {
- if bn.IsRunning() {
- enr, err := bn.ENR()
- if err != nil {
- return "", err
- }
- enrs = append(enrs, enr)
- }
- }
- return strings.Join(enrs, ","), nil
-}
-
-// Returns comma-separated P2PAddr of all running beacon nodes
-func (beacons BeaconClients) P2PAddrs() (string, error) {
- if len(beacons) == 0 {
- return "", nil
- }
- staticPeers := make([]string, 0)
- for _, bn := range beacons {
- if bn.IsRunning() {
- p2p, err := bn.P2PAddr()
- if err != nil {
- return "", err
- }
- staticPeers = append(staticPeers, p2p)
- }
- }
- return strings.Join(staticPeers, ","), nil
-}
-
-func (b *BeaconClient) WaitForExecutionPayload(ctx context.Context, timeoutSlots common.Slot) (ethcommon.Hash, error) {
- fmt.Printf("Waiting for execution payload on beacon %d\n", b.index)
- slotDuration := time.Duration(b.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = time.After(time.Second * time.Duration(uint64(timeoutSlots)*uint64(b.spec.SECONDS_PER_SLOT)))
- } else {
- timeout = make(<-chan time.Time)
- }
-
- for {
- select {
- case <-ctx.Done():
- return ethcommon.Hash{}, fmt.Errorf("context called")
- case <-timeout:
- return ethcommon.Hash{}, fmt.Errorf("Timeout")
- case <-timer.C:
- realTimeSlot := b.spec.TimeToSlot(common.Timestamp(time.Now().Unix()), b.genesisTime)
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- return ethcommon.Hash{}, fmt.Errorf("WaitForExecutionPayload: failed to poll head: %v", err)
- } else if !exists {
- return ethcommon.Hash{}, fmt.Errorf("WaitForExecutionPayload: failed to poll head: !exists")
- }
- if !headInfo.Canonical {
- continue
- }
-
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(headInfo.Root), &versionedBlock); err != nil {
- // some clients fail to return the head because the client recently re-org'd,
- // keep checking anyway...
- continue
- } else if !exists {
- return ethcommon.Hash{}, fmt.Errorf("WaitForExecutionPayload: block not found")
- }
- var execution ethcommon.Hash
- if versionedBlock.Version == "bellatrix" {
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- copy(execution[:], block.Message.Body.ExecutionPayload.BlockHash[:])
- }
- zero := ethcommon.Hash{}
- fmt.Printf("WaitForExecutionPayload: beacon %d: slot=%d, realTimeSlot=%d, head=%s, exec=%s\n", b.index, headInfo.Header.Message.Slot, realTimeSlot, shorten(headInfo.Root.String()), shorten(execution.Hex()))
- if bytes.Compare(execution[:], zero[:]) != 0 {
- return execution, nil
- }
- }
- }
-}
-
-type BlockV2OptimisticResponse struct {
- Version string `json:"version"`
- ExecutionOptimistic bool `json:"execution_optimistic"`
-}
-
-func (b *BeaconClient) CheckBlockIsOptimistic(ctx context.Context, blockID eth2api.BlockId) (bool, error) {
- var headOptStatus BlockV2OptimisticResponse
- if exists, err := eth2api.SimpleRequest(ctx, b.API, eth2api.FmtGET("/eth/v2/beacon/blocks/%s", blockID.BlockId()), &headOptStatus); err != nil {
- return false, err
- } else if !exists {
- // Block still not synced
- return false, fmt.Errorf("Block not found (!exists)")
- }
- return headOptStatus.ExecutionOptimistic, nil
-}
-
-func (b *BeaconClient) WaitForOptimisticState(ctx context.Context, timeoutSlots common.Slot, blockID eth2api.BlockId, optimistic bool) (*eth2api.BeaconBlockHeaderAndInfo, error) {
- fmt.Printf("Waiting for optimistic sync on beacon %d\n", b.index)
- slotDuration := time.Duration(b.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = time.After(time.Second * time.Duration(uint64(timeoutSlots)*uint64(b.spec.SECONDS_PER_SLOT)))
- } else {
- timeout = make(<-chan time.Time)
- }
-
- for {
- select {
- case <-ctx.Done():
- return nil, fmt.Errorf("context done")
- case <-timeout:
- return nil, fmt.Errorf("Timeout")
- case <-timer.C:
- var headOptStatus BlockV2OptimisticResponse
- if exists, err := eth2api.SimpleRequest(ctx, b.API, eth2api.FmtGET("/eth/v2/beacon/blocks/%s", blockID.BlockId()), &headOptStatus); err != nil {
- // Block still not synced
- continue
- } else if !exists {
- // Block still not synced
- continue
- }
- if headOptStatus.ExecutionOptimistic != optimistic {
- continue
- }
- // Return the block
- var blockInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, blockID, &blockInfo); err != nil {
- return nil, fmt.Errorf("WaitForExecutionPayload: failed to poll block: %v", err)
- } else if !exists {
- return nil, fmt.Errorf("WaitForExecutionPayload: failed to poll block: !exists")
- }
- return &blockInfo, nil
- }
- }
-}
-
-//
-func (bn *BeaconClient) GetLatestExecutionBeaconBlock(ctx context.Context) (*bellatrix.SignedBeaconBlock, error) {
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, bn.API, eth2api.BlockHead, &headInfo); err != nil {
- return nil, fmt.Errorf("failed to poll head: %v", err)
- } else if !exists {
- return nil, fmt.Errorf("no head block")
- }
- for slot := headInfo.Header.Message.Slot; slot > 0; slot-- {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- return nil, fmt.Errorf("failed to retrieve block: %v", err)
- } else if !exists {
- return nil, fmt.Errorf("block not found")
- }
- if versionedBlock.Version != "bellatrix" {
- return nil, nil
- }
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- payload := block.Message.Body.ExecutionPayload
- if ethcommon.BytesToHash(payload.BlockHash[:]) != (ethcommon.Hash{}) {
- return block, nil
- }
- }
- return nil, nil
-}
-
-func (bn *BeaconClient) GetFirstExecutionBeaconBlock(ctx context.Context) (*bellatrix.SignedBeaconBlock, error) {
- lastSlot := bn.spec.TimeToSlot(common.Timestamp(time.Now().Unix()), bn.genesisTime)
- for slot := common.Slot(0); slot <= lastSlot; slot++ {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- continue
- } else if !exists {
- continue
- }
- if versionedBlock.Version != "bellatrix" {
- continue
- }
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- payload := block.Message.Body.ExecutionPayload
- if ethcommon.BytesToHash(payload.BlockHash[:]) != (ethcommon.Hash{}) {
- return block, nil
- }
- }
- return nil, nil
-}
-
-func (bn *BeaconClient) GetBeaconBlockByExecutionHash(ctx context.Context, hash ethcommon.Hash) (*bellatrix.SignedBeaconBlock, error) {
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, bn.API, eth2api.BlockHead, &headInfo); err != nil {
- return nil, fmt.Errorf("failed to poll head: %v", err)
- } else if !exists {
- return nil, fmt.Errorf("no head block")
- }
-
- for slot := int(headInfo.Header.Message.Slot); slot > 0; slot -= 1 {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- continue
- } else if !exists {
- continue
- }
- if versionedBlock.Version != "bellatrix" {
- // Block can't contain an executable payload, and we are not going to find it going backwards, so return.
- return nil, nil
- }
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- payload := block.Message.Body.ExecutionPayload
- if bytes.Compare(payload.BlockHash[:], hash[:]) == 0 {
- return block, nil
- }
- }
- return nil, nil
-}
-
-func (b BeaconClients) GetBeaconBlockByExecutionHash(ctx context.Context, hash ethcommon.Hash) (*bellatrix.SignedBeaconBlock, error) {
- for _, bn := range b {
- block, err := bn.GetBeaconBlockByExecutionHash(ctx, hash)
- if err != nil || block != nil {
- return block, err
- }
- }
- return nil, nil
-}
-
-type ValidatorClient struct {
- T *hivesim.T
- HiveClient *hivesim.Client
- ClientType string
- OptionsGenerator func([]*setup.KeyDetails) ([]hivesim.StartOption, error)
- Keys []*setup.KeyDetails
-}
-
-func NewValidatorClient(t *hivesim.T, validatorDef *hivesim.ClientDefinition, optionsGenerator func([]*setup.KeyDetails) ([]hivesim.StartOption, error), keys []*setup.KeyDetails) *ValidatorClient {
- return &ValidatorClient{
- T: t,
- ClientType: validatorDef.Name,
- OptionsGenerator: optionsGenerator,
- Keys: keys,
- }
-}
-
-func (vc *ValidatorClient) Start(extraOptions ...hivesim.StartOption) error {
- if vc.HiveClient != nil {
- return fmt.Errorf("Client already started")
- }
- if len(vc.Keys) == 0 {
- vc.T.Logf("Skipping validator because it has 0 validator keys")
- return nil
- }
- vc.T.Logf("Starting client %s", vc.ClientType)
- opts, err := vc.OptionsGenerator(vc.Keys)
- if err != nil {
- return fmt.Errorf("Unable to get start options: %v", err)
- }
- for _, opt := range extraOptions {
- opts = append(opts, opt)
- }
- vc.HiveClient = vc.T.StartClient(vc.ClientType, opts...)
- return nil
-}
-
-func (vc *ValidatorClient) Shutdown() error {
- if err := vc.T.Sim.StopClient(vc.T.SuiteID, vc.T.TestID, vc.HiveClient.Container); err != nil {
- return err
- }
- vc.HiveClient = nil
- return nil
-}
-
-func (vc *ValidatorClient) IsRunning() bool {
- return vc.HiveClient != nil
-}
-
-func (v *ValidatorClient) ContainsKey(pk [48]byte) bool {
- for _, k := range v.Keys {
- if k.ValidatorPubkey == pk {
- return true
- }
- }
- return false
-}
-
-type ValidatorClients []*ValidatorClient
-
-// Return subset of clients that are currently running
-func (all ValidatorClients) Running() ValidatorClients {
- res := make(ValidatorClients, 0)
- for _, vc := range all {
- if vc.IsRunning() {
- res = append(res, vc)
- }
- }
- return res
-}
-
-// A validator client bundle consists of:
-// - Execution client
-// - Beacon client
-// - Validator client
-type NodeClientBundle struct {
- T *hivesim.T
- Index int
- ExecutionClient *ExecutionClient
- BeaconClient *BeaconClient
- ValidatorClient *ValidatorClient
- Verification bool
-}
-
-// Starts all clients included in the bundle
-func (cb *NodeClientBundle) Start(extraOptions ...hivesim.StartOption) error {
- cb.T.Logf("Starting validator client bundle %d", cb.Index)
- if cb.ExecutionClient != nil {
- if err := cb.ExecutionClient.Start(extraOptions...); err != nil {
- return err
- }
- } else {
- cb.T.Logf("No execution client started")
- }
- if cb.BeaconClient != nil {
- if err := cb.BeaconClient.Start(extraOptions...); err != nil {
- return err
- }
- } else {
- cb.T.Logf("No beacon client started")
- }
- if cb.ValidatorClient != nil {
- if err := cb.ValidatorClient.Start(extraOptions...); err != nil {
- return err
- }
- } else {
- cb.T.Logf("No validator client started")
- }
- return nil
-}
-
-func (cb *NodeClientBundle) Shutdown() error {
- if err := cb.ExecutionClient.Shutdown(); err != nil {
- return err
- }
- if err := cb.BeaconClient.Shutdown(); err != nil {
- return err
- }
- if err := cb.ValidatorClient.Shutdown(); err != nil {
- return err
- }
- return nil
-}
-
-type NodeClientBundles []*NodeClientBundle
-
-// Return all execution clients, even the ones not currently running
-func (cbs NodeClientBundles) ExecutionClients() ExecutionClients {
- en := make(ExecutionClients, 0)
- for _, cb := range cbs {
- if cb.ExecutionClient != nil {
- en = append(en, cb.ExecutionClient)
- }
- }
- return en
-}
-
-// Return all proxy pointers, even the ones not currently running
-func (cbs NodeClientBundles) Proxies() Proxies {
- ps := make(Proxies, 0)
- for _, cb := range cbs {
- if cb.ExecutionClient != nil {
- ps = append(ps, cb.ExecutionClient.proxy)
- }
- }
- return ps
-}
-
-// Return all beacon clients, even the ones not currently running
-func (cbs NodeClientBundles) BeaconClients() BeaconClients {
- bn := make(BeaconClients, 0)
- for _, cb := range cbs {
- if cb.BeaconClient != nil {
- bn = append(bn, cb.BeaconClient)
- }
- }
- return bn
-}
-
-// Return all validator clients, even the ones not currently running
-func (cbs NodeClientBundles) ValidatorClients() ValidatorClients {
- vc := make(ValidatorClients, 0)
- for _, cb := range cbs {
- if cb.ValidatorClient != nil {
- vc = append(vc, cb.ValidatorClient)
- }
- }
- return vc
-}
-
-// Return subset of nodes which are marked as verification nodes
-func (all NodeClientBundles) VerificationNodes() NodeClientBundles {
- // If none is set as verification, then all are verification nodes
- var any bool
- for _, cb := range all {
- if cb.Verification {
- any = true
- break
- }
- }
- if !any {
- return all
- }
-
- res := make(NodeClientBundles, 0)
- for _, cb := range all {
- if cb.Verification {
- res = append(res, cb)
- }
- }
- return res
-}
-
-func (cbs NodeClientBundles) RemoveNodeAsVerifier(id int) error {
- if id >= len(cbs) {
- return fmt.Errorf("Node %d does not exist", id)
- }
- var any bool
- for _, cb := range cbs {
- if cb.Verification {
- any = true
- break
- }
- }
- if any {
- cbs[id].Verification = false
- } else {
- // If no node is set as verifier, we will set all other nodes as verifiers then
- for i := range cbs {
- cbs[i].Verification = (i != id)
- }
- }
- return nil
-}
diff --git a/simulators/eth2/engine/roles.go b/simulators/eth2/engine/roles.go
deleted file mode 100644
index c4de1b004b..0000000000
--- a/simulators/eth2/engine/roles.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package main
-
-import "github.com/ethereum/hive/hivesim"
-
-type ClientDefinitionsByRole struct {
- Beacon []*hivesim.ClientDefinition `json:"beacon"`
- Validator []*hivesim.ClientDefinition `json:"validator"`
- Eth1 []*hivesim.ClientDefinition `json:"eth1"`
- Other []*hivesim.ClientDefinition `json:"Other"`
-}
-
-func ClientsByRole(available []*hivesim.ClientDefinition) *ClientDefinitionsByRole {
- var out ClientDefinitionsByRole
- for _, client := range available {
- if client.HasRole("beacon") {
- out.Beacon = append(out.Beacon, client)
- }
- if client.HasRole("validator") {
- out.Validator = append(out.Validator, client)
- }
- if client.HasRole("eth1") {
- out.Eth1 = append(out.Eth1, client)
- }
- }
- return &out
-}
-
-func (c *ClientDefinitionsByRole) ClientByNameAndRole(name, role string) *hivesim.ClientDefinition {
- switch role {
- case "beacon":
- return byName(c.Beacon, name)
- case "validator":
- return byName(c.Validator, name)
- case "eth1":
- return byName(c.Eth1, name)
- }
- return nil
-}
-
-func byName(clients []*hivesim.ClientDefinition, name string) *hivesim.ClientDefinition {
- for _, client := range clients {
- if client.Name == name {
- return client
- }
- }
- return nil
-}
-
-func (c *ClientDefinitionsByRole) Combinations() []node {
- var nodes []node
- for _, beacon := range c.Beacon {
- for _, eth1 := range c.Eth1 {
- nodes = append(nodes, node{ExecutionClient: eth1.Name, ConsensusClient: beacon.Name[:len(beacon.Name)-3]})
- }
- }
- return nodes
-}
diff --git a/simulators/eth2/engine/running_testnet.go b/simulators/eth2/engine/running_testnet.go
deleted file mode 100644
index f697d0a46f..0000000000
--- a/simulators/eth2/engine/running_testnet.go
+++ /dev/null
@@ -1,713 +0,0 @@
-package main
-
-import (
- "bytes"
- "context"
- "fmt"
- "math/big"
- "net/http"
- "sync"
- "time"
-
- ethcommon "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/beaconapi"
- "github.com/protolambda/eth2api/client/debugapi"
- "github.com/protolambda/zrnt/eth2/beacon/altair"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/zrnt/eth2/beacon/phase0"
- "github.com/protolambda/zrnt/eth2/util/math"
- "github.com/protolambda/ztyp/tree"
-
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
-)
-
-var MAX_PARTICIPATION_SCORE = 7
-
-type Testnet struct {
- *hivesim.T
- NodeClientBundles
-
- genesisTime common.Timestamp
- genesisValidatorsRoot common.Root
-
- // Consensus chain configuration
- spec *common.Spec
- // Execution chain configuration and genesis info
- eth1Genesis *setup.Eth1Genesis
-}
-
-func startTestnet(t *hivesim.T, env *testEnv, config *Config) *Testnet {
- prep := prepareTestnet(t, env, config)
- testnet := prep.createTestnet(t)
- genesisTime := testnet.GenesisTime()
- countdown := genesisTime.Sub(time.Now())
- t.Logf("Created new testnet, genesis at %s (%s from now)", genesisTime, countdown)
-
- testnet.NodeClientBundles = make(NodeClientBundles, len(config.Nodes))
-
- // Init all client bundles
- for nodeIndex := range testnet.NodeClientBundles {
- testnet.NodeClientBundles[nodeIndex] = new(NodeClientBundle)
- }
-
- // For each key partition, we start a client bundle that consists of:
- // - 1 execution client
- // - 1 beacon client
- // - 1 validator client,
- for nodeIndex, node := range config.Nodes {
- // Prepare clients for this node
- var (
- nodeClient = testnet.NodeClientBundles[nodeIndex]
-
- executionDef = env.Clients.ClientByNameAndRole(node.ExecutionClient, "eth1")
- beaconDef = env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-bn", node.ConsensusClient), "beacon")
- validatorDef = env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-vc", node.ConsensusClient), "validator")
- )
-
- if executionDef == nil || beaconDef == nil || validatorDef == nil {
- t.Fatalf("FAIL: Unable to get client")
- }
-
- // Prepare the client objects with all the information necessary to eventually start
- nodeClient.ExecutionClient = prep.prepareExecutionNode(testnet, executionDef, config.Eth1Consensus, node.ExecutionClientTTD, nodeIndex, node.Chain, node.ExecutionSubnet)
- if node.ConsensusClient != "" {
- nodeClient.BeaconClient = prep.prepareBeaconNode(testnet, beaconDef, node.BeaconNodeTTD, nodeIndex, nodeClient.ExecutionClient)
- nodeClient.ValidatorClient = prep.prepareValidatorClient(testnet, validatorDef, nodeClient.BeaconClient, nodeIndex)
- }
-
- // Add rest of properties
- nodeClient.T = t
- nodeClient.Index = nodeIndex
- nodeClient.Verification = node.TestVerificationNode
-
- // Start the node clients if specified so
- if !node.DisableStartup {
- nodeClient.Start()
- }
- }
-
- return testnet
-}
-
-func (t *Testnet) stopTestnet() {
- for _, p := range t.Proxies().Running() {
- p.cancel()
- }
-}
-
-func (t *Testnet) GenesisTime() time.Time {
- return time.Unix(int64(t.genesisTime), 0)
-}
-
-func (t *Testnet) SlotsTimeout(slots common.Slot) <-chan time.Time {
- return time.After(time.Duration(uint64(slots)*uint64(t.spec.SECONDS_PER_SLOT)) * time.Second)
-}
-
-func (t *Testnet) ValidatorClientIndex(pk [48]byte) (int, error) {
- for i, v := range t.ValidatorClients() {
- if v.ContainsKey(pk) {
- return i, nil
- }
- }
- return 0, fmt.Errorf("key not found in any validator client")
-}
-
-// WaitForFinality blocks until a beacon client reaches finality,
-// or timeoutSlots have passed, whichever happens first.
-func (t *Testnet) WaitForFinality(ctx context.Context, timeoutSlots common.Slot) (common.Checkpoint, error) {
- genesis := t.GenesisTime()
- slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- done := make(chan common.Checkpoint, len(runningBeacons))
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = t.SlotsTimeout(timeoutSlots)
- } else {
- timeout = make(<-chan time.Time)
- }
- for {
- select {
- case <-ctx.Done():
- return common.Checkpoint{}, fmt.Errorf("context called")
- case <-timeout:
- return common.Checkpoint{}, fmt.Errorf("Timeout")
- case finalized := <-done:
- return finalized, nil
- case tim := <-timer.C:
- // start polling after first slot of genesis
- if tim.Before(genesis.Add(slotDuration)) {
- t.Logf("Time till genesis: %s", genesis.Sub(tim))
- continue
- }
-
- // new slot, log and check status of all beacon nodes
- type res struct {
- idx int
- msg string
- err error
- }
- var (
- wg sync.WaitGroup
- ch = make(chan res, len(runningBeacons))
- )
- for i, b := range runningBeacons {
- wg.Add(1)
- go func(ctx context.Context, i int, b *BeaconClient, ch chan res) {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- var (
- slot common.Slot
- head string
- justified string
- finalized string
- execution string
- health float64
- )
-
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: no head block", i)}
- return
- }
-
- var checkpoints eth2api.FinalityCheckpoints
- if exists, err := beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil || !exists {
- if exists, err = beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdSlot(headInfo.Header.Message.Slot), &checkpoints); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll finality checkpoint: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: Expected state for head block", i)}
- return
- }
- }
-
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(headInfo.Root), &versionedBlock); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to retrieve block: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: block not found", i)}
- return
- }
- switch versionedBlock.Version {
- case "phase0":
- execution = "0x0000..0000"
- case "altair":
- execution = "0x0000..0000"
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- execution = shorten(block.Message.Body.ExecutionPayload.BlockHash.String())
- }
-
- slot = headInfo.Header.Message.Slot
- head = shorten(headInfo.Root.String())
- justified = shorten(checkpoints.CurrentJustified.String())
- finalized = shorten(checkpoints.Finalized.String())
- health, err := getHealth(ctx, b.API, t.spec, slot)
- if err != nil {
- // warning is printed here instead because some clients
- // don't support the required REST endpoint.
- fmt.Printf("WARN: beacon %d: %s\n", i, err)
- }
-
- ep := t.spec.SlotToEpoch(slot)
- if ep > 4 && ep > checkpoints.Finalized.Epoch+2 {
- ch <- res{err: fmt.Errorf("failed to finalize, head slot %d (epoch %d) is more than 2 ahead of finality checkpoint %d", slot, ep, checkpoints.Finalized.Epoch)}
- } else {
- ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s, health=%.2f, exec_payload=%s, justified=%s, finalized=%s", i, slot, head, health, execution, justified, finalized), nil}
- }
-
- if (checkpoints.Finalized != common.Checkpoint{}) {
- done <- checkpoints.Finalized
- }
- }(ctx, i, b, ch)
- }
- wg.Wait()
- close(ch)
-
- // print out logs in ascending idx order
- sorted := make([]string, len(runningBeacons))
- for out := range ch {
- if out.err != nil {
- return common.Checkpoint{}, out.err
- }
- sorted[out.idx] = out.msg
- }
- for _, msg := range sorted {
- t.Logf(msg)
- }
- }
- }
-}
-
-// WaitForExecutionFinality blocks until a beacon client reaches finality
-// and the finality checkpoint contains an execution payload,
-// or timeoutSlots have passed, whichever happens first.
-func (t *Testnet) WaitForExecutionFinality(ctx context.Context, timeoutSlots common.Slot) (common.Checkpoint, error) {
- genesis := t.GenesisTime()
- slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- done := make(chan common.Checkpoint, len(runningBeacons))
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = t.SlotsTimeout(timeoutSlots)
- } else {
- timeout = make(<-chan time.Time)
- }
- for {
- select {
- case <-ctx.Done():
- return common.Checkpoint{}, fmt.Errorf("context called")
- case <-timeout:
- return common.Checkpoint{}, fmt.Errorf("Timeout")
- case finalized := <-done:
- return finalized, nil
- case tim := <-timer.C:
- // start polling after first slot of genesis
- if tim.Before(genesis.Add(slotDuration)) {
- t.Logf("Time till genesis: %s", genesis.Sub(tim))
- continue
- }
-
- // new slot, log and check status of all beacon nodes
- type res struct {
- idx int
- msg string
- err error
- }
- var (
- wg sync.WaitGroup
- ch = make(chan res, len(runningBeacons))
- )
- for i, b := range runningBeacons {
- wg.Add(1)
- go func(ctx context.Context, i int, b *BeaconClient, ch chan res) {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- var (
- slot common.Slot
- head string
- justified string
- finalized string
- )
-
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: no head block", i)}
- return
- }
-
- var checkpoints eth2api.FinalityCheckpoints
- if exists, err := beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil || !exists {
- if exists, err = beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdSlot(headInfo.Header.Message.Slot), &checkpoints); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll finality checkpoint: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: Expected state for head block", i)}
- return
- }
- }
-
- slot = headInfo.Header.Message.Slot
- head = shorten(headInfo.Root.String())
- justified = shorten(checkpoints.CurrentJustified.String())
- finalized = shorten(checkpoints.Finalized.String())
-
- var (
- execution tree.Root
- executionStr = "0x0000..0000"
- )
-
- if (checkpoints.Finalized != common.Checkpoint{}) {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(checkpoints.Finalized.Root), &versionedBlock); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to retrieve block: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: block not found", i)}
- return
- }
-
- switch versionedBlock.Version {
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- execution = block.Message.Body.ExecutionPayload.BlockHash
- executionStr = shorten(execution.String())
- }
- }
-
- ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s, finalized_exec_payload=%s, justified=%s, finalized=%s", i, slot, head, executionStr, justified, finalized), nil}
-
- if (execution != tree.Root{}) {
- done <- checkpoints.Finalized
- }
- }(ctx, i, b, ch)
- }
- wg.Wait()
- close(ch)
-
- // print out logs in ascending idx order
- sorted := make([]string, len(runningBeacons))
- for out := range ch {
- if out.err != nil {
- return common.Checkpoint{}, out.err
- }
- sorted[out.idx] = out.msg
- }
- for _, msg := range sorted {
- t.Logf(msg)
- }
- }
- }
-}
-
-// Waits for the current epoch to be finalized, or timeoutSlots have passed, whichever happens first.
-func (t *Testnet) WaitForCurrentEpochFinalization(ctx context.Context, timeoutSlots common.Slot) (common.Checkpoint, error) {
- genesis := t.GenesisTime()
- slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- done := make(chan common.Checkpoint, len(runningBeacons))
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = t.SlotsTimeout(timeoutSlots)
- } else {
- timeout = make(<-chan time.Time)
- }
-
- // Get the current head root which must be finalized
- var (
- epochToBeFinalized common.Epoch
- headInfo eth2api.BeaconBlockHeaderAndInfo
- )
- if exists, err := beaconapi.BlockHeader(ctx, runningBeacons[0].API, eth2api.BlockHead, &headInfo); err != nil {
- return common.Checkpoint{}, fmt.Errorf("failed to poll head: %v", err)
- } else if !exists {
- return common.Checkpoint{}, fmt.Errorf("no head block")
- }
- epochToBeFinalized = t.spec.SlotToEpoch(headInfo.Header.Message.Slot)
-
- for {
- select {
- case <-ctx.Done():
- return common.Checkpoint{}, fmt.Errorf("context called")
- case <-timeout:
- return common.Checkpoint{}, fmt.Errorf("Timeout")
- case finalized := <-done:
- return finalized, nil
- case tim := <-timer.C:
- // start polling after first slot of genesis
- if tim.Before(genesis.Add(slotDuration)) {
- t.Logf("Time till genesis: %s", genesis.Sub(tim))
- continue
- }
-
- // new slot, log and check status of all beacon nodes
- type res struct {
- idx int
- msg string
- err error
- }
- var (
- wg sync.WaitGroup
- ch = make(chan res, len(runningBeacons))
- )
- for i, b := range runningBeacons {
- wg.Add(1)
- go func(ctx context.Context, i int, b *BeaconClient, ch chan res) {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- var (
- slot common.Slot
- head string
- justified string
- finalized string
- )
-
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: no head block", i)}
- return
- }
-
- var checkpoints eth2api.FinalityCheckpoints
- if exists, err := beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil || !exists {
- if exists, err = beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdSlot(headInfo.Header.Message.Slot), &checkpoints); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll finality checkpoint: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: Expected state for head block", i)}
- return
- }
- }
-
- slot = headInfo.Header.Message.Slot
- head = shorten(headInfo.Root.String())
- justified = shorten(checkpoints.CurrentJustified.String())
- finalized = shorten(checkpoints.Finalized.String())
-
- ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s justified=%s, finalized=%s, epoch_to_finalize=%d", i, slot, head, justified, finalized, epochToBeFinalized), nil}
-
- if checkpoints.Finalized != (common.Checkpoint{}) && checkpoints.Finalized.Epoch >= epochToBeFinalized {
- done <- checkpoints.Finalized
- }
- }(ctx, i, b, ch)
- }
- wg.Wait()
- close(ch)
-
- // print out logs in ascending idx order
- sorted := make([]string, len(runningBeacons))
- for out := range ch {
- if out.err != nil {
- return common.Checkpoint{}, out.err
- }
- sorted[out.idx] = out.msg
- }
- for _, msg := range sorted {
- t.Logf(msg)
- }
- }
- }
-}
-
-// Waits for any execution payload to be available included in a beacon block (merge),
-// or timeoutSlots have passed, whichever happens first.
-func (t *Testnet) WaitForExecutionPayload(ctx context.Context, timeoutSlots common.Slot) (ethcommon.Hash, error) {
- genesis := t.GenesisTime()
- slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- done := make(chan ethcommon.Hash, len(runningBeacons))
- userRPCAddress, err := t.ExecutionClients().Running()[0].UserRPCAddress()
- if err != nil {
- panic(err)
- }
- client := &http.Client{}
- rpcClient, _ := rpc.DialHTTPWithClient(userRPCAddress, client)
- ttdReached := false
- var timeout <-chan time.Time
- if timeoutSlots > 0 {
- timeout = t.SlotsTimeout(timeoutSlots)
- } else {
- timeout = make(<-chan time.Time)
- }
- for {
- select {
- case <-ctx.Done():
- return ethcommon.Hash{}, fmt.Errorf("context called")
- case result := <-done:
- return result, nil
- case <-timeout:
- return ethcommon.Hash{}, fmt.Errorf("Timeout")
- case tim := <-timer.C:
- // start polling after first slot of genesis
- if tim.Before(genesis.Add(slotDuration)) {
- t.Logf("Time till genesis: %s", genesis.Sub(tim))
- continue
- }
-
- if !ttdReached {
- // Check if TTD has been reached
- var td *TotalDifficultyHeader
- if err := rpcClient.CallContext(ctx, &td, "eth_getBlockByNumber", "latest", false); err == nil {
- if td.TotalDifficulty.ToInt().Cmp(t.eth1Genesis.Genesis.Config.TerminalTotalDifficulty) >= 0 {
- t.Logf("ttd (%d) reached at execution block %d", t.eth1Genesis.Genesis.Config.TerminalTotalDifficulty, td.Number)
- ttdReached = true
- }
- } else {
- t.Logf("Error querying eth1 for TTD: %v", err)
- }
- }
-
- // new slot, log and check status of all beacon nodes
- type res struct {
- idx int
- msg string
- err error
- }
-
- var (
- wg sync.WaitGroup
- ch = make(chan res, len(runningBeacons))
- )
- for i, b := range runningBeacons {
- wg.Add(1)
- go func(ctx context.Context, i int, b *BeaconClient, ch chan res) {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- var (
- slot common.Slot
- head string
- execution ethcommon.Hash
- health float64
- )
-
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: no head block", i)}
- return
- }
-
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(headInfo.Root), &versionedBlock); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to retrieve block: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: block not found", i)}
- return
- }
- switch versionedBlock.Version {
- case "phase0":
- execution = ethcommon.Hash{}
- case "altair":
- execution = ethcommon.Hash{}
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- zero := ethcommon.Hash{}
-
- copy(execution[:], block.Message.Body.ExecutionPayload.BlockHash[:])
-
- if bytes.Compare(execution[:], zero[:]) != 0 {
- done <- execution
- }
- }
-
- slot = headInfo.Header.Message.Slot
- head = shorten(headInfo.Root.String())
- health, err := getHealth(ctx, b.API, t.spec, slot)
- if err != nil {
- // warning is printed here instead because some clients
- // don't support the required REST endpoint.
- fmt.Printf("WARN: beacon %d: %s\n", i, err)
- }
-
- ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s, health=%.2f, exec_payload=%s", i, slot, head, health, shorten(execution.Hex())), nil}
-
- }(ctx, i, b, ch)
- }
- wg.Wait()
- close(ch)
-
- // print out logs in ascending idx order
- sorted := make([]string, len(runningBeacons))
- for out := range ch {
- if out.err != nil {
- return ethcommon.Hash{}, out.err
- }
- sorted[out.idx] = out.msg
- }
- for _, msg := range sorted {
- t.Logf(msg)
- }
-
- }
- }
-}
-
-func getHealth(ctx context.Context, api *eth2api.Eth2HttpClient, spec *common.Spec, slot common.Slot) (float64, error) {
- var (
- health float64
- stateInfo eth2api.VersionedBeaconState
- )
- if exists, err := debugapi.BeaconStateV2(ctx, api, eth2api.StateIdSlot(slot), &stateInfo); err != nil {
- return 0, fmt.Errorf("failed to retrieve state: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("block not found")
- }
- switch stateInfo.Version {
- case "phase0":
- state := stateInfo.Data.(*phase0.BeaconState)
- epoch := spec.SlotToEpoch(slot)
- validatorIds := make([]eth2api.ValidatorId, 0, len(state.Validators))
- for id, validator := range state.Validators {
- if epoch >= validator.ActivationEligibilityEpoch && epoch < validator.ExitEpoch && !validator.Slashed {
- validatorIds = append(validatorIds, eth2api.ValidatorIdIndex(id))
- }
- }
- var (
- beforeEpoch = 0
- afterEpoch = spec.SlotToEpoch(slot)
- balancesBefore []eth2api.ValidatorBalanceResponse
- balancesAfter []eth2api.ValidatorBalanceResponse
- )
-
- // If it's genesis, keep before also set to 0.
- if afterEpoch != 0 {
- beforeEpoch = int(spec.SlotToEpoch(slot)) - 1
- }
- if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(beforeEpoch*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesBefore); err != nil {
- return 0, fmt.Errorf("failed to retrieve validator balances: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("validator balances not found")
- }
- if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(int(afterEpoch)*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesAfter); err != nil {
- return 0, fmt.Errorf("failed to retrieve validator balances: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("validator balances not found")
- }
- health = legacyCalcHealth(spec, balancesBefore, balancesAfter)
- case "altair":
- state := stateInfo.Data.(*altair.BeaconState)
- health = calcHealth(state.CurrentEpochParticipation)
- case "bellatrix":
- state := stateInfo.Data.(*bellatrix.BeaconState)
- health = calcHealth(state.CurrentEpochParticipation)
- }
- return health, nil
-}
-
-func calcHealth(p altair.ParticipationRegistry) float64 {
- sum := 0
- for _, p := range p {
- sum += int(p)
- }
- avg := float64(sum) / float64(len(p))
- return avg / float64(MAX_PARTICIPATION_SCORE)
-}
-
-// legacyCalcHealth calculates the health of the network based on balances at
-// the beginning of an epoch versus the balances at the end.
-//
-// NOTE: this isn't strictly the most correct way of doing things, but it is
-// quite accurate and doesn't require implementing the attestation processing
-// logic here.
-func legacyCalcHealth(spec *common.Spec, before, after []eth2api.ValidatorBalanceResponse) float64 {
- sum_before := big.NewInt(0)
- sum_after := big.NewInt(0)
- for i := range before {
- sum_before.Add(sum_before, big.NewInt(int64(before[i].Balance)))
- sum_after.Add(sum_after, big.NewInt(int64(after[i].Balance)))
- }
- count := big.NewInt(int64(len(before)))
- avg_before := big.NewInt(0).Div(sum_before, count).Uint64()
- avg_after := sum_after.Div(sum_after, count).Uint64()
- reward := avg_before * uint64(spec.BASE_REWARD_FACTOR) / math.IntegerSquareRootPrysm(sum_before.Uint64()) / uint64(spec.HYSTERESIS_QUOTIENT)
- return float64(avg_after-avg_before) / float64(reward*common.BASE_REWARDS_PER_EPOCH)
-}
diff --git a/simulators/eth2/engine/scenarios.go b/simulators/eth2/engine/scenarios.go
index 1af868d97a..7edbab8780 100644
--- a/simulators/eth2/engine/scenarios.go
+++ b/simulators/eth2/engine/scenarios.go
@@ -11,14 +11,18 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- ethcommon "github.com/ethereum/go-ethereum/common"
+ api "github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/engine/setup"
+ "github.com/ethereum/hive/simulators/eth2/common/chain_generators/pow"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+ "github.com/ethereum/hive/simulators/eth2/common/debug"
+ payload_spoof "github.com/ethereum/hive/simulators/eth2/common/spoofing/payload"
+ "github.com/ethereum/hive/simulators/eth2/common/spoofing/proxy"
+ tn "github.com/ethereum/hive/simulators/eth2/common/testnet"
"github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/beaconapi"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
beacon "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/rauljordan/engine-proxy/proxy"
+ spoof "github.com/rauljordan/engine-proxy/proxy"
)
var (
@@ -26,24 +30,28 @@ var (
DEFAULT_SLOT_TIME uint64 = 6
DEFAULT_TERMINAL_TOTAL_DIFFICULTY uint64 = 100
- EPOCHS_TO_FINALITY uint64 = 4
+ EPOCHS_TO_FINALITY beacon.Epoch = 4
// Default config used for all tests unless a client specific config exists
- DEFAULT_CONFIG = &Config{
- ValidatorCount: big.NewInt(int64(DEFAULT_VALIDATOR_COUNT)),
- SlotTime: big.NewInt(int64(DEFAULT_SLOT_TIME)),
- TerminalTotalDifficulty: big.NewInt(int64(DEFAULT_TERMINAL_TOTAL_DIFFICULTY)),
- AltairForkEpoch: common.Big0,
- MergeForkEpoch: common.Big0,
- Eth1Consensus: &setup.Eth1CliqueConsensus{},
+ DEFAULT_CONFIG = &tn.Config{
+ ValidatorCount: big.NewInt(int64(DEFAULT_VALIDATOR_COUNT)),
+ SlotTime: big.NewInt(int64(DEFAULT_SLOT_TIME)),
+ TerminalTotalDifficulty: big.NewInt(
+ int64(DEFAULT_TERMINAL_TOTAL_DIFFICULTY),
+ ),
+ AltairForkEpoch: common.Big0,
+ BellatrixForkEpoch: common.Big0,
+ Eth1Consensus: &el.ExecutionCliqueConsensus{},
}
// Clients that do not support starting on epoch 0 with all forks enabled.
// Tests take longer for these clients.
- INCREMENTAL_FORKS_CONFIG = &Config{
- TerminalTotalDifficulty: big.NewInt(int64(DEFAULT_TERMINAL_TOTAL_DIFFICULTY) * 5),
- AltairForkEpoch: common.Big1,
- MergeForkEpoch: common.Big2,
+ INCREMENTAL_FORKS_CONFIG = &tn.Config{
+ TerminalTotalDifficulty: big.NewInt(
+ int64(DEFAULT_TERMINAL_TOTAL_DIFFICULTY) * 5,
+ ),
+ AltairForkEpoch: common.Big1,
+ BellatrixForkEpoch: common.Big2,
}
INCREMENTAL_FORKS_CLIENTS = map[string]bool{
"nimbus": true,
@@ -53,122 +61,187 @@ var (
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE = map[string]*big.Int{}
)
-func getClientConfig(n node) *Config {
+func getClientConfig(n clients.NodeDefinition) *tn.Config {
config := DEFAULT_CONFIG
- if INCREMENTAL_FORKS_CLIENTS[n.ConsensusClient] == true {
- config = config.join(INCREMENTAL_FORKS_CONFIG)
+ if INCREMENTAL_FORKS_CLIENTS[n.ConsensusClient] {
+ config = config.Join(INCREMENTAL_FORKS_CONFIG)
}
return config
}
-func TransitionTestnet(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: []node{
+func TransitionTestnet(t *hivesim.T, env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- ctx, cancel := context.WithCancel(context.Background())
+ finalityCtx, cancel := testnet.Spec().EpochTimeoutContext(
+ ctx,
+ EPOCHS_TO_FINALITY+1,
+ )
defer cancel()
- finalized, err := testnet.WaitForFinality(ctx, testnet.spec.SLOTS_PER_EPOCH*beacon.Slot(EPOCHS_TO_FINALITY+1))
+
+ finalized, err := testnet.WaitForFinality(finalityCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for finality: %v", err)
}
- if err := VerifyParticipation(testnet, ctx, FirstSlotAfterCheckpoint{&finalized}, 0.95); err != nil {
+
+ if err := testnet.VerifyParticipation(
+ ctx,
+ tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized},
+ 0.95,
+ ); err != nil {
t.Fatalf("FAIL: Verifying participation: %v", err)
}
- if err := VerifyExecutionPayloadIsCanonical(testnet, ctx, LastSlotAtCheckpoint{&finalized}); err != nil {
+
+ if err := testnet.VerifyExecutionPayloadIsCanonical(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ ); err != nil {
t.Fatalf("FAIL: Verifying execution payload is canonical: %v", err)
}
- if err := VerifyProposers(testnet, ctx, LastSlotAtCheckpoint{&finalized}, false); err != nil {
+
+ if err := testnet.VerifyProposers(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ false,
+ ); err != nil {
t.Fatalf("FAIL: Verifying proposers: %v", err)
}
}
-func TestRPCError(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: []node{
+func TestRPCError(t *hivesim.T, env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- ctx, cancel := context.WithCancel(context.Background())
+ finalityCtx, cancel := testnet.Spec().EpochTimeoutContext(
+ ctx,
+ EPOCHS_TO_FINALITY+2,
+ )
defer cancel()
- finalized, err := testnet.WaitForExecutionFinality(ctx, testnet.spec.SLOTS_PER_EPOCH*beacon.Slot(EPOCHS_TO_FINALITY+2))
+
+ finalized, err := testnet.WaitForExecutionFinality(finalityCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for finality: %v", err)
}
- if err := VerifyParticipation(testnet, ctx, FirstSlotAfterCheckpoint{&finalized}, 0.95); err != nil {
+
+ if err := testnet.VerifyParticipation(
+ ctx,
+ tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized},
+ 0.95,
+ ); err != nil {
t.Fatalf("FAIL: Verifying participation: %v", err)
}
- if err := VerifyExecutionPayloadIsCanonical(testnet, ctx, LastSlotAtCheckpoint{&finalized}); err != nil {
+
+ if err := testnet.VerifyExecutionPayloadIsCanonical(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ ); err != nil {
t.Fatalf("FAIL: Verifying execution payload is canonical: %v", err)
}
- if err := VerifyProposers(testnet, ctx, LastSlotAtCheckpoint{&finalized}, true); err != nil {
+
+ if err := testnet.VerifyProposers(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ true,
+ ); err != nil {
t.Fatalf("FAIL: Verifying proposers: %v", err)
}
- if err := VerifyELHeads(testnet, ctx); err != nil {
+
+ if err := testnet.VerifyELHeads(ctx); err != nil {
t.Fatalf("FAIL: Verifying EL Heads: %v", err)
}
+
fields := make(map[string]interface{})
fields["headBlockHash"] = "weird error"
- spoof := &proxy.Spoof{
+ spoof := &spoof.Spoof{
Method: EngineForkchoiceUpdatedV1,
Fields: fields,
}
+
testnet.Proxies().Running()[0].AddRequest(spoof)
+
time.Sleep(24 * time.Second)
- if err := VerifyParticipation(testnet, ctx, FirstSlotAfterCheckpoint{&finalized}, 0.95); err != nil {
+
+ if err := testnet.VerifyParticipation(
+ ctx,
+ tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized},
+ 0.95,
+ ); err != nil {
t.Fatalf("FAIL: %v", err)
}
- if err := VerifyELHeads(testnet, ctx); err == nil {
+
+ if err := testnet.VerifyELHeads(ctx); err == nil {
t.Fatalf("FAIL: Expected different heads after spoof %v", err)
}
}
// Test `latest`, `safe`, `finalized` block labels on the post-merge testnet.
-func BlockLatestSafeFinalized(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: []node{
+func BlockLatestSafeFinalized(t *hivesim.T, env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- ctx, cancel := context.WithCancel(context.Background())
+ finalityCtx, cancel := testnet.Spec().EpochTimeoutContext(
+ ctx,
+ EPOCHS_TO_FINALITY+2,
+ )
defer cancel()
- _, err := testnet.WaitForExecutionFinality(ctx, testnet.spec.SLOTS_PER_EPOCH*beacon.Slot(EPOCHS_TO_FINALITY+2))
+
+ _, err := testnet.WaitForExecutionFinality(finalityCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution finality: %v", err)
}
- if err := VerifyELBlockLabels(testnet, ctx); err != nil {
+
+ if err := testnet.VerifyELBlockLabels(ctx); err != nil {
t.Fatalf("FAIL: Verifying EL block labels: %v", err)
}
}
-// Generate a testnet where the transition payload contains an unknown PoW parent.
-// Verify that the testnet can finalize after this.
-func UnknownPoWParent(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+/*
+Generate a testnet where the transition payload contains an unknown PoW parent.
+Verify that the testnet can finalize after this.
+*/
+func UnknownPoWParent(t *hivesim.T, env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
getPayloadLock sync.Mutex
@@ -181,57 +254,80 @@ func UnknownPoWParent(t *hivesim.T, env *testEnv, n node) {
invalidPayloadNodeID int
)
- // The EL mock will intercept an engine_getPayloadV1 call and set a random parent block in the response
- getPayloadCallbackGen := func(node int) func([]byte, []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ // The EL mock will intercept an engine_getPayloadV1 call and set a random
+ // parent block in the response
+ getPayloadCallbackGen := func(node int) func([]byte, []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
getPayloadLock.Lock()
defer getPayloadLock.Unlock()
getPayloadCount++
// Invalidate the transition payload
if getPayloadCount == 1 {
var (
- payload ExecutableDataV1
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCResponse(res, &payload)
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &payload)
if err != nil {
panic(err)
}
- t.Logf("INFO (%v): Generating payload with unknown PoW parent: %s", t.TestID, res)
- invalidPayloadHash, spoof, err = generateInvalidPayloadSpoof(EngineGetPayloadV1, &payload, InvalidParentHash)
+ t.Logf(
+ "INFO (%v): Generating payload with unknown PoW parent: %s",
+ t.TestID,
+ res,
+ )
+ invalidPayloadHash, spoof, err = payload_spoof.GenerateInvalidPayloadSpoof(
+ EngineGetPayloadV1,
+ &payload,
+ payload_spoof.InvalidParentHash,
+ VaultSigner,
+ )
if err != nil {
panic(err)
}
- t.Logf("INFO (%v): Invalidated payload hash: %v", t.TestID, invalidPayloadHash)
+ t.Logf(
+ "INFO (%v): Invalidated payload hash: %v",
+ t.TestID,
+ invalidPayloadHash,
+ )
invalidPayloadNodeID = node
return spoof
}
return nil
}
}
- // The EL mock will intercept an engine_newPayloadV1 on the node that generated the invalid hash in order to validate it and broadcast it.
- newPayloadCallbackGen := func(node int) func([]byte, []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ // The EL mock will intercept an engine_newPayloadV1 on the node that
+ // generated the invalid hash in order to validate it and broadcast it.
+ newPayloadCallbackGen := func(node int) func([]byte, []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
var (
- payload ExecutableDataV1
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCRequest(req, &payload)
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &payload)
if err != nil {
panic(err)
}
// Validate the new payload in the node that produced it
- if invalidPayloadNodeID == node && payload.BlockHash == invalidPayloadHash {
- t.Logf("INFO (%v): Validating new payload: %s", t.TestID, payload.BlockHash)
+ if invalidPayloadNodeID == node &&
+ payload.BlockHash == invalidPayloadHash {
+ t.Logf(
+ "INFO (%v): Validating new payload: %s",
+ t.TestID,
+ payload.BlockHash,
+ )
- spoof, err = payloadStatusSpoof(EngineNewPayloadV1, &PayloadStatusV1{
- Status: Valid,
- LatestValidHash: &payload.BlockHash,
- ValidationError: nil,
- })
+ spoof, err = payload_spoof.PayloadStatusSpoof(
+ EngineNewPayloadV1,
+ &api.PayloadStatusV1{
+ Status: Valid,
+ LatestValidHash: &payload.BlockHash,
+ ValidationError: nil,
+ },
+ )
if err != nil {
panic(err)
}
@@ -240,29 +336,39 @@ func UnknownPoWParent(t *hivesim.T, env *testEnv, n node) {
return nil
}
}
- // The EL mock will intercept an engine_forkchoiceUpdatedV1 on the node that generated the invalid hash in order to validate it and broadcast it.
- fcUCallbackGen := func(node int) func([]byte, []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ // The EL mock will intercept an engine_forkchoiceUpdatedV1 on the node
+ // that generated the invalid hash in order to validate and broadcast it.
+ fcUCallbackGen := func(node int) func([]byte, []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
var (
- fcState ForkchoiceStateV1
- pAttr PayloadAttributesV1
- spoof *proxy.Spoof
+ fcState api.ForkchoiceStateV1
+ pAttr api.PayloadAttributes
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
if err != nil {
panic(err)
}
// Validate the new payload in the node that produced it
- if invalidPayloadNodeID == node && fcState.HeadBlockHash == invalidPayloadHash {
- t.Logf("INFO (%v): Validating forkchoiceUpdated: %s", t.TestID, fcState.HeadBlockHash)
+ if invalidPayloadNodeID == node &&
+ fcState.HeadBlockHash == invalidPayloadHash {
+ t.Logf(
+ "INFO (%v): Validating forkchoiceUpdated: %s",
+ t.TestID,
+ fcState.HeadBlockHash,
+ )
- spoof, err = forkchoiceResponseSpoof(EngineForkchoiceUpdatedV1, PayloadStatusV1{
- Status: Valid,
- LatestValidHash: &fcState.HeadBlockHash,
- ValidationError: nil,
- }, nil)
+ spoof, err = payload_spoof.ForkchoiceResponseSpoof(
+ EngineForkchoiceUpdatedV1,
+ api.PayloadStatusV1{
+ Status: Valid,
+ LatestValidHash: &fcState.HeadBlockHash,
+ ValidationError: nil,
+ },
+ nil,
+ )
if err != nil {
panic(err)
}
@@ -278,43 +384,75 @@ func UnknownPoWParent(t *hivesim.T, env *testEnv, n node) {
}
// Network should recover from this
- ctx, cancel := context.WithCancel(context.Background())
+ finalityCtx, cancel := testnet.Spec().EpochTimeoutContext(
+ ctx,
+ EPOCHS_TO_FINALITY+1,
+ )
defer cancel()
- finalized, err := testnet.WaitForFinality(ctx, testnet.spec.SLOTS_PER_EPOCH*beacon.Slot(EPOCHS_TO_FINALITY+1))
+
+ finalized, err := testnet.WaitForFinality(finalityCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for finality: %v", err)
}
- // Lowering participation requirement since we invalidated one block temporarily
- if err := VerifyParticipation(testnet, ctx, FirstSlotAfterCheckpoint{&finalized}, 0.80); err != nil {
+
+ // Lowering participation requirement since we invalidated one block
+ // temporarily
+ if err := testnet.VerifyParticipation(
+ ctx,
+ tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized},
+ 0.80,
+ ); err != nil {
t.Fatalf("FAIL: Verifying participation: %v", err)
}
- if err := VerifyExecutionPayloadIsCanonical(testnet, ctx, LastSlotAtCheckpoint{&finalized}); err != nil {
+
+ if err := testnet.VerifyExecutionPayloadIsCanonical(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ ); err != nil {
t.Fatalf("FAIL: Verifying execution payload is canonical: %v", err)
}
- if err := VerifyProposers(testnet, ctx, LastSlotAtCheckpoint{&finalized}, true); err != nil {
+
+ if err := testnet.VerifyProposers(
+ ctx,
+ tn.LastSlotAtCheckpoint{Checkpoint: &finalized},
+ true,
+ ); err != nil {
t.Fatalf("FAIL: Verifying proposers: %v", err)
}
- if err := VerifyELHeads(testnet, ctx); err != nil {
+
+ if err := testnet.VerifyELHeads(ctx); err != nil {
t.Fatalf("FAIL: Verifying EL Heads: %v", err)
}
-
}
-// Generates a testnet case where one payload is invalidated in the recipient nodes.
-// invalidPayloadNumber: The number of the payload to invalidate -- 1 is transition payload, 2+ is any canonical chain payload.
-// invalidStatusResponse: The validation error response to inject in the recipient nodes.
-func InvalidPayloadGen(invalidPayloadNumber int, invalidStatusResponse PayloadStatus) func(t *hivesim.T, env *testEnv, n node) {
- return func(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+/*
+Generates a testnet case where one payload is invalidated in the recipient
+nodes.
+
+invalidPayloadNumber: The number of the payload to invalidate.
+
+ 1 is transition payload, 2+ is any canonical chain payload.
+
+invalidStatusResponse: The validation error response to inject in the
+
+ recipient nodes.
+*/
+func InvalidPayloadGen(
+ invalidPayloadNumber int,
+ invalidStatusResponse PayloadStatus,
+) func(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ return func(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// All proxies will use the same callback, therefore we need to use a lock and a counter
var (
@@ -325,8 +463,8 @@ func InvalidPayloadGen(invalidPayloadNumber int, invalidStatusResponse PayloadSt
)
// The EL mock will intercept the first engine_getPayloadV1 and corrupt the stateRoot in the response
- getPayloadCallbackGen := func(id int) func(res []byte, req []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ getPayloadCallbackGen := func(id int) func(res []byte, req []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
getPayloadLock.Lock()
defer getPayloadLock.Unlock()
getPayloadCount++
@@ -334,9 +472,9 @@ func InvalidPayloadGen(invalidPayloadNumber int, invalidStatusResponse PayloadSt
// We are not going to spoof anything here, we just need to save the transition payload hash and the id of the validator that generated it
// to invalidate it in other clients.
var (
- payload ExecutableDataV1
+ payload api.ExecutableData
)
- err := UnmarshalFromJsonRPCResponse(res, &payload)
+ err := proxy.UnmarshalFromJsonRPCResponse(res, &payload)
if err != nil {
panic(err)
}
@@ -350,82 +488,114 @@ func InvalidPayloadGen(invalidPayloadNumber int, invalidStatusResponse PayloadSt
}
// Here we will intercept the response from the rest of the clients that did not generate the payload to artificially invalidate them
- newPayloadCallbackGen := func(id int) func(res []byte, req []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ newPayloadCallbackGen := func(id int) func(res []byte, req []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
t.Logf("INFO: newPayload callback node %d", id)
var (
- payload ExecutableDataV1
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCRequest(req, &payload)
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &payload)
if err != nil {
panic(err)
}
- // Only invalidate if the payload hash matches the invalid payload hash and this validator is not the one that generated it
- if invalidPayloadProxyId != id && payload.BlockHash == invalidPayloadHash {
+ // Only invalidate if the payload hash matches the invalid
+ // payload hash and this validator is not the one that
+ // generated it
+ if invalidPayloadProxyId != id &&
+ payload.BlockHash == invalidPayloadHash {
var latestValidHash common.Hash
// Latest valid hash depends on the error we are injecting
- if invalidPayloadNumber == 1 || invalidStatusResponse == InvalidBlockHash {
- // The transition payload has a PoW parent, hash must be 0.
- // If the payload has an invalid hash, we cannot link it to any other payload, hence 0.
+ if invalidPayloadNumber == 1 ||
+ invalidStatusResponse == InvalidBlockHash {
+ /* The transition payload has a PoW parent, hash must
+ be 0. If the payload has an invalid hash, we cannot
+ link it to any other payload, hence 0.
+ */
latestValidHash = common.Hash{}
} else {
latestValidHash = payload.ParentHash
}
- status := PayloadStatusV1{
- Status: invalidStatusResponse,
+ status := api.PayloadStatusV1{
+ Status: string(invalidStatusResponse),
LatestValidHash: &latestValidHash,
ValidationError: nil,
}
- spoof, err = payloadStatusSpoof(EngineNewPayloadV1, &status)
+ spoof, err = payload_spoof.PayloadStatusSpoof(
+ EngineNewPayloadV1,
+ &status,
+ )
if err != nil {
panic(err)
}
- t.Logf("INFO: Invalidating payload on validator %d: %v", id, payload.BlockHash)
+ t.Logf(
+ "INFO: Invalidating payload on validator %d: %v",
+ id,
+ payload.BlockHash,
+ )
}
return spoof
}
}
- // We pass the id of the proxy to identify which one it is within the callback
+ /* We pass the id of the proxy to identify which one it is within the
+ callback
+ */
for i, p := range testnet.Proxies().Running() {
p.AddResponseCallback(EngineGetPayloadV1, getPayloadCallbackGen(i))
p.AddResponseCallback(EngineNewPayloadV1, newPayloadCallbackGen(i))
}
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
// Wait 5 slots after the invalidated payload
- time.Sleep(time.Duration(testnet.spec.SECONDS_PER_SLOT) * time.Second * time.Duration(5+invalidPayloadNumber))
+ <-testnet.Spec().SlotsTimeout(5)
// Verify beacon block with invalid payload is not accepted
- b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByHead{}, invalidPayloadHash)
- if err != nil {
+ if b, err := testnet.VerifyExecutionPayloadHashInclusion(
+ ctx,
+ tn.LastestSlotByHead{},
+ invalidPayloadHash,
+ ); err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid Payload %v was included in slot %d (%v)", invalidPayloadHash, b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf(
+ "FAIL: Invalid Payload %v was included in slot %d (%v)",
+ invalidPayloadHash,
+ b.Slot(),
+ b.StateRoot(),
+ )
}
}
}
// The produced and broadcasted payload contains an invalid prevrandao value.
// The PREVRANDAO opcode is not used in any transaction and therefore not introduced in the state changes.
-func IncorrectHeaderPrevRandaoPayload(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+func IncorrectHeaderPrevRandaoPayload(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// All proxies will use the same callback, therefore we need to use a lock and a counter
var (
@@ -435,27 +605,36 @@ func IncorrectHeaderPrevRandaoPayload(t *hivesim.T, env *testEnv, n node) {
)
// The EL mock will intercept an engine_getPayloadV1 call and corrupt the prevRandao in the response
- c := func(res []byte, req []byte) *proxy.Spoof {
+ c := func(res []byte, req []byte) *spoof.Spoof {
getPayloadLock.Lock()
defer getPayloadLock.Unlock()
getPayloadCount++
// Invalidate a payload after the transition payload
if getPayloadCount == 2 {
var (
- payload ExecutableDataV1
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCResponse(res, &payload)
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &payload)
if err != nil {
panic(err)
}
t.Logf("INFO (%v): Invalidating payload: %s", t.TestID, res)
- invalidPayloadHash, spoof, err = generateInvalidPayloadSpoof(EngineGetPayloadV1, &payload, InvalidPrevRandao)
+ invalidPayloadHash, spoof, err = payload_spoof.GenerateInvalidPayloadSpoof(
+ EngineGetPayloadV1,
+ &payload,
+ payload_spoof.InvalidPrevRandao,
+ VaultSigner,
+ )
if err != nil {
panic(err)
}
- t.Logf("INFO (%v): Invalidated payload hash: %v", t.TestID, invalidPayloadHash)
+ t.Logf(
+ "INFO (%v): Invalidated payload hash: %v",
+ t.TestID,
+ invalidPayloadHash,
+ )
return spoof
}
return nil
@@ -464,35 +643,45 @@ func IncorrectHeaderPrevRandaoPayload(t *hivesim.T, env *testEnv, n node) {
p.AddResponseCallback(EngineGetPayloadV1, c)
}
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
// Wait 5 slots
- time.Sleep(time.Duration(testnet.spec.SECONDS_PER_SLOT) * time.Second * 5)
+ time.Sleep(
+ time.Duration(testnet.Spec().SECONDS_PER_SLOT) * time.Second * 5,
+ )
// Verify beacon block with invalid payload is not accepted
- b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByHead{}, invalidPayloadHash)
+ b, err := testnet.VerifyExecutionPayloadHashInclusion(
+ ctx,
+ tn.LastestSlotByHead{},
+ invalidPayloadHash,
+ )
if err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid Payload %v was included in slot %d (%v)", invalidPayloadHash, b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf("FAIL: Invalid Payload %v was included in slot %d (%v)", invalidPayloadHash, b.StateRoot())
}
}
// The responses for `engine_newPayloadV1` and `engine_forkchoiceUpdatedV1` are delayed by `timeout` - 1s.
-func Timeouts(t *hivesim.T, env *testEnv, n node) {
+func Timeouts(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
var (
ForkchoiceUpdatedTimeoutSeconds = 8
NewPayloadTimeoutSeconds = 8
ToleranceSeconds = 1
+ ctx = context.Background()
)
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
},
@@ -500,17 +689,15 @@ func Timeouts(t *hivesim.T, env *testEnv, n node) {
SlotTime: big.NewInt(int64(12)),
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- var (
- delayEnabled = make(chan interface{})
- )
+ delayEnabled := make(chan interface{})
// The EL mock will intercept an `engine_newPayloadV1` and `engine_forkchoiceUpdatedV1` to
// introduce an artificial delay which should almost max out the time limit of the beacon client.
- gen := func(delaySeconds int) func([]byte, []byte) *proxy.Spoof {
- return func(res []byte, req []byte) *proxy.Spoof {
+ gen := func(delaySeconds int) func([]byte, []byte) *spoof.Spoof {
+ return func(res []byte, req []byte) *spoof.Spoof {
select {
case <-time.After(time.Duration(delaySeconds) * time.Second):
case <-delayEnabled:
@@ -523,34 +710,47 @@ func Timeouts(t *hivesim.T, env *testEnv, n node) {
p0 = testnet.Proxies().Running()[0]
p1 = testnet.Proxies().Running()[1]
)
- p0.AddResponseCallback(EngineNewPayloadV1, gen(NewPayloadTimeoutSeconds-ToleranceSeconds))
- p1.AddResponseCallback(EngineForkchoiceUpdatedV1, gen(ForkchoiceUpdatedTimeoutSeconds-ToleranceSeconds))
+ p0.AddResponseCallback(
+ EngineNewPayloadV1,
+ gen(NewPayloadTimeoutSeconds-ToleranceSeconds),
+ )
+ p1.AddResponseCallback(
+ EngineForkchoiceUpdatedV1,
+ gen(ForkchoiceUpdatedTimeoutSeconds-ToleranceSeconds),
+ )
// Finality should be reached anyway because the time limit is not reached on the engine calls
- ctx, cancel := context.WithCancel(context.Background())
+ finalityCtx, cancel := testnet.Spec().EpochTimeoutContext(
+ ctx,
+ EPOCHS_TO_FINALITY+1,
+ )
defer cancel()
- _, err := testnet.WaitForFinality(ctx, testnet.spec.SLOTS_PER_EPOCH*beacon.Slot(EPOCHS_TO_FINALITY+1))
+ _, err := testnet.WaitForFinality(finalityCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for finality: %v", err)
}
-
}
// The payload produced by the execution client contains an invalid timestamp value.
// This test covers scenario where the value of the timestamp is so high such that
// the next validators' attempts to produce payloads could fail by invalid payload
// attributes.
-func InvalidTimestampPayload(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+func InvalidTimestampPayload(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// All proxies will use the same callback, therefore we need to use a lock and a counter
var (
@@ -561,22 +761,30 @@ func InvalidTimestampPayload(t *hivesim.T, env *testEnv, n node) {
)
// The EL mock will intercept an engine_getPayloadV1 call and invalidate the timestamp in the response
- c := func(res []byte, req []byte) *proxy.Spoof {
+ c := func(res []byte, req []byte) *spoof.Spoof {
getPayloadLock.Lock()
defer getPayloadLock.Unlock()
getPayloadCount++
var (
- payload ExecutableDataV1
- payloadID PayloadID
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ payloadID api.PayloadID
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCResponse(res, &payload)
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &payload)
+ if err != nil {
+ panic(err)
+ }
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &payloadID)
if err != nil {
panic(err)
}
- err = UnmarshalFromJsonRPCRequest(req, &payloadID)
- t.Logf("INFO: Got payload %v, parent=%v, from PayloadID=%x", payload.BlockHash, payload.ParentHash, payloadID)
+ t.Logf(
+ "INFO: Got payload %v, parent=%v, from PayloadID=%x",
+ payload.BlockHash,
+ payload.ParentHash,
+ payloadID,
+ )
// Invalidate a payload after the transition payload
if getPayloadCount == 2 {
t.Logf("INFO (%v): Invalidating payload: %s", t.TestID, res)
@@ -585,15 +793,22 @@ func InvalidTimestampPayload(t *hivesim.T, env *testEnv, n node) {
newTimestamp := payload.Timestamp + config.SlotTime.Uint64()
// We add some extraData to guarantee we can identify the payload we altered
extraData := []byte("alt")
- invalidPayloadHash, spoof, err = customizePayloadSpoof(EngineGetPayloadV1, &payload,
- &CustomPayloadData{
+ invalidPayloadHash, spoof, err = payload_spoof.CustomizePayloadSpoof(
+ EngineGetPayloadV1,
+ &payload,
+ &payload_spoof.CustomPayloadData{
Timestamp: &newTimestamp,
ExtraData: &extraData,
- })
+ },
+ )
if err != nil {
panic(err)
}
- t.Logf("INFO (%v): Invalidated payload hash: %v", t.TestID, invalidPayloadHash)
+ t.Logf(
+ "INFO (%v): Invalidated payload hash: %v",
+ t.TestID,
+ invalidPayloadHash,
+ )
select {
case done <- nil:
default:
@@ -613,7 +828,15 @@ func InvalidTimestampPayload(t *hivesim.T, env *testEnv, n node) {
for _, p := range testnet.Proxies().Running() {
p.AddResponseCallback(EngineGetPayloadV1, c)
- p.AddResponseCallback(EngineForkchoiceUpdatedV1, CheckErrorOnForkchoiceUpdatedPayloadAttr(&fcuLock, fcUCountLimit, &fcUAttrCount, fcudone))
+ p.AddResponseCallback(
+ EngineForkchoiceUpdatedV1,
+ payload_spoof.CheckErrorOnForkchoiceUpdatedPayloadAttributes(
+ &fcuLock,
+ fcUCountLimit,
+ &fcUAttrCount,
+ fcudone,
+ ),
+ )
}
// Wait until the invalid payload is produced
@@ -625,22 +848,34 @@ func InvalidTimestampPayload(t *hivesim.T, env *testEnv, n node) {
}
// Verify beacon block with invalid payload is not accepted
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByHead{}, invalidPayloadHash)
+ b, err := testnet.VerifyExecutionPayloadHashInclusion(
+ ctx,
+ tn.LastestSlotByHead{},
+ invalidPayloadHash,
+ )
if err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid Payload %v was included in slot %d (%v)", invalidPayloadHash, b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf(
+ "FAIL: Invalid Payload %v was included in slot %d (%v)",
+ invalidPayloadHash,
+ b.Slot(),
+ b.StateRoot(),
+ )
}
}
-func IncorrectTTDConfigEL(t *hivesim.T, env *testEnv, n node) {
+func IncorrectTTDConfigEL(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
config := getClientConfig(n)
elTTD := config.TerminalTotalDifficulty.Int64() - 2
- config = config.join(&Config{
- Nodes: Nodes{
- node{
+ config = config.Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
+ clients.NodeDefinition{
// Add a node with an incorrect TTD to reject the invalid payload
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
@@ -649,59 +884,67 @@ func IncorrectTTDConfigEL(t *hivesim.T, env *testEnv, n node) {
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
builder = testnet.BeaconClients().Running()[0]
- eth = testnet.ExecutionClients().Running()[0]
- ec = NewEngineClient(t, eth, big.NewInt(elTTD))
+ ec = testnet.ExecutionClients().Running()[0]
)
-
- if !ec.waitForTTDWithTimeout(setup.CLIQUE_PERIOD_DEFAULT, time.After(time.Duration(setup.CLIQUE_PERIOD_DEFAULT*uint64(elTTD)*2)*time.Second)) {
- t.Fatalf("FAIL: Bad TTD was never reached by the Execution Client")
+ ttdCtx, cancel := context.WithTimeout(
+ ctx,
+ time.Duration(el.CLIQUE_PERIOD_DEFAULT*uint64(elTTD)*2)*time.Second,
+ )
+ defer cancel()
+ if err := ec.WaitForTerminalTotalDifficulty(ttdCtx); err != nil {
+ t.Fatalf("FAIL: %v", err)
}
// Wait a couple of slots
time.Sleep(time.Duration(config.SlotTime.Uint64()*5) * time.Second)
// Try to get the latest execution payload, must be nil
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- b, err := builder.GetLatestExecutionBeaconBlock(ctx)
- if err != nil {
- t.Fatalf("FAIL: Unable to query for the latest execution payload: %v", err)
- }
- if b != nil {
- t.Fatalf("FAIL: Execution payload was included in the beacon chain with a misconfigured TTD on the EL: %v", b.Message.StateRoot)
+ if b, err := builder.GetLatestExecutionBeaconBlock(ctx); err != nil {
+ t.Fatalf(
+ "FAIL: Unable to query for the latest execution payload: %v",
+ err,
+ )
+ } else if b != nil {
+ t.Fatalf(
+ "FAIL: Execution payload was included in the beacon chain with a misconfigured TTD on the EL: %v",
+ b.StateRoot(),
+ )
}
}
// The produced and broadcasted transition payload has parent with an invalid total difficulty.
-func IncorrectTerminalBlockGen(ttdDelta int64) func(t *hivesim.T, env *testEnv, n node) {
- return func(t *hivesim.T, env *testEnv, n node) {
+func IncorrectTerminalBlockGen(
+ ttdDelta int64,
+) func(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ return func(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ ctx := context.Background()
config := getClientConfig(n)
BadTTD := big.NewInt(config.TerminalTotalDifficulty.Int64() + ttdDelta)
- config = config.join(&Config{
- Nodes: Nodes{
- node{
+ config = config.Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
TestVerificationNode: true,
},
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
TestVerificationNode: true,
},
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
TestVerificationNode: true,
},
- node{
+ clients.NodeDefinition{
// Add a node with an incorrect TTD to reject the invalid payload
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
@@ -712,39 +955,94 @@ func IncorrectTerminalBlockGen(ttdDelta int64) func(t *hivesim.T, env *testEnv,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- var (
- badTTDImporter = testnet.BeaconClients().Running()[3]
- )
+ badTTDImporter := testnet.BeaconClients().Running()[3]
// Wait for all execution clients with the correct TTD reach the merge
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- transitionPayloadHash, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ transitionPayloadHash, err := testnet.WaitForExecutionPayload(
+ execPayloadCtx,
+ )
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
- ec := NewEngineClient(t, testnet.ExecutionClients().Running()[0], config.TerminalTotalDifficulty)
- transitionHeader, err := ec.Eth.HeaderByHash(ec.Ctx(), transitionPayloadHash)
+
+ ec := testnet.ExecutionClients().Running()[0]
+
+ transitionHeader, err := ec.HeaderByHash(ctx, transitionPayloadHash)
if err != nil {
- t.Fatalf("FAIL: Unable to get transition payload header from execution client: %v", err)
+ t.Fatalf(
+ "FAIL: Unable to get transition payload header from execution client: %v",
+ err,
+ )
}
- var tb, tbp *TotalDifficultyHeader
- if err := ec.cEth.CallContext(ec.Ctx(), &tb, "eth_getBlockByHash", transitionHeader.ParentHash, false); err != nil {
- t.Fatalf("FAIL: Unable to get terminal block header from execution client: %v", err)
+
+ terminalHeader, err := ec.HeaderByHash(
+ ctx,
+ transitionHeader.ParentHash,
+ )
+ if err != nil {
+ t.Fatalf(
+ "FAIL: Unable to get transition payload header from execution client: %v",
+ err,
+ )
}
- if err := ec.cEth.CallContext(ec.Ctx(), &tbp, "eth_getBlockByHash", tb.ParentHash, false); err != nil {
- t.Fatalf("FAIL: Unable to get terminal block header from execution client: %v", err)
+ terminalBlockTD, err := ec.TotalDifficultyByHash(
+ ctx,
+ terminalHeader.Hash(),
+ )
+ if err != nil {
+ t.Fatalf(
+ "FAIL: Unable to get terminal block total difficulty from execution client: %v",
+ err,
+ )
}
- t.Logf("INFO: CorrectTTD=%d, BadTTD=%d, TerminalBlockTotalDifficulty=%d, TerminalBlockParentTotalDifficulty=%d", config.TerminalTotalDifficulty, BadTTD, (*big.Int)(tb.TotalDifficulty), (*big.Int)(tbp.TotalDifficulty))
+
+ terminalParentHeader, err := ec.HeaderByHash(
+ ctx,
+ terminalHeader.ParentHash,
+ )
+ if err != nil {
+ t.Fatalf(
+ "FAIL: Unable to get transition payload header from execution client: %v",
+ err,
+ )
+ }
+ terminalBlockParentTD, err := ec.TotalDifficultyByHash(
+ ctx,
+ terminalParentHeader.Hash(),
+ )
+ if err != nil {
+ t.Fatalf(
+ "FAIL: Unable to get terminal block total difficulty from execution client: %v",
+ err,
+ )
+ }
+
+ t.Logf(
+ "INFO: CorrectTTD=%d, BadTTD=%d, TerminalBlockTotalDifficulty=%d, TerminalBlockParentTotalDifficulty=%d",
+ config.TerminalTotalDifficulty,
+ BadTTD,
+ terminalBlockTD,
+ terminalBlockParentTD,
+ )
// Wait a couple of slots
time.Sleep(time.Duration(5*config.SlotTime.Uint64()) * time.Second)
// Transition payload should not be part of the beacon node with bad TTD
- b, err := VerifyExecutionPayloadHashInclusionNode(testnet, ctx, LastestSlotByHead{}, badTTDImporter, transitionPayloadHash)
+ b, err := testnet.VerifyExecutionPayloadHashInclusionNode(
+ ctx,
+ tn.LastestSlotByHead{},
+ badTTDImporter,
+ transitionPayloadHash,
+ )
if err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
@@ -753,25 +1051,30 @@ func IncorrectTerminalBlockGen(ttdDelta int64) func(t *hivesim.T, env *testEnv,
}
}
-func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+func SyncingWithInvalidChain(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder 1
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
TestVerificationNode: false,
},
// Builder 2
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
TestVerificationNode: false,
},
// Importer
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
@@ -780,27 +1083,27 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
transitionPayloadHeight uint64
lastValidHash common.Hash
invalidPayloadHashes = make([]common.Hash, 0)
- payloadMap = make(map[common.Hash]ExecutableDataV1)
+ payloadMap = make(map[common.Hash]api.ExecutableData)
done = make(chan interface{})
)
// Payloads will be intercepted here and spoofed to simulate sync.
// Then after 4 payloads (p1, p2, p3, p4), the last one will be marked `INVALID` with
// `latestValidHash==p1.Hash`
- newPayloadCallback := func(res []byte, req []byte) *proxy.Spoof {
+ newPayloadCallback := func(res []byte, req []byte) *spoof.Spoof {
var (
- payload ExecutableDataV1
- spoof *proxy.Spoof
+ payload api.ExecutableData
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCRequest(req, &payload)
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &payload)
if err != nil {
panic(err)
}
@@ -809,17 +1112,21 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
// This is the transition payload (P1) because it's the first time this callback is called
transitionPayloadHeight = payload.Number
lastValidHash = payload.BlockHash
- t.Logf("INFO: Last VALID hash %d: %v", payload.Number-transitionPayloadHeight, payload.BlockHash)
+ t.Logf(
+ "INFO: Last VALID hash %d: %v",
+ payload.Number-transitionPayloadHeight,
+ payload.BlockHash,
+ )
} else {
if payload.Number >= transitionPayloadHeight+3 {
// This is P4
invalidPayloadHashes = append(invalidPayloadHashes, payload.BlockHash)
- status := PayloadStatusV1{
+ status := api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &lastValidHash,
ValidationError: nil,
}
- spoof, err = payloadStatusSpoof(EngineNewPayloadV1, &status)
+ spoof, err = payload_spoof.PayloadStatusSpoof(EngineNewPayloadV1, &status)
if err != nil {
panic(err)
}
@@ -831,12 +1138,12 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
} else if payload.Number > transitionPayloadHeight {
// For all other payloads, including P2/P3, return SYNCING
invalidPayloadHashes = append(invalidPayloadHashes, payload.BlockHash)
- status := PayloadStatusV1{
+ status := api.PayloadStatusV1{
Status: Syncing,
LatestValidHash: nil,
ValidationError: nil,
}
- spoof, err = payloadStatusSpoof(EngineNewPayloadV1, &status)
+ spoof, err = payload_spoof.PayloadStatusSpoof(EngineNewPayloadV1, &status)
if err != nil {
panic(err)
}
@@ -846,19 +1153,23 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
return spoof
}
- forkchoiceUpdatedCallback := func(res []byte, req []byte) *proxy.Spoof {
+ forkchoiceUpdatedCallback := func(res []byte, req []byte) *spoof.Spoof {
var (
- fcState ForkchoiceStateV1
- pAttr PayloadAttributesV1
- spoof *proxy.Spoof
+ fcState api.ForkchoiceStateV1
+ pAttr api.PayloadAttributes
+ spoof *spoof.Spoof
err error
)
- err = UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
+ err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr)
if err != nil {
panic(err)
}
if lastValidHash == (common.Hash{}) {
- panic(fmt.Errorf("NewPayload was not called before ForkchoiceUpdated"))
+ panic(
+ fmt.Errorf(
+ "NewPayload was not called before ForkchoiceUpdated",
+ ),
+ )
}
payload, ok := payloadMap[fcState.HeadBlockHash]
if !ok {
@@ -868,24 +1179,32 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
if payload.Number != transitionPayloadHeight {
if payload.Number == transitionPayloadHeight+3 {
// This is P4, but we probably won't receive this since NewPayload(P4) already returned INVALID
- status := PayloadStatusV1{
+ status := api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &lastValidHash,
ValidationError: nil,
}
- spoof, err = forkchoiceResponseSpoof(EngineForkchoiceUpdatedV1, status, nil)
+ spoof, err = payload_spoof.ForkchoiceResponseSpoof(
+ EngineForkchoiceUpdatedV1,
+ status,
+ nil,
+ )
if err != nil {
panic(err)
}
- t.Logf("INFO: Returning INVALID payload %d (ForkchoiceUpdated): %v", payload.Number-transitionPayloadHeight, payload.BlockHash)
+ t.Logf(
+ "INFO: Returning INVALID payload %d (ForkchoiceUpdated): %v",
+ payload.Number-transitionPayloadHeight,
+ payload.BlockHash,
+ )
} else {
// For all other payloads, including P2/P3, return SYNCING
- status := PayloadStatusV1{
+ status := api.PayloadStatusV1{
Status: Syncing,
LatestValidHash: nil,
ValidationError: nil,
}
- spoof, err = forkchoiceResponseSpoof(EngineForkchoiceUpdatedV1, status, nil)
+ spoof, err = payload_spoof.ForkchoiceResponseSpoof(EngineForkchoiceUpdatedV1, status, nil)
if err != nil {
panic(err)
}
@@ -895,113 +1214,156 @@ func SyncingWithInvalidChain(t *hivesim.T, env *testEnv, n node) {
return spoof
}
- var (
- importerProxy = testnet.Proxies().Running()[2]
- )
+ importerProxy := testnet.Proxies().Running()[2]
// Add the callback to the last proxy which will not produce blocks
importerProxy.AddResponseCallback(EngineNewPayloadV1, newPayloadCallback)
- importerProxy.AddResponseCallback(EngineForkchoiceUpdatedV1, forkchoiceUpdatedCallback)
+ importerProxy.AddResponseCallback(
+ EngineForkchoiceUpdatedV1,
+ forkchoiceUpdatedCallback,
+ )
<-done
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
// Wait a few slots for re-org to happen
- time.Sleep(time.Duration(testnet.spec.SECONDS_PER_SLOT) * time.Second * 5)
+ time.Sleep(
+ time.Duration(testnet.Spec().SECONDS_PER_SLOT) * time.Second * 5,
+ )
// Verify the head of the chain, it should be a block with the latestValidHash included
for _, bn := range testnet.VerificationNodes().BeaconClients().Running() {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockHead, &versionedBlock); err != nil {
+ versionedBlock, err := bn.BlockV2(ctx, eth2api.BlockHead)
+ if err != nil {
t.Fatalf("FAIL: Unable to poll beacon chain head: %v", err)
- } else if !exists {
- t.Fatalf("FAIL: Unable to poll beacon chain head")
}
if versionedBlock.Version != "bellatrix" {
// Block can't contain an executable payload
t.Fatalf("FAIL: Head of the chain is not a bellatrix fork block")
}
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- payload := block.Message.Body.ExecutionPayload
- if bytes.Compare(payload.BlockHash[:], lastValidHash[:]) != 0 {
- t.Fatalf("FAIL: Head does not contain the expected execution payload: %v != %v", payload.BlockHash.String(), lastValidHash.Hex())
+ if payload, err := versionedBlock.ExecutionPayload(); err == nil {
+ t.Fatalf(
+ "FAIL: error getting execution payload: %v",
+ err,
+ )
+ } else if !bytes.Equal(payload.BlockHash[:], lastValidHash[:]) {
+ t.Fatalf(
+ "FAIL: Head does not contain the expected execution payload: %v != %v",
+ payload.BlockHash.String(),
+ lastValidHash.Hex(),
+ )
}
}
// Verify payloads
- if b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByHead{}, lastValidHash); b == nil || err != nil {
+ if b, err := testnet.VerifyExecutionPayloadHashInclusion(ctx, tn.LastestSlotByHead{}, lastValidHash); b == nil ||
+ err != nil {
if err != nil {
- t.Fatalf("FAIL: Valid Payload %v could not be found: %v", lastValidHash, err)
+ t.Fatalf(
+ "FAIL: Valid Payload %v could not be found: %v",
+ lastValidHash,
+ err,
+ )
}
t.Fatalf("FAIL: Valid Payload %v could not be found", lastValidHash)
}
for i, p := range invalidPayloadHashes {
- b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByHead{}, p)
+ b, err := testnet.VerifyExecutionPayloadHashInclusion(
+ ctx,
+ tn.LastestSlotByHead{},
+ p,
+ )
if err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid Payload (%d) %v was included in slot %d (%v)", i+1, p, b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf(
+ "FAIL: Invalid Payload (%d) %v was included in slot %d (%v)",
+ i+1, p, b.Slot(), b.StateRoot(),
+ )
}
}
-
}
-func BaseFeeEncodingCheck(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
+func BaseFeeEncodingCheck(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
InitialBaseFeePerGas: big.NewInt(9223372036854775807), // 2**63 - 1
- Nodes: []node{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- transitionPayloadHash, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ transitionPayloadHash, err := testnet.WaitForExecutionPayload(
+ execPayloadCtx,
+ )
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
// Check the base fee value in the transition payload.
// Must be at least 256 to guarantee that the endianess encoding is correct.
- ec := NewEngineClient(t, testnet.ExecutionClients().Running()[0], config.TerminalTotalDifficulty)
- h, err := ec.Eth.HeaderByHash(ec.Ctx(), transitionPayloadHash)
+ ec := testnet.ExecutionClients().Running()[0]
+ h, err := ec.HeaderByHash(ctx, transitionPayloadHash)
if err != nil {
- t.Fatalf("FAIL: Unable to get transition payload header from execution client: %v", err)
+ t.Fatalf(
+ "FAIL: Unable to get transition payload header from execution client: %v",
+ err,
+ )
}
if h.Difficulty.Cmp(common.Big0) != 0 {
- t.Fatalf("FAIL: Transition header obtained is not PoS header: difficulty=%x", h.Difficulty)
+ t.Fatalf(
+ "FAIL: Transition header obtained is not PoS header: difficulty=%x",
+ h.Difficulty,
+ )
}
if h.BaseFee.Cmp(common.Big256) < 0 {
t.Fatalf("FAIL: Basefee insufficient for test: %x", h.BaseFee)
}
- t.Logf("INFO: Transition Payload created with sufficient baseFee: %x", h.BaseFee)
+ t.Logf(
+ "INFO: Transition Payload created with sufficient baseFee: %x",
+ h.BaseFee,
+ )
}
-func EqualTimestampTerminalTransitionBlock(t *hivesim.T, env *testEnv, n node) {
+func EqualTimestampTerminalTransitionBlock(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
config := getClientConfig(n)
- config = config.join(&Config{
+ config = config.Join(&tn.Config{
// We are increasing the clique period, therefore we can reduce the TTD
- TerminalTotalDifficulty: big.NewInt(config.TerminalTotalDifficulty.Int64() / 3),
- Nodes: []node{
+ TerminalTotalDifficulty: big.NewInt(
+ config.TerminalTotalDifficulty.Int64() / 3,
+ ),
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
// The clique period needs to be equal to the slot time to try to get the CL client to attempt to produce
// a payload with the same timestamp as the terminal block
- Eth1Consensus: &setup.Eth1CliqueConsensus{
+ Eth1Consensus: &el.ExecutionCliqueConsensus{
CliquePeriod: config.SlotTime.Uint64(),
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// No ForkchoiceUpdated with payload attributes should fail, which could happen if CL tries to create
// the payload with `timestamp==terminalBlock.timestamp`.
@@ -1013,7 +1375,15 @@ func EqualTimestampTerminalTransitionBlock(t *hivesim.T, env *testEnv, n node) {
)
for _, p := range testnet.Proxies().Running() {
- p.AddResponseCallback(EngineForkchoiceUpdatedV1, CheckErrorOnForkchoiceUpdatedPayloadAttr(&fcuLock, fcUCountLimit, &fcUAttrCount, fcudone))
+ p.AddResponseCallback(
+ EngineForkchoiceUpdatedV1,
+ payload_spoof.CheckErrorOnForkchoiceUpdatedPayloadAttributes(
+ &fcuLock,
+ fcUCountLimit,
+ &fcUAttrCount,
+ fcudone,
+ ),
+ )
}
// Wait until we verified all subsequent forkchoiceUpdated calls
@@ -1022,54 +1392,74 @@ func EqualTimestampTerminalTransitionBlock(t *hivesim.T, env *testEnv, n node) {
}
}
-func TTDBeforeBellatrix(t *hivesim.T, env *testEnv, n node) {
+func TTDBeforeBellatrix(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
config := getClientConfig(n)
- config = config.join(&Config{
+ config = config.Join(&tn.Config{
AltairForkEpoch: common.Big1,
- MergeForkEpoch: common.Big2,
+ BellatrixForkEpoch: common.Big2,
TerminalTotalDifficulty: big.NewInt(150),
- Nodes: []node{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
- for i, e := range testnet.ExecutionClients().Running() {
- ec := NewEngineClient(t, e, config.TerminalTotalDifficulty)
- if b, err := ec.Eth.BlockByNumber(ec.Ctx(), nil); err == nil {
- t.Logf("INFO: Last block on execution client %d: number=%d, hash=%s", i, b.NumberU64(), b.Hash())
+ for i, ec := range testnet.ExecutionClients().Running() {
+ if b, err := ec.BlockByNumber(ctx, nil); err == nil {
+ t.Logf(
+ "INFO: Last block on execution client %d: number=%d, hash=%s",
+ i,
+ b.NumberU64(),
+ b.Hash(),
+ )
}
}
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
- if err := VerifyELHeads(testnet, ctx); err != nil {
+ if err := testnet.VerifyELHeads(ctx); err != nil {
t.Fatalf("FAIL: Verifying EL Heads: %v", err)
}
}
-func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+func InvalidQuantityPayloadFields(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
+ ctx := context.Background()
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
n,
n,
n,
},
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// First we are going to wait for the transition to happen
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload: %v", err)
}
@@ -1092,23 +1482,39 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
InvalidationTypeCount
)
- invalidateQuantityType := func(id int, method string, response []byte, q QuantityType, invType InvalidationType) *proxy.Spoof {
+ invalidateQuantityType := func(id int, method string, response []byte, q QuantityType, invType InvalidationType) *spoof.Spoof {
responseFields := make(map[string]json.RawMessage)
- if err := UnmarshalFromJsonRPCResponse(response, &responseFields); err != nil {
- panic(fmt.Errorf("Unable to unmarshal: %v. json: %s", err, response))
+ if err := proxy.UnmarshalFromJsonRPCResponse(response, &responseFields); err != nil {
+ panic(
+ fmt.Errorf("unable to unmarshal: %v. json: %s", err, response),
+ )
}
var fieldOriginalValue string
if err := json.Unmarshal(responseFields[q.Name], &fieldOriginalValue); err != nil {
- panic(fmt.Errorf("Unable to unmarshal: %v. json: %s", err, responseFields[q.Name]))
+ panic(
+ fmt.Errorf(
+ "unable to unmarshal: %v. json: %s",
+ err,
+ responseFields[q.Name],
+ ),
+ )
}
fields := make(map[string]interface{})
switch invType {
case Overflow:
overflowingStringSize := int((q.BitSize / 4) + 1)
- fields[q.Name] = "0x" + strings.Repeat("0", overflowingStringSize-(len(fieldOriginalValue)-2)) + fieldOriginalValue[2:]
+ fields[q.Name] = "0x" + strings.Repeat(
+ "0",
+ overflowingStringSize-(len(fieldOriginalValue)-2),
+ ) + fieldOriginalValue[2:]
case LeadingZero:
if !strings.HasPrefix(fieldOriginalValue, "0x") {
- panic(fmt.Errorf("Invalid original value: %v", fieldOriginalValue))
+ panic(
+ fmt.Errorf(
+ "invalid original value: %v",
+ fieldOriginalValue,
+ ),
+ )
}
fields[q.Name] = "0x0" + fieldOriginalValue[2:]
case Empty:
@@ -1120,9 +1526,15 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
panic("Invalid QUANTITY invalidation type")
}
- t.Logf("INFO: Spoofing (node %d) %s, %s -> %s", id, q.Name, fieldOriginalValue, fields[q.Name])
+ t.Logf(
+ "INFO: Spoofing (node %d) %s, %s -> %s",
+ id,
+ q.Name,
+ fieldOriginalValue,
+ fields[q.Name],
+ )
// Return the new payload status spoof
- return &proxy.Spoof{
+ return &spoof.Spoof{
Method: method,
Fields: fields,
}
@@ -1160,23 +1572,23 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
)
// The EL mock will intercept the first engine_getPayloadV1 and corrupt the stateRoot in the response
- getPayloadCallbackGen := func(id int) func([]byte, []byte) *proxy.Spoof {
- return func(res, req []byte) *proxy.Spoof {
+ getPayloadCallbackGen := func(id int) func([]byte, []byte) *spoof.Spoof {
+ return func(res, req []byte) *spoof.Spoof {
getPayloadLock.Lock()
defer getPayloadLock.Unlock()
defer func() {
getPayloadCount++
}()
- var (
- payload ExecutableDataV1
- )
- err := UnmarshalFromJsonRPCResponse(res, &payload)
+ var payload api.ExecutableData
+ err := proxy.UnmarshalFromJsonRPCResponse(res, &payload)
if err != nil {
panic(err)
}
field := getPayloadCount / int(InvalidationTypeCount)
- invType := InvalidationType(getPayloadCount % int(InvalidationTypeCount))
+ invType := InvalidationType(
+ getPayloadCount % int(InvalidationTypeCount),
+ )
if field >= len(allQuantityFields) {
select {
@@ -1186,12 +1598,31 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
return nil
}
// Customize to get a different hash in order to properly check that the payload is actually not included
- customExtraData := []byte(fmt.Sprintf("invalid %s %d", allQuantityFields[field].Name, invType))
- newHash, spoof, _ := customizePayloadSpoof(EngineGetPayloadV1, &payload, &CustomPayloadData{
- ExtraData: &customExtraData,
- })
+ customExtraData := []byte(
+ fmt.Sprintf(
+ "invalid %s %d",
+ allQuantityFields[field].Name,
+ invType,
+ ),
+ )
+ newHash, spoof, _ := payload_spoof.CustomizePayloadSpoof(
+ EngineGetPayloadV1,
+ &payload,
+ &payload_spoof.CustomPayloadData{
+ ExtraData: &customExtraData,
+ },
+ )
invalidPayloadHashes = append(invalidPayloadHashes, newHash)
- return combine(spoof, invalidateQuantityType(id, EngineGetPayloadV1, res, allQuantityFields[field], invType))
+ return proxy.Combine(
+ spoof,
+ invalidateQuantityType(
+ id,
+ EngineGetPayloadV1,
+ res,
+ allQuantityFields[field],
+ invType,
+ ),
+ )
}
}
@@ -1202,20 +1633,43 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
// Wait until we are done
var testFailed bool
+ timeoutCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ beacon.Slot(len(allQuantityFields)*int(InvalidationTypeCount)*2),
+ )
+ defer cancel()
select {
case <-done:
- case <-testnet.SlotsTimeout(beacon.Slot(len(allQuantityFields) * int(InvalidationTypeCount) * 2)):
- t.Logf("FAIL: Timeout while waiting for CL requesting all payloads, test is invalid.")
+ case <-timeoutCtx.Done():
+ t.Logf(
+ "FAIL: Timeout while waiting for CL requesting all payloads, test is invalid.",
+ )
testFailed = true
}
// Check that none of the invalidated payloads made it into the beacon chain
for i, p := range invalidPayloadHashes {
- b, err := VerifyExecutionPayloadHashInclusion(testnet, ctx, LastestSlotByTime{}, p)
+ b, err := testnet.VerifyExecutionPayloadHashInclusion(
+ ctx,
+ tn.LastestSlotByTime{},
+ p,
+ )
if err != nil {
t.Fatalf("FAIL: Error during payload verification: %v", err)
} else if b != nil {
- t.Logf("FAIL: Invalid Payload #%d, %v (%s), was included in slot %d (%v)", i+1, p, ([]byte)(b.Message.Body.ExecutionPayload.ExtraData), b.Message.Slot, b.Message.StateRoot)
+
+ if execPayload, err := b.ExecutionPayload(); err != nil {
+ t.Logf(
+ "FAIL: Beacon block does not contain a payload, slot %d (%v)",
+ b.Slot(), b.StateRoot(),
+ )
+ } else {
+ t.Logf(
+ "FAIL: Invalid Payload #%d, %v (%x), was included in slot %d (%v)",
+ i+1, p, execPayload.ExtraData, b.Slot(), b.StateRoot(),
+ )
+ }
+
// Mark test as failure, but continue checking all variations
testFailed = true
}
@@ -1227,44 +1681,49 @@ func InvalidQuantityPayloadFields(t *hivesim.T, env *testEnv, n node) {
}
}
-func SyncingWithChainHavingValidTransitionBlock(t *hivesim.T, env *testEnv, n node) {
+func SyncingWithChainHavingValidTransitionBlock(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
var (
safeSlotsToImportOptimistically = big.NewInt(8)
safeSlotsImportThreshold = uint64(4)
+ ctx = context.Background()
)
if clientSafeSlots, ok := SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE[n.ConsensusClient]; ok {
safeSlotsToImportOptimistically = clientSafeSlots
}
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
// Importer
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
},
- Eth1Consensus: setup.Eth1PreChain{},
+ Eth1Consensus: el.ExecutionPreChain{},
SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically,
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
builder = testnet.BeaconClients()[0]
@@ -1272,17 +1731,22 @@ func SyncingWithChainHavingValidTransitionBlock(t *hivesim.T, env *testEnv, n no
importerProxy = testnet.Proxies().Running()[1]
)
- importerResponseMocker := NewEngineResponseMocker(&EngineResponse{
- // By default we respond SYNCING to any payload
- Status: Syncing,
- LatestValidHash: nil,
- })
+ importerResponseMocker := payload_spoof.NewEngineResponseMocker(
+ &api.PayloadStatusV1{
+ // By default we respond SYNCING to any payload
+ Status: Syncing,
+ LatestValidHash: nil,
+ },
+ )
importerResponseMocker.AddCallbacksToProxy(importerProxy)
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
defer cancel()
// Wait until the builder creates the first block with an execution payload
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload on builder: %v", err)
}
@@ -1291,32 +1755,57 @@ func SyncingWithChainHavingValidTransitionBlock(t *hivesim.T, env *testEnv, n no
if err != nil || builderExecutionBlock == nil {
t.Fatalf("FAIL: Could not find first execution block")
}
- t.Logf("Builder Execution block found on slot %d", builderExecutionBlock.Message.Slot)
+ t.Logf(
+ "Builder Execution block found on slot %d",
+ builderExecutionBlock.Slot(),
+ )
// We wait until the importer reaches optimistic sync
- _, err = importer.WaitForOptimisticState(context.Background(), beacon.Slot(safeSlotsToImportOptimistically.Uint64()+safeSlotsImportThreshold), eth2api.BlockIdSlot(builderExecutionBlock.Message.Slot), true)
+ optimisticStateCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ beacon.Slot(
+ safeSlotsToImportOptimistically.Uint64()+
+ safeSlotsImportThreshold),
+ )
+ defer cancel()
+ _, err = importer.WaitForOptimisticState(
+ optimisticStateCtx,
+ eth2api.BlockIdSlot(builderExecutionBlock.Slot()),
+ true,
+ )
if err != nil {
- t.Fatalf("FAIL: Timeout waiting for beacon node to become optimistic: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to become optimistic: %v",
+ err,
+ )
}
// Mocked responses are disabled, so the EL can finally validate payloads
importerResponseMocker.Mocking = false
// Wait until newPayload or forkchoiceUpdated are called at least once
- ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Second*20)
+ ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
select {
case <-importerResponseMocker.NewPayloadCalled:
case <-importerResponseMocker.ForkchoiceUpdatedCalled:
case <-ctxTimeout.Done():
- t.Fatalf("FAIL: Timeout waiting for beacon node to send engine directive: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to send engine directive: %v",
+ err,
+ )
}
// Wait a couple of slots here to make sure syncing does not produce a false positive
time.Sleep(time.Duration(config.SlotTime.Uint64()*10) * time.Second)
// Wait for the importer to get an execution payload
- _, err = importer.WaitForExecutionPayload(ctx, beacon.Slot(safeSlotsToImportOptimistically.Uint64()+safeSlotsImportThreshold))
+ execPayloadCtx, cancel = testnet.Spec().SlotTimeoutContext(
+ ctx,
+ beacon.Slot(safeSlotsToImportOptimistically.Uint64()+safeSlotsImportThreshold),
+ )
+ defer cancel()
+ _, err = importer.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload on importer: %v", err)
}
@@ -1324,82 +1813,88 @@ func SyncingWithChainHavingValidTransitionBlock(t *hivesim.T, env *testEnv, n no
// Compare heads, the importer must have the same head as the builder,
// and `execution_optimistic==false`.
var (
- importerHeadInfo eth2api.BeaconBlockHeaderAndInfo
- builderHeadInfo eth2api.BeaconBlockHeaderAndInfo
+ importerHeadInfo *eth2api.BeaconBlockHeaderAndInfo
+ builderHeadInfo *eth2api.BeaconBlockHeaderAndInfo
)
- ctxTimeout, cancel = context.WithTimeout(context.Background(), time.Second*5)
- defer cancel()
- if exists, err := beaconapi.BlockHeader(ctxTimeout, importer.API, eth2api.BlockHead, &importerHeadInfo); err != nil {
+ importerHeadInfo, err = importer.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
t.Fatalf("FAIL: Failed to poll head importer head: %v", err)
- } else if !exists {
- t.Fatalf("FAIL: Failed to poll head importer head: !exists")
}
- ctxTimeout, cancel = context.WithTimeout(context.Background(), time.Second*5)
- defer cancel()
- if exists, err := beaconapi.BlockHeader(ctxTimeout, builder.API, eth2api.BlockHead, &builderHeadInfo); err != nil {
+
+ builderHeadInfo, err = builder.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
t.Fatalf("FAIL: Failed to poll head builder head: %v", err)
- } else if !exists {
- t.Fatalf("FAIL: Failed to poll head builder head: !exists")
}
if importerHeadInfo.Root != builderHeadInfo.Root {
- t.Fatalf("FAIL: importer and builder heads are not equal: %v != %v", importerHeadInfo.Root, builderHeadInfo.Root)
+ t.Fatalf(
+ "FAIL: importer and builder heads are not equal: %v != %v",
+ importerHeadInfo.Root,
+ builderHeadInfo.Root,
+ )
}
- var headOptStatus BlockV2OptimisticResponse
- ctxTimeout, cancel = context.WithTimeout(context.Background(), time.Second*5)
+ var headOptStatus clients.BlockV2OptimisticResponse
+ ctxTimeout, cancel = context.WithTimeout(ctx, time.Second*5)
defer cancel()
if exists, err := eth2api.SimpleRequest(ctxTimeout, importer.API, eth2api.FmtGET("/eth/v2/beacon/blocks/%s", eth2api.BlockHead.BlockId()), &headOptStatus); err != nil {
t.Fatalf("FAIL: Failed to poll head importer head: %v", err)
} else if !exists {
t.Fatalf("FAIL: Failed to poll head importer head: !exists")
}
- if headOptStatus.ExecutionOptimistic == true {
- t.Fatalf("FAIL: importer still optimistic: execution_optimistic==%t", headOptStatus.ExecutionOptimistic)
+ if headOptStatus.ExecutionOptimistic {
+ t.Fatalf(
+ "FAIL: importer still optimistic: execution_optimistic==%t",
+ headOptStatus.ExecutionOptimistic,
+ )
}
-
}
-func SyncingWithChainHavingInvalidTransitionBlock(t *hivesim.T, env *testEnv, n node) {
+func SyncingWithChainHavingInvalidTransitionBlock(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
var (
safeSlotsToImportOptimistically = big.NewInt(8)
safeSlotsImportThreshold = uint64(4)
+ ctx = context.Background()
)
if clientSafeSlots, ok := SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE[n.ConsensusClient]; ok {
safeSlotsToImportOptimistically = clientSafeSlots
}
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
// Importer
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
},
AltairForkEpoch: common.Big1,
- MergeForkEpoch: common.Big2,
- Eth1Consensus: setup.Eth1PreChain{},
+ BellatrixForkEpoch: common.Big2,
+ Eth1Consensus: el.ExecutionPreChain{},
SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically,
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
builder = testnet.BeaconClients()[0]
@@ -1407,20 +1902,27 @@ func SyncingWithChainHavingInvalidTransitionBlock(t *hivesim.T, env *testEnv, n
importerProxy = testnet.Proxies().Running()[1]
)
- importerResponseMocker := NewEngineResponseMocker(&EngineResponse{
- // By default we respond SYNCING to any payload
- Status: Syncing,
- LatestValidHash: nil,
- })
+ importerResponseMocker := payload_spoof.NewEngineResponseMocker(
+ &api.PayloadStatusV1{
+ // By default we respond SYNCING to any payload
+ Status: Syncing,
+ LatestValidHash: nil,
+ },
+ )
importerResponseMocker.AddCallbacksToProxy(importerProxy)
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
// Wait until the builder creates the first block with an execution payload
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
+ defer cancel()
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
- t.Fatalf("FAIL: Timeout waiting for execution payload on builder: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for execution payload on builder: %v",
+ err,
+ )
}
// Fetch the first execution block which will be used for verification
@@ -1429,30 +1931,50 @@ func SyncingWithChainHavingInvalidTransitionBlock(t *hivesim.T, env *testEnv, n
t.Fatalf("FAIL: Could not find first execution block")
}
- t.Logf("INFO: First execution block: %d, %v", builderExecutionBlock.Message.Slot, builderExecutionBlock.Message.StateRoot)
+ t.Logf(
+ "INFO: First execution block: %d, %v",
+ builderExecutionBlock.Slot(), builderExecutionBlock.StateRoot(),
+ )
// We wait until the importer reaches optimistic sync
- _, err = importer.WaitForOptimisticState(ctx, beacon.Slot(safeSlotsToImportOptimistically.Uint64()+safeSlotsImportThreshold), eth2api.BlockIdSlot(builderExecutionBlock.Message.Slot), true)
+ optimisticStateCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ beacon.Slot(
+ safeSlotsToImportOptimistically.Uint64()+
+ safeSlotsImportThreshold),
+ )
+ defer cancel()
+ _, err = importer.WaitForOptimisticState(
+ optimisticStateCtx,
+ eth2api.BlockIdSlot(builderExecutionBlock.Slot()),
+ true,
+ )
if err != nil {
- t.Fatalf("FAIL: Timeout waiting for beacon node to become optimistic: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to become optimistic: %v",
+ err,
+ )
}
// We invalidate the entire proof-of-stake chain
t.Logf("INFO: Changing default response to INVALID")
- importerResponseMocker.SetDefaultResponse(&EngineResponse{
+ importerResponseMocker.SetDefaultResponse(&api.PayloadStatusV1{
// The default is now that the execution client returns INVALID + LVH==0x00..00
Status: Invalid,
LatestValidHash: &(common.Hash{}),
})
// Wait until newPayload or forkchoiceUpdated are called at least once
- ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Second*20)
+ ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
select {
case <-importerResponseMocker.NewPayloadCalled:
case <-importerResponseMocker.ForkchoiceUpdatedCalled:
case <-ctxTimeout.Done():
- t.Fatalf("FAIL: Timeout waiting for beacon node to send engine directive: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to send engine directive: %v",
+ err,
+ )
}
// Wait a couple of slots here to make sure syncing does not produce a false positive
@@ -1460,69 +1982,90 @@ func SyncingWithChainHavingInvalidTransitionBlock(t *hivesim.T, env *testEnv, n
// Query the beacon chain head of the importer node, it should still
// point to a pre-merge block.
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, importer.API, eth2api.BlockHead, &headInfo); err != nil {
+ headInfo, err := importer.BlockHeader(ctx, eth2api.BlockHead)
+ if err != nil {
t.Fatalf("FAIL: Failed to poll head importer head: %v", err)
- } else if !exists {
- t.Fatalf("FAIL: Failed to poll head importer head: !exists")
}
- if headInfo.Header.Message.Slot != (builderExecutionBlock.Message.Slot - 1) {
- ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ if headInfo.Header.Message.Slot != (builderExecutionBlock.Slot() - 1) {
+ ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
- var headOptStatus BlockV2OptimisticResponse
- if exists, err := eth2api.SimpleRequest(ctxTimeout, importer.API, eth2api.FmtGET("/eth/v2/beacon/blocks/%s", eth2api.BlockHead.BlockId()), &headOptStatus); err != nil {
+ var headOptStatus clients.BlockV2OptimisticResponse
+ if exists, err := eth2api.SimpleRequest(
+ ctxTimeout, importer.API,
+ eth2api.FmtGET(
+ "/eth/v2/beacon/blocks/%s",
+ eth2api.BlockHead.BlockId(),
+ ),
+ &headOptStatus,
+ ); err != nil {
// Block still not synced
- fmt.Printf("DEBUG: Queried block %s: %v\n", eth2api.BlockHead.BlockId(), err)
+ fmt.Printf(
+ "DEBUG: Queried block %s: %v\n",
+ eth2api.BlockHead.BlockId(),
+ err,
+ )
} else if !exists {
// Block still not synced
fmt.Printf("DEBUG: Queried block %s: %v\n", eth2api.BlockHead.BlockId(), err)
}
- t.Fatalf("FAIL: Importer head is beyond the invalid execution payload block: importer=%v:%d, builder=%v:%d, execution_optimistic=%t", headInfo.Root, headInfo.Header.Message.Slot, builderExecutionBlock.Message.StateRoot, builderExecutionBlock.Message.Slot, headOptStatus.ExecutionOptimistic)
+ t.Fatalf(
+ "FAIL: Importer head is beyond the invalid execution payload block: importer=%v:%d, builder=%v:%d, execution_optimistic=%t",
+ headInfo.Root,
+ headInfo.Header.Message.Slot,
+ builderExecutionBlock.StateRoot(),
+ builderExecutionBlock.Slot(),
+ headOptStatus.ExecutionOptimistic,
+ )
}
}
-func SyncingWithChainHavingInvalidPostTransitionBlock(t *hivesim.T, env *testEnv, n node) {
+func SyncingWithChainHavingInvalidPostTransitionBlock(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
var (
safeSlotsToImportOptimistically = big.NewInt(8)
safeSlotsImportThreshold = uint64(4)
+ ctx = context.Background()
)
if clientSafeSlots, ok := SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE[n.ConsensusClient]; ok {
safeSlotsToImportOptimistically = clientSafeSlots
}
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
// Importer
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
- ChainGenerator: &PoWChainGenerator{
+ ChainGenerator: &pow.ChainGenerator{
BlockCount: 1,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
},
},
},
AltairForkEpoch: common.Big1,
- MergeForkEpoch: common.Big2,
- Eth1Consensus: setup.Eth1PreChain{},
+ BellatrixForkEpoch: common.Big2,
+ Eth1Consensus: el.ExecutionPreChain{},
SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically,
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
builder = testnet.BeaconClients()[0]
@@ -1530,17 +2073,22 @@ func SyncingWithChainHavingInvalidPostTransitionBlock(t *hivesim.T, env *testEnv
importerProxy = testnet.Proxies().Running()[1]
)
- importerResponseMocker := NewEngineResponseMocker(&EngineResponse{
- // By default we respond SYNCING to any payload
- Status: Syncing,
- LatestValidHash: nil,
- })
+ importerResponseMocker := payload_spoof.NewEngineResponseMocker(
+ &api.PayloadStatusV1{
+ // By default we respond SYNCING to any payload
+ Status: Syncing,
+ LatestValidHash: nil,
+ },
+ )
importerResponseMocker.AddCallbacksToProxy(importerProxy)
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
// Wait until the builder creates the first block with an execution payload
- _, err := testnet.WaitForExecutionPayload(ctx, SlotsUntilMerge(testnet, config))
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config),
+ )
+ defer cancel()
+ _, err := testnet.WaitForExecutionPayload(execPayloadCtx)
if err != nil {
t.Fatalf("FAIL: Waiting for execution payload on builder: %v", err)
}
@@ -1550,22 +2098,43 @@ func SyncingWithChainHavingInvalidPostTransitionBlock(t *hivesim.T, env *testEnv
if err != nil || builderExecutionBlock == nil {
t.Fatalf("FAIL: Could not find first execution block")
}
- transitionPayloadHash := common.BytesToHash(builderExecutionBlock.Message.Body.ExecutionPayload.BlockHash[:])
- t.Logf("Builder Execution block found on slot %d, hash=%s", builderExecutionBlock.Message.Slot, transitionPayloadHash)
+ execPayload, _ := builderExecutionBlock.ExecutionPayload()
+ transitionPayloadHash := execPayload.BlockHash
+ t.Logf(
+ "Builder Execution block found on slot %d, hash=%s",
+ builderExecutionBlock.Slot(),
+ transitionPayloadHash,
+ )
// We wait until the importer reaches optimistic sync
- _, err = importer.WaitForOptimisticState(ctx, beacon.Slot(safeSlotsToImportOptimistically.Uint64()+safeSlotsImportThreshold), eth2api.BlockIdSlot(builderExecutionBlock.Message.Slot), true)
+ optimisticStateCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ beacon.Slot(safeSlotsToImportOptimistically.Uint64()+
+ safeSlotsImportThreshold),
+ )
+ defer cancel()
+ _, err = importer.WaitForOptimisticState(
+ optimisticStateCtx,
+ eth2api.BlockIdSlot(builderExecutionBlock.Slot()),
+ true,
+ )
if err != nil {
- t.Fatalf("FAIL: Timeout waiting for beacon node to become optimistic: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to become optimistic: %v",
+ err,
+ )
}
// We invalidate the chain after the transition payload
- importerResponseMocker.AddResponse(transitionPayloadHash, &EngineResponse{
- // Transition payload is valid
- Status: Valid,
- LatestValidHash: &transitionPayloadHash,
- })
- importerResponseMocker.SetDefaultResponse(&EngineResponse{
+ importerResponseMocker.AddResponse(
+ transitionPayloadHash,
+ &api.PayloadStatusV1{
+ // Transition payload is valid
+ Status: Valid,
+ LatestValidHash: &transitionPayloadHash,
+ },
+ )
+ importerResponseMocker.SetDefaultResponse(&api.PayloadStatusV1{
// The default is now that the execution client returns INVALID
// with latest valid hash equal to the transition payload
Status: Invalid,
@@ -1573,32 +2142,44 @@ func SyncingWithChainHavingInvalidPostTransitionBlock(t *hivesim.T, env *testEnv
})
// Wait until newPayload or forkchoiceUpdated are called at least once
- ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Second*20)
+ ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
select {
case <-importerResponseMocker.NewPayloadCalled:
case <-importerResponseMocker.ForkchoiceUpdatedCalled:
case <-ctxTimeout.Done():
- t.Fatalf("FAIL: Timeout waiting for beacon node to send engine directive: %v", err)
+ t.Fatalf(
+ "FAIL: Timeout waiting for beacon node to send engine directive: %v",
+ err,
+ )
}
// Wait a couple of slots here to make sure syncing does not produce a false positive
- time.Sleep(time.Duration((config.SlotTime.Uint64()+5)*uint64(testnet.spec.SECONDS_PER_SLOT)) * time.Second)
+ <-testnet.Spec().SlotsTimeout(5)
- // Query the beacon chain head of the importer node, it should point to transition payload block.
+ // Query the beacon chain head of the importer node,
+ // it should point to transition payload block.
block, err := importer.GetFirstExecutionBeaconBlock(ctx)
if err != nil || block == nil {
t.Fatalf("FAIL: Block not found: %v", err)
}
- payload := block.Message.Body.ExecutionPayload
- if ethcommon.BytesToHash(payload.BlockHash[:]) != transitionPayloadHash {
- t.Fatalf("FAIL: Latest payload in the importer is not the transition payload: %v", ethcommon.BytesToHash(payload.BlockHash[:]))
+ payload, _ := block.ExecutionPayload()
+ if common.BytesToHash(payload.BlockHash[:]) != transitionPayloadHash {
+ t.Fatalf(
+ "FAIL: Latest payload in the importer is not the transition payload: %v",
+ common.BytesToHash(payload.BlockHash[:]),
+ )
}
}
-func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n node) {
+func ReOrgSyncWithChainHavingInvalidTerminalBlock(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
var (
safeSlotsToImportOptimistically = big.NewInt(8)
+ ctx = context.Background()
)
if clientSafeSlots, ok := SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE[n.ConsensusClient]; ok {
safeSlotsToImportOptimistically = clientSafeSlots
@@ -1606,22 +2187,22 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
// We are going to produce two PoW chains for three different clients
// EL_A:
- EL_A := &PoWChainGenerator{ // TD = 0x40000
+ EL_A := &pow.ChainGenerator{ // TD = 0x40000
BlockCount: 2,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
}
// EL_B:
- EL_B := &PoWChainGenerator{ // TD = 0x40000
+ EL_B := &pow.ChainGenerator{ // TD = 0x40000
BlockCount: 2,
- Config: PoWChainGeneratorDefaults,
+ Config: pow.Defaults,
}
// Network is partitioned from the start, execution client subnets A and B will never be able to communicate with
// each other.
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder 1
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 10,
@@ -1629,7 +2210,7 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
ExecutionSubnet: "A",
},
// Importer 1
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
@@ -1637,7 +2218,7 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
ExecutionSubnet: "A",
},
// Builder 2
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 10,
@@ -1645,7 +2226,7 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
ExecutionSubnet: "B",
},
// Importer 2
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
@@ -1653,42 +2234,50 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
ExecutionSubnet: "B",
},
},
- Eth1Consensus: setup.Eth1PreChain{},
+ Eth1Consensus: el.ExecutionPreChain{},
TerminalTotalDifficulty: big.NewInt(0x40000),
SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically,
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
// One pair of clients will produce the first execution payload, to which the other pair won't be able to sync,
// because they are not interconnected.
// Therefore only one client pair will end up in optimistic sync mode.
type BuilderImporterInfo struct {
- Builder *NodeClientBundle
- Importer *NodeClientBundle
- ChainGenerator *PoWChainGenerator
+ Builder *clients.Node
+ Importer *clients.Node
+ ChainGenerator *pow.ChainGenerator
}
builderImporterPairs := []BuilderImporterInfo{
{
- Builder: testnet.NodeClientBundles[0],
- Importer: testnet.NodeClientBundles[1],
+ Builder: testnet.Nodes[0],
+ Importer: testnet.Nodes[1],
ChainGenerator: EL_A,
},
{
- Builder: testnet.NodeClientBundles[2],
- Importer: testnet.NodeClientBundles[3],
+ Builder: testnet.Nodes[2],
+ Importer: testnet.Nodes[3],
ChainGenerator: EL_B,
},
}
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
optimisticPairChan := make(chan *BuilderImporterInfo)
for i, p := range builderImporterPairs {
p := p
// Only one pair will reach optimistic sync
go func(i int, p *BuilderImporterInfo) {
- _, err := p.Builder.BeaconClient.WaitForOptimisticState(ctx, SlotsUntilMerge(testnet, config)+beacon.Slot(safeSlotsToImportOptimistically.Uint64()+4), eth2api.BlockHead, true)
+ optimisticStateCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ SlotsUntilMerge(ctx, testnet, config)+
+ beacon.Slot(safeSlotsToImportOptimistically.Uint64()+4),
+ )
+ defer cancel()
+ _, err := p.Builder.BeaconClient.WaitForOptimisticState(
+ optimisticStateCtx,
+ eth2api.BlockHead,
+ true,
+ )
if err != nil {
return
}
@@ -1703,103 +2292,148 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock(t *hivesim.T, env *testEnv, n
var optimisticPair *BuilderImporterInfo
select {
case optimisticPair = <-optimisticPairChan:
- case <-time.After(SlotsToDuration(SlotsUntilMerge(testnet, config)+beacon.Slot(safeSlotsToImportOptimistically.Uint64()+4), testnet.spec)):
+ case <-testnet.Spec().SlotsTimeout(SlotsUntilMerge(ctx, testnet, config) +
+ beacon.Slot(safeSlotsToImportOptimistically.Uint64()+4)):
t.Fatalf("FAIL: Timeout waiting for pair to become optimistic")
}
- t.Logf("INFO: Reached optimistic sync on nodes %d + %d", optimisticPair.Builder.Index, optimisticPair.Importer.Index)
+ t.Logf(
+ "INFO: Reached optimistic sync on nodes %d + %d",
+ optimisticPair.Builder.Index,
+ optimisticPair.Importer.Index,
+ )
// After the client pair reaches optimistic sync, invalidate the execution payload to trigger a
- responseMocker := NewEngineResponseMocker(&EngineResponse{
- Status: Invalid,
- LatestValidHash: &(common.Hash{}),
- })
+ responseMocker := payload_spoof.NewEngineResponseMocker(
+ &api.PayloadStatusV1{
+ Status: Invalid,
+ LatestValidHash: &(common.Hash{}),
+ },
+ )
// Every payload generated by this same pair is not invalidated
- responseMocker.AddGetPayloadPassthroughToProxy(optimisticPair.Builder.ExecutionClient.Proxy())
+ responseMocker.AddGetPayloadPassthroughToProxy(
+ optimisticPair.Builder.ExecutionClient.Proxy(),
+ )
// The original head of the PoW chain needs to passthrough too
- responseMocker.AddPassthrough(optimisticPair.ChainGenerator.Head().Hash(), true)
+ responseMocker.AddPassthrough(
+ optimisticPair.ChainGenerator.Head().Hash(),
+ true,
+ )
// Add the callbacks to the optimistic sync pair
- responseMocker.AddCallbacksToProxy(optimisticPair.Builder.ExecutionClient.Proxy())
- responseMocker.AddCallbacksToProxy(optimisticPair.Importer.ExecutionClient.Proxy())
+ responseMocker.AddCallbacksToProxy(
+ optimisticPair.Builder.ExecutionClient.Proxy(),
+ )
+ responseMocker.AddCallbacksToProxy(
+ optimisticPair.Importer.ExecutionClient.Proxy(),
+ )
// Wait until the optimistic builder creates its first block with an execution payload.
// At this point the builder is no longer optimistic
- _, err := optimisticPair.Builder.BeaconClient.WaitForExecutionPayload(ctx, beacon.Slot(12))
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ 12,
+ )
+ defer cancel()
+ _, err := optimisticPair.Builder.BeaconClient.WaitForExecutionPayload(
+ execPayloadCtx)
if err != nil {
- if err := PrintAllBeaconBlocks(testnet, ctx); err != nil {
+ if err := debug.PrintAllTestnetBeaconBlocks(ctx, t, testnet.BeaconClients().Running()); err != nil {
t.Logf("FAIL: Error while printing all blocks: %v", err)
}
- t.Fatalf("FAIL: Waiting for execution payload on optimistic builder: %v", err)
+ t.Fatalf(
+ "FAIL: Waiting for execution payload on optimistic builder: %v",
+ err,
+ )
}
- // Wait until the optimistic importer fetches the first execution payload from the optimistic builder
- _, err = optimisticPair.Importer.BeaconClient.WaitForExecutionPayload(ctx, beacon.Slot(12))
+ // Wait until the optimistic importer fetches the first execution payload
+ // from the optimistic builder
+ execPayloadCtx, cancel = testnet.Spec().SlotTimeoutContext(
+ ctx,
+ 12,
+ )
+ defer cancel()
+ _, err = optimisticPair.Importer.BeaconClient.WaitForExecutionPayload(
+ execPayloadCtx)
if err != nil {
// Print all heads for debugging
- if err := PrintAllBeaconBlocks(testnet, ctx); err != nil {
+ if err := debug.PrintAllTestnetBeaconBlocks(ctx, t, testnet.BeaconClients().Running()); err != nil {
t.Logf("FAIL: Error while printing all blocks: %v", err)
}
- t.Fatalf("FAIL: Waiting for execution payload on optimistic importer: %v", err)
+ t.Fatalf(
+ "FAIL: Waiting for execution payload on optimistic importer: %v",
+ err,
+ )
}
// Verify the heads match
- if match, err := CheckHeads(ctx, ExecutionClients{
+ optimisticClients := clients.ExecutionClients{
optimisticPair.Builder.ExecutionClient,
optimisticPair.Importer.ExecutionClient,
- }); err != nil {
+ }
+ if match, err := optimisticClients.CheckHeads(t, ctx); err != nil {
t.Fatalf("FAIL: Error getting head of optimistic clients: %v", err)
} else if !match {
// Print all heads for debugging
- if err := PrintAllBeaconBlocks(testnet, ctx); err != nil {
+ if err := debug.PrintAllTestnetBeaconBlocks(ctx, t, testnet.BeaconClients().Running()); err != nil {
t.Logf("FAIL: Error while printing all blocks: %v", err)
}
t.Fatalf("FAIL: Heads of the optimistic clients don't match")
}
+
// Verify heads of the two client pairs are different
- if match, err := CheckHeads(ctx, ExecutionClients{
+ forkedClients := clients.ExecutionClients{
testnet.ExecutionClients().Running()[0],
testnet.ExecutionClients().Running()[2],
- }); err != nil {
+ }
+ if match, err := forkedClients.CheckHeads(t, ctx); err != nil {
t.Fatalf("FAIL: Error getting head of clients: %v", err)
} else if match {
// Print all heads for debugging
- if err := PrintAllBeaconBlocks(testnet, ctx); err != nil {
+ if err := debug.PrintAllTestnetBeaconBlocks(ctx, t, testnet.BeaconClients().Running()); err != nil {
t.Logf("FAIL: Error while printing all blocks: %v", err)
}
t.Fatalf("FAIL: Heads of the clients match")
}
- time.Sleep(time.Duration(testnet.spec.SECONDS_PER_SLOT) * time.Second * 6)
- if err := PrintAllBeaconBlocks(testnet, ctx); err != nil {
- t.Fatalf("PrintAllBeaconBlocks failed: %v", err)
+ time.Sleep(
+ time.Duration(testnet.Spec().SECONDS_PER_SLOT) * time.Second * 6,
+ )
+ if err := debug.PrintAllTestnetBeaconBlocks(ctx, t, testnet.BeaconClients().Running()); err != nil {
+ t.Fatalf("PrintAllTestnetBeaconBlocks failed: %v", err)
}
}
-func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
+func NoViableHeadDueToOptimisticSync(
+ t *hivesim.T,
+ env *tn.Environment,
+ n clients.NodeDefinition,
+) {
var (
safeSlotsToImportOptimistically = big.NewInt(8)
// safeSlotsImportThreshold = uint64(4)
+ ctx = context.Background()
)
if clientSafeSlots, ok := SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE[n.ConsensusClient]; ok {
safeSlotsToImportOptimistically = clientSafeSlots
}
- config := getClientConfig(n).join(&Config{
- Nodes: Nodes{
+ config := getClientConfig(n).Join(&tn.Config{
+ NodeDefinitions: clients.NodeDefinitions{
// Builder 1
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 1,
},
// Importer
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
ValidatorShares: 0,
TestVerificationNode: true,
},
// Builder 2
- node{
+ clients.NodeDefinition{
ExecutionClient: n.ExecutionClient,
ConsensusClient: n.ConsensusClient,
// We are going to duplicate keys from builder 1
@@ -1808,16 +2442,16 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
DisableStartup: true,
},
},
- AltairForkEpoch: common.Big1,
- MergeForkEpoch: big.NewInt(4), // Slot 128
- Eth1Consensus: setup.Eth1EthashConsensus{
+ AltairForkEpoch: common.Big1,
+ BellatrixForkEpoch: big.NewInt(4), // Slot 128
+ Eth1Consensus: el.ExecutionEthashConsensus{
MiningNodes: 2,
},
SafeSlotsToImportOptimistically: safeSlotsToImportOptimistically,
})
- testnet := startTestnet(t, env, config)
- defer testnet.stopTestnet()
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
var (
builder1 = testnet.BeaconClients()[0]
@@ -1826,13 +2460,19 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
importerProxy = testnet.Proxies().Running()[1]
// Not yet started
builder2 = testnet.BeaconClients()[2]
- builder2Proxy *Proxy
+ builder2Proxy *proxy.Proxy
)
- importerNewPayloadResponseMocker := NewEngineResponseMocker(nil)
- importerFcUResponseMocker := NewEngineResponseMocker(nil)
- importerNewPayloadResponseMocker.AddNewPayloadCallbackToProxy(importerProxy)
- importerFcUResponseMocker.AddForkchoiceUpdatedCallbackToProxy(importerProxy)
+ importerNewPayloadResponseMocker := payload_spoof.NewEngineResponseMocker(
+ nil,
+ )
+ importerFcUResponseMocker := payload_spoof.NewEngineResponseMocker(nil)
+ importerNewPayloadResponseMocker.AddNewPayloadCallbackToProxy(
+ importerProxy,
+ )
+ importerFcUResponseMocker.AddForkchoiceUpdatedCallbackToProxy(
+ importerProxy,
+ )
// We will count the number of payloads produced by builder 1.
// On Payload 33, the test continues.
@@ -1842,13 +2482,13 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
invalidHashes = make([]common.Hash, 0)
invalidPayload common.Hash
)
- getPayloadCallback := func(res []byte, req []byte) *proxy.Spoof {
+ getPayloadCallback := func(res []byte, req []byte) *spoof.Spoof {
getPayloadCount++
var (
- payload ExecutableDataV1
+ payload api.ExecutableData
err error
)
- err = UnmarshalFromJsonRPCResponse(res, &payload)
+ err = proxy.UnmarshalFromJsonRPCResponse(res, &payload)
if err != nil {
panic(err)
}
@@ -1860,35 +2500,41 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
}
// Return syncing for these payloads
- importerNewPayloadResponseMocker.AddResponse(payload.BlockHash, &EngineResponse{
- Status: Syncing,
- LatestValidHash: nil,
- })
- importerFcUResponseMocker.AddResponse(payload.BlockHash, &EngineResponse{
- Status: Syncing,
- LatestValidHash: nil,
- })
+ importerNewPayloadResponseMocker.AddResponse(
+ payload.BlockHash,
+ &api.PayloadStatusV1{
+ Status: Syncing,
+ LatestValidHash: nil,
+ },
+ )
+ importerFcUResponseMocker.AddResponse(
+ payload.BlockHash,
+ &api.PayloadStatusV1{
+ Status: Syncing,
+ LatestValidHash: nil,
+ },
+ )
} else if getPayloadCount >= 33 {
// Invalidate these payloads
if getPayloadCount == 33 {
invalidPayload = payload.BlockHash
for _, h := range invalidHashes {
- importerNewPayloadResponseMocker.AddResponse(h, &EngineResponse{
+ importerNewPayloadResponseMocker.AddResponse(h, &api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &latestValidHash,
})
- importerFcUResponseMocker.AddResponse(h, &EngineResponse{
+ importerFcUResponseMocker.AddResponse(h, &api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &latestValidHash,
})
}
// Validate latest valid hash too
- importerNewPayloadResponseMocker.AddResponse(latestValidHash, &EngineResponse{
+ importerNewPayloadResponseMocker.AddResponse(latestValidHash, &api.PayloadStatusV1{
Status: Valid,
LatestValidHash: &latestValidHash,
})
- importerFcUResponseMocker.AddResponse(latestValidHash, &EngineResponse{
+ importerFcUResponseMocker.AddResponse(latestValidHash, &api.PayloadStatusV1{
Status: Valid,
LatestValidHash: &latestValidHash,
})
@@ -1896,11 +2542,11 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
}
invalidHashes = append(invalidHashes, payload.BlockHash)
- importerNewPayloadResponseMocker.AddResponse(payload.BlockHash, &EngineResponse{
+ importerNewPayloadResponseMocker.AddResponse(payload.BlockHash, &api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &latestValidHash,
})
- importerFcUResponseMocker.AddResponse(payload.BlockHash, &EngineResponse{
+ importerFcUResponseMocker.AddResponse(payload.BlockHash, &api.PayloadStatusV1{
Status: Invalid,
LatestValidHash: &latestValidHash,
})
@@ -1910,13 +2556,15 @@ func NoViableHeadDueToOptimisticSync(t *hivesim.T, env *testEnv, n node) {
}
builder1Proxy.AddResponseCallback(EngineGetPayloadV1, getPayloadCallback)
- ctx, cancel := context.WithCancel(context.Background())
+ execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ 32,
+ )
defer cancel()
- var err error
- _, err = testnet.WaitForExecutionPayload(ctx, 1000)
- if err != nil {
+ if _, err := testnet.WaitForExecutionPayload(execPayloadCtx); err != nil {
t.Fatalf("Error waiting for execution payload")
}
+
forloop:
for {
select {
@@ -1936,7 +2584,7 @@ forloop:
t.Fatalf("FAIL: Payload was not invalidated")
}
}
- case <-ctx.Done():
+ case <-testnet.Spec().SlotsTimeout(beacon.Slot(12)):
t.Fatalf("FAIL: Context done while waiting for invalidated payload")
}
}
@@ -1946,32 +2594,56 @@ forloop:
// We need to check that the latestValidHash Block is indeed optimistic
// First look for the block on the builder
- lvhBeaconBlock, err := builder1.GetBeaconBlockByExecutionHash(ctx, latestValidHash)
+ lvhBeaconBlock, err := builder1.GetBeaconBlockByExecutionHash(
+ ctx,
+ latestValidHash,
+ )
if err != nil {
- t.Fatalf("FAIL: Error querying latest valid hash from builder 1: %v", err)
+ t.Fatalf(
+ "FAIL: Error querying latest valid hash from builder 1: %v",
+ err,
+ )
}
- t.Logf("INFO: latest valid hash from builder 1: slot %d, root %v", lvhBeaconBlock.Message.Slot, lvhBeaconBlock.Message.StateRoot)
+ t.Logf(
+ "INFO: latest valid hash from builder 1: slot %d, root %v",
+ lvhBeaconBlock.Slot(),
+ lvhBeaconBlock.StateRoot(),
+ )
- lastInvalidBeaconBlock, err := builder1.GetBeaconBlockByExecutionHash(ctx, invalidPayload)
+ lastInvalidBeaconBlock, err := builder1.GetBeaconBlockByExecutionHash(
+ ctx,
+ invalidPayload,
+ )
if err != nil {
- t.Fatalf("FAIL: Error querying latest invalid hash from builder 1: %v", err)
+ t.Fatalf(
+ "FAIL: Error querying latest invalid hash from builder 1: %v",
+ err,
+ )
}
- t.Logf("INFO: latest invalid hash from builder 1: slot %d, root %v", lastInvalidBeaconBlock.Message.Slot, lastInvalidBeaconBlock.Message.StateRoot)
+ t.Logf(
+ "INFO: latest invalid hash from builder 1: slot %d, root %v",
+ lastInvalidBeaconBlock.Slot(),
+ lastInvalidBeaconBlock.StateRoot(),
+ )
// Check whether the importer is still optimistic for these blocks
- var (
- retriesLeft = 20
- )
+
+ retriesLeft := 20
+
for {
// Retry several times in order to give the node some time to re-org if necessary
if retriesLeft--; retriesLeft == 0 {
- importer.PrintAllBeaconBlocks(ctx)
+ debug.PrintAllBeaconBlocks(ctx, t, importer)
t.Fatalf("FAIL: Unable to get latestValidHash block: %v", err)
}
time.Sleep(time.Second)
- t.Logf("INFO: retry %d to obtain beacon block at height %d", 20-retriesLeft, lvhBeaconBlock.Message.Slot)
+ t.Logf(
+ "INFO: retry %d to obtain beacon block at height %d",
+ 20-retriesLeft,
+ lvhBeaconBlock.Slot(),
+ )
- if opt, err := importer.CheckBlockIsOptimistic(ctx, eth2api.BlockHead); err != nil {
+ if opt, err := importer.BlockIsOptimistic(ctx, eth2api.BlockHead); err != nil {
continue
} else if opt {
t.Logf("INFO: Head is optimistic from the importer's perspective")
@@ -1996,8 +2668,12 @@ forloop:
t.Fatalf("FAIL: Proxy failed to start")
}
- importerNewPayloadResponseMocker.AddNewPayloadCallbackToProxy(builder2Proxy)
- importerFcUResponseMocker.AddForkchoiceUpdatedCallbackToProxy(builder2Proxy)
+ importerNewPayloadResponseMocker.AddNewPayloadCallbackToProxy(
+ builder2Proxy,
+ )
+ importerFcUResponseMocker.AddForkchoiceUpdatedCallbackToProxy(
+ builder2Proxy,
+ )
// Then start the beacon node
if err := testnet.BeaconClients()[2].Start(); err != nil {
@@ -2009,30 +2685,48 @@ forloop:
t.Fatalf("FAIL: Unable to start validator client: %v", err)
}
- c, err := testnet.WaitForCurrentEpochFinalization(ctx, testnet.spec.SLOTS_PER_EPOCH*3)
+ finalizationContext, cancel := testnet.Spec().SlotTimeoutContext(
+ ctx,
+ testnet.Spec().SLOTS_PER_EPOCH*3,
+ )
+ defer cancel()
+ c, err := testnet.WaitForCurrentEpochFinalization(finalizationContext)
if err != nil {
- importer.PrintAllBeaconBlocks(ctx)
- builder2.PrintAllBeaconBlocks(ctx)
- t.Fatalf("FAIL: Error waiting for finality after builder 2 started: %v", err)
+ debug.PrintAllBeaconBlocks(ctx, t, importer)
+ debug.PrintAllBeaconBlocks(ctx, t, builder2)
+ t.Fatalf(
+ "FAIL: Error waiting for finality after builder 2 started: %v",
+ err,
+ )
}
t.Logf("INFO: Finality reached after builder 2 started: epoch %v", c.Epoch)
// Check that importer is no longer optimistic
- if opt, err := importer.CheckBlockIsOptimistic(ctx, eth2api.BlockHead); err != nil {
- t.Fatalf("FAIL: Error querying optimistic status after finalization on importer: %v", err)
+ if opt, err := importer.BlockIsOptimistic(ctx, eth2api.BlockHead); err != nil {
+ t.Fatalf(
+ "FAIL: Error querying optimistic status after finalization on importer: %v",
+ err,
+ )
} else if opt {
t.Fatalf("FAIL: Importer is still optimistic after finalization: execution_optimistic=%t", opt)
}
// Check that neither the first invalid payload nor the last invalid payload are included in the importer
+
if b, err := importer.GetBeaconBlockByExecutionHash(ctx, invalidHashes[0]); err != nil {
t.Fatalf("FAIL: Error querying invalid payload: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid payload found in importer chain: %d, %v", b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf(
+ "FAIL: Invalid payload found in importer chain: %d, %v",
+ b.Slot(), b.StateRoot(),
+ )
}
if b, err := importer.GetBeaconBlockByExecutionHash(ctx, invalidPayload); err != nil {
t.Fatalf("FAIL: Error querying invalid payload: %v", err)
} else if b != nil {
- t.Fatalf("FAIL: Invalid payload found in importer chain: %d, %v", b.Message.Slot, b.Message.StateRoot)
+ t.Fatalf(
+ "FAIL: Invalid payload found in importer chain: %d, %v",
+ b.Slot(), b.StateRoot(),
+ )
}
}
diff --git a/simulators/eth2/engine/setup/files.go b/simulators/eth2/engine/setup/files.go
deleted file mode 100644
index 874b5cebfc..0000000000
--- a/simulators/eth2/engine/setup/files.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package setup
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
-
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/ztyp/codec"
- "gopkg.in/yaml.v2"
-
- "github.com/ethereum/hive/hivesim"
-)
-
-func bytesSource(data []byte) func() (io.ReadCloser, error) {
- return func() (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewReader(data)), nil
- }
-}
-
-func Eth1Bundle(genesis *core.Genesis) (hivesim.StartOption, error) {
- out, err := json.Marshal(genesis)
- if err != nil {
- return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
- }
- return hivesim.WithDynamicFile("genesis.json", bytesSource(out)), nil
-}
-
-func StateBundle(state common.BeaconState) (hivesim.StartOption, error) {
- var stateBytes bytes.Buffer
- if err := state.Serialize(codec.NewEncodingWriter(&stateBytes)); err != nil {
- return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
- }
- return hivesim.WithDynamicFile("/hive/input/genesis.ssz", bytesSource(stateBytes.Bytes())), nil
-}
-
-func ConsensusConfigsBundle(spec *common.Spec, genesis *core.Genesis, valCount uint64) (hivesim.StartOption, error) {
- config, err := yaml.Marshal(spec.Config)
- if err != nil {
- return nil, err
- }
- phase0Preset, err := yaml.Marshal(spec.Phase0Preset)
- if err != nil {
- return nil, err
- }
- altairPreset, err := yaml.Marshal(spec.AltairPreset)
- if err != nil {
- return nil, err
- }
- bellatrixPreset, err := yaml.Marshal(spec.BellatrixPreset)
- if err != nil {
- return nil, err
- }
- genesisHash := genesis.ToBlock().Hash()
- return hivesim.Bundle(
- hivesim.WithDynamicFile("/hive/input/config.yaml", bytesSource(config)),
- hivesim.WithDynamicFile("/hive/input/preset_phase0.yaml", bytesSource(phase0Preset)),
- hivesim.WithDynamicFile("/hive/input/preset_altair.yaml", bytesSource(altairPreset)),
- hivesim.WithDynamicFile("/hive/input/preset_bellatrix.yaml", bytesSource(bellatrixPreset)),
- hivesim.Params{
- "HIVE_ETH2_ETH1_GENESIS_HASH": genesisHash.String(),
- },
- ), nil
-}
-
-func ChainBundle(chain []*types.Block) (hivesim.StartOption, error) {
- var buf bytes.Buffer
- for _, block := range chain {
- if err := block.EncodeRLP(&buf); err != nil {
- return nil, err
- }
- }
- return hivesim.WithDynamicFile("/chain.rlp", bytesSource(buf.Bytes())), nil
-}
-
-func KeysBundle(keys []*KeyDetails) hivesim.StartOption {
- opts := make([]hivesim.StartOption, 0, len(keys)*2)
- for _, k := range keys {
- p := fmt.Sprintf("/hive/input/keystores/0x%x/keystore.json", k.ValidatorPubkey[:])
- opts = append(opts, hivesim.WithDynamicFile(p, bytesSource(k.ValidatorKeystoreJSON)))
- p = fmt.Sprintf("/hive/input/secrets/0x%x", k.ValidatorPubkey[:])
- opts = append(opts, hivesim.WithDynamicFile(p, bytesSource([]byte(k.ValidatorKeystorePass))))
- }
- return hivesim.Bundle(opts...)
-}
diff --git a/simulators/eth2/engine/setup/genesis.go b/simulators/eth2/engine/setup/genesis.go
deleted file mode 100644
index fd3d16538c..0000000000
--- a/simulators/eth2/engine/setup/genesis.go
+++ /dev/null
@@ -1,223 +0,0 @@
-package setup
-
-import (
- "crypto/sha256"
- "fmt"
-
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/holiman/uint256"
- "github.com/protolambda/zrnt/eth2/beacon/altair"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/zrnt/eth2/beacon/phase0"
- "github.com/protolambda/zrnt/eth2/configs"
- "github.com/protolambda/ztyp/tree"
- "github.com/protolambda/ztyp/view"
-)
-
-func genesisPayloadHeader(eth1GenesisBlock *types.Block, spec *common.Spec) (*common.ExecutionPayloadHeader, error) {
- extra := eth1GenesisBlock.Extra()
- if len(extra) > common.MAX_EXTRA_DATA_BYTES {
- return nil, fmt.Errorf("extra data is %d bytes, max is %d", len(extra), common.MAX_EXTRA_DATA_BYTES)
- }
- if len(eth1GenesisBlock.Transactions()) != 0 {
- return nil, fmt.Errorf("expected no transactions in genesis execution payload")
- }
-
- baseFee, overflow := uint256.FromBig(eth1GenesisBlock.BaseFee())
- if overflow {
- return nil, fmt.Errorf("basefee larger than 2^256-1")
- }
-
- return &common.ExecutionPayloadHeader{
- ParentHash: common.Root(eth1GenesisBlock.ParentHash()),
- FeeRecipient: common.Eth1Address(eth1GenesisBlock.Coinbase()),
- StateRoot: common.Bytes32(eth1GenesisBlock.Root()),
- ReceiptsRoot: common.Bytes32(eth1GenesisBlock.ReceiptHash()),
- LogsBloom: common.LogsBloom(eth1GenesisBlock.Bloom()),
- PrevRandao: common.Bytes32{},
- BlockNumber: view.Uint64View(eth1GenesisBlock.NumberU64()),
- GasLimit: view.Uint64View(eth1GenesisBlock.GasLimit()),
- GasUsed: view.Uint64View(eth1GenesisBlock.GasUsed()),
- Timestamp: common.Timestamp(eth1GenesisBlock.Time()),
- ExtraData: extra,
- BaseFeePerGas: view.Uint256View(*baseFee),
- BlockHash: common.Root(eth1GenesisBlock.Hash()),
- // empty transactions root
- TransactionsRoot: common.PayloadTransactionsType(spec).DefaultNode().MerkleRoot(tree.GetHashFn()),
- }, nil
-}
-
-func createValidators(spec *common.Spec, keys []*KeyDetails) []phase0.KickstartValidatorData {
- validators := make([]phase0.KickstartValidatorData, 0, len(keys))
- hasher := sha256.New()
- withdrawalCred := func(k common.BLSPubkey) (out common.Root) {
- hasher.Reset()
- hasher.Write(k[:])
- dat := hasher.Sum(nil)
- copy(out[:], dat)
- out[0] = common.BLS_WITHDRAWAL_PREFIX
- return
- }
- for _, key := range keys {
- validators = append(validators, phase0.KickstartValidatorData{
- Pubkey: key.ValidatorPubkey,
- WithdrawalCredentials: withdrawalCred(key.WithdrawalPubkey),
- Balance: spec.MAX_EFFECTIVE_BALANCE,
- })
- }
- return validators
-}
-
-// BuildBeaconState creates a beacon state, with either ExecutionFromGenesis or NoExecutionFromGenesis, the given timestamp, and validators derived from the given keys.
-// The deposit contract will be recognized as an empty tree, ready for new deposits, thus skipping any transactions for pre-mined validators.
-//
-// TODO: instead of providing a eth1 genesis, provide an eth1 chain, so we can simulate a merge genesis state that embeds an existing eth1 chain.
-func BuildBeaconState(spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisTime common.Timestamp, keys []*KeyDetails) (common.BeaconState, error) {
- if uint64(len(keys)) < uint64(spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) {
- return nil, fmt.Errorf("WARNING: not enough validator keys for genesis. Got %d, but need at least %d.\n",
- len(keys), spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT)
- }
-
- eth1GenesisBlock := eth1Genesis.ToBlock()
- eth1BlockHash := common.Root(eth1GenesisBlock.Hash())
-
- validators := createValidators(spec, keys)
-
- hFn := tree.GetHashFn()
-
- var state common.BeaconState
- var forkVersion common.Version
- var emptyBodyRoot common.Root
- if spec.BELLATRIX_FORK_EPOCH == 0 {
- state = bellatrix.NewBeaconStateView(spec)
- forkVersion = spec.BELLATRIX_FORK_VERSION
- emptyBodyRoot = bellatrix.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
- } else if spec.ALTAIR_FORK_EPOCH == 0 {
- state = bellatrix.NewBeaconStateView(spec)
- forkVersion = spec.ALTAIR_FORK_VERSION
- emptyBodyRoot = altair.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
- } else {
- state = phase0.NewBeaconStateView(spec)
- forkVersion = spec.GENESIS_FORK_VERSION
- emptyBodyRoot = phase0.BeaconBlockBodyType(configs.Mainnet).New().HashTreeRoot(hFn)
- }
-
- if err := state.SetGenesisTime(eth2GenesisTime); err != nil {
- return nil, err
- }
-
- if err := state.SetFork(common.Fork{
- PreviousVersion: forkVersion, // duplicate, since there is nothing before genesis.
- CurrentVersion: forkVersion,
- Epoch: common.GENESIS_EPOCH,
- }); err != nil {
- return nil, err
- }
- // Empty deposit-tree
- eth1Dat := common.Eth1Data{
- DepositRoot: phase0.NewDepositRootsView().HashTreeRoot(tree.GetHashFn()),
- DepositCount: 0,
- BlockHash: eth1BlockHash,
- }
- if err := state.SetEth1Data(eth1Dat); err != nil {
- return nil, err
- }
- // sanity check: Leave the deposit index to 0. No deposits happened.
- if i, err := state.Eth1DepositIndex(); err != nil {
- return nil, err
- } else if i != 0 {
- return nil, fmt.Errorf("expected 0 deposit index in state, got %d", i)
- }
- if err := state.SetLatestBlockHeader(&common.BeaconBlockHeader{BodyRoot: emptyBodyRoot}); err != nil {
- return nil, err
- }
- // Seed RANDAO with Eth1 entropy
- if err := state.SeedRandao(spec, eth1BlockHash); err != nil {
- return nil, err
- }
-
- for _, v := range validators {
- if err := state.AddValidator(spec, v.Pubkey, v.WithdrawalCredentials, v.Balance); err != nil {
- return nil, err
- }
- }
- vals, err := state.Validators()
- if err != nil {
- return nil, err
- }
- // Process activations
- for i := 0; i < len(validators); i++ {
- val, err := vals.Validator(common.ValidatorIndex(i))
- if err != nil {
- return nil, err
- }
- vEff, err := val.EffectiveBalance()
- if err != nil {
- return nil, err
- }
- if vEff == spec.MAX_EFFECTIVE_BALANCE {
- if err := val.SetActivationEligibilityEpoch(common.GENESIS_EPOCH); err != nil {
- return nil, err
- }
- if err := val.SetActivationEpoch(common.GENESIS_EPOCH); err != nil {
- return nil, err
- }
- }
- }
- if err := state.SetGenesisValidatorsRoot(vals.HashTreeRoot(tree.GetHashFn())); err != nil {
- return nil, err
- }
- if st, ok := state.(common.SyncCommitteeBeaconState); ok {
- indicesBounded, err := common.LoadBoundedIndices(vals)
- if err != nil {
- return nil, err
- }
- active := common.ActiveIndices(indicesBounded, common.GENESIS_EPOCH)
- indices, err := common.ComputeSyncCommitteeIndices(spec, state, common.GENESIS_EPOCH, active)
- if err != nil {
- return nil, fmt.Errorf("failed to compute sync committee indices: %v", err)
- }
- pubs, err := common.NewPubkeyCache(vals)
- if err != nil {
- return nil, err
- }
- // Note: A duplicate committee is assigned for the current and next committee at genesis
- syncCommittee, err := common.IndicesToSyncCommittee(indices, pubs)
- if err != nil {
- return nil, err
- }
- syncCommitteeView, err := syncCommittee.View(spec)
- if err != nil {
- return nil, err
- }
- if err := st.SetCurrentSyncCommittee(syncCommitteeView); err != nil {
- return nil, err
- }
- if err := st.SetNextSyncCommittee(syncCommitteeView); err != nil {
- return nil, err
- }
- }
-
- if st, ok := state.(*bellatrix.BeaconStateView); ok {
- // did we hit the TTD at genesis block?
- tdd := uint256.Int(spec.TERMINAL_TOTAL_DIFFICULTY)
- embedExecAtGenesis := tdd.ToBig().Cmp(eth1Genesis.Difficulty) < 0
-
- var execPayloadHeader *common.ExecutionPayloadHeader
- if embedExecAtGenesis {
- execPayloadHeader, err = genesisPayloadHeader(eth1GenesisBlock, spec)
- } else {
- // we didn't build any on the eth1 chain though,
- // so we just put the genesis hash here (it could be any block from eth1 chain before TTD that is not ahead of eth2)
- execPayloadHeader = new(common.ExecutionPayloadHeader)
- }
-
- if err := st.SetLatestExecutionPayloadHeader(execPayloadHeader); err != nil {
- return nil, err
- }
- }
-
- return state, nil
-}
diff --git a/simulators/eth2/engine/verification.go b/simulators/eth2/engine/verification.go
deleted file mode 100644
index f8167d7d37..0000000000
--- a/simulators/eth2/engine/verification.go
+++ /dev/null
@@ -1,470 +0,0 @@
-package main
-
-import (
- "bytes"
- "context"
- "fmt"
- "math/big"
- "net/http"
- "sort"
- "time"
-
- ethcommon "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/beaconapi"
- "github.com/protolambda/zrnt/eth2/beacon/altair"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/zrnt/eth2/beacon/phase0"
- "github.com/protolambda/ztyp/tree"
-)
-
-// Interface to specify on which slot the verification will be performed
-type VerificationSlot interface {
- Slot(t *Testnet, ctx context.Context, bn *BeaconClient) (common.Slot, error)
-}
-
-// Return the slot at the start of the checkpoint's following epoch
-type FirstSlotAfterCheckpoint struct {
- *common.Checkpoint
-}
-
-func (c FirstSlotAfterCheckpoint) Slot(t *Testnet, _ context.Context, _ *BeaconClient) (common.Slot, error) {
- return t.spec.EpochStartSlot(c.Checkpoint.Epoch + 1)
-}
-
-// Return the slot at the end of a checkpoint
-type LastSlotAtCheckpoint struct {
- *common.Checkpoint
-}
-
-func (c LastSlotAtCheckpoint) Slot(t *Testnet, _ context.Context, _ *BeaconClient) (common.Slot, error) {
- return t.spec.SLOTS_PER_EPOCH * common.Slot(c.Checkpoint.Epoch), nil
-}
-
-// Get last slot according to current time
-type LastestSlotByTime struct{}
-
-func (l LastestSlotByTime) Slot(t *Testnet, _ context.Context, _ *BeaconClient) (common.Slot, error) {
- return t.spec.TimeToSlot(common.Timestamp(time.Now().Unix()), t.genesisTime), nil
-}
-
-// Get last slot according to current head of a beacon node
-type LastestSlotByHead struct{}
-
-func (l LastestSlotByHead) Slot(t *Testnet, ctx context.Context, bn *BeaconClient) (common.Slot, error) {
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, bn.API, eth2api.BlockHead, &headInfo); err != nil {
- return common.Slot(0), fmt.Errorf("failed to poll head: %v", err)
- } else if !exists {
- return common.Slot(0), fmt.Errorf("no head block")
- }
- return headInfo.Header.Message.Slot, nil
-}
-
-// VerifyParticipation ensures that the participation of the finialized epoch
-// of a given checkpoint is above the expected threshold.
-func VerifyParticipation(t *Testnet, ctx context.Context, vs VerificationSlot, expected float64) error {
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- slot, err := vs.Slot(t, ctx, runningBeacons[0])
- if err != nil {
- return err
- }
- if t.spec.BELLATRIX_FORK_EPOCH <= t.spec.SlotToEpoch(slot) {
- // slot-1 to target last slot in finalized epoch
- slot = slot - 1
- }
- for i, b := range runningBeacons {
- health, err := getHealth(ctx, b.API, t.spec, slot)
- if err != nil {
- return err
- }
- if health < expected {
- return fmt.Errorf("beacon %d: participation not healthy (got: %.2f, expected: %.2f)", i, health, expected)
- }
- t.Logf("beacon %d: epoch=%d participation=%.2f", i, t.spec.SlotToEpoch(slot), health)
- }
- return nil
-}
-
-// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the
-// finalized block and verifies that is in the execution client's canonical
-// chain.
-func VerifyExecutionPayloadIsCanonical(t *Testnet, ctx context.Context, vs VerificationSlot) error {
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- slot, err := vs.Slot(t, ctx, runningBeacons[0])
- if err != nil {
- return err
- }
- var blockId eth2api.BlockIdSlot
- blockId = eth2api.BlockIdSlot(slot)
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, runningBeacons[0].API, blockId, &versionedBlock); err != nil {
- return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err)
- } else if !exists {
- return fmt.Errorf("beacon %d: block not found", 0)
- }
- if versionedBlock.Version != "bellatrix" {
- return nil
- }
- payload := versionedBlock.Data.(*bellatrix.SignedBeaconBlock).Message.Body.ExecutionPayload
-
- for i, proxy := range t.VerificationNodes().Proxies().Running() {
- client := ethclient.NewClient(proxy.RPC())
- block, err := client.BlockByNumber(ctx, big.NewInt(int64(payload.BlockNumber)))
- if err != nil {
- return fmt.Errorf("eth1 %d: %s", 0, err)
- }
- if block.Hash() != [32]byte(payload.BlockHash) {
- return fmt.Errorf("eth1 %d: blocks don't match (got=%s, expected=%s)", i, shorten(block.Hash().String()), shorten(payload.BlockHash.String()))
- }
- }
- return nil
-}
-
-// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the
-// finalized block and verifies that is in the execution client's canonical
-// chain.
-func VerifyExecutionPayloadHashInclusion(t *Testnet, ctx context.Context, vs VerificationSlot, hash ethcommon.Hash) (*bellatrix.SignedBeaconBlock, error) {
- for _, bn := range t.VerificationNodes().BeaconClients().Running() {
- b, err := VerifyExecutionPayloadHashInclusionNode(t, ctx, vs, bn, hash)
- if err != nil || b != nil {
- return b, err
- }
- }
- return nil, nil
-}
-
-func VerifyExecutionPayloadHashInclusionNode(t *Testnet, ctx context.Context, vs VerificationSlot, bn *BeaconClient, hash ethcommon.Hash) (*bellatrix.SignedBeaconBlock, error) {
- lastSlot, err := vs.Slot(t, ctx, bn)
- if err != nil {
- return nil, err
- }
- for slot := lastSlot; slot > 0; slot -= 1 {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- continue
- } else if !exists {
- continue
- }
- if versionedBlock.Version != "bellatrix" {
- // Block can't contain an executable payload
- break
- }
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- payload := block.Message.Body.ExecutionPayload
- if bytes.Compare(payload.BlockHash[:], hash[:]) == 0 {
- return block, nil
- }
- }
- return nil, nil
-}
-
-// VerifyProposers checks that all validator clients have proposed a block on
-// the finalized beacon chain that includes an execution payload.
-func VerifyProposers(t *Testnet, ctx context.Context, vs VerificationSlot, allow_empty_blocks bool) error {
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- lastSlot, err := vs.Slot(t, ctx, runningBeacons[0])
- if err != nil {
- return err
- }
- proposers := make([]bool, len(runningBeacons))
- for slot := common.Slot(0); slot <= lastSlot; slot += 1 {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, runningBeacons[0].API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- if allow_empty_blocks {
- continue
- }
- return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err)
- } else if !exists {
- if allow_empty_blocks {
- continue
- }
- return fmt.Errorf("beacon %d: block not found", 0)
- }
- var proposerIndex common.ValidatorIndex
- switch versionedBlock.Version {
- case "phase0":
- block := versionedBlock.Data.(*phase0.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- case "altair":
- block := versionedBlock.Data.(*altair.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- }
-
- var validator eth2api.ValidatorResponse
- if exists, err := beaconapi.StateValidator(ctx, runningBeacons[0].API, eth2api.StateIdSlot(slot), eth2api.ValidatorIdIndex(proposerIndex), &validator); err != nil {
- return fmt.Errorf("beacon %d: failed to retrieve validator: %v", 0, err)
- } else if !exists {
- return fmt.Errorf("beacon %d: validator not found", 0)
- }
- idx, err := t.ValidatorClientIndex([48]byte(validator.Validator.Pubkey))
- if err != nil {
- return fmt.Errorf("pub key not found on any validator client")
- }
- proposers[idx] = true
- }
- for i, proposed := range proposers {
- if !proposed {
- return fmt.Errorf("beacon %d: did not propose a block", i)
- }
- }
- return nil
-}
-
-func VerifyELBlockLabels(t *Testnet, ctx context.Context) error {
- runningExecution := t.VerificationNodes().ExecutionClients().Running()
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
- for i := 0; i < len(runningExecution); i++ {
- el := runningExecution[i]
- bn := runningBeacons[i]
- // Get the head
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, bn.API, eth2api.BlockHead, &headInfo); err != nil {
- return err
- } else if !exists {
- return fmt.Errorf("beacon %d: head info not found", i)
- }
-
- // Get the checkpoints
- var checkpoints eth2api.FinalityCheckpoints
- if exists, err := beaconapi.FinalityCheckpoints(ctx, bn.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil || !exists {
- if exists, err = beaconapi.FinalityCheckpoints(ctx, bn.API, eth2api.StateIdSlot(headInfo.Header.Message.Slot), &checkpoints); err != nil {
- return err
- } else if !exists {
- return fmt.Errorf("beacon %d: finality checkpoints not found", i)
- }
- }
- blockLabels := map[string]tree.Root{
- "latest": headInfo.Root,
- "finalized": checkpoints.Finalized.Root,
- "safe": checkpoints.CurrentJustified.Root,
- }
-
- for label, root := range blockLabels {
- // Get the beacon block
- var (
- versionedBlock eth2api.VersionedSignedBeaconBlock
- expectedExec ethcommon.Hash
- )
- if exists, err := beaconapi.BlockV2(ctx, bn.API, eth2api.BlockIdRoot(root), &versionedBlock); err != nil {
- return err
- } else if !exists {
- return fmt.Errorf("beacon %d: beacon block to query %s not found", i, label)
- }
- switch versionedBlock.Version {
- case "phase0":
- expectedExec = ethcommon.Hash{}
- case "altair":
- expectedExec = ethcommon.Hash{}
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- expectedExec = ethcommon.BytesToHash(block.Message.Body.ExecutionPayload.BlockHash[:])
- }
-
- // Get the el block and compare
- rpcAddr, _ := el.UserRPCAddress()
- rpcClient, _ := rpc.DialHTTPWithClient(rpcAddr, &http.Client{})
- var h types.Header
-
- if err := rpcClient.CallContext(ctx, &h, "eth_getBlockByNumber", label, false); err != nil {
- if expectedExec != (ethcommon.Hash{}) {
- return err
- }
- } else {
- if h.Hash() != expectedExec {
- return fmt.Errorf("beacon %d: Execution hash found in checkpoint block (%s) does not match what the el returns: %v != %v", i, label, expectedExec, h.Hash())
- }
- fmt.Printf("beacon %d: Execution hash matches beacon checkpoint block (%s) information: %v\n", i, label, h.Hash())
- }
-
- }
- }
- return nil
-}
-
-func VerifyELHeads(t *Testnet, ctx context.Context) error {
- runningExecution := t.VerificationNodes().ExecutionClients().Running()
- client := ethclient.NewClient(runningExecution[0].HiveClient.RPC())
- head, err := client.HeaderByNumber(ctx, nil)
- if err != nil {
- return err
- }
-
- t.Logf("Verifying EL heads at %v", head.Hash())
- for i, node := range runningExecution {
- client := ethclient.NewClient(node.HiveClient.RPC())
- head2, err := client.HeaderByNumber(ctx, nil)
- if err != nil {
- return err
- }
- if head.Hash() != head2.Hash() {
- return fmt.Errorf("different heads: %v: %v %v: %v", 0, head, i, head2)
- }
- }
- return nil
-}
-
-// Helper debugging functions
-func (b *BeaconClient) PrintAllBeaconBlocks(ctx context.Context) error {
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- return fmt.Errorf("PrintAllBeaconBlocks: failed to poll head: %v", err)
- } else if !exists {
- return fmt.Errorf("PrintAllBeaconBlocks: failed to poll head: !exists")
- }
- fmt.Printf("PrintAllBeaconBlocks: Printing beacon chain from %s\n", b.HiveClient.Container)
- fmt.Printf("PrintAllBeaconBlocks: Head, slot %d, root %v\n", headInfo.Header.Message.Slot, headInfo.Root)
- for i := 1; i <= int(headInfo.Header.Message.Slot); i++ {
- var bHeader eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockIdSlot(i), &bHeader); err != nil {
- fmt.Printf("PrintAllBeaconBlocks: Slot %d, not found\n", i)
- continue
- } else if !exists {
- fmt.Printf("PrintAllBeaconBlocks: Slot %d, not found\n", i)
- continue
- }
- var (
- root = bHeader.Root
- execution = "0x0000..0000"
- )
-
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(root), &versionedBlock); err == nil && exists {
- switch versionedBlock.Version {
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- execution = shorten(block.Message.Body.ExecutionPayload.BlockHash.String())
- }
- }
-
- fmt.Printf("PrintAllBeaconBlocks: Slot=%d, root=%v, exec=%s\n", i, root, execution)
- }
- return nil
-}
-
-type BeaconBlockInfo struct {
- Root tree.Root
- Parent tree.Root
- Execution ethcommon.Hash
- Nodes []int
-}
-
-type BeaconBlockList []*BeaconBlockInfo
-
-func (bl BeaconBlockList) Add(root tree.Root, parent tree.Root, execution ethcommon.Hash, nodeId int) (BeaconBlockList, error) {
- for _, b := range bl {
- if root == b.Root {
- if parent != b.Parent {
- return bl, fmt.Errorf("roots equal (%s), parent root mismatch: %s != %s", root.String(), parent.String(), b.Parent.String())
- }
- if execution != b.Execution {
- return bl, fmt.Errorf("roots equal (%s), exec hash mismatch: %s != %s", root.String(), execution.String(), b.Execution.String())
- }
- for _, n := range b.Nodes {
- if nodeId == n {
- return bl, nil
- }
- }
- b.Nodes = append(b.Nodes, nodeId)
- return bl, nil
- }
- }
- return append(bl, &BeaconBlockInfo{
- Root: root,
- Parent: parent,
- Execution: execution,
- Nodes: []int{nodeId},
- }), nil
-}
-
-type BeaconBlockMap map[common.Slot]BeaconBlockList
-
-func (bm BeaconBlockMap) Add(slot common.Slot, root tree.Root, parent tree.Root, execution ethcommon.Hash, nodeId int) error {
- if _, found := bm[slot]; !found {
- bm[slot] = make(BeaconBlockList, 0)
- }
- var err error
- bm[slot], err = bm[slot].Add(root, parent, execution, nodeId)
- if err != nil {
- return fmt.Errorf("Conflicting block on slot %d: %v", slot, err)
- }
- return nil
-}
-func (bm BeaconBlockMap) Print(l Logging) error {
- slots := make([]int, 0, len(bm))
- for s := range bm {
- slots = append(slots, int(s))
- }
- sort.Ints(slots)
- for _, s := range slots {
- l.Logf("- Slot=%d\n", s)
- for i, b := range bm[common.Slot(s)] {
- l.Logf(" Fork %d: root=%v, parent=%v, exec=%s, nodes=%v \n", i, shorten(b.Root.String()), shorten(b.Parent.String()), shorten(b.Execution.String()), b.Nodes)
- }
- }
- return nil
-}
-func PrintAllBeaconBlocks(t *Testnet, ctx context.Context) error {
- runningBeacons := t.VerificationNodes().BeaconClients().Running()
-
- beaconTree := make(BeaconBlockMap)
-
- for nodeId, beaconNode := range runningBeacons {
-
- var (
- nextBlock eth2api.BlockId
- )
-
- nextBlock = eth2api.BlockHead
-
- for {
- if nextBlock.BlockId() == eth2api.BlockIdRoot(tree.Root{}).BlockId() {
- break
- }
- // Get block header
- var bHeader eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, beaconNode.API, nextBlock, &bHeader); err != nil {
- t.Logf("Error fetching block (%s) from beacon node %d: %v", nextBlock.BlockId(), nodeId, err)
- break
- } else if !exists {
- t.Logf("Unable to fetch block (%s) from beacon node %d: !exists", nextBlock.BlockId(), nodeId)
- break
- }
-
- var (
- root = bHeader.Root
- parent = bHeader.Header.Message.ParentRoot
- execution = ethcommon.Hash{}
- )
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, beaconNode.API, eth2api.BlockIdRoot(root), &versionedBlock); err == nil && exists {
- switch versionedBlock.Version {
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- execution = ethcommon.BytesToHash(block.Message.Body.ExecutionPayload.BlockHash[:])
- t.Logf("Node %d: Execution payload: hash=%s", nodeId, shorten(execution.String()))
- }
- } else if err != nil {
- t.Logf("Error getting versioned block=%s node=%d: %v", nextBlock.BlockId(), nodeId, err)
- break
- } else if !exists {
- t.Logf("Error getting versioned block=%s node=%d: !exists", nextBlock.BlockId(), nodeId)
- break
- }
- if err := beaconTree.Add(bHeader.Header.Message.Slot, root, parent, execution, nodeId); err != nil {
- return err
- }
- nextBlock = eth2api.BlockIdRoot(parent)
- }
-
- }
- beaconTree.Print(t)
- return nil
-}
diff --git a/simulators/eth2/go.work b/simulators/eth2/go.work
new file mode 100644
index 0000000000..e7295a1dba
--- /dev/null
+++ b/simulators/eth2/go.work
@@ -0,0 +1,8 @@
+go 1.18
+
+use (
+ ./common
+ ./engine
+ ./testnet
+ ./withdrawals
+)
diff --git a/simulators/eth2/go.work.sum b/simulators/eth2/go.work.sum
new file mode 100644
index 0000000000..75c9b9b23e
--- /dev/null
+++ b/simulators/eth2/go.work.sum
@@ -0,0 +1,980 @@
+bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+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/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
+github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
+github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
+github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
+github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
+github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
+github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
+github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
+github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
+github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
+github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
+github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
+github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
+github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
+github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
+github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
+github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
+github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
+github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
+github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
+github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
+github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
+github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
+github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
+github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
+github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
+github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
+github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
+github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
+github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
+github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
+github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
+github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
+github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
+github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
+github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
+github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
+github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
+github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
+github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
+github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
+github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
+github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
+github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
+github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
+github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
+github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/ethereum/hive/hiveproxy v0.0.0-20220708193637-ec524d7345a1/go.mod h1:XtF0Q/5ESJpak7na/6prPgfpTZ+IAFU2qQzHvnqc5as=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/fsouza/go-dockerclient v1.8.1/go.mod h1:zmA2ogSxRnXmbZcy0Aq7yhRoCdP/bDns/qghCK9SWtM=
+github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
+github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
+github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
+github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/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/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+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/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+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.3/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+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/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.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/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
+github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
+github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
+github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+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/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/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/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+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=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/marioevz/eth2api v0.0.0-20230110222620-e349e704f20c h1:SMr9xLO/+oftAWC1oms31EQd22cOH7C9QRqdSKpV03A=
+github.com/marioevz/eth2api v0.0.0-20230110222620-e349e704f20c/go.mod h1:4WbGGB4Bv17hKsiytlJY4IQDNpRS234DvFvIBNLnd60=
+github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
+github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
+github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
+github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
+github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q=
+github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY=
+github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g=
+github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
+github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
+github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
+github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
+github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
+github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
+github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
+github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
+github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
+github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+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.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+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.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/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/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
+github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
+github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+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.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
+golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/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/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
+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-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-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/lint v0.0.0-20210508222113-6edffad5e616/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.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/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-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-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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+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/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+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-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/sys v0.0.0-20190130150945-aca44879d564/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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/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-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/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-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/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-20200217220822-9197077df867/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-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-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-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+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-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/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-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/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-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/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-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-20200505023115-26f46d2f7ef8/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-20200616133436-c1934b75d054/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-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
+google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+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.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/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/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-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/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-20200117163144-32f20d992d24/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-20200513103714-09dca8ec2884/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-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+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/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+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/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/protobuf v1.22.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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/yaml.v2 v2.2.3/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=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+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.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=
+k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
+k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
+k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
+k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
+k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
+k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
+k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
+k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
+k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
+k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
+k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
+k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
+k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
+k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
+k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
+k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
+k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
+k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/simulators/eth2/testnet/Dockerfile b/simulators/eth2/testnet/Dockerfile
index c7cdb3e13f..a8ec5ae3d7 100644
--- a/simulators/eth2/testnet/Dockerfile
+++ b/simulators/eth2/testnet/Dockerfile
@@ -1,11 +1,16 @@
FROM golang:1-alpine AS builder
RUN apk --no-cache add gcc musl-dev linux-headers cmake make clang build-base clang-static clang-dev
+
+# Prepare workspace.
+# Note: the build context of this simulator image is the parent directory!
ADD . /source
-WORKDIR /source
+
+# Build within simulator folder
+WORKDIR /source/testnet
RUN go build -o ./sim .
# Build the runner container.
FROM alpine:latest
ADD . /
-COPY --from=builder /source/sim /
+COPY --from=builder /source/testnet/sim /
ENTRYPOINT ["./sim"]
diff --git a/simulators/eth2/testnet/go.mod b/simulators/eth2/testnet/go.mod
index 0189e9d049..174f1c9097 100644
--- a/simulators/eth2/testnet/go.mod
+++ b/simulators/eth2/testnet/go.mod
@@ -2,77 +2,30 @@ module github.com/ethereum/hive/simulators/eth2/testnet
go 1.18
-require (
- github.com/ethereum/go-ethereum v1.10.26
- github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b
- github.com/google/uuid v1.3.0
- github.com/herumi/bls-eth-go-binary v1.28.1
- github.com/pkg/errors v0.9.1
- github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0
- github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564
- github.com/protolambda/zrnt v0.28.0
- github.com/protolambda/ztyp v0.2.2
- github.com/tyler-smith/go-bip39 v1.1.0
- github.com/wealdtech/go-eth2-util v1.8.0
-)
+require github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b
require (
- github.com/VictoriaMetrics/fastcache v1.12.0 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
- github.com/ferranbt/fastssz v0.1.2 // indirect
- github.com/go-kit/kit v0.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
- github.com/holiman/uint256 v1.2.1
- github.com/mattn/go-runewidth v0.0.14 // indirect
- github.com/minio/sha256-simd v1.0.0 // indirect
- github.com/mitchellh/mapstructure v1.5.0 // indirect
- github.com/olekukonko/tablewriter v0.0.5 // indirect
- github.com/prometheus/tsdb v0.10.0 // indirect
- github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
golang.org/x/sys v0.3.0 // indirect
- golang.org/x/text v0.5.0 // indirect
- gopkg.in/yaml.v2 v2.4.0
- gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
- github.com/edsrzf/mmap-go v1.1.0 // indirect
- github.com/fjl/memsize v0.0.1 // indirect
- github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
- github.com/go-logfmt/logfmt v0.5.1 // indirect
- github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
+ github.com/ethereum/go-ethereum v1.10.26 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
- github.com/hashicorp/go-bexpr v0.1.11 // indirect
- github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
- github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
- github.com/julienschmidt/httprouter v1.3.0 // indirect
- github.com/kilic/bls12-381 v0.1.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.2 // indirect
- github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
- github.com/rivo/uniseg v0.4.3 // indirect
- github.com/rjeczalik/notify v0.9.2 // indirect
- github.com/rs/cors v1.8.2 // indirect
- github.com/status-im/keycard-go v0.2.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
- github.com/urfave/cli/v2 v2.23.7 // indirect
- github.com/wealdtech/go-bytesutil v1.2.0 // indirect
- github.com/wealdtech/go-eth2-types/v2 v2.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/net v0.4.0 // indirect
- golang.org/x/sync v0.1.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
diff --git a/simulators/eth2/testnet/go.sum b/simulators/eth2/testnet/go.sum
index e8a8c52346..ccf4fc742d 100644
--- a/simulators/eth2/testnet/go.sum
+++ b/simulators/eth2/testnet/go.sum
@@ -1,58 +1,9 @@
-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=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
-github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
-github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
-github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-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/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
-github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
-github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
-github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
-github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-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/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
-github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -61,65 +12,20 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS3
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
-github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
-github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s=
github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b h1:uWfa1x0lA7o5O6XgFxENIxAlevy9W5U6nAp79naD7e4=
github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b/go.mod h1:G8XiiUErpj6++yb93r6y6T1nWBh4Bgoi3QFwUSbzt/U=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
-github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
-github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
-github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
-github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
-github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
-github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-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/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
-github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
-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-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
-github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
-github.com/gogo/googleapis v1.1.0/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.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
-github.com/golang-jwt/jwt/v4 v4.4.3/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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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.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=
@@ -128,262 +34,44 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.2/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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-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.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY=
-github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-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/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
-github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA=
-github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
-github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
-github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
-github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
-github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
-github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
-github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
-github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-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/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
-github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.2 h1:xPMwiykqNK9VK0NYC3+jTMYv9I6Vl3YdjZgPZKG3zO0=
-github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
-github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
-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/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
-github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
-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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
-github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
-github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
-github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
-github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
-github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w=
-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/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0 h1:/0Dm3GrX4sk0aAYdrjtFvJigvPZ8HcAQ3ZT7kW+da7M=
-github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0/go.mod h1:dzegbgrVD+2MQZ86RHWQvgWfnFxEjlDNkzf69afaSnA=
-github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564 h1:yCXGkFjrZ8EggxW+Y7ueRZesNcBk0avLU0mVU/I2KtU=
-github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564/go.mod h1:Xda3KO8+DMyWaTr+LwUUpVRTB5SdFzoKu0ivXNI6p1s=
-github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M=
-github.com/protolambda/zrnt v0.28.0 h1:vdEL8JDqJ3wdzgqgh6Fhz1Wr3+AMGbUZ2nqoNt6QVX0=
-github.com/protolambda/zrnt v0.28.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
-github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY=
-github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
-github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
-github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
-github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-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/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
-github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+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/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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-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/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-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=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -395,123 +83,45 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
-github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
-github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
-github.com/wealdtech/go-bytesutil v1.2.0 h1:GEIzvAZEIgqOoRfnEAaMRNL73gl8e+YlQzqxhFyR30Y=
-github.com/wealdtech/go-bytesutil v1.2.0/go.mod h1:FHQSlwhzfSZGffu1osaUGdnNtl5C8tBKwmqvPdB66pM=
-github.com/wealdtech/go-eth2-types/v2 v2.8.0 h1:Cts9J78ryXVp8jwotdSSVU75S+QWJrgVCArXreD2X8A=
-github.com/wealdtech/go-eth2-types/v2 v2.8.0/go.mod h1:tJazo9o28kdQs3V/U4VafQ4neG+/sL3OBozQ8J3CWmo=
-github.com/wealdtech/go-eth2-util v1.8.0 h1:hhs3h2y3Ldty18lppFdpe46nZpdDAMbY7QqiHO5BvE0=
-github.com/wealdtech/go-eth2-util v1.8.0/go.mod h1:rSuE0v5zX+uyZrqW/iUmXOxeDpB7lTvhcZvAVh0KlMU=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-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=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/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-20190404232315-eb5bcb51f2a3/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
-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/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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-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-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20181122145206-62eef0e2fa9b/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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/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-20191005200804-aed5e4c7ecf9/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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
@@ -519,54 +129,18 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.3.0/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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=
@@ -575,36 +149,18 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
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=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1 h1:iiHuQZCNgYPmFQxd3BBN/Nc5+dAwzZuq5y40s20oQw0=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/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=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/simulators/eth2/testnet/helper.go b/simulators/eth2/testnet/helper.go
deleted file mode 100644
index d2a27fef08..0000000000
--- a/simulators/eth2/testnet/helper.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/big"
-
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/testnet/setup"
- blsu "github.com/protolambda/bls12-381-util"
-)
-
-type ConsensusType int
-
-const (
- Ethash ConsensusType = iota
- Clique
-)
-
-type testSpec struct {
- Name string
- About string
- Run func(*hivesim.T, *testEnv, node)
-}
-
-type testEnv struct {
- Clients *ClientDefinitionsByRole
- Keys []*setup.KeyDetails
- Secrets *[]blsu.SecretKey
-}
-
-type node struct {
- ExecutionClient string
- ConsensusClient string
-}
-
-func (n *node) String() string {
- return fmt.Sprintf("%s-%s", n.ConsensusClient, n.ExecutionClient)
-}
-
-type config struct {
- AltairForkEpoch uint64
- MergeForkEpoch uint64
- ValidatorCount uint64
- KeyTranches uint64
- SlotTime uint64
- TerminalTotalDifficulty *big.Int
-
- // Node configurations to launch. Each node as a proportional share of
- // validators.
- Nodes []node
- Eth1Consensus ConsensusType
-}
-
-func (c *config) activeFork() string {
- if c.MergeForkEpoch == 0 {
- return "merge"
- } else if c.AltairForkEpoch == 0 {
- return "altair"
- } else {
- return "phase0"
- }
-}
-
-func shorten(s string) string {
- start := s[0:6]
- end := s[62:]
- return fmt.Sprintf("%s..%s", start, end)
-}
diff --git a/simulators/eth2/testnet/hive_context.txt b/simulators/eth2/testnet/hive_context.txt
new file mode 100644
index 0000000000..a96aa0ea9d
--- /dev/null
+++ b/simulators/eth2/testnet/hive_context.txt
@@ -0,0 +1 @@
+..
\ No newline at end of file
diff --git a/simulators/eth2/testnet/main.go b/simulators/eth2/testnet/main.go
index accdb98739..475bb2a660 100644
--- a/simulators/eth2/testnet/main.go
+++ b/simulators/eth2/testnet/main.go
@@ -4,9 +4,17 @@ import (
"fmt"
"github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/testnet/setup"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ cl "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
)
+type testSpec struct {
+ Name string
+ About string
+ Run func(*hivesim.T, *testnet.Environment, clients.NodeDefinition)
+}
+
var tests = []testSpec{
// {Name: "single-client-testnet", Run: Phase0Testnet},
{Name: "transition-testnet", Run: TransitionTestnet},
@@ -25,7 +33,7 @@ func main() {
if err != nil {
t.Fatal(err)
}
- c := ClientsByRole(clientTypes)
+ c := clients.ClientsByRole(clientTypes)
if len(c.Eth1) != 1 {
t.Fatalf("choose 1 eth1 client type")
}
@@ -41,11 +49,11 @@ func main() {
hivesim.MustRunSuite(hivesim.New(), suite)
}
-func runAllTests(t *hivesim.T, c *ClientDefinitionsByRole) {
+func runAllTests(t *hivesim.T, c *clients.ClientDefinitionsByRole) {
mnemonic := "couple kiwi radio river setup fortune hunt grief buddy forward perfect empty slim wear bounce drift execute nation tobacco dutch chapter festival ice fog"
// Generate validator keys to use for all tests.
- keySrc := &setup.MnemonicsKeySource{
+ keySrc := &cl.MnemonicsKeySource{
From: 0,
To: 64,
Validator: mnemonic,
@@ -55,7 +63,7 @@ func runAllTests(t *hivesim.T, c *ClientDefinitionsByRole) {
if err != nil {
t.Fatal(err)
}
- secrets, err := setup.SecretKeys(keys)
+ secrets, err := cl.SecretKeys(keys)
if err != nil {
t.Fatal(err)
}
@@ -63,10 +71,14 @@ func runAllTests(t *hivesim.T, c *ClientDefinitionsByRole) {
for _, test := range tests {
test := test
t.Run(hivesim.TestSpec{
- Name: fmt.Sprintf("%s-%s", test.Name, node),
+ Name: fmt.Sprintf("%s-%s", test.Name, node.String()),
Description: test.About,
Run: func(t *hivesim.T) {
- env := &testEnv{c, keys, secrets}
+ env := &testnet.Environment{
+ Clients: c,
+ Keys: keys,
+ Secrets: secrets,
+ }
test.Run(t, env, node)
},
})
diff --git a/simulators/eth2/testnet/nodes.go b/simulators/eth2/testnet/nodes.go
deleted file mode 100644
index 12cfffdbff..0000000000
--- a/simulators/eth2/testnet/nodes.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package main
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/testnet/setup"
- "github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/nodeapi"
-)
-
-const (
- PortUserRPC = 8545
- PortEngineRPC = 8551
- PortBeaconTCP = 9000
- PortBeaconUDP = 9000
- PortBeaconAPI = 4000
- PortBeaconGRPC = 4001
- PortMetrics = 8080
- PortValidatorAPI = 5000
-)
-
-// TODO: we assume the clients were configured with default ports.
-// Would be cleaner to run a script in the client to get the address without assumptions
-
-type Eth1Node struct {
- *hivesim.Client
-}
-
-func (en *Eth1Node) UserRPCAddress() (string, error) {
- return fmt.Sprintf("http://%v:%d", en.IP, PortUserRPC), nil
-}
-
-func (en *Eth1Node) EngineRPCAddress() (string, error) {
- // TODO what will the default port be?
- return fmt.Sprintf("http://%v:%d", en.IP, PortEngineRPC), nil
-}
-
-func (en *Eth1Node) MustGetEnode() string {
- addr, err := en.EnodeURL()
- if err != nil {
- panic(err)
- }
- return addr
-}
-
-type BeaconNode struct {
- *hivesim.Client
- API *eth2api.Eth2HttpClient
-}
-
-func NewBeaconNode(cl *hivesim.Client) *BeaconNode {
- return &BeaconNode{
- Client: cl,
- API: ð2api.Eth2HttpClient{
- Addr: fmt.Sprintf("http://%s:%d", cl.IP, PortBeaconAPI),
- Cli: &http.Client{},
- Codec: eth2api.JSONCodec{},
- },
- }
-}
-
-func (bn *BeaconNode) ENR() (string, error) {
- ctx, _ := context.WithTimeout(context.Background(), time.Second*10)
- var out eth2api.NetworkIdentity
- if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
- return "", err
- }
- fmt.Printf("p2p addrs: %v\n", out.P2PAddresses)
- fmt.Printf("peer id: %s\n", out.PeerID)
- return out.ENR, nil
-}
-
-func (bn *BeaconNode) P2PAddr() (string, error) {
- ctx, _ := context.WithTimeout(context.Background(), time.Second*10)
- var out eth2api.NetworkIdentity
- if err := nodeapi.Identity(ctx, bn.API, &out); err != nil {
- return "", err
- }
- return out.P2PAddresses[0], nil
-}
-
-func (bn *BeaconNode) EnodeURL() (string, error) {
- return "", errors.New("beacon node does not have an discv4 Enode URL, use ENR or multi-address instead")
-}
-
-type ValidatorClient struct {
- *hivesim.Client
- keys []*setup.KeyDetails
-}
-
-func (v *ValidatorClient) ContainsKey(pk [48]byte) bool {
- for _, k := range v.keys {
- if k.ValidatorPubkey == pk {
- return true
- }
- }
- return false
-}
diff --git a/simulators/eth2/testnet/prepared_testnet.go b/simulators/eth2/testnet/prepared_testnet.go
deleted file mode 100644
index f2b8d98d25..0000000000
--- a/simulators/eth2/testnet/prepared_testnet.go
+++ /dev/null
@@ -1,263 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "strings"
- "time"
-
- "github.com/holiman/uint256"
- blsu "github.com/protolambda/bls12-381-util"
- "github.com/protolambda/ztyp/view"
-
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/zrnt/eth2/configs"
-
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/testnet/setup"
-)
-
-var depositAddress common.Eth1Address
-
-func init() {
- _ = depositAddress.UnmarshalText([]byte("0x4242424242424242424242424242424242424242"))
-}
-
-// PreparedTestnet has all the options for starting nodes, ready to build the network.
-type PreparedTestnet struct {
- // Consensus chain configuration
- spec *common.Spec
-
- // Execution chain configuration and genesis info
- eth1Genesis *setup.Eth1Genesis
- // Consensus genesis state
- eth2Genesis common.BeaconState
- // Secret keys of validators, to fabricate extra signed test messages with during testnet/
- // E.g. to test a slashable offence that would not otherwise happen.
- keys *[]blsu.SecretKey
-
- // Configuration to apply to every node of the given type
- executionOpts hivesim.StartOption
- validatorOpts hivesim.StartOption
- beaconOpts hivesim.StartOption
-
- // A tranche is a group of validator keys to run on 1 node
- keyTranches [][]*setup.KeyDetails
-}
-
-// Build all artifacts require to start a testnet.
-func prepareTestnet(t *hivesim.T, env *testEnv, config *config) *PreparedTestnet {
- eth1GenesisTime := common.Timestamp(time.Now().Unix())
- eth2GenesisTime := eth1GenesisTime + 30
-
- // Generate genesis for execution clients
- eth1Genesis := setup.BuildEth1Genesis(config.TerminalTotalDifficulty, uint64(eth1GenesisTime), config.Eth1Consensus == Clique)
- eth1ConfigOpt := eth1Genesis.ToParams(depositAddress)
- eth1Bundle, err := setup.Eth1Bundle(eth1Genesis.Genesis)
- if err != nil {
- t.Fatal(err)
- }
- execNodeOpts := hivesim.Params{
- "HIVE_LOGLEVEL": os.Getenv("HIVE_LOGLEVEL"),
- "HIVE_NODETYPE": "full",
- }
- executionOpts := hivesim.Bundle(eth1ConfigOpt, eth1Bundle, execNodeOpts)
-
- // Generate beacon spec
- //
- // TODO: specify build-target based on preset, to run clients in mainnet or minimal mode.
- // copy the default mainnet config, and make some minimal modifications for testnet usage
- specCpy := *configs.Mainnet
- spec := &specCpy
- spec.Config.DEPOSIT_CONTRACT_ADDRESS = depositAddress
- spec.Config.DEPOSIT_CHAIN_ID = view.Uint64View(eth1Genesis.Genesis.Config.ChainID.Uint64())
- spec.Config.DEPOSIT_NETWORK_ID = view.Uint64View(eth1Genesis.NetworkID)
- spec.Config.ETH1_FOLLOW_DISTANCE = 1
-
- spec.Config.ALTAIR_FORK_EPOCH = common.Epoch(config.AltairForkEpoch)
- spec.Config.BELLATRIX_FORK_EPOCH = common.Epoch(config.MergeForkEpoch)
- spec.Config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT = view.Uint64View(config.ValidatorCount)
- spec.Config.SECONDS_PER_SLOT = common.Timestamp(config.SlotTime)
- tdd, _ := uint256.FromBig(config.TerminalTotalDifficulty)
- spec.Config.TERMINAL_TOTAL_DIFFICULTY = view.Uint256View(*tdd)
-
- // Generate keys opts for validators
- keyTranches := setup.KeyTranches(env.Keys, uint64(len(config.Nodes)))
-
- consensusConfigOpts, err := setup.ConsensusConfigsBundle(spec, eth1Genesis.Genesis, config.ValidatorCount)
- if err != nil {
- t.Fatal(err)
- }
-
- // prepare genesis beacon state, with all the validators in it.
- state, err := setup.BuildBeaconState(spec, eth1Genesis.Genesis, eth2GenesisTime, env.Keys)
- if err != nil {
- t.Fatal(err)
- }
-
- // Write info so that the genesis state can be generated by the client
- stateOpt, err := setup.StateBundle(state)
- if err != nil {
- t.Fatal(err)
- }
-
- // Define additional start options for beacon chain
- commonOpts := hivesim.Params{
- "HIVE_ETH2_BN_API_PORT": fmt.Sprintf("%d", PortBeaconAPI),
- "HIVE_ETH2_BN_GRPC_PORT": fmt.Sprintf("%d", PortBeaconGRPC),
- "HIVE_ETH2_METRICS_PORT": fmt.Sprintf("%d", PortMetrics),
- "HIVE_ETH2_CONFIG_DEPOSIT_CONTRACT_ADDRESS": depositAddress.String(),
- }
- beaconOpts := hivesim.Bundle(
- commonOpts,
- hivesim.Params{
- "HIVE_CHECK_LIVE_PORT": fmt.Sprintf("%d", PortBeaconAPI),
- "HIVE_ETH2_MERGE_ENABLED": "1",
- "HIVE_ETH2_ETH1_GENESIS_TIME": fmt.Sprintf("%d", eth1Genesis.Genesis.Timestamp),
- "HIVE_ETH2_GENESIS_FORK": config.activeFork(),
- },
- stateOpt,
- consensusConfigOpts,
- )
-
- validatorOpts := hivesim.Bundle(
- commonOpts,
- hivesim.Params{
- "HIVE_CHECK_LIVE_PORT": "0",
- },
- consensusConfigOpts,
- )
-
- return &PreparedTestnet{
- spec: spec,
- eth1Genesis: eth1Genesis,
- eth2Genesis: state,
- keys: env.Secrets,
- executionOpts: executionOpts,
- beaconOpts: beaconOpts,
- validatorOpts: validatorOpts,
- keyTranches: keyTranches,
- }
-}
-
-func (p *PreparedTestnet) createTestnet(t *hivesim.T) *Testnet {
- genesisTime, _ := p.eth2Genesis.GenesisTime()
- genesisValidatorsRoot, _ := p.eth2Genesis.GenesisValidatorsRoot()
- return &Testnet{
- t: t,
- genesisTime: genesisTime,
- genesisValidatorsRoot: genesisValidatorsRoot,
- spec: p.spec,
- eth1Genesis: p.eth1Genesis,
- }
-}
-
-func (p *PreparedTestnet) startEth1Node(testnet *Testnet, eth1Def *hivesim.ClientDefinition, consensus ConsensusType) {
- testnet.t.Logf("Starting eth1 node: %s (%s)", eth1Def.Name, eth1Def.Version)
-
- opts := []hivesim.StartOption{p.executionOpts}
- if len(testnet.eth1) == 0 {
- // we only make the first eth1 node a miner
- if consensus == Ethash {
- opts = append(opts, hivesim.Params{"HIVE_MINER": "1212121212121212121212121212121212121212"})
- } else if consensus == Clique {
- opts = append(opts, hivesim.Params{
- "HIVE_CLIQUE_PRIVATEKEY": "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c",
- "HIVE_MINER": "658bdf435d810c91414ec09147daa6db62406379",
- })
- }
- } else {
- bootnode, err := testnet.eth1[0].EnodeURL()
- if err != nil {
- testnet.t.Fatalf("failed to get eth1 bootnode URL: %v", err)
- }
-
- // Make the client connect to the first eth1 node, as a bootnode for the eth1 net
- opts = append(opts, hivesim.Params{"HIVE_BOOTNODE": bootnode})
- }
- en := &Eth1Node{testnet.t.StartClient(eth1Def.Name, opts...)}
- testnet.eth1 = append(testnet.eth1, en)
-}
-
-func (p *PreparedTestnet) startBeaconNode(testnet *Testnet, beaconDef *hivesim.ClientDefinition, eth1Endpoints []int) {
- testnet.t.Logf("Starting beacon node: %s (%s)", beaconDef.Name, beaconDef.Version)
-
- opts := []hivesim.StartOption{p.beaconOpts}
- // Hook up beacon node to (maybe multiple) eth1 nodes
- for _, index := range eth1Endpoints {
- if index < 0 || index >= len(testnet.eth1) {
- testnet.t.Fatalf("only have %d eth1 nodes, cannot find index %d for BN", len(testnet.eth1), index)
- }
- }
-
- var addrs []string
- var engineAddrs []string
- for _, index := range eth1Endpoints {
- eth1Node := testnet.eth1[index]
- userRPC, err := eth1Node.UserRPCAddress()
- if err != nil {
- testnet.t.Fatalf("eth1 node used for beacon without available RPC: %v", err)
- }
- addrs = append(addrs, userRPC)
- engineRPC, err := eth1Node.EngineRPCAddress()
- if err != nil {
- testnet.t.Fatalf("eth1 node used for beacon without available RPC: %v", err)
- }
- engineAddrs = append(engineAddrs, engineRPC)
- }
- opts = append(opts, hivesim.Params{
- "HIVE_ETH2_ETH1_RPC_ADDRS": strings.Join(addrs, ","),
- "HIVE_ETH2_ETH1_ENGINE_RPC_ADDRS": strings.Join(engineAddrs, ","),
- })
-
- if len(testnet.beacons) > 0 {
- bootnodeENR, err := testnet.beacons[0].ENR()
- if err != nil {
- testnet.t.Fatalf("failed to get ENR as bootnode for beacon node: %v", err)
- }
- opts = append(opts, hivesim.Params{"HIVE_ETH2_BOOTNODE_ENRS": bootnodeENR})
- }
-
- if len(testnet.beacons) > 0 {
- var staticPeers []string
- for _, bn := range testnet.beacons {
- staticPeer, err := bn.P2PAddr()
- if err != nil {
- testnet.t.Fatalf("failed to get multiaddr for beacon node: %v", err)
- }
- staticPeers = append(staticPeers, staticPeer)
- }
- opts = append(opts, hivesim.Params{"HIVE_ETH2_STATIC_PEERS": strings.Join(staticPeers, ",")})
- }
-
- // TODO
- //if p.configName != "mainnet" && hasBuildTarget(beaconDef, p.configName) {
- // opts = append(opts, hivesim.WithBuildTarget(p.configName))
- //}
- bn := NewBeaconNode(testnet.t.StartClient(beaconDef.Name, opts...))
- testnet.beacons = append(testnet.beacons, bn)
-}
-
-func (p *PreparedTestnet) startValidatorClient(testnet *Testnet, validatorDef *hivesim.ClientDefinition, bnIndex int, keyIndex int) {
- testnet.t.Logf("Starting validator client: %s (%s)", validatorDef.Name, validatorDef.Version)
-
- if bnIndex >= len(testnet.beacons) {
- testnet.t.Fatalf("only have %d beacon nodes, cannot find index %d for VC", len(testnet.beacons), bnIndex)
- }
- bn := testnet.beacons[bnIndex]
- // Hook up validator to beacon node
- bnAPIOpt := hivesim.Params{
- "HIVE_ETH2_BN_API_IP": bn.IP.String(),
- }
- if keyIndex >= len(p.keyTranches) {
- testnet.t.Fatalf("only have %d key tranches, cannot find index %d for VC", len(p.keyTranches), keyIndex)
- }
- keysOpt := setup.KeysBundle(p.keyTranches[keyIndex])
- opts := []hivesim.StartOption{p.validatorOpts, keysOpt, bnAPIOpt}
- // TODO
- //if p.configName != "mainnet" && hasBuildTarget(validatorDef, p.configName) {
- // opts = append(opts, hivesim.WithBuildTarget(p.configName))
- //}
- vc := &ValidatorClient{testnet.t.StartClient(validatorDef.Name, opts...), p.keyTranches[keyIndex]}
- testnet.validators = append(testnet.validators, vc)
-}
diff --git a/simulators/eth2/testnet/running_testnet.go b/simulators/eth2/testnet/running_testnet.go
deleted file mode 100644
index 934b55c68f..0000000000
--- a/simulators/eth2/testnet/running_testnet.go
+++ /dev/null
@@ -1,352 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "math/big"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/ethclient"
- "github.com/protolambda/eth2api"
- "github.com/protolambda/eth2api/client/beaconapi"
- "github.com/protolambda/eth2api/client/debugapi"
- "github.com/protolambda/zrnt/eth2/beacon/altair"
- "github.com/protolambda/zrnt/eth2/beacon/bellatrix"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/zrnt/eth2/beacon/phase0"
- "github.com/protolambda/zrnt/eth2/util/math"
-
- "github.com/ethereum/hive/hivesim"
- "github.com/ethereum/hive/simulators/eth2/testnet/setup"
-)
-
-var MAX_PARTICIPATION_SCORE = 7
-
-type Testnet struct {
- t *hivesim.T
-
- genesisTime common.Timestamp
- genesisValidatorsRoot common.Root
-
- // Consensus chain configuration
- spec *common.Spec
- // Execution chain configuration and genesis info
- eth1Genesis *setup.Eth1Genesis
-
- beacons []*BeaconNode
- validators []*ValidatorClient
- eth1 []*Eth1Node
-}
-
-func (t *Testnet) GenesisTime() time.Time {
- return time.Unix(int64(t.genesisTime), 0)
-}
-
-func (t *Testnet) ValidatorClientIndex(pk [48]byte) (int, error) {
- for i, v := range t.validators {
- if v.ContainsKey(pk) {
- return i, nil
- }
- }
- return 0, fmt.Errorf("key not found in any validator client")
-}
-
-// WaitForFinality blocks until a beacon client reaches finality.
-func (t *Testnet) WaitForFinality(ctx context.Context) (common.Checkpoint, error) {
- genesis := t.GenesisTime()
- slotDuration := time.Duration(t.spec.SECONDS_PER_SLOT) * time.Second
- timer := time.NewTicker(slotDuration)
- done := make(chan common.Checkpoint, len(t.beacons))
-
- for {
- select {
- case <-ctx.Done():
- return common.Checkpoint{}, fmt.Errorf("context called")
- case finalized := <-done:
- return finalized, nil
- case tim := <-timer.C:
- // start polling after first slot of genesis
- if tim.Before(genesis.Add(slotDuration)) {
- t.t.Logf("Time till genesis: %s", genesis.Sub(tim))
- continue
- }
-
- // new slot, log and check status of all beacon nodes
- type res struct {
- idx int
- msg string
- err error
- }
- var (
- wg sync.WaitGroup
- ch = make(chan res, len(t.beacons))
- )
- for i, b := range t.beacons {
- wg.Add(1)
- go func(ctx context.Context, i int, b *BeaconNode, ch chan res) {
- defer wg.Done()
- ctx, cancel := context.WithTimeout(ctx, time.Second*5)
- defer cancel()
-
- var (
- slot common.Slot
- head string
- justified string
- finalized string
- execution string
- health float64
- )
-
- var headInfo eth2api.BeaconBlockHeaderAndInfo
- if exists, err := beaconapi.BlockHeader(ctx, b.API, eth2api.BlockHead, &headInfo); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll head: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: no head block", i)}
- return
- }
-
- var checkpoints eth2api.FinalityCheckpoints
- if exists, err := beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdRoot(headInfo.Header.Message.StateRoot), &checkpoints); err != nil || !exists {
- if exists, err = beaconapi.FinalityCheckpoints(ctx, b.API, eth2api.StateIdSlot(headInfo.Header.Message.Slot), &checkpoints); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to poll finality checkpoint: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: Expected state for head block", i)}
- return
- }
- }
-
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, b.API, eth2api.BlockIdRoot(headInfo.Root), &versionedBlock); err != nil {
- ch <- res{err: fmt.Errorf("beacon %d: failed to retrieve block: %v", i, err)}
- return
- } else if !exists {
- ch <- res{err: fmt.Errorf("beacon %d: block not found", i)}
- return
- }
- switch versionedBlock.Version {
- case "phase0":
- execution = "0x0000..0000"
- case "altair":
- execution = "0x0000..0000"
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- execution = shorten(block.Message.Body.ExecutionPayload.BlockHash.String())
- }
-
- slot = headInfo.Header.Message.Slot
- head = shorten(headInfo.Root.String())
- justified = shorten(checkpoints.CurrentJustified.String())
- finalized = shorten(checkpoints.Finalized.String())
- health, err := getHealth(ctx, b.API, t.spec, slot)
- if err != nil {
- // warning is printed here instead because some clients
- // don't support the required REST endpoint.
- fmt.Printf("WARN: beacon %d: %s\n", i, err)
- }
-
- ep := t.spec.SlotToEpoch(slot)
- if ep > 4 && ep > checkpoints.Finalized.Epoch+2 {
- ch <- res{err: fmt.Errorf("failed to finalize, head slot %d (epoch %d) is more than 2 ahead of finality checkpoint %d", slot, ep, checkpoints.Finalized.Epoch)}
- } else {
- ch <- res{i, fmt.Sprintf("beacon %d: slot=%d, head=%s, health=%.2f, exec_payload=%s, justified=%s, finalized=%s", i, slot, head, health, execution, justified, finalized), nil}
- }
-
- if (checkpoints.Finalized != common.Checkpoint{}) {
- done <- checkpoints.Finalized
- }
- }(ctx, i, b, ch)
- }
- wg.Wait()
- close(ch)
-
- // print out logs in ascending idx order
- sorted := make([]string, len(t.beacons))
- for out := range ch {
- if out.err != nil {
- return common.Checkpoint{}, out.err
- }
- sorted[out.idx] = out.msg
- }
- for _, msg := range sorted {
- t.t.Logf(msg)
- }
- }
- }
-}
-
-// VerifyParticipation ensures that the participation of the finialized epoch
-// of a given checkpoint is above the expected threshold.
-func (t *Testnet) VerifyParticipation(ctx context.Context, checkpoint common.Checkpoint, expected float64) error {
- slot, _ := t.spec.EpochStartSlot(checkpoint.Epoch + 1)
- if t.spec.BELLATRIX_FORK_EPOCH <= checkpoint.Epoch {
- // slot-1 to target last slot in finalized epoch
- slot = slot - 1
- }
- for i, b := range t.beacons {
- health, err := getHealth(ctx, b.API, t.spec, slot)
- if err != nil {
- return err
- }
- if health < expected {
- return fmt.Errorf("beacon %d: participation not healthy (got: %.2f, expected: %.2f)", i, health, expected)
- }
- t.t.Logf("beacon %d: epoch=%d participation=%.2f", i, checkpoint.Epoch, health)
- }
- return nil
-}
-
-// VerifyExecutionPayloadIsCanonical retrieves the execution payload from the
-// finalized block and verifies that is in the execution client's canonical
-// chain.
-func (t *Testnet) VerifyExecutionPayloadIsCanonical(ctx context.Context, checkpoint common.Checkpoint) error {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, t.beacons[0].API, eth2api.BlockIdRoot(checkpoint.Root), &versionedBlock); err != nil {
- return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err)
- } else if !exists {
- return fmt.Errorf("beacon %d: block not found", 0)
- }
- if versionedBlock.Version != "bellatrix" {
- return nil
- }
- payload := versionedBlock.Data.(*bellatrix.SignedBeaconBlock).Message.Body.ExecutionPayload
-
- for i, e := range t.eth1 {
- client := ethclient.NewClient(e.Client.RPC())
- block, err := client.BlockByNumber(ctx, big.NewInt(int64(payload.BlockNumber)))
- if err != nil {
- return fmt.Errorf("eth1 %d: %s", 0, err)
- }
- if block.Hash() != [32]byte(payload.BlockHash) {
- return fmt.Errorf("eth1 %d: blocks don't match (got=%s, expected=%s)", i, shorten(block.Hash().String()), shorten(payload.BlockHash.String()))
- }
- }
- return nil
-}
-
-// VerifyProposers checks that all validator clients have proposed a block on
-// the finalized beacon chain that includes an execution payload.
-func (t *Testnet) VerifyProposers(ctx context.Context, checkpoint common.Checkpoint) error {
- proposers := make([]bool, len(t.beacons))
- for slot := 0; slot < int(t.spec.SLOTS_PER_EPOCH)*int(checkpoint.Epoch); slot += 1 {
- var versionedBlock eth2api.VersionedSignedBeaconBlock
- if exists, err := beaconapi.BlockV2(ctx, t.beacons[0].API, eth2api.BlockIdSlot(slot), &versionedBlock); err != nil {
- return fmt.Errorf("beacon %d: failed to retrieve block: %v", 0, err)
- } else if !exists {
- return fmt.Errorf("beacon %d: block not found", 0)
- }
- var proposerIndex common.ValidatorIndex
- switch versionedBlock.Version {
- case "phase0":
- block := versionedBlock.Data.(*phase0.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- case "altair":
- block := versionedBlock.Data.(*altair.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- case "bellatrix":
- block := versionedBlock.Data.(*bellatrix.SignedBeaconBlock)
- proposerIndex = block.Message.ProposerIndex
- }
-
- var validator eth2api.ValidatorResponse
- if exists, err := beaconapi.StateValidator(ctx, t.beacons[0].API, eth2api.StateIdSlot(slot), eth2api.ValidatorIdIndex(proposerIndex), &validator); err != nil {
- return fmt.Errorf("beacon %d: failed to retrieve validator: %v", 0, err)
- } else if !exists {
- return fmt.Errorf("beacon %d: validator not found", 0)
- }
- idx, err := t.ValidatorClientIndex([48]byte(validator.Validator.Pubkey))
- if err != nil {
- return fmt.Errorf("pub key not found on any validator client")
- }
- proposers[idx] = true
- }
- for i, proposed := range proposers {
- if !proposed {
- return fmt.Errorf("beacon %d: did not propose a block", i)
- }
- }
- return nil
-}
-
-func getHealth(ctx context.Context, api *eth2api.Eth2HttpClient, spec *common.Spec, slot common.Slot) (float64, error) {
- var (
- health float64
- stateInfo eth2api.VersionedBeaconState
- )
- if exists, err := debugapi.BeaconStateV2(ctx, api, eth2api.StateIdSlot(slot), &stateInfo); err != nil {
- return 0, fmt.Errorf("failed to retrieve state: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("block not found")
- }
- switch stateInfo.Version {
- case "phase0":
- state := stateInfo.Data.(*phase0.BeaconState)
- epoch := spec.SlotToEpoch(slot)
- validatorIds := make([]eth2api.ValidatorId, 0, len(state.Validators))
- for id, validator := range state.Validators {
- if epoch >= validator.ActivationEligibilityEpoch && epoch < validator.ExitEpoch && !validator.Slashed {
- validatorIds = append(validatorIds, eth2api.ValidatorIdIndex(id))
- }
- }
- var (
- beforeEpoch = 0
- afterEpoch = spec.SlotToEpoch(slot)
- balancesBefore []eth2api.ValidatorBalanceResponse
- balancesAfter []eth2api.ValidatorBalanceResponse
- )
-
- // If it's genesis, keep before also set to 0.
- if afterEpoch != 0 {
- beforeEpoch = int(spec.SlotToEpoch(slot)) - 1
- }
- if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(beforeEpoch*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesBefore); err != nil {
- return 0, fmt.Errorf("failed to retrieve validator balances: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("validator balances not found")
- }
- if exists, err := beaconapi.StateValidatorBalances(ctx, api, eth2api.StateIdSlot(int(afterEpoch)*int(spec.SLOTS_PER_EPOCH)), validatorIds, &balancesAfter); err != nil {
- return 0, fmt.Errorf("failed to retrieve validator balances: %v", err)
- } else if !exists {
- return 0, fmt.Errorf("validator balances not found")
- }
- health = legacyCalcHealth(spec, balancesBefore, balancesAfter)
- case "altair":
- state := stateInfo.Data.(*altair.BeaconState)
- health = calcHealth(state.CurrentEpochParticipation)
- case "bellatrix":
- state := stateInfo.Data.(*bellatrix.BeaconState)
- health = calcHealth(state.CurrentEpochParticipation)
- }
- return health, nil
-}
-
-func calcHealth(p altair.ParticipationRegistry) float64 {
- sum := 0
- for _, p := range p {
- sum += int(p)
- }
- avg := float64(sum) / float64(len(p))
- return avg / float64(MAX_PARTICIPATION_SCORE)
-}
-
-// legacyCalcHealth calculates the health of the network based on balances at
-// the beginning of an epoch versus the balances at the end.
-//
-// NOTE: this isn't strictly the most correct way of doing things, but it is
-// quite accurate and doesn't require implementing the attestation processing
-// logic here.
-func legacyCalcHealth(spec *common.Spec, before, after []eth2api.ValidatorBalanceResponse) float64 {
- sum_before := big.NewInt(0)
- sum_after := big.NewInt(0)
- for i := range before {
- sum_before.Add(sum_before, big.NewInt(int64(before[i].Balance)))
- sum_after.Add(sum_after, big.NewInt(int64(after[i].Balance)))
- }
- count := big.NewInt(int64(len(before)))
- avg_before := big.NewInt(0).Div(sum_before, count).Uint64()
- avg_after := sum_after.Div(sum_after, count).Uint64()
- reward := avg_before * uint64(spec.BASE_REWARD_FACTOR) / math.IntegerSquareRootPrysm(sum_before.Uint64()) / uint64(spec.HYSTERESIS_QUOTIENT)
- return float64(avg_after-avg_before) / float64(reward*common.BASE_REWARDS_PER_EPOCH)
-}
diff --git a/simulators/eth2/testnet/scenarios.go b/simulators/eth2/testnet/scenarios.go
index ab7b854545..2c30f1ca98 100644
--- a/simulators/eth2/testnet/scenarios.go
+++ b/simulators/eth2/testnet/scenarios.go
@@ -2,97 +2,80 @@ package main
import (
"context"
- "fmt"
"math/big"
- "time"
"github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+ tn "github.com/ethereum/hive/simulators/eth2/common/testnet"
)
var (
- VALIDATOR_COUNT uint64 = 64
- SLOT_TIME uint64 = 6
- TERMINAL_TOTAL_DIFFICULTY = big.NewInt(100)
+ VALIDATOR_COUNT = big.NewInt(64)
+ SLOT_TIME = big.NewInt(6)
+ TERMINAL_TOTAL_DIFFICULTY = big.NewInt(100)
)
-func startTestnet(t *hivesim.T, env *testEnv, config *config) *Testnet {
- prep := prepareTestnet(t, env, config)
- testnet := prep.createTestnet(t)
-
- genesisTime := testnet.GenesisTime()
- countdown := genesisTime.Sub(time.Now())
- t.Logf("Created new testnet, genesis at %s (%s from now)", genesisTime, countdown)
-
- // for each key partition, we start a validator client with its own beacon node and eth1 node
- for i, node := range config.Nodes {
- prep.startEth1Node(testnet, env.Clients.ClientByNameAndRole(node.ExecutionClient, "eth1"), config.Eth1Consensus)
- prep.startBeaconNode(testnet, env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-bn", node.ConsensusClient), "beacon"), []int{i})
- prep.startValidatorClient(testnet, env.Clients.ClientByNameAndRole(fmt.Sprintf("%s-vc", node.ConsensusClient), "validator"), i, i)
- }
-
- return testnet
-}
-
-func Phase0Testnet(t *hivesim.T, env *testEnv, n node) {
- config := config{
- AltairForkEpoch: 10,
- MergeForkEpoch: 20,
+func Phase0Testnet(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ config := tn.Config{
+ AltairForkEpoch: big.NewInt(10),
+ BellatrixForkEpoch: big.NewInt(20),
ValidatorCount: VALIDATOR_COUNT,
SlotTime: SLOT_TIME,
TerminalTotalDifficulty: TERMINAL_TOTAL_DIFFICULTY,
- Nodes: []node{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
- Eth1Consensus: Clique,
+ Eth1Consensus: el.ExecutionCliqueConsensus{},
}
- testnet := startTestnet(t, env, &config)
-
ctx := context.Background()
+ testnet := tn.StartTestnet(ctx, t, env, &config)
+
finalized, err := testnet.WaitForFinality(ctx)
if err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyParticipation(ctx, finalized, 0.95); err != nil {
+ if err := testnet.VerifyParticipation(ctx, tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized}, 0.95); err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, finalized); err != nil {
+ if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, tn.LastSlotAtCheckpoint{Checkpoint: &finalized}); err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyProposers(ctx, finalized); err != nil {
+ if err := testnet.VerifyProposers(ctx, tn.LastSlotAtCheckpoint{Checkpoint: &finalized}, false); err != nil {
t.Fatalf("%v", err)
}
}
-func TransitionTestnet(t *hivesim.T, env *testEnv, n node) {
- config := config{
- AltairForkEpoch: 0,
- MergeForkEpoch: 0,
+func TransitionTestnet(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) {
+ config := tn.Config{
+ AltairForkEpoch: big.NewInt(0),
+ BellatrixForkEpoch: big.NewInt(0),
ValidatorCount: VALIDATOR_COUNT,
SlotTime: SLOT_TIME,
TerminalTotalDifficulty: TERMINAL_TOTAL_DIFFICULTY,
- Nodes: []node{
+ NodeDefinitions: []clients.NodeDefinition{
n,
n,
},
- Eth1Consensus: Clique,
+ Eth1Consensus: el.ExecutionCliqueConsensus{},
}
- testnet := startTestnet(t, env, &config)
-
ctx := context.Background()
+ testnet := tn.StartTestnet(ctx, t, env, &config)
+
finalized, err := testnet.WaitForFinality(ctx)
if err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyParticipation(ctx, finalized, 0.95); err != nil {
+ if err := testnet.VerifyParticipation(ctx, tn.FirstSlotAfterCheckpoint{Checkpoint: &finalized}, 0.95); err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, finalized); err != nil {
+ if err := testnet.VerifyExecutionPayloadIsCanonical(ctx, tn.LastSlotAtCheckpoint{Checkpoint: &finalized}); err != nil {
t.Fatalf("%v", err)
}
- if err := testnet.VerifyProposers(ctx, finalized); err != nil {
+ if err := testnet.VerifyProposers(ctx, tn.LastSlotAtCheckpoint{Checkpoint: &finalized}, false); err != nil {
t.Fatalf("%v", err)
}
}
diff --git a/simulators/eth2/testnet/setup/eth1config.go b/simulators/eth2/testnet/setup/eth1config.go
deleted file mode 100644
index 49b4d3f59f..0000000000
--- a/simulators/eth2/testnet/setup/eth1config.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package setup
-
-import (
- "encoding/json"
- "fmt"
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/params"
-
- "github.com/ethereum/hive/hivesim"
-)
-
-// The runtime deposit contract code, along with the storage that would otherwise have been initialized
-// in the deployment constructor call.
-// The storage tracks the default zero-hash of each binary tree layer, to shape the initial stack of an empty tree.
-var embeddedDepositContract = `
-{
- "balance": "0",
- "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033",
- "storage": {
- "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
- "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71",
- "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c",
- "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c",
- "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30",
- "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1",
- "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c",
- "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193",
- "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1",
- "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b",
- "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220",
- "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f",
- "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e",
- "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784",
- "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb",
- "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb",
- "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab",
- "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4",
- "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f",
- "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa",
- "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c",
- "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167",
- "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7",
- "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0",
- "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544",
- "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765",
- "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4",
- "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1",
- "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636",
- "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c",
- "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7"
- }
-}
-`
-
-type Eth1Genesis struct {
- Genesis *core.Genesis
- DepositAddress common.Address
- NetworkID uint64
-}
-
-func BuildEth1Genesis(ttd *big.Int, genesisTime uint64, clique bool) *Eth1Genesis {
- depositContractAddr := common.HexToAddress("0x4242424242424242424242424242424242424242")
- var depositContractAcc core.GenesisAccount
- if err := json.Unmarshal([]byte(embeddedDepositContract), &depositContractAcc); err != nil {
- panic(err)
- }
- genesis := Eth1Genesis{
- Genesis: &core.Genesis{
- Config: ¶ms.ChainConfig{
- ChainID: big.NewInt(1),
- HomesteadBlock: big.NewInt(0),
- DAOForkBlock: nil,
- DAOForkSupport: false,
- EIP150Block: big.NewInt(0),
- EIP150Hash: common.Hash{},
- EIP155Block: big.NewInt(0),
- EIP158Block: big.NewInt(0),
- ByzantiumBlock: big.NewInt(0),
- ConstantinopleBlock: big.NewInt(0),
- PetersburgBlock: big.NewInt(0),
- IstanbulBlock: big.NewInt(0),
- MuirGlacierBlock: big.NewInt(0),
- BerlinBlock: big.NewInt(0),
- LondonBlock: big.NewInt(0),
- ArrowGlacierBlock: big.NewInt(0),
- MergeNetsplitBlock: big.NewInt(0),
- TerminalTotalDifficulty: ttd,
- Clique: nil,
- },
- Nonce: 0,
- Timestamp: genesisTime,
- ExtraData: nil,
- GasLimit: 30_000_000,
- Difficulty: big.NewInt(0),
- Mixhash: common.Hash{},
- Coinbase: common.Address{},
- Alloc: core.GenesisAlloc{
- depositContractAddr: depositContractAcc,
- },
- },
- DepositAddress: depositContractAddr,
- NetworkID: 1,
- }
- if clique {
- genesis.Genesis.Config.Clique = ¶ms.CliqueConfig{Period: 2, Epoch: 0}
- genesis.Genesis.ExtraData = common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
- }
- return &genesis
-}
-
-func (conf *Eth1Genesis) ToParams(depositAddress [20]byte) hivesim.Params {
- params := hivesim.Params{
- "HIVE_DEPOSIT_CONTRACT_ADDRESS": common.Address(depositAddress).String(),
- "HIVE_NETWORK_ID": fmt.Sprintf("%d", conf.NetworkID),
- "HIVE_CHAIN_ID": conf.Genesis.Config.ChainID.String(),
- "HIVE_FORK_HOMESTEAD": conf.Genesis.Config.HomesteadBlock.String(),
- //"HIVE_FORK_DAO_BLOCK": conf.Genesis.Config.DAOForkBlock.String(), // nil error, not used anyway
- "HIVE_FORK_TANGERINE": conf.Genesis.Config.EIP150Block.String(),
- "HIVE_FORK_SPURIOUS": conf.Genesis.Config.EIP155Block.String(), // also eip558
- "HIVE_FORK_BYZANTIUM": conf.Genesis.Config.ByzantiumBlock.String(),
- "HIVE_FORK_CONSTANTINOPLE": conf.Genesis.Config.ConstantinopleBlock.String(),
- "HIVE_FORK_PETERSBURG": conf.Genesis.Config.PetersburgBlock.String(),
- "HIVE_FORK_ISTANBUL": conf.Genesis.Config.IstanbulBlock.String(),
- "HIVE_FORK_MUIRGLACIER": conf.Genesis.Config.MuirGlacierBlock.String(),
- "HIVE_FORK_BERLIN": conf.Genesis.Config.BerlinBlock.String(),
- "HIVE_FORK_LONDON": conf.Genesis.Config.LondonBlock.String(),
- "HIVE_FORK_ARROWGLACIER": conf.Genesis.Config.ArrowGlacierBlock.String(),
- "HIVE_MERGE_BLOCK_ID": conf.Genesis.Config.MergeNetsplitBlock.String(),
- "HIVE_TERMINAL_TOTAL_DIFFICULTY": conf.Genesis.Config.TerminalTotalDifficulty.String(),
- }
- if conf.Genesis.Config.Clique != nil {
- params["HIVE_CLIQUE_PERIOD"] = fmt.Sprint(conf.Genesis.Config.Clique.Period)
- }
- return params
-}
diff --git a/simulators/eth2/testnet/setup/files.go b/simulators/eth2/testnet/setup/files.go
deleted file mode 100644
index eb27dd7d56..0000000000
--- a/simulators/eth2/testnet/setup/files.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package setup
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
-
- "github.com/ethereum/go-ethereum/core"
- "github.com/protolambda/zrnt/eth2/beacon/common"
- "github.com/protolambda/ztyp/codec"
- "gopkg.in/yaml.v2"
-
- "github.com/ethereum/hive/hivesim"
-)
-
-func bytesSource(data []byte) func() (io.ReadCloser, error) {
- return func() (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewReader(data)), nil
- }
-}
-
-func Eth1Bundle(genesis *core.Genesis) (hivesim.StartOption, error) {
- out, err := json.Marshal(genesis)
- if err != nil {
- return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
- }
- return hivesim.WithDynamicFile("genesis.json", bytesSource(out)), nil
-}
-
-func StateBundle(state common.BeaconState) (hivesim.StartOption, error) {
- var stateBytes bytes.Buffer
- if err := state.Serialize(codec.NewEncodingWriter(&stateBytes)); err != nil {
- return nil, fmt.Errorf("failed to serialize genesis state: %v", err)
- }
- return hivesim.WithDynamicFile("/hive/input/genesis.ssz", bytesSource(stateBytes.Bytes())), nil
-}
-
-func ConsensusConfigsBundle(spec *common.Spec, genesis *core.Genesis, valCount uint64) (hivesim.StartOption, error) {
- config, err := yaml.Marshal(spec.Config)
- if err != nil {
- return nil, err
- }
- phase0Preset, err := yaml.Marshal(spec.Phase0Preset)
- if err != nil {
- return nil, err
- }
- altairPreset, err := yaml.Marshal(spec.AltairPreset)
- if err != nil {
- return nil, err
- }
- bellatrixPreset, err := yaml.Marshal(spec.BellatrixPreset)
- if err != nil {
- return nil, err
- }
- genesisHash := genesis.ToBlock().Hash()
- return hivesim.Bundle(
- hivesim.WithDynamicFile("/hive/input/config.yaml", bytesSource(config)),
- hivesim.WithDynamicFile("/hive/input/preset_phase0.yaml", bytesSource(phase0Preset)),
- hivesim.WithDynamicFile("/hive/input/preset_altair.yaml", bytesSource(altairPreset)),
- hivesim.WithDynamicFile("/hive/input/preset_bellatrix.yaml", bytesSource(bellatrixPreset)),
- hivesim.Params{
- "HIVE_ETH2_ETH1_GENESIS_HASH": genesisHash.String(),
- },
- ), nil
-}
-
-func KeysBundle(keys []*KeyDetails) hivesim.StartOption {
- opts := make([]hivesim.StartOption, 0, len(keys)*2)
- for _, k := range keys {
- p := fmt.Sprintf("/hive/input/keystores/0x%x/keystore.json", k.ValidatorPubkey[:])
- opts = append(opts, hivesim.WithDynamicFile(p, bytesSource(k.ValidatorKeystoreJSON)))
- p = fmt.Sprintf("/hive/input/secrets/0x%x", k.ValidatorPubkey[:])
- opts = append(opts, hivesim.WithDynamicFile(p, bytesSource([]byte(k.ValidatorKeystorePass))))
- }
- return hivesim.Bundle(opts...)
-}
diff --git a/simulators/eth2/testnet/setup/validator_keys.go b/simulators/eth2/testnet/setup/validator_keys.go
deleted file mode 100644
index f6d54844bf..0000000000
--- a/simulators/eth2/testnet/setup/validator_keys.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package setup
-
-import (
- "crypto/rand"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "strings"
-
- blsu "github.com/protolambda/bls12-381-util"
-
- "github.com/google/uuid"
- hbls "github.com/herumi/bls-eth-go-binary/bls"
- "github.com/pkg/errors"
- "github.com/protolambda/go-keystorev4"
- "github.com/tyler-smith/go-bip39"
- util "github.com/wealdtech/go-eth2-util"
-)
-
-// TODO: replace wealdtech util with more minimal key derivation lib, can then also remove herumi BLS
-func init() {
- if err := hbls.Init(hbls.BLS12_381); err != nil {
- panic(err)
- }
- if err := hbls.SetETHmode(hbls.EthModeLatest); err != nil {
- panic(err)
- }
-}
-
-type KeyDetails struct {
- // ValidatorKeystoreJSON encodes an EIP-2335 keystore, serialized in JSON
- // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2335.md
- ValidatorKeystoreJSON []byte
- // ValidatorKeystorePass holds the secret used for ValidatorKeystoreJSON
- ValidatorKeystorePass string
- // ValidatorSecretKey is the serialized secret key for validator duties
- ValidatorSecretKey [32]byte
- // ValidatorSecretKey is the serialized pubkey derived from ValidatorSecretKey
- ValidatorPubkey [48]byte
- // WithdrawalSecretKey is the serialized secret key for withdrawing stake
- WithdrawalSecretKey [32]byte
- // WithdrawalPubkey is the serialized pubkey derived from WithdrawalSecretKey
- WithdrawalPubkey [48]byte
-}
-
-// MnemonicsKeySource creates a range of BLS validator and withdrawal keys.
-// "m/12381/3600/%d/0/0" path for validator keys
-// "m/12381/3600/%d/0" path for withdrawal keys
-type MnemonicsKeySource struct {
- // From account range start, inclusive
- From uint64 `yaml:"from"`
- // To account range end, exclusive
- To uint64 `yaml:"to"`
- // Validator mnemonic
- Validator string `yaml:"validator"`
- // Withdrawal mnemonic
- Withdrawal string `yaml:"withdrawal"`
-
- // cache loaded validator details
- cache []*KeyDetails `yaml:"-"`
-}
-
-func mnemonicToSeed(mnemonic string) (seed []byte, err error) {
- mnemonic = strings.TrimSpace(mnemonic)
- if !bip39.IsMnemonicValid(mnemonic) {
- return nil, errors.New("mnemonic is not valid")
- }
- return bip39.NewSeed(mnemonic, ""), nil
-}
-
-func weakKeystore(secret []byte, pub []byte, passphrase []byte) (*keystorev4.Keystore, error) {
- var salt [32]byte
- if _, err := rand.Read(salt[:]); err != nil {
- return nil, err
- }
- kdfParams := &keystorev4.PBKDF2Params{
- Dklen: 32,
- C: 2, // INSECURE but much faster, this is an ephemeral testnet
- Prf: "hmac-sha256",
- Salt: salt[:],
- }
- cipherParams, err := keystorev4.NewAES128CTRParams()
- if err != nil {
- return nil, fmt.Errorf("failed to create AES128CTR params: %w", err)
- }
- crypto, err := keystorev4.Encrypt(secret, passphrase, kdfParams, keystorev4.Sha256ChecksumParams, cipherParams)
- if err != nil {
- return nil, fmt.Errorf("failed to encrypt secret: %w", err)
- }
- id, err := uuid.NewUUID()
- if err != nil {
- return nil, fmt.Errorf("failed to generate UUID: %w", err)
- }
- return &keystorev4.Keystore{
- Crypto: *crypto,
- Description: "",
- Pubkey: pub,
- Path: "",
- UUID: id,
- Version: 4,
- }, nil
-}
-
-// Same crypto, but not secure, for testing only!
-// Just generate weak keystores, so encryption and decryption doesn't take as long during testing.
-func marshalWeakKeystoreJSON(priv []byte, pub []byte, normedPass []byte) ([]byte, error) {
- store, err := weakKeystore(priv, pub, normedPass)
- if err != nil {
- return nil, fmt.Errorf("failed to encrypt keystore: %v", err)
- }
- return json.MarshalIndent(store, "", " ")
-}
-
-func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) {
- if k.cache != nil {
- return k.cache, nil
- }
- valSeed, err := mnemonicToSeed(k.Validator)
- if err != nil {
- return nil, fmt.Errorf("bad validator seed: %w", err)
- }
- withdrSeed, err := mnemonicToSeed(k.Withdrawal)
- if err != nil {
- return nil, fmt.Errorf("bad validator seed: %w", err)
- }
- if k.From > k.To {
- return nil, fmt.Errorf("invalid key range: from %d > to %d", k.From, k.To)
- }
- out := make([]*KeyDetails, 0, k.To-k.From)
- for i := k.From; i < k.To; i++ {
- path := fmt.Sprintf("m/12381/3600/%d/0/0", i)
- valPrivateKey, err := util.PrivateKeyFromSeedAndPath(valSeed, path)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create validator private key for path %q", path)
- }
- path = fmt.Sprintf("m/12381/3600/%d/0", i)
- withdrPrivateKey, err := util.PrivateKeyFromSeedAndPath(withdrSeed, path)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create withdrawal private key for path %q", path)
- }
- var passRandomness [32]byte
- _, err = rand.Read(passRandomness[:])
- if err != nil {
- return nil, fmt.Errorf("failed to generate keystore password: %w", err)
- }
- priv := valPrivateKey.Marshal()
- if len(priv) != 32 {
- return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs.
- }
- pub := valPrivateKey.PublicKey().Marshal()
- if len(pub) != 48 {
- return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs.
- }
- wPriv := withdrPrivateKey.Marshal()
- if len(priv) != 32 {
- return nil, fmt.Errorf("expected priv key of 32 bytes, got: %x", priv) // testing, we can log privs.
- }
- wPub := withdrPrivateKey.PublicKey().Marshal()
- if len(pub) != 48 {
- return nil, fmt.Errorf("expected pub key of 48 bytes, got: %x", pub) // testing, we can log privs.
- }
- // We don't have fancy password norming, just use a base64 pass instead.
- passphrase := base64.URLEncoding.EncodeToString(passRandomness[:])
- jsonData, err := marshalWeakKeystoreJSON(priv, pub, []byte(passphrase))
- k := &KeyDetails{
- ValidatorKeystoreJSON: jsonData,
- ValidatorKeystorePass: passphrase,
- }
- copy(k.ValidatorPubkey[:], pub)
- copy(k.ValidatorSecretKey[:], priv)
- copy(k.WithdrawalPubkey[:], wPub)
- copy(k.WithdrawalSecretKey[:], wPriv)
-
- out = append(out, k)
- }
- k.cache = out
- return out, nil
-}
-
-func SecretKeys(keys []*KeyDetails) (*[]blsu.SecretKey, error) {
- secrets := make([]blsu.SecretKey, len(keys))
- for i := 0; i < len(keys); i++ {
- if err := secrets[i].Deserialize(&keys[i].ValidatorSecretKey); err != nil {
- return nil, fmt.Errorf("validator %d has invalid key: %v", i, err)
- }
- }
- return &secrets, nil
-}
-
-func KeyTranches(keys []*KeyDetails, keyTranches uint64) [][]*KeyDetails {
- tranches := make([][]*KeyDetails, 0, keyTranches)
- valCount := uint64(len(keys))
- for i := uint64(0); i < keyTranches; i++ {
- // Give each validator client an equal subset of the genesis validator keys
- startIndex := valCount * i / keyTranches
- endIndex := valCount * (i + 1) / keyTranches
- tranches = append(tranches, keys[startIndex:endIndex])
- }
- return tranches
-}
diff --git a/simulators/eth2/withdrawals/Dockerfile b/simulators/eth2/withdrawals/Dockerfile
new file mode 100644
index 0000000000..999e8f550a
--- /dev/null
+++ b/simulators/eth2/withdrawals/Dockerfile
@@ -0,0 +1,18 @@
+# Build the simulator binary
+FROM golang:1-alpine AS builder
+RUN apk --no-cache add gcc musl-dev linux-headers cmake make clang build-base clang-static clang-dev
+
+# Prepare workspace.
+# Note: the build context of this simulator image is the parent directory!
+ADD . /source
+
+# Build within simulator folder
+WORKDIR /source/withdrawals
+RUN go build -o ./sim .
+
+# Build the runner container.
+FROM alpine:latest
+ADD . /
+COPY --from=builder /source/withdrawals/sim /
+
+ENTRYPOINT ["./sim"]
diff --git a/simulators/eth2/withdrawals/README.md b/simulators/eth2/withdrawals/README.md
new file mode 100644
index 0000000000..ba59de351d
--- /dev/null
+++ b/simulators/eth2/withdrawals/README.md
@@ -0,0 +1,162 @@
+# Withdrawals Interop Hive Simulator
+
+The simulator contains the implementation of the tests described in this
+document.
+
+
+## General Considerations for all tests
+- A single validating node comprises an execution client, beacon client and validator client (unless specified otherwise)
+- All validating nodes have the same number of validators (unless specified otherwise)
+- An importer node is a node that has no validators but might be connected to the network
+- Execution client Shanghai timestamp transition is automatically calculated from the Capella Epoch timestamp
+
+
+## Test Cases
+
+### Capella/Shanghai Transition
+
+* [x] Capella/Shanghai Transition
+
+ Click for details
+
+ - Start two validating nodes that begin on Bellatrix/Merge genesis
+ - Capella/Shanghai transition occurs on Epoch 1
+ - Total of 128 Validators, 64 for each validating node
+ - All validators contain 0x01 withdrawal credentials
+ - Wait for Capella fork + `128 / MAX_WITHDRAWALS_PER_PAYLOAD` slots
+ - Verify on the execution client:
+ - All active validators' balances increase
+
+
+
+### Capella/Shanghai Genesis
+
+* [x] Capella/Shanghai Genesis
+
+ Click for details
+
+ - Start two validating nodes that begin on Capella genesis
+ - Total of 128 Validators, 64 for each validating node
+ - All validators contain 0x01 withdrawal credentials
+ - Wait `128 / MAX_WITHDRAWALS_PER_PAYLOAD` slots
+ - Verify on the execution client:
+ - All active validators' balances increase
+
+
+
+### BLS-To-Execution-Change
+
+* [x] BLS-To-Execution-Changes
+
+ Click for details
+
+ - Start two validating nodes on Bellatrix/Merge genesis
+ - Capella/Shanghai transition occurs on Epoch 1
+ - Half genesis validators have BLS withdrawal credentials
+ - If any of the clients supports receiving BLS-To-Execution-Changes during Bellatrix, sign and submit half of the BLS validators during the first epoch.
+ - Wait for Capella fork
+ - Submit the remaining BLS-To-Execution-Changes to all nodes
+ - Wait and verify on the beacon state that withdrawal credentials are updated
+ - Verify on the execution client:
+ - All active validators' balances increase
+
+ * [x] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes before transition to Capella/Shanghai
+ * [x] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes after transition to Capella/Shanghai
+
+
+
+* [x] BLS-To-Execution-Changes of Exited/Slashed Validators
+
+ Click for details
+
+ - Start two validating nodes on Bellatrix/Merge genesis
+ - Capella/Shanghai transition occurs on Epoch 1
+ - Total of 128 Validators, 64 for each validating node
+ - Half genesis validators have BLS withdrawal credentials
+ - 1 every 8 validators start on Voluntary Exit state
+ - 1 every 8 validators start on Slashed state
+ - If any of the clients supports receiving BLS-To-Execution-Changes during Bellatrix, sign and submit half of the BLS validators during the first epoch.
+ - Wait for Capella fork
+ - Submit the remaining BLS-To-Execution-Changes to all nodes
+ - Wait and verify on the beacon state that withdrawal credentials are updated
+ - Verify on the beacon state:
+ - Withdrawal credentials are updated
+ - Fully exited validators' balances drop to zero
+ - Verify on the execution client:
+ - All active validators' balances increase
+ - Fully exited validators' balances are equal to the full withdrawn amount
+
+ * [x] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes before transition to Capella/Shanghai
+ * [x] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes after transition to Capella/Shanghai
+
+
+
+
+
+* [ ] BLS-To-Execution-Changes Broadcast
+
+ Click for details
+
+ - Start two validating nodes and one importer node on Capella/Shanghai genesis
+ - All genesis validators have BLS withdrawal credentials
+ - Sign and submit BLS-To-Execution-Changes to the importer node of all validators to change withdrawal credentials to different execution addresses
+ - Wait until the importer node broadcasts the BLS-To-Execution-Changes
+ - Verify on the beacon state:
+ - Withdrawal credentials are updated
+ - Verify on the execution client:
+ - All active validators' balances increase
+
+ * [ ] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes before transition to Capella/Shanghai
+ * [ ] Test on Bellatrix/Merge genesis, submit BLS-To-Execution-Changes after transition to Capella/Shanghai
+
+
+
+### Withdrawals During Re-Orgs
+
+* [ ] Partial Withdrawal of Validators on Re-Org
+
+ Click for details
+
+ - Start three validating nodes on Capella/Shanghai genesis
+ - Two nodes, `A` and `B`, are connected to each other, and one node `C` is disconnected from the others
+ - Total of 128 Validators, 42 for each validating node
+ - All genesis validators have BLS withdrawal credentials
+ - On Epoch 0, submit BLS-To-Execution changes to node `C` of all the validating keys contained in this same node
+ - Verify that:
+ - BLS-To-Execution changes are included in node `C` chain
+ - Partial withdrawals on node `C` execution client
+ - Submit BLS-To-Execution changes to nodes `A` and `B` of all the validating keys contained in node `C`, but the execution addresses must differ of the ones originally submitted to node `C`
+ - Connect node `C` to nodes `A` and `B`
+ - Wait until node `C` re-orgs to chain formed by nodes `A` and `B`
+ - Verify on the beacon state `C`:
+ - Withdrawal credentials are correctly updated to the execution addresses specified on nodes `A` and `B`
+ - Verify on the execution client:
+ - Withdrawal addresses specified on node `C` are empty
+ - Withdrawal addresses specified on node `A` and `B` are partially withdrawing
+
+
+
+* [ ] Full Withdrawal of Validators on Re-Org
+
+ Click for details
+
+ - Start three validating nodes on Capella/Shanghai genesis
+ - Two nodes, `A` and `B`, are connected to each other, and one node `C` is disconnected from the others
+ - Total of 128 Validators, 42 for each validating node
+ - All genesis validators have BLS withdrawal credentials
+ - 1 every 8 validators start on Voluntary Exit state
+ - 1 every 8 validators start on Slashed state
+ - On Epoch 0, submit BLS-To-Execution changes to node `C` of all the inactive validating keys
+ - Verify that:
+ - BLS-To-Execution changes are included in node `C` chain
+ - Full withdrawals on node `C` execution client
+ - Submit BLS-To-Execution changes to nodes `A` and `B` of all the exited validating keys, but the execution addresses must differ of the ones originally submitted to node `C`
+ - Connect node `C` to nodes `A` and `B`
+ - Wait until node `C` re-orgs to chain formed by nodes `A` and `B`
+ - Verify on the beacon state `C`:
+ - Withdrawal credentials are correctly updated to the execution addresses specified on nodes `A` and `B`
+ - Verify on the execution client:
+ - Withdrawal addresses specified on node `C` are empty
+ - Withdrawal addresses specified on node `A` and `B` are fully withdrawing
+
+
diff --git a/simulators/eth2/withdrawals/go.mod b/simulators/eth2/withdrawals/go.mod
new file mode 100644
index 0000000000..132c3d3384
--- /dev/null
+++ b/simulators/eth2/withdrawals/go.mod
@@ -0,0 +1,86 @@
+module github.com/ethereum/hive/simulators/eth2/withdrawals
+
+go 1.18
+
+require (
+ github.com/ethereum/go-ethereum v1.10.26
+ github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b
+ github.com/golang-jwt/jwt/v4 v4.4.3
+ github.com/google/uuid v1.3.0
+ github.com/herumi/bls-eth-go-binary v1.28.1
+ github.com/pkg/errors v0.9.1
+ github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0
+ github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564
+ github.com/protolambda/zrnt v0.29.0
+ github.com/protolambda/ztyp v0.2.2
+ github.com/rauljordan/engine-proxy v0.0.0-20220517190449-e62b2e2f6e27
+ github.com/tyler-smith/go-bip39 v1.1.0
+ github.com/wealdtech/go-eth2-util v1.8.0
+)
+
+require (
+ github.com/VictoriaMetrics/fastcache v1.12.0 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/deckarep/golang-set v1.8.0 // indirect
+ github.com/ferranbt/fastssz v0.1.2 // indirect
+ github.com/go-kit/kit v0.10.0 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/go-stack/stack v1.8.1 // indirect
+ github.com/holiman/uint256 v1.2.1
+ github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/minio/sha256-simd v1.0.0 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/prometheus/tsdb v0.10.0 // indirect
+ github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
+ github.com/shirou/gopsutil v3.21.11+incompatible // indirect
+ github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
+ github.com/tklauser/go-sysconf v0.3.11 // indirect
+ golang.org/x/sys v0.3.0 // indirect
+ golang.org/x/text v0.5.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+require (
+ github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
+ github.com/edsrzf/mmap-go v1.1.0 // indirect
+ github.com/fjl/memsize v0.0.1 // indirect
+ github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
+ github.com/go-logfmt/logfmt v0.5.1 // indirect
+ github.com/golang/snappy v0.0.4 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/hashicorp/go-bexpr v0.1.11 // indirect
+ github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
+ github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
+ github.com/julienschmidt/httprouter v1.3.0 // indirect
+ github.com/kilic/bls12-381 v0.1.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.2 // indirect
+ github.com/kr/pretty v0.3.1 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/rivo/uniseg v0.4.3 // indirect
+ github.com/rjeczalik/notify v0.9.2 // indirect
+ github.com/rs/cors v1.8.2 // indirect
+ github.com/sirupsen/logrus v1.9.0 // indirect
+ github.com/status-im/keycard-go v0.2.0 // indirect
+ github.com/stretchr/testify v1.8.1 // indirect
+ github.com/tklauser/numcpus v0.6.0 // indirect
+ github.com/urfave/cli/v2 v2.23.7 // indirect
+ github.com/wealdtech/go-bytesutil v1.2.0 // indirect
+ github.com/wealdtech/go-eth2-types/v2 v2.8.0 // indirect
+ github.com/yusufpapurcu/wmi v1.2.2 // indirect
+ golang.org/x/crypto v0.4.0 // indirect
+ golang.org/x/net v0.4.0 // indirect
+ golang.org/x/sync v0.1.0 // indirect
+ golang.org/x/time v0.3.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
+)
+
+replace github.com/rauljordan/engine-proxy => github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea
+
+replace github.com/ethereum/go-ethereum v1.10.26 => github.com/lightclient/go-ethereum v1.10.10-0.20230116085521-6ab6d738866f
+
+replace github.com/protolambda/eth2api => github.com/marioevz/eth2api v0.0.0-20230110222620-e349e704f20c
diff --git a/simulators/eth2/withdrawals/go.sum b/simulators/eth2/withdrawals/go.sum
new file mode 100644
index 0000000000..04e9aa5a07
--- /dev/null
+++ b/simulators/eth2/withdrawals/go.sum
@@ -0,0 +1,617 @@
+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=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
+github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+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/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
+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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+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/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
+github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
+github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
+github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s=
+github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
+github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b h1:uWfa1x0lA7o5O6XgFxENIxAlevy9W5U6nAp79naD7e4=
+github.com/ethereum/hive v0.0.0-20221123180504-f0f647240e9b/go.mod h1:G8XiiUErpj6++yb93r6y6T1nWBh4Bgoi3QFwUSbzt/U=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
+github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
+github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
+github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
+github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+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/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+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-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
+github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gogo/googleapis v1.1.0/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.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
+github.com/golang-jwt/jwt/v4 v4.4.3/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-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+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.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.2/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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+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.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY=
+github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+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/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
+github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA=
+github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
+github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
+github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
+github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
+github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+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/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
+github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.2 h1:xPMwiykqNK9VK0NYC3+jTMYv9I6Vl3YdjZgPZKG3zO0=
+github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea h1:9ahHMPkNvYf9Nn3+U072ZKMDm05gaXfRESAmwP07Q+M=
+github.com/marioevz/engine-proxy v0.0.0-20220617181151-e8661eb39eea/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
+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/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
+github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
+github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
+github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w=
+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/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0 h1:/0Dm3GrX4sk0aAYdrjtFvJigvPZ8HcAQ3ZT7kW+da7M=
+github.com/protolambda/eth2api v0.0.0-20220822011642-f7735dd471e0/go.mod h1:dzegbgrVD+2MQZ86RHWQvgWfnFxEjlDNkzf69afaSnA=
+github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564 h1:yCXGkFjrZ8EggxW+Y7ueRZesNcBk0avLU0mVU/I2KtU=
+github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564/go.mod h1:Xda3KO8+DMyWaTr+LwUUpVRTB5SdFzoKu0ivXNI6p1s=
+github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M=
+github.com/protolambda/zrnt v0.28.0 h1:vdEL8JDqJ3wdzgqgh6Fhz1Wr3+AMGbUZ2nqoNt6QVX0=
+github.com/protolambda/zrnt v0.28.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
+github.com/protolambda/zrnt v0.29.0 h1:pHCagNwM1KJztMnXXCZ6RAvQL4nVTCJ1v1tTyl/nP0o=
+github.com/protolambda/zrnt v0.29.0/go.mod h1:qcdX9CXFeVNCQK/q0nswpzhd+31RHMk2Ax/2lMsJ4Jw=
+github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY=
+github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
+github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
+github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
+github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+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/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
+github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
+github.com/shirou/gopsutil v3.21.11+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.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+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/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+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=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
+github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
+github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
+github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
+github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
+github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
+github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
+github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
+github.com/wealdtech/go-bytesutil v1.2.0 h1:GEIzvAZEIgqOoRfnEAaMRNL73gl8e+YlQzqxhFyR30Y=
+github.com/wealdtech/go-bytesutil v1.2.0/go.mod h1:FHQSlwhzfSZGffu1osaUGdnNtl5C8tBKwmqvPdB66pM=
+github.com/wealdtech/go-eth2-types/v2 v2.8.0 h1:Cts9J78ryXVp8jwotdSSVU75S+QWJrgVCArXreD2X8A=
+github.com/wealdtech/go-eth2-types/v2 v2.8.0/go.mod h1:tJazo9o28kdQs3V/U4VafQ4neG+/sL3OBozQ8J3CWmo=
+github.com/wealdtech/go-eth2-util v1.8.0 h1:hhs3h2y3Ldty18lppFdpe46nZpdDAMbY7QqiHO5BvE0=
+github.com/wealdtech/go-eth2-util v1.8.0/go.mod h1:rSuE0v5zX+uyZrqW/iUmXOxeDpB7lTvhcZvAVh0KlMU=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
+github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-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=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
+golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/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-20190404232315-eb5bcb51f2a3/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+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/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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+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-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20181122145206-62eef0e2fa9b/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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/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-20191005200804-aed5e4c7ecf9/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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+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.3.0/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+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=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20200109203555-b30bc20e4fd1 h1:iiHuQZCNgYPmFQxd3BBN/Nc5+dAwzZuq5y40s20oQw0=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/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=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/simulators/eth2/withdrawals/helper.go b/simulators/eth2/withdrawals/helper.go
new file mode 100644
index 0000000000..4332a40793
--- /dev/null
+++ b/simulators/eth2/withdrawals/helper.go
@@ -0,0 +1,394 @@
+package main
+
+import (
+ "context"
+ "crypto/ecdsa"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ cl "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
+ blsu "github.com/protolambda/bls12-381-util"
+ beacon "github.com/protolambda/zrnt/eth2/beacon/common"
+ "github.com/protolambda/ztyp/tree"
+)
+
+// API call names
+const (
+ EngineForkchoiceUpdatedV1 = "engine_forkchoiceUpdatedV1"
+ EngineGetPayloadV1 = "engine_getPayloadV1"
+ EngineNewPayloadV1 = "engine_newPayloadV1"
+ EthGetBlockByHash = "eth_getBlockByHash"
+ EthGetBlockByNumber = "eth_getBlockByNumber"
+)
+
+// Engine API Types
+
+type PayloadStatus string
+
+const (
+ Unknown = ""
+ Valid = "VALID"
+ Invalid = "INVALID"
+ Accepted = "ACCEPTED"
+ Syncing = "SYNCING"
+ InvalidBlockHash = "INVALID_BLOCK_HASH"
+)
+
+// Signer for all txs
+type Signer struct {
+ ChainID *big.Int
+ PrivateKey *ecdsa.PrivateKey
+}
+
+func (vs Signer) SignTx(
+ baseTx *types.Transaction,
+) (*types.Transaction, error) {
+ signer := types.NewEIP155Signer(vs.ChainID)
+ return types.SignTx(baseTx, signer, vs.PrivateKey)
+}
+
+var VaultSigner = Signer{
+ ChainID: CHAIN_ID,
+ PrivateKey: VAULT_KEY,
+}
+
+// Helper struct to keep track of current status of a validator withdrawal state
+type Validator struct {
+ Index beacon.ValidatorIndex
+ WithdrawAddress *common.Address
+ Exited bool
+ ExitCondition string
+ ExactWithdrawableBalance *big.Int
+ Keys *cl.KeyDetails
+ BLSToExecutionChangeDomain *beacon.BLSDomain
+ Verified bool
+}
+
+func (v *Validator) VerifyWithdrawnBalance(
+ ctx context.Context,
+ ec *clients.ExecutionClient,
+) (bool, error) {
+ if v.Verified {
+ // Validator already verified on a previous iteration
+ return true, nil
+ }
+ // Check the withdrawal address, if empty this is an error
+ if v.WithdrawAddress == nil {
+ return false, fmt.Errorf(
+ "checked balance for validator without a withdrawal address",
+ )
+ }
+ execAddress := *v.WithdrawAddress
+
+ // First get the balance
+ balance, err := ec.BalanceAt(ctx, execAddress, nil)
+ if err != nil {
+ return false, err
+ }
+
+ // If balance is zero, there have not been any withdrawals yet,
+ // but this is not an error
+ if balance.Cmp(common.Big0) == 0 {
+ return false, nil
+ }
+
+ // If we have an exact withdrawal expected balance, then verify it
+ if v.ExactWithdrawableBalance != nil {
+ if v.ExactWithdrawableBalance.Cmp(balance) == 0 {
+ fmt.Printf(
+ "INFO: %s validator %d fully withdrawn: %d\n",
+ v.ExitCondition,
+ v.Index,
+ v.ExactWithdrawableBalance,
+ )
+ v.Verified = true
+ return true, nil
+ } else {
+ return true, fmt.Errorf("unexepected balance: want=%d, got=%d", v.ExactWithdrawableBalance, balance)
+ }
+ }
+
+ // Otherwise simply return true, as a signal that a - potentially partial - withdrawal has taken place
+ fmt.Printf(
+ "INFO: Validator %d partially withdrawn: %d\n",
+ v.Index,
+ balance,
+ )
+ v.Verified = true
+ return true, nil
+}
+
+// Signs the BLS-to-execution-change for the given address
+func (v *Validator) SignBLSToExecutionChange(
+ executionAddress common.Address,
+) (*beacon.SignedBLSToExecutionChange, error) {
+ if v.Keys == nil {
+ return nil, fmt.Errorf("no key to sign")
+ }
+ if v.BLSToExecutionChangeDomain == nil {
+ return nil, fmt.Errorf("no domain to sign")
+ }
+ if v.WithdrawAddress != nil {
+ return nil, fmt.Errorf("execution address already set")
+ }
+ kdPubKey := beacon.BLSPubkey{}
+ copy(kdPubKey[:], v.Keys.WithdrawalPubkey[:])
+ eth1Address := beacon.Eth1Address{}
+ copy(eth1Address[:], executionAddress[:])
+ blsToExecChange := beacon.BLSToExecutionChange{
+ ValidatorIndex: v.Index,
+ FromBLSPubKey: kdPubKey,
+ ToExecutionAddress: eth1Address,
+ }
+ sigRoot := beacon.ComputeSigningRoot(
+ blsToExecChange.HashTreeRoot(tree.GetHashFn()),
+ *v.BLSToExecutionChangeDomain,
+ )
+ sk := new(blsu.SecretKey)
+ sk.Deserialize(&v.Keys.WithdrawalSecretKey)
+ signature := blsu.Sign(sk, sigRoot[:]).Serialize()
+ return &beacon.SignedBLSToExecutionChange{
+ BLSToExecutionChange: blsToExecChange,
+ Signature: beacon.BLSSignature(signature),
+ }, nil
+}
+
+// Sign and send the BLS-to-execution-change.
+// Also internally update the withdraw address.
+func (v *Validator) SignSendBLSToExecutionChange(
+ ctx context.Context,
+ bc *clients.BeaconClient,
+ executionAddress common.Address,
+) error {
+ signedBLS, err := v.SignBLSToExecutionChange(executionAddress)
+ if err != nil {
+ return err
+ }
+ if err := bc.SubmitPoolBLSToExecutionChange(ctx, beacon.SignedBLSToExecutionChanges{
+ *signedBLS,
+ }); err != nil {
+ return err
+ }
+
+ v.WithdrawAddress = &executionAddress
+ return nil
+}
+
+type Validators []*Validator
+
+// Verify all validators have withdrawn
+func (vs Validators) VerifyWithdrawnBalance(
+ ctx context.Context,
+ ec *clients.ExecutionClient,
+) (bool, error) {
+ for i, v := range vs {
+ if withdrawn, err := v.VerifyWithdrawnBalance(ctx, ec); err != nil {
+ return withdrawn, fmt.Errorf(
+ "error verifying validator %d balance: %v",
+ i,
+ err,
+ )
+ } else if !withdrawn {
+ return false, nil
+ }
+ }
+ return true, nil
+}
+
+func (vs Validators) NonWithdrawable() Validators {
+ ret := make(Validators, 0)
+ for _, v := range vs {
+ v := v
+ if v.WithdrawAddress == nil {
+ ret = append(ret, v)
+ }
+ }
+ return ret
+}
+
+func (vs Validators) Withdrawable() Validators {
+ ret := make(Validators, 0)
+ for _, v := range vs {
+ v := v
+ if v.WithdrawAddress != nil {
+ ret = append(ret, v)
+ }
+ }
+ return ret
+}
+
+func (vs Validators) FullyWithdrawable() Validators {
+ ret := make(Validators, 0)
+ for _, v := range vs {
+ v := v
+ if v.WithdrawAddress != nil && v.Exited {
+ ret = append(ret, v)
+ }
+ }
+ return ret
+}
+
+func (vs Validators) Exited() Validators {
+ ret := make(Validators, 0)
+ for _, v := range vs {
+ v := v
+ if v.Exited {
+ ret = append(ret, v)
+ }
+ }
+ return ret
+}
+
+func (vs Validators) Chunks(totalShares int) []Validators {
+ ret := make([]Validators, totalShares)
+ countPerChunk := len(vs) / totalShares
+ for i := range ret {
+ ret[i] = vs[i*countPerChunk : (i*countPerChunk)+countPerChunk]
+ }
+ return ret
+}
+
+func ValidatorFromBeaconValidator(
+ index beacon.ValidatorIndex,
+ source beacon.Validator,
+ balance beacon.Gwei,
+ keys *cl.KeyDetails,
+ domain *beacon.BLSDomain,
+) (*Validator, error) {
+ // Assume genesis state
+ currentEpoch := beacon.Epoch(0)
+
+ v := new(Validator)
+
+ v.Index = index
+ v.Keys = keys
+ v.BLSToExecutionChangeDomain = domain
+
+ wc, err := source.WithdrawalCredentials()
+ if err != nil {
+ return nil, err
+ }
+ if wc[0] == beacon.ETH1_ADDRESS_WITHDRAWAL_PREFIX {
+ withdrawAddress := common.Address{}
+ copy(withdrawAddress[:], wc[12:])
+ v.WithdrawAddress = &withdrawAddress
+ }
+
+ exitEpoch, err := source.ExitEpoch()
+ if err != nil {
+ return nil, err
+ }
+
+ slashed, err := source.Slashed()
+ if err != nil {
+ return nil, err
+ }
+
+ // Assuming this is the genesis beacon state
+ if exitEpoch <= currentEpoch || slashed {
+ v.Exited = true
+ if slashed {
+ v.ExitCondition = "Slashed"
+ } else {
+ v.ExitCondition = "Voluntary Exited"
+ }
+ v.ExactWithdrawableBalance = big.NewInt(int64(balance))
+ v.ExactWithdrawableBalance.Mul(
+ v.ExactWithdrawableBalance,
+ big.NewInt(1e9),
+ )
+ }
+ return v, nil
+}
+
+func ValidatorFromBeaconState(
+ state beacon.BeaconState,
+ index beacon.ValidatorIndex,
+ keys *cl.KeyDetails,
+ domain *beacon.BLSDomain,
+) (*Validator, error) {
+ stateVals, err := state.Validators()
+ if err != nil {
+ return nil, err
+ }
+ balances, err := state.Balances()
+ if err != nil {
+ return nil, err
+ }
+ beaconVal, err := stateVals.Validator(index)
+ if err != nil {
+ return nil, err
+ }
+ balance, err := balances.GetBalance(index)
+ if err != nil {
+ return nil, err
+ }
+ return ValidatorFromBeaconValidator(
+ index,
+ beaconVal,
+ balance,
+ keys,
+ domain,
+ )
+}
+
+func ValidatorsFromBeaconState(
+ state beacon.BeaconState,
+ keys []*cl.KeyDetails,
+ domain *beacon.BLSDomain,
+) (Validators, error) {
+ stateVals, err := state.Validators()
+ if err != nil {
+ return nil, err
+ }
+ balances, err := state.Balances()
+ if err != nil {
+ return nil, err
+ }
+ validatorCount, err := stateVals.ValidatorCount()
+ if err != nil {
+ return nil, err
+ } else if validatorCount == 0 {
+ return nil, fmt.Errorf("got zero validators")
+ } else if validatorCount != uint64(len(keys)) {
+ return nil, fmt.Errorf("incorrect amount of keys: want=%d, got=%d", validatorCount, len(keys))
+ }
+ validators := make(Validators, 0)
+ for i := beacon.ValidatorIndex(0); i < beacon.ValidatorIndex(validatorCount); i++ {
+ beaconVal, err := stateVals.Validator(beacon.ValidatorIndex(i))
+ if err != nil {
+ return nil, err
+ }
+ balance, err := balances.GetBalance(i)
+ if err != nil {
+ return nil, err
+ }
+ validator, err := ValidatorFromBeaconValidator(
+ i,
+ beaconVal,
+ balance,
+ keys[i],
+ domain,
+ )
+ if err != nil {
+ return nil, err
+ }
+ validators = append(validators, validator)
+
+ }
+ return validators, nil
+}
+
+func ComputeBLSToExecutionDomain(
+ t *testnet.Testnet,
+) beacon.BLSDomain {
+ return beacon.ComputeDomain(
+ beacon.DOMAIN_BLS_TO_EXECUTION_CHANGE,
+ t.Spec().GENESIS_FORK_VERSION,
+ t.GenesisValidatorsRoot(),
+ )
+}
diff --git a/simulators/eth2/withdrawals/hive_context.txt b/simulators/eth2/withdrawals/hive_context.txt
new file mode 100644
index 0000000000..a96aa0ea9d
--- /dev/null
+++ b/simulators/eth2/withdrawals/hive_context.txt
@@ -0,0 +1 @@
+..
\ No newline at end of file
diff --git a/simulators/eth2/withdrawals/main.go b/simulators/eth2/withdrawals/main.go
new file mode 100644
index 0000000000..a308110261
--- /dev/null
+++ b/simulators/eth2/withdrawals/main.go
@@ -0,0 +1,138 @@
+package main
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ consensus_config "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
+)
+
+var (
+ CHAIN_ID = big.NewInt(1)
+ // This is the account that send transactions.
+ VAULT_ACCOUNT_ADDR = common.HexToAddress(
+ "0xcf49fda3be353c69b41ed96333cd24302da4556f",
+ )
+ VAULT_KEY, _ = crypto.HexToECDSA(
+ "63b508a03c3b5937ceb903af8b1b0c191012ef6eb7e9c3fb7afa94e5d214d376",
+ )
+)
+
+type TestSpec interface {
+ GetName() string
+ GetDescription() string
+ Execute(*hivesim.T, *testnet.Environment, []clients.NodeDefinition)
+ GetValidatorKeys(string) []*consensus_config.KeyDetails
+}
+
+var tests = []TestSpec{
+ BaseWithdrawalsTestSpec{
+ Name: "test-capella-fork",
+ Description: `
+ Sanity test to check the fork transition to capella.
+ All validators start with Execution Withdrawal Credentials,
+ therefore no BLS-To-Execution changes are tested here.
+ `,
+ CapellaGenesis: false,
+ GenesisExecutionWithdrawalCredentialsShares: 1,
+ },
+
+ BaseWithdrawalsTestSpec{
+ Name: "test-capella-genesis",
+ Description: `
+ Sanity test to check the beacon clients can start with capella genesis.
+ All validators start with Execution Withdrawal Credentials,
+ therefore no BLS-To-Execution changes are tested here.
+ `,
+ CapellaGenesis: true,
+ GenesisExecutionWithdrawalCredentialsShares: 1,
+ },
+
+ BaseWithdrawalsTestSpec{
+ Name: "test-bls-to-execution-changes-on-capella",
+ Description: `
+ Send BLS-To-Execution-Changes after capella fork has happened.
+ Half of the validators still on BLS withdrawal credentials, and the
+ BLS-To-Execution-Change directives are sent for all the remaining
+ validators.
+ `,
+ CapellaGenesis: false,
+ GenesisExecutionWithdrawalCredentialsShares: 2,
+ SubmitBLSChangesOnBellatrix: true,
+ },
+
+ BaseWithdrawalsTestSpec{
+ Name: "test-full-withdrawals-bls-to-execution-changes-bellatrix-genesis",
+ Description: `
+ Test BLS-To-Execution-Changes to fully exit validators.
+ `,
+ CapellaGenesis: false,
+ GenesisExecutionWithdrawalCredentialsShares: 2,
+ GenesisExitedShares: 8,
+ GenesisSlashedShares: 8,
+ },
+}
+
+func main() {
+ // Create simulator that runs all tests
+ sim := hivesim.New()
+ // From the simulator we can get all client types provided
+ clientTypes, err := sim.ClientTypes()
+ if err != nil {
+ panic(err)
+ }
+ c := clients.ClientsByRole(clientTypes)
+
+ // Create the test suites
+ engineSuite := hivesim.Suite{
+ Name: "eth2-engine",
+ Description: `Collection of test vectors that use a ExecutionClient+BeaconNode+ValidatorClient testnet.`,
+ }
+
+ // Add all tests to the suites
+ addAllTests(&engineSuite, c, tests)
+
+ // Mark suites for execution
+ hivesim.MustRunSuite(sim, engineSuite)
+}
+
+func addAllTests(
+ suite *hivesim.Suite,
+ c *clients.ClientDefinitionsByRole,
+ tests []TestSpec,
+) {
+ mnemonic := "couple kiwi radio river setup fortune hunt grief buddy forward perfect empty slim wear bounce drift execute nation tobacco dutch chapter festival ice fog"
+
+ clientCombinations := c.Combinations()
+ for _, test := range tests {
+ test := test
+ suite.Add(hivesim.TestSpec{
+ Name: fmt.Sprintf(
+ "%s-%s",
+ test.GetName(),
+ strings.Join(clientCombinations.ClientTypes(), "-"),
+ ),
+ Description: test.GetDescription(),
+ Run: func(t *hivesim.T) {
+ keys := test.GetValidatorKeys(mnemonic)
+ secrets, err := consensus_config.SecretKeys(keys)
+ if err != nil {
+ panic(err)
+ }
+ env := &testnet.Environment{
+ Clients: c,
+ Keys: keys,
+ Secrets: secrets,
+ }
+ test.Execute(t, env, clientCombinations)
+ },
+ },
+ )
+ }
+}
diff --git a/simulators/eth2/withdrawals/scenarios.go b/simulators/eth2/withdrawals/scenarios.go
new file mode 100644
index 0000000000..67871a88c7
--- /dev/null
+++ b/simulators/eth2/withdrawals/scenarios.go
@@ -0,0 +1,215 @@
+package main
+
+import (
+ "bytes"
+ "context"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/hive/hivesim"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
+ tn "github.com/ethereum/hive/simulators/eth2/common/testnet"
+ "github.com/protolambda/eth2api"
+ beacon "github.com/protolambda/zrnt/eth2/beacon/common"
+)
+
+var ConsensusClientsSupportingBLSChangesBeforeCapella = []string{
+ "prysm",
+}
+
+// Generic withdrawals test routine, capable of running most of the test
+// scenarios.
+func (ts BaseWithdrawalsTestSpec) Execute(
+ t *hivesim.T,
+ env *testnet.Environment,
+ n []clients.NodeDefinition,
+) {
+ config := ts.GetTestnetConfig(n)
+ ctx := context.Background()
+
+ testnet := tn.StartTestnet(ctx, t, env, config)
+ defer testnet.Stop()
+
+ blsDomain := ComputeBLSToExecutionDomain(testnet)
+
+ // Get all validators info
+ allValidators, err := ValidatorsFromBeaconState(
+ testnet.GenesisBeaconState(),
+ env.Keys,
+ &blsDomain,
+ )
+ if err != nil {
+ t.Fatalf("FAIL: Error parsing validators from beacon state")
+ }
+ genesisNonWithdrawable := allValidators.NonWithdrawable()
+
+ // Wait for beacon chain genesis to happen
+ testnet.WaitForGenesis(ctx)
+
+ // Wait for 3 slots to pass
+ <-time.After(
+ 3 * time.Second * time.Duration(testnet.Spec().SECONDS_PER_SLOT),
+ )
+
+ if beaconClients := testnet.FilterByCL(ConsensusClientsSupportingBLSChangesBeforeCapella).
+ BeaconClients(); len(
+ beaconClients,
+ ) > 0 &&
+ ts.SubmitBLSChangesOnBellatrix {
+ // If there are clients that support sending BLS to execution
+ // changes in bellatrix, we send half of the changes here
+ if len(genesisNonWithdrawable) > 0 {
+ nonWithdrawableValidators := genesisNonWithdrawable.Chunks(2)[0]
+
+ if len(nonWithdrawableValidators) > 0 {
+ t.Logf(
+ "INFO: Sending %d validators' BLS-to-exec-change on bellatrix",
+ len(nonWithdrawableValidators),
+ )
+ for i := 0; i < len(nonWithdrawableValidators); i++ {
+ b := beaconClients[i%len(beaconClients)]
+ v := nonWithdrawableValidators[i]
+ if err := v.SignSendBLSToExecutionChange(
+ ctx,
+ b,
+ common.Address{byte(v.Index + 0x100)},
+ ); err != nil {
+ t.Fatalf(
+ "FAIL: Unable to submit bls-to-execution changes: %v",
+ err,
+ )
+ }
+ }
+
+ }
+
+ } else {
+ t.Logf("INFO: no validators left on BLS credentials")
+ }
+ } else {
+ t.Logf("INFO: No beacon clients support BLS-To-Execution-Changes on bellatrix, skipping")
+ }
+
+ // Wait for Capella
+ if config.CapellaForkEpoch.Uint64() > 0 {
+ slotsUntilCapella := beacon.Slot(
+ config.CapellaForkEpoch.Uint64(),
+ ) * testnet.Spec().SLOTS_PER_EPOCH
+ testnet.WaitSlots(ctx, slotsUntilCapella)
+ }
+
+ // If there are any remaining validators that cannot withdraw yet, send
+ // them now
+ nonWithdrawableValidators := allValidators.NonWithdrawable()
+ if len(nonWithdrawableValidators) > 0 {
+ beaconClients := testnet.BeaconClients()
+ for i := 0; i < len(nonWithdrawableValidators); i++ {
+ b := beaconClients[i%len(beaconClients)]
+ v := nonWithdrawableValidators[i]
+ if err := v.SignSendBLSToExecutionChange(
+ ctx,
+ b,
+ common.Address{byte(v.Index + 0x100)},
+ ); err != nil {
+ t.Fatalf(
+ "FAIL: Unable to submit bls-to-execution changes: %v",
+ err,
+ )
+ }
+ }
+ } else {
+ t.Logf("INFO: no validators left on BLS credentials")
+ }
+
+ // Wait for all BLS to execution to be included
+ slotsForAllBlsInclusion := beacon.Slot(
+ len(genesisNonWithdrawable)/int(
+ testnet.Spec().MAX_BLS_TO_EXECUTION_CHANGES,
+ ) + 1,
+ )
+ testnet.WaitSlots(ctx, slotsForAllBlsInclusion)
+
+ // Get the beacon state and verify the credentials were updated
+ var versionedBeaconState *clients.VersionedBeaconStateResponse
+ for _, bn := range testnet.BeaconClients().Running() {
+ versionedBeaconState, err = bn.BeaconStateV2ByBlock(
+ ctx,
+ eth2api.BlockHead,
+ )
+ if err != nil || versionedBeaconState == nil {
+ t.Logf("WARN: Unable to get latest beacon state: %v", err)
+ }
+ }
+ if versionedBeaconState == nil {
+ t.Fatalf(
+ "FAIL: Unable to get latest beacon state from any client: %v",
+ err,
+ )
+ }
+
+ validators := versionedBeaconState.Validators()
+ for _, v := range genesisNonWithdrawable {
+ validator := validators[v.Index]
+ credentials := validator.WithdrawalCredentials
+ if !bytes.Equal(
+ credentials[:1],
+ []byte{beacon.ETH1_ADDRESS_WITHDRAWAL_PREFIX},
+ ) {
+ t.Fatalf(
+ "FAIL: Withdrawal credential not updated for validator %d: %v",
+ v.Index,
+ credentials,
+ )
+ }
+ if v.WithdrawAddress == nil {
+ t.Fatalf(
+ "FAIL: BLS-to-execution change was not sent for validator %d",
+ v.Index,
+ )
+ }
+ if !bytes.Equal(v.WithdrawAddress[:], credentials[12:]) {
+ t.Fatalf(
+ "FAIL: Incorrect withdrawal credential for validator %d: want=%x, got=%x",
+ v.Index,
+ v.WithdrawAddress,
+ credentials[12:],
+ )
+ }
+ t.Logf("INFO: Successful BLS to execution change: %s", credentials)
+ }
+
+ // Wait for all validators to withdraw
+ waitSlotsForAllWithdrawals := beacon.Slot(
+ (len(validators)/int(testnet.Spec().MAX_WITHDRAWALS_PER_PAYLOAD) +
+ 5), // Wiggle room
+ )
+ slotCtx, cancel := testnet.Spec().
+ SlotTimeoutContext(ctx, waitSlotsForAllWithdrawals)
+ defer cancel()
+loop:
+ for {
+ select {
+ case <-slotCtx.Done():
+ t.Fatalf("FAIL: Timeout waiting on all accounts to withdraw")
+ case <-time.After(time.Duration(testnet.Spec().SECONDS_PER_SLOT) * time.Second):
+ // Print all info
+ testnet.BeaconClients().Running().PrintStatus(slotCtx, t)
+
+ // Check all accounts
+ for _, ec := range testnet.ExecutionClients().Running() {
+ if allAccountsWithdrawn, err := allValidators.Withdrawable().VerifyWithdrawnBalance(ctx, ec); err != nil {
+ t.Fatalf("FAIL: %v", err)
+ } else if allAccountsWithdrawn {
+ t.Logf("INFO: All accounts have successfully withdrawn")
+ break loop
+ }
+ }
+ }
+ }
+
+ // Lastly check all clients are on the same head
+ testnet.VerifyELHeads(ctx)
+
+ // TODO: Should we wait for finalization every time?
+}
diff --git a/simulators/eth2/withdrawals/specs.go b/simulators/eth2/withdrawals/specs.go
new file mode 100644
index 0000000000..f9594b5af0
--- /dev/null
+++ b/simulators/eth2/withdrawals/specs.go
@@ -0,0 +1,174 @@
+package main
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/hive/simulators/eth2/common/clients"
+ cl "github.com/ethereum/hive/simulators/eth2/common/config/consensus"
+ el "github.com/ethereum/hive/simulators/eth2/common/config/execution"
+ "github.com/ethereum/hive/simulators/eth2/common/testnet"
+ beacon "github.com/protolambda/zrnt/eth2/beacon/common"
+)
+
+type BaseWithdrawalsTestSpec struct {
+ // Spec
+ Name string
+ Description string
+
+ // Testnet Nodes
+ NodeCount int
+ ValidatingNodeCount int
+
+ // Beacon Chain
+ ValidatorCount uint64
+ CapellaGenesis bool
+
+ // Genesis Validators Configuration
+ // (One every Nth validator, 1 means all validators, 2 means half, etc...)
+ GenesisExecutionWithdrawalCredentialsShares int
+ GenesisExitedShares int
+ GenesisSlashedShares int
+
+ // Other Testing Configuration
+ SubmitBLSChangesOnBellatrix bool
+}
+
+var (
+ DEFAULT_VALIDATOR_COUNT uint64 = 128
+ DEFAULT_SLOT_TIME uint64 = 6
+
+ EPOCHS_TO_FINALITY beacon.Epoch = 4
+
+ // Default config used for all tests unless a client specific config exists
+ DEFAULT_CONFIG = &testnet.Config{
+ ValidatorCount: big.NewInt(int64(DEFAULT_VALIDATOR_COUNT)),
+ SlotTime: big.NewInt(int64(DEFAULT_SLOT_TIME)),
+ TerminalTotalDifficulty: common.Big0,
+ AltairForkEpoch: common.Big0,
+ BellatrixForkEpoch: common.Big0,
+ CapellaForkEpoch: common.Big1,
+ Eth1Consensus: &el.ExecutionCliqueConsensus{},
+ }
+
+ // Clients that do not support starting on epoch 0 with all forks enabled.
+ // Tests take longer for these clients.
+ /*
+ INCREMENTAL_FORKS_CONFIG = &testnet.Config{
+ AltairForkEpoch: common.Big0,
+ BellatrixForkEpoch: common.Big0,
+ CapellaForkEpoch: common.Big1,
+ }
+ INCREMENTAL_FORKS_CLIENTS = map[string]bool{
+ "nimbus": true,
+ "prysm": true,
+ }
+ */
+)
+
+func (ts BaseWithdrawalsTestSpec) GetTestnetConfig(
+ allNodeDefinitions []clients.NodeDefinition,
+) *testnet.Config {
+ config := DEFAULT_CONFIG
+
+ /*
+ if INCREMENTAL_FORKS_CLIENTS[n.ConsensusClient] {
+ config = config.Join(INCREMENTAL_FORKS_CONFIG)
+ }
+ */
+
+ if ts.CapellaGenesis {
+ config.CapellaForkEpoch = common.Big0
+ }
+
+ nodeCount := 2
+ if len(allNodeDefinitions) == 0 {
+ panic("incorrect number of node definitions")
+ } else if len(allNodeDefinitions) > 1 {
+ nodeCount = len(allNodeDefinitions)
+ }
+ if ts.NodeCount > 0 {
+ nodeCount = ts.NodeCount
+ }
+ maxValidatingNodeIndex := nodeCount - 1
+ if ts.ValidatingNodeCount > 0 {
+ maxValidatingNodeIndex = ts.ValidatingNodeCount - 1
+ }
+ nodeDefinitions := make(clients.NodeDefinitions, 0)
+ for i := 0; i < nodeCount; i++ {
+ n := allNodeDefinitions[i%len(allNodeDefinitions)]
+ if i <= maxValidatingNodeIndex {
+ n.ValidatorShares = 1
+ } else {
+ n.ValidatorShares = 0
+ }
+ nodeDefinitions = append(nodeDefinitions, n)
+ }
+ return config.Join(&testnet.Config{
+ NodeDefinitions: nodeDefinitions,
+ })
+}
+
+func (ts BaseWithdrawalsTestSpec) CanRun(clients.NodeDefinitions) bool {
+ // Base test specs can always run
+ return true
+}
+
+func (ts BaseWithdrawalsTestSpec) GetName() string {
+ return ts.Name
+}
+
+func (ts BaseWithdrawalsTestSpec) GetDescription() string {
+ return ts.Description
+}
+
+func (ts BaseWithdrawalsTestSpec) GetValidatorCount() uint64 {
+ if ts.ValidatorCount != 0 {
+ return ts.ValidatorCount
+ }
+ return DEFAULT_VALIDATOR_COUNT
+}
+
+func (ts BaseWithdrawalsTestSpec) GetValidatorKeys(
+ mnemonic string,
+) []*cl.KeyDetails {
+ keySrc := &cl.MnemonicsKeySource{
+ From: 0,
+ To: ts.GetValidatorCount(),
+ Validator: mnemonic,
+ Withdrawal: mnemonic,
+ }
+ keys, err := keySrc.Keys()
+ if err != nil {
+ panic(err)
+ }
+
+ for index, key := range keys {
+ // All validators have idiosyncratic balance amounts to identify them
+ key.ExtraInitialBalance = beacon.Gwei(index + 1)
+
+ if ts.GenesisExecutionWithdrawalCredentialsShares > 0 &&
+ (index%ts.GenesisExecutionWithdrawalCredentialsShares) == 0 {
+ key.WithdrawalCredentialType = beacon.ETH1_ADDRESS_WITHDRAWAL_PREFIX
+ key.WithdrawalExecAddress = beacon.Eth1Address{byte(index + 0x100)}
+ }
+ if ts.GenesisExitedShares > 1 && (index%ts.GenesisExitedShares) == 1 {
+ key.Exited = true
+ }
+ if ts.GenesisSlashedShares > 2 &&
+ (index%ts.GenesisSlashedShares) == 2 {
+ key.Slashed = true
+ }
+ fmt.Printf(
+ "INFO: Validator %d, extra_gwei=%d, exited=%v, slashed=%v, key_type=%d\n",
+ index,
+ key.ExtraInitialBalance,
+ key.Exited,
+ key.Slashed,
+ key.WithdrawalCredentialType,
+ )
+ }
+
+ return keys
+}