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 +}