diff --git a/simulators/eth2/common/builder/builder.go b/simulators/eth2/common/builder/builder.go deleted file mode 100644 index 268fd223b2..0000000000 --- a/simulators/eth2/common/builder/builder.go +++ /dev/null @@ -1,17 +0,0 @@ -package builder - -import ( - api "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/common" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" -) - -type Builder interface { - Address() string - Cancel() error - GetBuiltPayloadsCount() int - GetSignedBeaconBlockCount() int - GetSignedBeaconBlocks() map[beacon.Slot]common.SignedBeaconBlock - GetModifiedPayloads() map[beacon.Slot]*api.ExecutableData - GetBuiltPayloads() map[beacon.Slot]*api.ExecutableData -} diff --git a/simulators/eth2/common/builder/mock/README.md b/simulators/eth2/common/builder/mock/README.md deleted file mode 100644 index 4cb2273731..0000000000 --- a/simulators/eth2/common/builder/mock/README.md +++ /dev/null @@ -1,65 +0,0 @@ -## Hive Configurable Builder API Mock Server - -Instantiates a server that listens for Builder API (https://github.com/ethereum/builder-specs/) directives and responds with payloads built using an execution client. - -Currently, the builder will produce payloads with the following correct fields: -- PrevRandao -- Timestamp -- SuggestedFeeRecipient -- Withdrawals - -For the builder to function properly, the following parameters are necessary: -- Execution client: Required to build the payloads -- Beacon client: Required to fetch the state of the previous slot, and calculate, e.g., the prevrandao value - -## Mock Payload Building -The builder can inject modifications into the built payloads at predefined slots by using configurable callbacks: -- Before sending the ForkchoiceUpdated directive to the execution client, by modifying the payload attributes, using `WithPayloadAttributesModifier` option -- Before responding with the build payload to the consensus client by modifying the any field in the payload, using `WithPayloadModifier` option - -Both callbacks are supplied with either the `PayloadAttributesV1`/`PayloadAttributesV2` or the `ExecutionPayloadV1`/`ExecutionPayloadV2` object, and the beacon slot number of the payload request. - -The callbacks must respond with a boolean indicating whether any modification was performed, and an error, if any. - -Predefined invalidation can also be configured by using `WithPayloadInvalidatorAtEpoch`, `WithPayloadInvalidatorAtSlot`, `WithPayloadAttributesInvalidatorAtEpoch` or `WithPayloadAttributesInvalidatorAtSlot`. - -## Payload Invalidation Types -- `state_root`: Inserts a random state root value in the built payload. Payload can only be deemed invalid after the payload has been unblinded -- `parent_hash`: Inserts a random parent hash value in the built payload. Payload can be deemed invalid without needing to unblind -- `coinbase`: Inserts a random address as coinbase in the built payload. Payload is not invalid -- `base_fee`: Increases the base fee value by 1 in the built payload. Payload can only be deemed invalid after the payload has been unblinded -- `uncle_hash`: Inserts a random uncle hash value in the built payload. Payload can be deemed invalid without needing to unblind -- `receipt_hash`: Inserts a random receipt hash value in the built payload. Payload can only be deemed invalid after the payload has been unblinded - -## Payload Attributes Invalidation Types -- `remove_withdrawal`: Removes a withdrawal from the correct list of expected withdrawals -- `extra_withdrawal`: Inserts an extra withdrawal to the correct list of expected withdrawals -- `withdrawal_address`, `withdrawal_amount`, `withdrawal_validator_index`, `withdrawal_index`: Invalidates a single withdrawal from the correct list of expected withdrawals -- `timestamp`: Modifies the expected timestamp value of the block (-2 epochs) -- `prevrandao`/`random`: Modifies the expected prevrandao - -The builder can also be configured to insert an error on: -- `/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}` using `WithErrorOnHeaderRequest` option -- `/eth/v1/builder/blinded_blocks` using `WithErrorOnPayloadReveal` option - -Both callbacks are supplied with the beacon slot number of the payload/blinded block request. - -The callback can then use the slot number to determine whether to throw an error or not. - -## Mock Builder REST API -### Mock Error -- `DELETE` `/mock/errors/payload_request`: Disables errors on `/eth/v1/builder/header/...` -- `POST` `/mock/errors/payload_request`: Enables errors on `/eth/v1/builder/header/...` -- `POST` `/mock/errors/payload_request//{slot/epoch number}`: Enables errors on `/eth/v1/builder/header/...` starting at the slot or epoch specified -- `DELETE` `/mock/errors/payload_reveal`: Disables errors on `/eth/v1/builder/blinded_blocks` -- `POST` `/mock/errors/payload_reveal`: Enables errors on `/eth/v1/builder/blinded_blocks` -- `POST` `/mock/errors/payload_reveal//{slot/epoch number}`: Enables errors on `/eth/v1/builder/blinded_blocks` starting at the slot or epoch specified - -### Mock Built Payloads -- `DELETE` `/mock/invalid/payload_attributes`: Disables any payload attributes modification -- `POST` `/mock/invalid/payload_attributes/{type}`: Enables specified [type](#payload-attributes-invalidation-types) payload attributes modification -- `POST` `/mock/invalid/payload_attributes/{type}//{slot/epoch number}`: Enables specified [type](#payload-attributes-invalidation-types) payload attributes modification starting at the slot or epoch specified - -- `DELETE` `/mock/invalid/payload`: Disables any modification to payload built -- `POST` `/mock/invalid/payload/{type}`: Enables specified [type](#payload-invalidation-types) of modification to payload built -- `POST` `/mock/invalid/payload/{type}//{slot/epoch number}`: Enables specified [type](#payload-invalidation-types) of modification to payload built starting at the slot or epoch specified \ No newline at end of file diff --git a/simulators/eth2/common/builder/mock/mock_builder.go b/simulators/eth2/common/builder/mock/mock_builder.go deleted file mode 100644 index dcc8fc7f8a..0000000000 --- a/simulators/eth2/common/builder/mock/mock_builder.go +++ /dev/null @@ -1,1491 +0,0 @@ -package mock_builder - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "math/rand" - "net" - "net/http" - "strconv" - "sync" - "time" - - api "github.com/ethereum/go-ethereum/beacon/engine" - el_common "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/bellatrix" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/capella" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/common" - "github.com/ethereum/hive/simulators/eth2/common/clients" - "github.com/gorilla/mux" - blsu "github.com/protolambda/bls12-381-util" - "github.com/protolambda/eth2api" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/tree" - "github.com/sirupsen/logrus" -) - -var ( - DOMAIN_APPLICATION_BUILDER = beacon.BLSDomainType{0x00, 0x00, 0x00, 0x01} - EMPTY_HASH = el_common.Hash{} -) - -type MockBuilder struct { - // Execution and consensus clients - el *clients.ExecutionClient - cl *clients.BeaconClient - - // General properties - srv *http.Server - sk *blsu.SecretKey - pk *blsu.Pubkey - pkBeacon beacon.BLSPubkey - builderApiDomain beacon.BLSDomain - - address string - cancel context.CancelFunc - - // Payload/Blocks history maps - suggestedFeeRecipients map[beacon.BLSPubkey]el_common.Address - suggestedFeeRecipientsMutex sync.Mutex - builtPayloads map[beacon.Slot]*api.ExecutableData - builtPayloadsMutex sync.Mutex - modifiedPayloads map[beacon.Slot]*api.ExecutableData - modifiedPayloadsMutex sync.Mutex - validatorPublicKeys map[beacon.Slot]*beacon.BLSPubkey - validatorPublicKeysMutex sync.Mutex - receivedSignedBeaconBlocks map[beacon.Slot]common.SignedBeaconBlock - receivedSignedBeaconBlocksMutex sync.Mutex - signedBeaconBlock map[tree.Root]bool - signedBeaconBlockMutex sync.Mutex - - // Configuration object - cfg *config -} - -const ( - DEFAULT_BUILDER_HOST = "0.0.0.0" - DEFAULT_BUILDER_PORT = 18550 -) - -func NewMockBuilder( - ctx context.Context, - el *clients.ExecutionClient, - cl *clients.BeaconClient, - opts ...Option, -) (*MockBuilder, error) { - if el == nil { - panic(fmt.Errorf("invalid EL provided: nil")) - } - var ( - err error - ) - - m := &MockBuilder{ - el: el, - cl: cl, - - suggestedFeeRecipients: make( - map[beacon.BLSPubkey]el_common.Address, - ), - builtPayloads: make(map[beacon.Slot]*api.ExecutableData), - modifiedPayloads: make(map[beacon.Slot]*api.ExecutableData), - validatorPublicKeys: make(map[beacon.Slot]*beacon.BLSPubkey), - receivedSignedBeaconBlocks: make( - map[beacon.Slot]common.SignedBeaconBlock, - ), - signedBeaconBlock: make(map[tree.Root]bool), - - cfg: &config{ - host: DEFAULT_BUILDER_HOST, - port: DEFAULT_BUILDER_PORT, - }, - } - - for _, o := range opts { - if err = o(m); err != nil { - return nil, err - } - } - - if m.cfg.spec == nil { - return nil, fmt.Errorf("no spec configured") - } - m.builderApiDomain = beacon.ComputeDomain( - DOMAIN_APPLICATION_BUILDER, - m.cfg.spec.GENESIS_FORK_VERSION, - tree.Root{}, - ) - - // builder key (not cryptographically secure) - rand.Seed(time.Now().UTC().UnixNano()) - skByte := [32]byte{} - sk := blsu.SecretKey{} - rand.Read(skByte[:]) - (&sk).Deserialize(&skByte) - m.sk = &sk - if m.pk, err = blsu.SkToPk(m.sk); err != nil { - panic(err) - } - pkBytes := m.pk.Serialize() - copy(m.pkBeacon[:], pkBytes[:]) - - router := mux.NewRouter() - - // Builder API - router.HandleFunc("/eth/v1/builder/validators", m.HandleValidators). - Methods("POST") - router.HandleFunc("/eth/v1/builder/header/{slot:[0-9]+}/{parenthash}/{pubkey}", m.HandleGetExecutionPayloadHeader). - Methods("GET") - router.HandleFunc("/eth/v1/builder/blinded_blocks", m.HandleSubmitBlindedBlock). - Methods("POST") - router.HandleFunc("/eth/v1/builder/status", m.HandleStatus).Methods("GET") - - // Mock customization - // Error on payload request - router.HandleFunc("/mock/errors/payload_request", m.HandleMockDisableErrorOnHeaderRequest). - Methods("DELETE") - router.HandleFunc("/mock/errors/payload_request", m.HandleMockEnableErrorOnHeaderRequest). - Methods("POST") - router.HandleFunc( - "/mock/errors/payload_request/slot/{slot:[0-9]+}", - m.HandleMockEnableErrorOnHeaderRequest, - ).Methods("POST") - router.HandleFunc( - "/mock/errors/payload_request/epoch/{epoch:[0-9]+}", - m.HandleMockEnableErrorOnHeaderRequest, - ).Methods("POST") - - // Error on block submission - router.HandleFunc("/mock/errors/payload_reveal", m.HandleMockDisableErrorOnPayloadReveal). - Methods("DELETE") - router.HandleFunc("/mock/errors/payload_reveal", m.HandleMockEnableErrorOnPayloadReveal). - Methods("POST") - router.HandleFunc( - "/mock/errors/payload_reveal/slot/{slot:[0-9]+}", - m.HandleMockEnableErrorOnPayloadReveal, - ).Methods("POST") - router.HandleFunc( - "/mock/errors/payload_reveal/epoch/{epoch:[0-9]+}", - m.HandleMockEnableErrorOnPayloadReveal, - ).Methods("POST") - - // Invalidate payload attributes - router.HandleFunc("/mock/invalid/payload_attributes", m.HandleMockDisableInvalidatePayloadAttributes). - Methods("DELETE") - router.HandleFunc( - "/mock/invalid/payload_attributes/{type}", - m.HandleMockEnableInvalidatePayloadAttributes, - ).Methods("POST") - router.HandleFunc( - "/mock/invalid/payload_attributes/{type}/slot/{slot:[0-9]+}", - m.HandleMockEnableInvalidatePayloadAttributes, - ).Methods("POST") - router.HandleFunc( - "/mock/invalid/payload_attributes/{type}/epoch/{epoch:[0-9]+}", - m.HandleMockEnableInvalidatePayloadAttributes, - ).Methods("POST") - - // Invalidate payload - router.HandleFunc("/mock/invalid/payload", m.HandleMockDisableInvalidatePayload). - Methods("DELETE") - router.HandleFunc( - "/mock/invalid/payload/{type}", - m.HandleMockEnableInvalidatePayload, - ).Methods("POST") - router.HandleFunc( - "/mock/invalid/payload/{type}/slot/{slot:[0-9]+}", - m.HandleMockEnableInvalidatePayload, - ).Methods("POST") - router.HandleFunc( - "/mock/invalid/payload/{type}/epoch/{epoch:[0-9]+}", - m.HandleMockEnableInvalidatePayload, - ).Methods("POST") - - m.srv = &http.Server{ - Handler: router, - Addr: fmt.Sprintf("%s:%d", m.cfg.host, m.cfg.port), - } - - ctx, cancel := context.WithCancel(ctx) - go func() { - if err := m.Start(ctx); err != nil && err != context.Canceled { - panic(err) - } - }() - m.cancel = cancel - - return m, nil -} - -func (m *MockBuilder) Cancel() error { - if m.cancel != nil { - m.cancel() - } - return nil -} - -func (m *MockBuilder) DefaultBuilderBidVersionResolver( - slot beacon.Slot, -) (builderBid common.BuilderBid, version string, err error) { - if m.cfg.spec.SlotToEpoch(slot) >= m.cfg.spec.CAPELLA_FORK_EPOCH { - return &capella.BuilderBid{}, "capella", nil - } else if m.cfg.spec.SlotToEpoch(slot) >= m.cfg.spec.BELLATRIX_FORK_EPOCH { - return &bellatrix.BuilderBid{}, "bellatrix", nil - } - return nil, "", fmt.Errorf("payload requested from improper fork") -} - -// Start a proxy server. -func (m *MockBuilder) Start(ctx context.Context) error { - m.srv.BaseContext = func(listener net.Listener) context.Context { - return ctx - } - var ( - el_address = "unknown yet" - cl_address = "unknown yet" - ) - - if addr, err := m.el.EngineRPCAddress(); err == nil { - el_address = addr - } - if addr, err := m.cl.BeaconAPIURL(); err == nil { - cl_address = addr - } - fields := logrus.Fields{ - "builder_id": m.cfg.id, - "address": m.address, - "port": m.cfg.port, - "pubkey": m.pkBeacon.String(), - "el_address": el_address, - "cl_address": cl_address, - } - if m.cfg.extraDataWatermark != "" { - fields["extra-data"] = m.cfg.extraDataWatermark - } - logrus.WithFields(fields).Info("Builder now listening") - go func() { - if err := m.srv.ListenAndServe(); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Error(err) - } - }() - for { - <-ctx.Done() - return m.srv.Shutdown(ctx) - } -} - -func (m *MockBuilder) Address() string { - return fmt.Sprintf( - "http://%s@%v:%d", - m.pkBeacon.String(), - m.cfg.externalIP, - m.cfg.port, - ) -} - -func (m *MockBuilder) GetBuiltPayloadsCount() int { - return len(m.builtPayloads) -} - -func (m *MockBuilder) GetSignedBeaconBlockCount() int { - return len(m.signedBeaconBlock) -} - -func (m *MockBuilder) GetBuiltPayloads() map[beacon.Slot]*api.ExecutableData { - mapCopy := make(map[beacon.Slot]*api.ExecutableData) - for k, v := range m.builtPayloads { - mapCopy[k] = v - } - return mapCopy -} - -func (m *MockBuilder) GetModifiedPayloads() map[beacon.Slot]*api.ExecutableData { - mapCopy := make(map[beacon.Slot]*api.ExecutableData) - for k, v := range m.modifiedPayloads { - mapCopy[k] = v - } - return mapCopy -} - -func (m *MockBuilder) GetSignedBeaconBlocks() map[beacon.Slot]common.SignedBeaconBlock { - m.receivedSignedBeaconBlocksMutex.Lock() - defer m.receivedSignedBeaconBlocksMutex.Unlock() - mapCopy := make(map[beacon.Slot]common.SignedBeaconBlock) - for k, v := range m.receivedSignedBeaconBlocks { - mapCopy[k] = v - } - return mapCopy -} - -func (m *MockBuilder) HandleValidators( - w http.ResponseWriter, - req *http.Request, -) { - requestBytes, err := ioutil.ReadAll(req.Body) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to read request body") - http.Error(w, "Unable to read request body", http.StatusBadRequest) - return - } - var signedValidatorRegistrations []common.SignedValidatorRegistrationV1 - if err := json.Unmarshal(requestBytes, &signedValidatorRegistrations); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request body") - http.Error(w, "Unable to parse request body", http.StatusBadRequest) - return - } - - for _, vr := range signedValidatorRegistrations { - // Verify signature - signingRoot := beacon.ComputeSigningRoot( - vr.Message.HashTreeRoot(tree.GetHashFn()), - m.builderApiDomain, - ) - - pk, err := vr.Message.PubKey.Pubkey() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to deserialize pubkey") - http.Error( - w, - "Unable to deserialize pubkey", - http.StatusBadRequest, - ) - return - } - - sig, err := vr.Signature.Signature() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to deserialize signature") - http.Error( - w, - "Unable to deserialize signature", - http.StatusBadRequest, - ) - return - } - - if !blsu.Verify(pk, signingRoot[:], sig) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "pubkey": vr.Message.PubKey, - "fee_recipient": vr.Message.FeeRecipient, - "timestamp": vr.Message.Timestamp, - "gas_limit": vr.Message.GasLimit, - "signature": vr.Signature, - }).Error("Unable to verify signature") - http.Error( - w, - "Unable to verify signature", - http.StatusBadRequest, - ) - return - } - var addr el_common.Address - copy(addr[:], vr.Message.FeeRecipient[:]) - m.suggestedFeeRecipientsMutex.Lock() - m.suggestedFeeRecipients[vr.Message.PubKey] = addr - m.suggestedFeeRecipientsMutex.Unlock() - } - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "validator_count": len(signedValidatorRegistrations), - }).Info( - "Received validator registrations", - ) - w.WriteHeader(http.StatusOK) - -} - -func (m *MockBuilder) SlotToTimestamp(slot beacon.Slot) uint64 { - return uint64( - m.cfg.beaconGenesisTime + beacon.Timestamp( - slot, - )*beacon.Timestamp( - m.cfg.spec.SECONDS_PER_SLOT, - ), - ) -} - -type PayloadHeaderRequestVarsParser map[string]string - -func (vars PayloadHeaderRequestVarsParser) Slot() (slot beacon.Slot, err error) { - if slotStr, ok := vars["slot"]; ok { - err = (&slot).UnmarshalJSON([]byte(slotStr)) - } else { - err = fmt.Errorf("no slot") - } - return slot, err -} - -func (vars PayloadHeaderRequestVarsParser) PubKey() (pubkey beacon.BLSPubkey, err error) { - if pubkeyStr, ok := vars["pubkey"]; ok { - err = (&pubkey).UnmarshalText([]byte(pubkeyStr)) - } else { - err = fmt.Errorf("no pubkey") - } - return pubkey, err -} - -func (vars PayloadHeaderRequestVarsParser) ParentHash() (el_common.Hash, error) { - if parentHashStr, ok := vars["parenthash"]; ok { - return el_common.HexToHash(parentHashStr), nil - } - return el_common.Hash{}, fmt.Errorf("no parent_hash") -} - -func (m *MockBuilder) HandleGetExecutionPayloadHeader( - w http.ResponseWriter, req *http.Request, -) { - var ( - prevRandao el_common.Hash - payloadModified = false - vars = PayloadHeaderRequestVarsParser(mux.Vars(req)) - ) - - slot, err := vars.Slot() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request url") - http.Error( - w, - "Unable to parse request url", - http.StatusBadRequest, - ) - return - } - - parentHash, err := vars.ParentHash() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request url") - http.Error( - w, - "Unable to parse request url", - http.StatusBadRequest, - ) - return - } - - pubkey, err := vars.PubKey() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request url") - http.Error( - w, - "Unable to parse request url", - http.StatusBadRequest, - ) - return - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - "parent_hash": parentHash, - "pubkey": pubkey, - }).Info( - "Received request for header", - ) - // Save the validator public key - m.validatorPublicKeysMutex.Lock() - m.validatorPublicKeys[slot] = &pubkey - m.validatorPublicKeysMutex.Unlock() - // Request head state from the CL - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - state, err := m.cl.BeaconStateV2(ctx, eth2api.StateHead) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - "err": err, - }).Error("Error getting beacon state from CL") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - var forkchoiceState *api.ForkchoiceStateV1 - if bytes.Equal(parentHash[:], EMPTY_HASH[:]) { - // Edge case where the CL is requesting us to build the very first block - ctx, cancel = context.WithTimeout(context.Background(), time.Second) - defer cancel() - genesis, err := m.el.BlockByNumber(ctx, nil) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error getting latest block from the EL") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - forkchoiceState = &api.ForkchoiceStateV1{ - HeadBlockHash: genesis.Hash(), - } - } else { - // Check if we have the correct beacon state - latestExecPayloadHeaderHash := state.LatestExecutionPayloadHeaderHash() - if !bytes.Equal(latestExecPayloadHeaderHash[:], parentHash[:]) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "latestExecPayloadHeaderHash": latestExecPayloadHeaderHash.String(), - "parentHash": parentHash.String(), - "err": "beacon state latest execution payload hash and parent hash requested don't match", - }).Error("Unable to respond to header request") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Check if we know the latest forkchoice updated - forkchoiceState, err = m.el.GetLatestForkchoiceUpdated(context.Background()) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("error getting the latest forkchoiceUpdated") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } else if forkchoiceState == nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Error("unable to get the latest forkchoiceUpdated") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } else if bytes.Equal(forkchoiceState.HeadBlockHash[:], EMPTY_HASH[:]) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Error("latest forkchoiceUpdated contains zero'd head") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Check if the requested parent matches the last fcu - if !bytes.Equal(forkchoiceState.HeadBlockHash[:], parentHash[:]) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": "last fcu head and requested parent don't match", - }).Error("Unable to respond to header request") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - } - - // Build payload attributes - - // PrevRandao - prevRandaoMixes := state.RandaoMixes() - prevRandaoRoot := prevRandaoMixes[m.cfg.spec.SlotToEpoch(slot-1)] - copy(prevRandao[:], prevRandaoRoot[:]) - - // Timestamp - timestamp := m.SlotToTimestamp(slot) - - // Suggested Fee Recipient - suggestedFeeRecipient := m.suggestedFeeRecipients[pubkey] - - // Withdrawals - var withdrawals types.Withdrawals - if m.cfg.spec.SlotToEpoch(slot) >= m.cfg.spec.CAPELLA_FORK_EPOCH { - wSsz, err := state.NextWithdrawals(slot) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to obtain correct list of withdrawals") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - withdrawals = make(types.Withdrawals, len(wSsz)) - for i, w := range wSsz { - newWithdrawal := types.Withdrawal{} - copy(newWithdrawal.Address[:], w.Address[:]) - newWithdrawal.Amount = uint64(w.Amount) - newWithdrawal.Index = uint64(w.Index) - newWithdrawal.Validator = uint64(w.ValidatorIndex) - withdrawals[i] = &newWithdrawal - } - } - - pAttr := api.PayloadAttributes{ - Timestamp: timestamp, - Random: prevRandao, - SuggestedFeeRecipient: suggestedFeeRecipient, - Withdrawals: withdrawals, - } - - m.cfg.mutex.Lock() - payloadAttrModifier := m.cfg.payloadAttrModifier - m.cfg.mutex.Unlock() - if payloadAttrModifier != nil { - if mod, err := payloadAttrModifier(&pAttr, slot); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to modify payload attributes using modifier") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } else if mod { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - }).Info("Modified payload attributes") - payloadModified = true - } - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "Timestamp": timestamp, - "PrevRandao": prevRandao, - "SuggestedFeeRecipient": suggestedFeeRecipient, - "Withdrawals": withdrawals, - }).Info("Built payload attributes for header") - - // Request a payload from the execution client - ctx, cancel = context.WithTimeout(context.Background(), time.Second) - defer cancel() - r, err := m.el.EngineForkchoiceUpdated( - ctx, - forkchoiceState, - &pAttr, - 2, - ) - if err != nil || r.PayloadID == nil { - fcuJson, _ := json.MarshalIndent(forkchoiceState, "", " ") - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - "forkchoiceState": string(fcuJson), - "payloadID": r.PayloadID, - }).Error("Error on ForkchoiceUpdated to EL") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Wait for EL to produce payload - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "payloadID": r.PayloadID.String(), - }).Info("Waiting for payload from EL") - - time.Sleep(200 * time.Millisecond) - - // Request payload from the EL - ctx, cancel = context.WithTimeout(context.Background(), time.Second) - defer cancel() - p, bValue, err := m.el.EngineGetPayload(ctx, r.PayloadID, 2) - if err != nil || p == nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - "payload": p, - }).Error("Error on GetPayload to EL") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Watermark payload - if m.cfg.extraDataWatermark != "" { - if err := ModifyExtraData(p, []byte(m.cfg.extraDataWatermark)); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error modifying payload") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - } - - // Modify the payload if necessary - m.cfg.mutex.Lock() - payloadModifier := m.cfg.payloadModifier - m.cfg.mutex.Unlock() - if payloadModifier != nil { - oldHash := p.BlockHash - if mod, err := payloadModifier(p, slot); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error modifying payload") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } else if mod { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - "previous_hash": oldHash.String(), - "new_hash": p.BlockHash.String(), - }).Info("Modified payload") - payloadModified = true - } - } - - // We are ready to respond to the CL - var ( - builderBid common.BuilderBid - version string - ) - - m.cfg.mutex.Lock() - builderBidVersionResolver := m.cfg.builderBidVersionResolver - m.cfg.mutex.Unlock() - if builderBidVersionResolver == nil { - builderBidVersionResolver = m.DefaultBuilderBidVersionResolver - } - - builderBid, version, err = builderBidVersionResolver(slot) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error getting builder bid version") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - if err := builderBid.FromExecutableData(m.cfg.spec, p); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error building bid from execution data") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - if m.cfg.payloadWeiValueModifier != nil { - // If requested, fake a higher gwei so the CL always takes the bid - bValue, err = m.cfg.payloadWeiValueModifier(bValue) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error modifiying bid") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - } - builderBid.SetValue(bValue) - builderBid.SetPubKey(m.pkBeacon) - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "payload": p.BlockHash.String(), - "value": bValue.String(), - }).Info("Built payload from EL") - - signedBid, err := builderBid.Sign(m.builderApiDomain, m.sk, m.pk) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error signing bid from execution data") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Check if we are supposed to simulate an error - m.cfg.mutex.Lock() - errOnHeadeReq := m.cfg.errorOnHeaderRequest - m.cfg.mutex.Unlock() - if errOnHeadeReq != nil { - if err := errOnHeadeReq(slot); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - "err": err, - }).Error("Simulated error") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - } - - versionedSignedBid := signedBid.Versioned(version) - if err := serveJSON(w, versionedSignedBid); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error versioning bid from execution data") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - - // Finally add the execution payload to the cache - m.builtPayloadsMutex.Lock() - m.builtPayloads[slot] = p - m.builtPayloadsMutex.Unlock() - if payloadModified { - m.modifiedPayloadsMutex.Lock() - m.modifiedPayloads[slot] = p - m.modifiedPayloadsMutex.Unlock() - } -} - -type SlotEnvelope struct { - Slot beacon.Slot `json:"slot" yaml:"slot"` -} - -type MessageSlotEnvelope struct { - SlotEnvelope SlotEnvelope `json:"message" yaml:"message"` -} - -func (m *MockBuilder) HandleSubmitBlindedBlock( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received submission for blinded blocks", - ) - requestBytes, err := ioutil.ReadAll(req.Body) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to read request body") - http.Error(w, "Unable to read request body", http.StatusBadRequest) - return - } - - // First try to find out the slot to get the version of the block - var messageSlotEnvelope MessageSlotEnvelope - if err := json.Unmarshal(requestBytes, &messageSlotEnvelope); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request body") - http.Error(w, "Unable to parse request body", http.StatusBadRequest) - return - } - - var ( - signedBeaconBlock common.SignedBeaconBlock - executionPayloadResp common.ExecutionPayloadResponse - ) - if m.cfg.spec.SlotToEpoch( - messageSlotEnvelope.SlotEnvelope.Slot, - ) >= m.cfg.spec.CAPELLA_FORK_EPOCH { - signedBeaconBlock = &capella.SignedBeaconBlock{} - executionPayloadResp.Version = "capella" - executionPayloadResp.Data = &capella.ExecutionPayload{} - } else if m.cfg.spec.SlotToEpoch(messageSlotEnvelope.SlotEnvelope.Slot) >= m.cfg.spec.BELLATRIX_FORK_EPOCH { - signedBeaconBlock = &bellatrix.SignedBeaconBlock{} - executionPayloadResp.Version = "bellatrix" - executionPayloadResp.Data = &bellatrix.ExecutionPayload{} - } else { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": fmt.Errorf("received signed beacon blinded block of unknown fork"), - }).Error("Invalid slot requested") - http.Error( - w, - "Unable to respond to header request", - http.StatusBadRequest, - ) - return - } - // Unmarshall the full signed beacon block - if err := json.Unmarshal(requestBytes, &signedBeaconBlock); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse request body") - http.Error(w, "Unable to parse request body", http.StatusBadRequest) - return - } - - // Look up the payload in the history of payloads - p, ok := m.builtPayloads[messageSlotEnvelope.SlotEnvelope.Slot] - if !ok { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - }).Error("Could not find payload in history") - http.Error(w, "Unable to get payload", http.StatusInternalServerError) - return - } - - // Prepare response - executionPayloadResp.Data.FromExecutableData(p) - - // Embed the execution payload in the block to obtain correct root - signedBeaconBlock.SetExecutionPayload( - executionPayloadResp.Data, - ) - - // Record the signed beacon block - signedBeaconBlockRoot := signedBeaconBlock.Root(m.cfg.spec) - m.signedBeaconBlockMutex.Lock() - m.signedBeaconBlock[signedBeaconBlockRoot] = true - m.signedBeaconBlockMutex.Unlock() - m.receivedSignedBeaconBlocksMutex.Lock() - m.receivedSignedBeaconBlocks[signedBeaconBlock.Slot()] = signedBeaconBlock - m.receivedSignedBeaconBlocksMutex.Unlock() - - // Verify signature - pubkey := m.validatorPublicKeys[signedBeaconBlock.Slot()] - if pubkey == nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - }).Error("Could not find public key in history") - http.Error( - w, - "Unable to validate signature", - http.StatusInternalServerError, - ) - return - } - if pk, err := pubkey.Pubkey(); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - }).Error("Could not convert public key") - http.Error( - w, - "Unable to validate signature", - http.StatusInternalServerError, - ) - return - } else { - root := signedBeaconBlock.Root(m.cfg.spec) - sig := signedBeaconBlock.BlockSignature() - s, err := sig.Signature() - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - "signature": signedBeaconBlock.BlockSignature().String(), - }).Error("Unable to validate signature") - http.Error( - w, - "Unable to validate signature", - http.StatusInternalServerError, - ) - return - } - - dom := beacon.ComputeDomain(beacon.DOMAIN_BEACON_PROPOSER, m.cfg.spec.ForkVersion(signedBeaconBlock.Slot()), *m.cl.Config.GenesisValidatorsRoot) - signingRoot := beacon.ComputeSigningRoot(root, dom) - if !blsu.Verify(pk, signingRoot[:], s) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - "pubkey": pubkey.String(), - "signature": signedBeaconBlock.BlockSignature().String(), - }).Error("invalid signature") - http.Error( - w, - "Invalid signature", - http.StatusInternalServerError, - ) - return - } - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "root": signedBeaconBlock.Root(m.cfg.spec).String(), - "stateRoot": signedBeaconBlock.StateRoot().String(), - "slot": signedBeaconBlock.Slot().String(), - "publicKey": pubkey.String(), - "signature": signedBeaconBlock.BlockSignature().String(), - }).Info("Received signed beacon block") - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "payload": p.BlockHash.String(), - }).Info("Built payload sent to CL") - - // Check if we are supposed to simulate an error - m.cfg.mutex.Lock() - errOnPayloadReveal := m.cfg.errorOnPayloadReveal - m.cfg.mutex.Unlock() - if errOnPayloadReveal != nil { - if err := errOnPayloadReveal(messageSlotEnvelope.SlotEnvelope.Slot); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": messageSlotEnvelope.SlotEnvelope.Slot, - "err": err, - }).Error("Simulated error") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } - } - - if err := serveJSON(w, executionPayloadResp); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Error preparing response from payload") - http.Error( - w, - "Unable to respond to header request", - http.StatusInternalServerError, - ) - return - } -} - -func (m *MockBuilder) HandleStatus( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received request for status", - ) - w.WriteHeader(http.StatusOK) -} - -// mock builder options handlers -func (m *MockBuilder) parseSlotEpochRequest( - vars map[string]string, -) (slot beacon.Slot, errcode int, err error) { - if slotStr, ok := vars["slot"]; ok { - var slotInt uint64 - if slotInt, err = strconv.ParseUint(slotStr, 10, 64); err != nil { - errcode = http.StatusBadRequest - return - } else { - slot = beacon.Slot(slotInt) - } - } else if epochStr, ok := vars["epoch"]; ok { - var epoch uint64 - if epoch, err = strconv.ParseUint(epochStr, 10, 64); err != nil { - errcode = http.StatusBadRequest - return - } else { - if m.cfg.spec == nil { - err = fmt.Errorf("unable to respond: spec not ready") - errcode = http.StatusInternalServerError - return - } - slot, err = m.cfg.spec.EpochStartSlot(beacon.Epoch(epoch)) - if err != nil { - errcode = http.StatusInternalServerError - return - } - } - } - return -} - -func (m *MockBuilder) HandleMockDisableErrorOnHeaderRequest( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received request to disable error on payload request", - ) - - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.errorOnHeaderRequest = nil - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockEnableErrorOnHeaderRequest( - w http.ResponseWriter, req *http.Request, -) { - var ( - vars = mux.Vars(req) - ) - - slot, code, err := m.parseSlotEpochRequest(vars) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse slot/epoch in request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - }).Info( - "Received request to enable error on payload request", - ) - - if err = WithErrorOnHeaderRequestAtSlot(slot)(m); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to respond request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockDisableErrorOnPayloadReveal( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received request to disable error on payload reveal", - ) - - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.errorOnPayloadReveal = nil - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockEnableErrorOnPayloadReveal( - w http.ResponseWriter, req *http.Request, -) { - var ( - vars = mux.Vars(req) - ) - - slot, code, err := m.parseSlotEpochRequest(vars) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse slot/epoch in request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "slot": slot, - }).Info( - "Received request to enable error on payload reveal", - ) - - if err = WithErrorOnPayloadRevealAtSlot(slot)(m); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to respond request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockDisableInvalidatePayloadAttributes( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received request to disable invalidation of payload attributes", - ) - - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadAttrModifier = nil - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockEnableInvalidatePayloadAttributes( - w http.ResponseWriter, req *http.Request, -) { - var ( - vars = mux.Vars(req) - invTyp PayloadAttributesInvalidation - ) - - slot, code, err := m.parseSlotEpochRequest(vars) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse slot/epoch in request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - if typeStr, ok := vars["type"]; !ok { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Error("Unable to parse request url: missing type var") - http.Error( - w, - "Unable to parse request url: missing type var", - http.StatusBadRequest, - ) - return - } else if invTyp, ok = PayloadAttrInvalidationTypes[typeStr]; !ok { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "type": typeStr, - }).Error("Unable to parse request url: unknown invalidity type") - http.Error( - w, - fmt.Sprintf("Unable to parse request url: unknown invalidity type: %s", typeStr), - http.StatusBadRequest, - ) - return - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "type": invTyp, - "slot": slot, - }).Info( - "Received request to enable payload attributes invalidation", - ) - - if err = WithPayloadAttributesInvalidatorAtSlot(slot, invTyp)(m); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to enable payload attr invalidation") - http.Error( - w, - "Unable to enable payload attr invalidation", - http.StatusInternalServerError, - ) - return - } - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockDisableInvalidatePayload( - w http.ResponseWriter, req *http.Request, -) { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Info( - "Received request to disable invalidation of payload", - ) - - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadModifier = nil - - w.WriteHeader(http.StatusOK) -} - -func (m *MockBuilder) HandleMockEnableInvalidatePayload( - w http.ResponseWriter, req *http.Request, -) { - var ( - vars = mux.Vars(req) - invTyp PayloadInvalidation - ) - - slot, code, err := m.parseSlotEpochRequest(vars) - if err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to parse slot/epoch in request") - http.Error( - w, - fmt.Sprintf("Unable to respond request: %v", err), - code, - ) - return - } - - if typeStr, ok := vars["type"]; !ok { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - }).Error("Unable to parse request url: missing type var") - http.Error( - w, - "Unable to parse request url: missing type var", - http.StatusBadRequest, - ) - return - } else if invTyp, ok = PayloadInvalidationTypes[typeStr]; !ok { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "type": typeStr, - }).Error("Unable to parse request url: unknown invalidity type") - http.Error( - w, - fmt.Sprintf("Unable to parse request url: unknown invalidity type: %s", typeStr), - http.StatusBadRequest, - ) - return - } - - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "type": invTyp, - "slot": slot, - }).Info( - "Received request to enable payload attributes invalidation", - ) - - if err = WithPayloadInvalidatorAtSlot(slot, invTyp)(m); err != nil { - logrus.WithFields(logrus.Fields{ - "builder_id": m.cfg.id, - "err": err, - }).Error("Unable to enable payload attr invalidation") - http.Error( - w, - "Unable to enable payload attr invalidation", - http.StatusInternalServerError, - ) - return - } - - w.WriteHeader(http.StatusOK) -} - -// helpers - -func serveJSON(w http.ResponseWriter, value interface{}) error { - resp, err := json.Marshal(value) - if err != nil { - return err - } - w.Header().Set("content-type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(resp) - return nil -} - -func ModifyExtraData(p *api.ExecutableData, newExtraData []byte) error { - if p == nil { - return fmt.Errorf("nil payload") - } - if b, err := api.ExecutableDataToBlock(*p); err != nil { - return err - } else { - h := b.Header() - h.Extra = newExtraData - p.ExtraData = newExtraData - p.BlockHash = h.Hash() - } - return nil -} diff --git a/simulators/eth2/common/builder/mock/options.go b/simulators/eth2/common/builder/mock/options.go deleted file mode 100644 index 31586b8d35..0000000000 --- a/simulators/eth2/common/builder/mock/options.go +++ /dev/null @@ -1,533 +0,0 @@ -package mock_builder - -import ( - "fmt" - "math/big" - "math/rand" - "net" - "sync" - - api "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/bellatrix" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/common" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" -) - -type PayloadAttributesModifier func(*api.PayloadAttributes, beacon.Slot) (bool, error) -type PayloadModifier func(*api.ExecutableData, beacon.Slot) (bool, error) -type ErrorProducer func(beacon.Slot) error -type PayloadWeiBidModifier func(*big.Int) (*big.Int, error) -type GetBuilderBidVersion func(beacon.Slot) (common.BuilderBid, string, error) - -type config struct { - id int - port int - host string - extraDataWatermark string - spec *beacon.Spec - externalIP net.IP - beaconGenesisTime beacon.Timestamp - payloadWeiValueModifier PayloadWeiBidModifier - - payloadAttrModifier PayloadAttributesModifier - payloadModifier PayloadModifier - errorOnHeaderRequest ErrorProducer - errorOnPayloadReveal ErrorProducer - - builderBidVersionResolver GetBuilderBidVersion - - mutex sync.Mutex -} - -type Option func(m *MockBuilder) error - -func WithID(id int) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.id = id - return nil - } -} - -func WithHost(host string) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.host = host - return nil - } -} - -func WithPort(port int) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.port = port - return nil - } -} - -func WithExtraDataWatermark(wm string) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.extraDataWatermark = wm - return nil - } -} - -func WithExternalIP(ip net.IP) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.externalIP = ip - return nil - } -} - -func WithSpec(spec *beacon.Spec) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.spec = spec - return nil - } -} - -func WithBeaconGenesisTime(t beacon.Timestamp) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.beaconGenesisTime = t - return nil - } -} - -func WithPayloadWeiValueBump(bump *big.Int) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadWeiValueModifier = func(orig *big.Int) (*big.Int, error) { - ret := new(big.Int).Set(orig) - ret.Add(ret, bump) - return ret, nil - } - return nil - } -} - -func WithPayloadWeiValueMultiplier(mult *big.Int) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadWeiValueModifier = func(orig *big.Int) (*big.Int, error) { - ret := new(big.Int).Set(orig) - ret.Mul(ret, mult) - return ret, nil - } - return nil - } -} - -func WithPayloadAttributesModifier(pam PayloadAttributesModifier) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadAttrModifier = pam - return nil - } -} - -func WithPayloadModifier(pm PayloadModifier) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.payloadModifier = pm - return nil - } -} - -func WithErrorOnHeaderRequest(e ErrorProducer) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.errorOnHeaderRequest = e - return nil - } -} - -func WithErrorOnHeaderRequestAtEpoch(epoch beacon.Epoch) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - var spec = m.cfg.spec - if spec == nil { - return fmt.Errorf("unknown spec") - } - startSlot, err := spec.EpochStartSlot(epoch) - if err != nil { - return err - } - - m.cfg.errorOnHeaderRequest = func(s beacon.Slot) error { - if s >= startSlot { - return fmt.Errorf("error generator") - } - - return nil - } - return nil - } -} - -func WithErrorOnHeaderRequestAtSlot(slot beacon.Slot) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.errorOnHeaderRequest = func(s beacon.Slot) error { - if s >= slot { - return fmt.Errorf("error generator") - } - return nil - } - return nil - } -} - -func WithErrorOnPayloadReveal(e ErrorProducer) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.errorOnPayloadReveal = e - return nil - } -} - -func WithErrorOnPayloadRevealAtEpoch(epoch beacon.Epoch) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - var spec = m.cfg.spec - if spec == nil { - return fmt.Errorf("unknown spec") - } - startSlot, err := spec.EpochStartSlot(epoch) - if err != nil { - return err - } - - m.cfg.errorOnPayloadReveal = func(s beacon.Slot) error { - if s >= startSlot { - return fmt.Errorf("error generator") - } - return nil - } - return nil - } -} - -func WithErrorOnPayloadRevealAtSlot(slot beacon.Slot) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - m.cfg.errorOnPayloadReveal = func(s beacon.Slot) error { - if s >= slot { - return fmt.Errorf("error generator") - } - return nil - } - return nil - } -} - -// Specific function modifiers - -type PayloadInvalidation string - -const ( - INVALIDATE_PAYLOAD_STATE_ROOT = "state_root" - INVALIDATE_PAYLOAD_PARENT_HASH = "parent_hash" - INVALIDATE_PAYLOAD_COINBASE = "coinbase" - INVALIDATE_PAYLOAD_BASE_FEE = "base_fee" - INVALIDATE_PAYLOAD_UNCLE_HASH = "uncle_hash" - INVALIDATE_PAYLOAD_RECEIPT_HASH = "receipt_hash" -) - -var PayloadInvalidationTypes = map[string]PayloadInvalidation{ - INVALIDATE_PAYLOAD_STATE_ROOT: INVALIDATE_PAYLOAD_STATE_ROOT, - INVALIDATE_PAYLOAD_PARENT_HASH: INVALIDATE_PAYLOAD_PARENT_HASH, - INVALIDATE_PAYLOAD_COINBASE: INVALIDATE_PAYLOAD_COINBASE, - INVALIDATE_PAYLOAD_BASE_FEE: INVALIDATE_PAYLOAD_BASE_FEE, - INVALIDATE_PAYLOAD_UNCLE_HASH: INVALIDATE_PAYLOAD_UNCLE_HASH, - INVALIDATE_PAYLOAD_RECEIPT_HASH: INVALIDATE_PAYLOAD_RECEIPT_HASH, -} - -func PayloadInvalidationTypeNames() []string { - res := make([]string, len(PayloadInvalidationTypes)) - i := 0 - for k := range PayloadInvalidationTypes { - res[i] = k - i += 1 - } - return res -} - -func genPayloadInvalidator( - slot beacon.Slot, - invType PayloadInvalidation, -) func(*api.ExecutableData, beacon.Slot) (bool, error) { - return func(ed *api.ExecutableData, s beacon.Slot) (bool, error) { - if s >= slot { - if b, err := api.ExecutableDataToBlock(*ed); err != nil { - return false, err - } else { - header := b.Header() - - switch invType { - case INVALIDATE_PAYLOAD_STATE_ROOT: - rand.Read(header.Root[:]) - copy(ed.StateRoot[:], header.Root[:]) - case INVALIDATE_PAYLOAD_PARENT_HASH: - rand.Read(header.ParentHash[:]) - copy(ed.ParentHash[:], header.ParentHash[:]) - case INVALIDATE_PAYLOAD_COINBASE: - rand.Read(header.Coinbase[:]) - copy(ed.FeeRecipient[:], header.Coinbase[:]) - case INVALIDATE_PAYLOAD_BASE_FEE: - header.BaseFee.Add(header.BaseFee, big.NewInt(1)) - ed.BaseFeePerGas = header.BaseFee - case INVALIDATE_PAYLOAD_UNCLE_HASH: - rand.Read(header.UncleHash[:]) - case INVALIDATE_PAYLOAD_RECEIPT_HASH: - rand.Read(header.ReceiptHash[:]) - copy(ed.ReceiptsRoot[:], header.ReceiptHash[:]) - default: - panic(fmt.Errorf( - "unknown invalidation type: %s", - invType, - )) - } - modifiedHash := header.Hash() - copy(ed.BlockHash[:], modifiedHash[:]) - return true, nil - } - } - return false, nil - } -} - -func WithPayloadInvalidatorAtEpoch( - epoch beacon.Epoch, - invType PayloadInvalidation, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - if m.cfg.spec == nil { - return fmt.Errorf("unknown spec") - } - startSlot, err := m.cfg.spec.EpochStartSlot(epoch) - if err != nil { - return err - } - - pm := genPayloadInvalidator(startSlot, invType) - m.cfg.payloadModifier = pm - return nil - } -} - -func WithPayloadInvalidatorAtSlot( - slot beacon.Slot, - invType PayloadInvalidation, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - pm := genPayloadInvalidator(slot, invType) - m.cfg.payloadModifier = pm - return nil - } -} - -type PayloadAttributesInvalidation string - -const ( - INVALIDATE_ATTR_REMOVE_WITHDRAWAL = "remove_withdrawal" - INVALIDATE_ATTR_EXTRA_WITHDRAWAL = "extra_withdrawal" - INVALIDATE_ATTR_WITHDRAWAL_ADDRESS = "withdrawal_address" - INVALIDATE_ATTR_WITHDRAWAL_AMOUNT = "withdrawal_amount" - INVALIDATE_ATTR_WITHDRAWAL_VALIDATOR_INDEX = "withdrawal_validator_index" - INVALIDATE_ATTR_WITHDRAWAL_INDEX = "withdrawal_index" - INVALIDATE_ATTR_TIMESTAMP = "timestamp" - INVALIDATE_ATTR_PREV_RANDAO = "prevrandao" - INVALIDATE_ATTR_RANDOM = "random" -) - -var PayloadAttrInvalidationTypes = map[string]PayloadAttributesInvalidation{ - INVALIDATE_ATTR_REMOVE_WITHDRAWAL: INVALIDATE_ATTR_REMOVE_WITHDRAWAL, - INVALIDATE_ATTR_EXTRA_WITHDRAWAL: INVALIDATE_ATTR_EXTRA_WITHDRAWAL, - INVALIDATE_ATTR_WITHDRAWAL_ADDRESS: INVALIDATE_ATTR_WITHDRAWAL_ADDRESS, - INVALIDATE_ATTR_WITHDRAWAL_AMOUNT: INVALIDATE_ATTR_WITHDRAWAL_AMOUNT, - INVALIDATE_ATTR_WITHDRAWAL_VALIDATOR_INDEX: INVALIDATE_ATTR_WITHDRAWAL_VALIDATOR_INDEX, - INVALIDATE_ATTR_WITHDRAWAL_INDEX: INVALIDATE_ATTR_WITHDRAWAL_INDEX, - INVALIDATE_ATTR_TIMESTAMP: INVALIDATE_ATTR_TIMESTAMP, - INVALIDATE_ATTR_PREV_RANDAO: INVALIDATE_ATTR_PREV_RANDAO, - INVALIDATE_ATTR_RANDOM: INVALIDATE_ATTR_RANDOM, -} - -func PayloadAttrInvalidationTypeNames() []string { - res := make([]string, len(PayloadAttrInvalidationTypes)) - i := 0 - for k := range PayloadAttrInvalidationTypes { - res[i] = k - i += 1 - } - return res -} - -func genPayloadAttributesInvalidator( - slot beacon.Slot, - invType PayloadAttributesInvalidation, - spec *beacon.Spec, -) func(*api.PayloadAttributes, beacon.Slot) (bool, error) { - return func(pa *api.PayloadAttributes, s beacon.Slot) (bool, error) { - if s >= slot { - switch invType { - case INVALIDATE_ATTR_WITHDRAWAL_ADDRESS, - INVALIDATE_ATTR_WITHDRAWAL_AMOUNT, - INVALIDATE_ATTR_WITHDRAWAL_VALIDATOR_INDEX, - INVALIDATE_ATTR_WITHDRAWAL_INDEX, - INVALIDATE_ATTR_REMOVE_WITHDRAWAL: - if len(pa.Withdrawals) > 0 { - switch invType { - case INVALIDATE_ATTR_WITHDRAWAL_ADDRESS: - pa.Withdrawals[0].Address[0]++ - case INVALIDATE_ATTR_WITHDRAWAL_AMOUNT: - pa.Withdrawals[0].Amount++ - case INVALIDATE_ATTR_WITHDRAWAL_VALIDATOR_INDEX: - pa.Withdrawals[0].Validator++ - case INVALIDATE_ATTR_WITHDRAWAL_INDEX: - pa.Withdrawals[0].Index++ - case INVALIDATE_ATTR_REMOVE_WITHDRAWAL: - pa.Withdrawals = pa.Withdrawals[1:] - } - return true, nil - } else { - return false, fmt.Errorf("unable to invalidate: no withdrawals") - } - case INVALIDATE_ATTR_EXTRA_WITHDRAWAL: - if pa.Withdrawals == nil { - pa.Withdrawals = make([]*types.Withdrawal, 0) - } - pa.Withdrawals = append(pa.Withdrawals, &types.Withdrawal{}) - return true, nil - case INVALIDATE_ATTR_TIMESTAMP: - pa.Timestamp = pa.Timestamp - uint64( - spec.SECONDS_PER_SLOT*2, - ) - return true, nil - case INVALIDATE_ATTR_PREV_RANDAO, INVALIDATE_ATTR_RANDOM: - rand.Read(pa.Random[:]) - return true, nil - } - panic(fmt.Errorf( - "unknown invalidation type: %s", - invType, - )) - } - return false, nil - } -} - -func WithPayloadAttributesInvalidatorAtEpoch( - epoch beacon.Epoch, - invType PayloadAttributesInvalidation, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - var spec = m.cfg.spec - if spec == nil { - return fmt.Errorf("unknown spec") - } - startSlot, err := spec.EpochStartSlot(epoch) - if err != nil { - return err - } - - pm := genPayloadAttributesInvalidator(startSlot, invType, spec) - m.cfg.payloadAttrModifier = pm - return nil - } -} - -func WithPayloadAttributesInvalidatorAtSlot( - slot beacon.Slot, - invType PayloadAttributesInvalidation, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - if m.cfg.spec == nil { - return fmt.Errorf("unknown spec") - } - - pm := genPayloadAttributesInvalidator(slot, invType, m.cfg.spec) - m.cfg.payloadAttrModifier = pm - return nil - } -} - -func WithInvalidBuilderBidVersionAtSlot( - activationSlot beacon.Slot, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - m.cfg.builderBidVersionResolver = func(slot beacon.Slot) (common.BuilderBid, string, error) { - if slot >= activationSlot { - // Always return Bellatrix, until theres a new fork that can override capella - return &bellatrix.BuilderBid{}, "bellatrix", nil - } - return m.DefaultBuilderBidVersionResolver(slot) - } - - return nil - } -} - -func WithInvalidBuilderBidVersionAtEpoch( - activationEpoch beacon.Epoch, -) Option { - return func(m *MockBuilder) error { - m.cfg.mutex.Lock() - defer m.cfg.mutex.Unlock() - - var spec = m.cfg.spec - if spec == nil { - return fmt.Errorf("unknown spec") - } - activationSlot, err := spec.EpochStartSlot(activationEpoch) - if err != nil { - return err - } - - m.cfg.builderBidVersionResolver = func(slot beacon.Slot) (common.BuilderBid, string, error) { - if slot >= activationSlot { - // Always return Bellatrix, until theres a new fork that can override capella - return &bellatrix.BuilderBid{}, "bellatrix", nil - } - return m.DefaultBuilderBidVersionResolver(slot) - } - - return nil - } -} diff --git a/simulators/eth2/common/builder/types/bellatrix/bellatrix.go b/simulators/eth2/common/builder/types/bellatrix/bellatrix.go deleted file mode 100644 index f95e1a0813..0000000000 --- a/simulators/eth2/common/builder/types/bellatrix/bellatrix.go +++ /dev/null @@ -1,226 +0,0 @@ -package bellatrix - -import ( - "fmt" - "math/big" - - api "github.com/ethereum/go-ethereum/beacon/engine" - el_common "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/common" - blsu "github.com/protolambda/bls12-381-util" - "github.com/protolambda/zrnt/eth2/beacon/bellatrix" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/tree" - "github.com/protolambda/ztyp/view" -) - -type SignedBeaconBlock bellatrix.SignedBeaconBlock - -func (s *SignedBeaconBlock) ExecutionPayloadHash() el_common.Hash { - var hash el_common.Hash - copy(hash[:], s.Message.Body.ExecutionPayload.BlockHash[:]) - return hash -} - -func (s *SignedBeaconBlock) Root(spec *beacon.Spec) tree.Root { - return s.Message.HashTreeRoot(spec, tree.GetHashFn()) -} - -func (s *SignedBeaconBlock) StateRoot() tree.Root { - return s.Message.StateRoot -} - -func (s *SignedBeaconBlock) Slot() beacon.Slot { - return s.Message.Slot -} - -func (s *SignedBeaconBlock) ProposerIndex() beacon.ValidatorIndex { - return s.Message.ProposerIndex -} - -func (s *SignedBeaconBlock) BlockSignature() *beacon.BLSSignature { - return &s.Signature -} - -func (s *SignedBeaconBlock) SetExecutionPayload( - ep common.ExecutionPayload, -) error { - s.Message.Body.ExecutionPayload.ParentHash = ep.GetParentHash() - s.Message.Body.ExecutionPayload.FeeRecipient = ep.GetFeeRecipient() - s.Message.Body.ExecutionPayload.StateRoot = ep.GetStateRoot() - s.Message.Body.ExecutionPayload.ReceiptsRoot = ep.GetReceiptsRoot() - s.Message.Body.ExecutionPayload.LogsBloom = ep.GetLogsBloom() - s.Message.Body.ExecutionPayload.PrevRandao = ep.GetPrevRandao() - s.Message.Body.ExecutionPayload.BlockNumber = ep.GetBlockNumber() - s.Message.Body.ExecutionPayload.GasLimit = ep.GetGasLimit() - s.Message.Body.ExecutionPayload.GasUsed = ep.GetGasUsed() - s.Message.Body.ExecutionPayload.Timestamp = ep.GetTimestamp() - s.Message.Body.ExecutionPayload.ExtraData = ep.GetExtraData() - s.Message.Body.ExecutionPayload.BaseFeePerGas = ep.GetBaseFeePerGas() - s.Message.Body.ExecutionPayload.BlockHash = ep.GetBlockHash() - s.Message.Body.ExecutionPayload.Transactions = ep.GetTransactions() - return nil -} - -type BuilderBid struct { - Header bellatrix.ExecutionPayloadHeader `json:"header" yaml:"header"` - Value view.Uint256View `json:"value" yaml:"value"` - PubKey beacon.BLSPubkey `json:"pubkey" yaml:"pubkey"` -} - -func (b *BuilderBid) HashTreeRoot(hFn tree.HashFn) tree.Root { - return hFn.HashTreeRoot( - &b.Header, - &b.Value, - &b.PubKey, - ) -} - -func (b *BuilderBid) FromExecutableData( - spec *beacon.Spec, - ed *api.ExecutableData, -) error { - if ed == nil { - return fmt.Errorf("nil execution payload") - } - copy(b.Header.ParentHash[:], ed.ParentHash[:]) - copy(b.Header.FeeRecipient[:], ed.FeeRecipient[:]) - copy(b.Header.StateRoot[:], ed.StateRoot[:]) - copy(b.Header.ReceiptsRoot[:], ed.ReceiptsRoot[:]) - copy(b.Header.LogsBloom[:], ed.LogsBloom[:]) - copy(b.Header.PrevRandao[:], ed.Random[:]) - - b.Header.BlockNumber = view.Uint64View(ed.Number) - b.Header.GasLimit = view.Uint64View(ed.GasLimit) - b.Header.GasUsed = view.Uint64View(ed.GasUsed) - b.Header.Timestamp = beacon.Timestamp(ed.Timestamp) - - b.Header.ExtraData = make(beacon.ExtraData, len(ed.ExtraData)) - copy(b.Header.ExtraData[:], ed.ExtraData[:]) - b.Header.BaseFeePerGas.SetFromBig(ed.BaseFeePerGas) - copy(b.Header.BlockHash[:], ed.BlockHash[:]) - - txs := make(beacon.PayloadTransactions, len(ed.Transactions)) - for i, tx := range ed.Transactions { - txs[i] = make(beacon.Transaction, len(tx)) - copy(txs[i][:], tx[:]) - } - txRoot := txs.HashTreeRoot(spec, tree.GetHashFn()) - copy(b.Header.TransactionsRoot[:], txRoot[:]) - - return nil -} - -func (b *BuilderBid) SetValue(value *big.Int) { - b.Value.SetFromBig(value) -} - -func (b *BuilderBid) SetPubKey(pk beacon.BLSPubkey) { - b.PubKey = pk -} - -func (b *BuilderBid) Sign( - domain beacon.BLSDomain, - sk *blsu.SecretKey, - pk *blsu.Pubkey, -) (*common.SignedBuilderBid, error) { - pkBytes := pk.Serialize() - copy(b.PubKey[:], pkBytes[:]) - sigRoot := beacon.ComputeSigningRoot( - b.HashTreeRoot(tree.GetHashFn()), - domain, - ) - return &common.SignedBuilderBid{ - Message: b, - Signature: beacon.BLSSignature(blsu.Sign(sk, sigRoot[:]).Serialize()), - }, nil -} - -type ExecutionPayload bellatrix.ExecutionPayload - -func (p *ExecutionPayload) FromExecutableData(ed *api.ExecutableData) error { - if ed == nil { - return fmt.Errorf("nil execution payload") - } - if ed.Withdrawals != nil { - return fmt.Errorf("execution data contains withdrawals") - } - copy(p.ParentHash[:], ed.ParentHash[:]) - copy(p.FeeRecipient[:], ed.FeeRecipient[:]) - copy(p.StateRoot[:], ed.StateRoot[:]) - copy(p.ReceiptsRoot[:], ed.ReceiptsRoot[:]) - copy(p.LogsBloom[:], ed.LogsBloom[:]) - copy(p.PrevRandao[:], ed.Random[:]) - - p.BlockNumber = view.Uint64View(ed.Number) - p.GasLimit = view.Uint64View(ed.GasLimit) - p.GasUsed = view.Uint64View(ed.GasUsed) - p.Timestamp = beacon.Timestamp(ed.Timestamp) - - p.ExtraData = make(beacon.ExtraData, len(ed.ExtraData)) - copy(p.ExtraData[:], ed.ExtraData[:]) - p.BaseFeePerGas.SetFromBig(ed.BaseFeePerGas) - copy(p.BlockHash[:], ed.BlockHash[:]) - p.Transactions = make(beacon.PayloadTransactions, len(ed.Transactions)) - for i, tx := range ed.Transactions { - p.Transactions[i] = make(beacon.Transaction, len(tx)) - copy(p.Transactions[i][:], tx[:]) - } - return nil -} - -func (p *ExecutionPayload) GetParentHash() beacon.Hash32 { - return p.ParentHash -} - -func (p *ExecutionPayload) GetFeeRecipient() beacon.Eth1Address { - return p.FeeRecipient -} - -func (p *ExecutionPayload) GetStateRoot() beacon.Bytes32 { - return p.StateRoot -} - -func (p *ExecutionPayload) GetReceiptsRoot() beacon.Bytes32 { - return p.ReceiptsRoot -} - -func (p *ExecutionPayload) GetLogsBloom() beacon.LogsBloom { - return p.LogsBloom -} - -func (p *ExecutionPayload) GetPrevRandao() beacon.Bytes32 { - return p.PrevRandao -} - -func (p *ExecutionPayload) GetBlockNumber() view.Uint64View { - return p.BlockNumber -} - -func (p *ExecutionPayload) GetGasLimit() view.Uint64View { - return p.GasLimit -} - -func (p *ExecutionPayload) GetGasUsed() view.Uint64View { - return p.GasUsed -} - -func (p *ExecutionPayload) GetTimestamp() beacon.Timestamp { - return p.Timestamp -} - -func (p *ExecutionPayload) GetExtraData() beacon.ExtraData { - return p.ExtraData -} - -func (p *ExecutionPayload) GetBaseFeePerGas() view.Uint256View { - return p.BaseFeePerGas -} - -func (p *ExecutionPayload) GetBlockHash() beacon.Hash32 { - return p.BlockHash -} - -func (p *ExecutionPayload) GetTransactions() beacon.PayloadTransactions { - return p.Transactions -} diff --git a/simulators/eth2/common/builder/types/capella/capella.go b/simulators/eth2/common/builder/types/capella/capella.go deleted file mode 100644 index 9a53462645..0000000000 --- a/simulators/eth2/common/builder/types/capella/capella.go +++ /dev/null @@ -1,255 +0,0 @@ -package capella - -import ( - "fmt" - "math/big" - - api "github.com/ethereum/go-ethereum/beacon/engine" - el_common "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/hive/simulators/eth2/common/builder/types/common" - blsu "github.com/protolambda/bls12-381-util" - "github.com/protolambda/zrnt/eth2/beacon/capella" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/tree" - "github.com/protolambda/ztyp/view" -) - -type SignedBeaconBlock capella.SignedBeaconBlock - -func (s *SignedBeaconBlock) ExecutionPayloadHash() el_common.Hash { - var hash el_common.Hash - copy(hash[:], s.Message.Body.ExecutionPayload.BlockHash[:]) - return hash -} - -func (s *SignedBeaconBlock) Root(spec *beacon.Spec) tree.Root { - return s.Message.HashTreeRoot(spec, tree.GetHashFn()) -} - -func (s *SignedBeaconBlock) StateRoot() tree.Root { - return s.Message.StateRoot -} - -func (s *SignedBeaconBlock) Slot() beacon.Slot { - return s.Message.Slot -} - -func (s *SignedBeaconBlock) ProposerIndex() beacon.ValidatorIndex { - return s.Message.ProposerIndex -} - -func (s *SignedBeaconBlock) BlockSignature() *beacon.BLSSignature { - return &s.Signature -} - -func (s *SignedBeaconBlock) SetExecutionPayload( - ep common.ExecutionPayload, -) error { - if ep, ok := ep.(common.ExecutionPayloadWithdrawals); ok { - s.Message.Body.ExecutionPayload.ParentHash = ep.GetParentHash() - s.Message.Body.ExecutionPayload.FeeRecipient = ep.GetFeeRecipient() - s.Message.Body.ExecutionPayload.StateRoot = ep.GetStateRoot() - s.Message.Body.ExecutionPayload.ReceiptsRoot = ep.GetReceiptsRoot() - s.Message.Body.ExecutionPayload.LogsBloom = ep.GetLogsBloom() - s.Message.Body.ExecutionPayload.PrevRandao = ep.GetPrevRandao() - s.Message.Body.ExecutionPayload.BlockNumber = ep.GetBlockNumber() - s.Message.Body.ExecutionPayload.GasLimit = ep.GetGasLimit() - s.Message.Body.ExecutionPayload.GasUsed = ep.GetGasUsed() - s.Message.Body.ExecutionPayload.Timestamp = ep.GetTimestamp() - s.Message.Body.ExecutionPayload.ExtraData = ep.GetExtraData() - s.Message.Body.ExecutionPayload.BaseFeePerGas = ep.GetBaseFeePerGas() - s.Message.Body.ExecutionPayload.BlockHash = ep.GetBlockHash() - s.Message.Body.ExecutionPayload.Transactions = ep.GetTransactions() - s.Message.Body.ExecutionPayload.Withdrawals = ep.GetWithdrawals() - return nil - } else { - return fmt.Errorf("invalid payload for capella") - } -} - -type BuilderBid struct { - Header capella.ExecutionPayloadHeader `json:"header" yaml:"header"` - Value view.Uint256View `json:"value" yaml:"value"` - PubKey beacon.BLSPubkey `json:"pubkey" yaml:"pubkey"` -} - -func (b *BuilderBid) HashTreeRoot(hFn tree.HashFn) tree.Root { - return hFn.HashTreeRoot( - &b.Header, - &b.Value, - &b.PubKey, - ) -} - -func (b *BuilderBid) FromExecutableData( - spec *beacon.Spec, - ed *api.ExecutableData, -) error { - if ed == nil { - return fmt.Errorf("nil execution payload") - } - if ed.Withdrawals == nil { - return fmt.Errorf("execution data does not contain withdrawals") - } - copy(b.Header.ParentHash[:], ed.ParentHash[:]) - copy(b.Header.FeeRecipient[:], ed.FeeRecipient[:]) - copy(b.Header.StateRoot[:], ed.StateRoot[:]) - copy(b.Header.ReceiptsRoot[:], ed.ReceiptsRoot[:]) - copy(b.Header.LogsBloom[:], ed.LogsBloom[:]) - copy(b.Header.PrevRandao[:], ed.Random[:]) - - b.Header.BlockNumber = view.Uint64View(ed.Number) - b.Header.GasLimit = view.Uint64View(ed.GasLimit) - b.Header.GasUsed = view.Uint64View(ed.GasUsed) - b.Header.Timestamp = beacon.Timestamp(ed.Timestamp) - - b.Header.ExtraData = make(beacon.ExtraData, len(ed.ExtraData)) - copy(b.Header.ExtraData[:], ed.ExtraData[:]) - b.Header.BaseFeePerGas.SetFromBig(ed.BaseFeePerGas) - copy(b.Header.BlockHash[:], ed.BlockHash[:]) - - txs := make(beacon.PayloadTransactions, len(ed.Transactions)) - for i, tx := range ed.Transactions { - txs[i] = make(beacon.Transaction, len(tx)) - copy(txs[i][:], tx[:]) - } - txRoot := txs.HashTreeRoot(spec, tree.GetHashFn()) - copy(b.Header.TransactionsRoot[:], txRoot[:]) - - withdrawals := make(beacon.Withdrawals, len(ed.Withdrawals)) - for i, w := range ed.Withdrawals { - withdrawals[i].Index = beacon.WithdrawalIndex(w.Index) - withdrawals[i].ValidatorIndex = beacon.ValidatorIndex(w.Validator) - copy(withdrawals[i].Address[:], w.Address[:]) - withdrawals[i].Amount = beacon.Gwei(w.Amount) - } - withdrawalsRoot := withdrawals.HashTreeRoot(spec, tree.GetHashFn()) - copy(b.Header.WithdrawalsRoot[:], withdrawalsRoot[:]) - - return nil -} - -func (b *BuilderBid) SetValue(value *big.Int) { - b.Value.SetFromBig(value) -} - -func (b *BuilderBid) SetPubKey(pk beacon.BLSPubkey) { - b.PubKey = pk -} - -func (b *BuilderBid) Sign( - domain beacon.BLSDomain, - sk *blsu.SecretKey, - pk *blsu.Pubkey, -) (*common.SignedBuilderBid, error) { - pkBytes := pk.Serialize() - copy(b.PubKey[:], pkBytes[:]) - sigRoot := beacon.ComputeSigningRoot( - b.HashTreeRoot(tree.GetHashFn()), - domain, - ) - return &common.SignedBuilderBid{ - Message: b, - Signature: beacon.BLSSignature(blsu.Sign(sk, sigRoot[:]).Serialize()), - }, nil -} - -type ExecutionPayload capella.ExecutionPayload - -func (p *ExecutionPayload) FromExecutableData(ed *api.ExecutableData) error { - if ed == nil { - return fmt.Errorf("nil execution payload") - } - if ed.Withdrawals == nil { - return fmt.Errorf("execution data does not contain withdrawals") - } - copy(p.ParentHash[:], ed.ParentHash[:]) - copy(p.FeeRecipient[:], ed.FeeRecipient[:]) - copy(p.StateRoot[:], ed.StateRoot[:]) - copy(p.ReceiptsRoot[:], ed.ReceiptsRoot[:]) - copy(p.LogsBloom[:], ed.LogsBloom[:]) - copy(p.PrevRandao[:], ed.Random[:]) - - p.BlockNumber = view.Uint64View(ed.Number) - p.GasLimit = view.Uint64View(ed.GasLimit) - p.GasUsed = view.Uint64View(ed.GasUsed) - p.Timestamp = beacon.Timestamp(ed.Timestamp) - - p.ExtraData = make(beacon.ExtraData, len(ed.ExtraData)) - copy(p.ExtraData[:], ed.ExtraData[:]) - p.BaseFeePerGas.SetFromBig(ed.BaseFeePerGas) - copy(p.BlockHash[:], ed.BlockHash[:]) - p.Transactions = make(beacon.PayloadTransactions, len(ed.Transactions)) - for i, tx := range ed.Transactions { - p.Transactions[i] = make(beacon.Transaction, len(tx)) - copy(p.Transactions[i][:], tx[:]) - } - p.Withdrawals = make(beacon.Withdrawals, len(ed.Withdrawals)) - for i, w := range ed.Withdrawals { - p.Withdrawals[i].Index = beacon.WithdrawalIndex(w.Index) - p.Withdrawals[i].ValidatorIndex = beacon.ValidatorIndex(w.Validator) - copy(p.Withdrawals[i].Address[:], w.Address[:]) - p.Withdrawals[i].Amount = beacon.Gwei(w.Amount) - } - return nil -} - -func (p *ExecutionPayload) GetParentHash() beacon.Hash32 { - return p.ParentHash -} - -func (p *ExecutionPayload) GetFeeRecipient() beacon.Eth1Address { - return p.FeeRecipient -} - -func (p *ExecutionPayload) GetStateRoot() beacon.Bytes32 { - return p.StateRoot -} - -func (p *ExecutionPayload) GetReceiptsRoot() beacon.Bytes32 { - return p.ReceiptsRoot -} - -func (p *ExecutionPayload) GetLogsBloom() beacon.LogsBloom { - return p.LogsBloom -} - -func (p *ExecutionPayload) GetPrevRandao() beacon.Bytes32 { - return p.PrevRandao -} - -func (p *ExecutionPayload) GetBlockNumber() view.Uint64View { - return p.BlockNumber -} - -func (p *ExecutionPayload) GetGasLimit() view.Uint64View { - return p.GasLimit -} - -func (p *ExecutionPayload) GetGasUsed() view.Uint64View { - return p.GasUsed -} - -func (p *ExecutionPayload) GetTimestamp() beacon.Timestamp { - return p.Timestamp -} - -func (p *ExecutionPayload) GetExtraData() beacon.ExtraData { - return p.ExtraData -} - -func (p *ExecutionPayload) GetBaseFeePerGas() view.Uint256View { - return p.BaseFeePerGas -} - -func (p *ExecutionPayload) GetBlockHash() beacon.Hash32 { - return p.BlockHash -} - -func (p *ExecutionPayload) GetTransactions() beacon.PayloadTransactions { - return p.Transactions -} - -func (p *ExecutionPayload) GetWithdrawals() beacon.Withdrawals { - return p.Withdrawals -} diff --git a/simulators/eth2/common/builder/types/common/common.go b/simulators/eth2/common/builder/types/common/common.go deleted file mode 100644 index 4db9a09529..0000000000 --- a/simulators/eth2/common/builder/types/common/common.go +++ /dev/null @@ -1,100 +0,0 @@ -package common - -import ( - "math/big" - - api "github.com/ethereum/go-ethereum/beacon/engine" - el_common "github.com/ethereum/go-ethereum/common" - blsu "github.com/protolambda/bls12-381-util" - "github.com/protolambda/zrnt/eth2/beacon/common" - beacon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/ztyp/tree" - "github.com/protolambda/ztyp/view" -) - -type ValidatorRegistrationV1 struct { - FeeRecipient common.Eth1Address `json:"fee_recipient" yaml:"fee_recipient"` - GasLimit view.Uint64View `json:"gas_limit" yaml:"gas_limit"` - Timestamp view.Uint64View `json:"timestamp" yaml:"timestamp"` - PubKey common.BLSPubkey `json:"pubkey" yaml:"pubkey"` -} - -func (vr *ValidatorRegistrationV1) HashTreeRoot(hFn tree.HashFn) tree.Root { - return hFn.HashTreeRoot( - &vr.FeeRecipient, - &vr.GasLimit, - &vr.Timestamp, - &vr.PubKey, - ) -} - -type SignedValidatorRegistrationV1 struct { - Message ValidatorRegistrationV1 `json:"message" yaml:"message"` - Signature common.BLSSignature `json:"signature" yaml:"signature"` -} - -type BuilderBid interface { - FromExecutableData(*beacon.Spec, *api.ExecutableData) error - SetValue(*big.Int) - SetPubKey(beacon.BLSPubkey) - Sign(domain beacon.BLSDomain, - sk *blsu.SecretKey, - pk *blsu.Pubkey) (*SignedBuilderBid, error) -} - -type SignedBuilderBid struct { - Message BuilderBid `json:"message" yaml:"message"` - Signature common.BLSSignature `json:"signature" yaml:"signature"` -} - -func (s *SignedBuilderBid) Versioned( - version string, -) *VersionedSignedBuilderBid { - return &VersionedSignedBuilderBid{ - Version: version, - Data: s, - } -} - -type VersionedSignedBuilderBid struct { - Version string `json:"version" yaml:"version"` - Data *SignedBuilderBid `json:"data" yaml:"data"` -} - -type SignedBeaconBlock interface { - ExecutionPayloadHash() el_common.Hash - Root(*beacon.Spec) tree.Root - StateRoot() tree.Root - SetExecutionPayload(ExecutionPayload) error - Slot() beacon.Slot - ProposerIndex() beacon.ValidatorIndex - BlockSignature() *common.BLSSignature -} - -type ExecutionPayload interface { - FromExecutableData(*api.ExecutableData) error - GetParentHash() beacon.Hash32 - GetFeeRecipient() beacon.Eth1Address - GetStateRoot() beacon.Bytes32 - GetReceiptsRoot() beacon.Bytes32 - GetLogsBloom() beacon.LogsBloom - GetPrevRandao() beacon.Bytes32 - GetBlockNumber() view.Uint64View - GetGasLimit() view.Uint64View - GetGasUsed() view.Uint64View - GetTimestamp() beacon.Timestamp - GetExtraData() beacon.ExtraData - GetBaseFeePerGas() view.Uint256View - GetBlockHash() beacon.Hash32 - GetTransactions() beacon.PayloadTransactions -} - -type ExecutionPayloadWithdrawals interface { - ExecutionPayload - GetWithdrawals() beacon.Withdrawals -} - -type ExecutionPayloadResponse struct { - Version string `json:"version" yaml:"version"` - Data ExecutionPayload `json:"data" yaml:"data"` -} diff --git a/simulators/eth2/common/clients/beacon.go b/simulators/eth2/common/clients/beacon.go deleted file mode 100644 index 09a6ac5918..0000000000 --- a/simulators/eth2/common/clients/beacon.go +++ /dev/null @@ -1,1328 +0,0 @@ -package clients - -import ( - "bytes" - "context" - "errors" - "fmt" - "net/http" - "strings" - "sync" - "time" - - ethcommon "github.com/ethereum/go-ethereum/common" - api "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/go-ethereum/core/types" - - "github.com/ethereum/hive/simulators/eth2/common/builder" - "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/zrnt/eth2/configs" - "github.com/protolambda/ztyp/tree" -) - -const ( - PortBeaconTCP = 9000 - PortBeaconUDP = 9000 - PortBeaconAPI = 4000 - PortBeaconGRPC = 4001 - PortMetrics = 8080 - PortValidatorAPI = 5000 -) - -var EMPTY_TREE_ROOT = tree.Root{} - -type BeaconClientConfig struct { - ClientIndex int - TerminalTotalDifficulty int64 - BeaconAPIPort int - Spec *common.Spec - GenesisValidatorsRoot *tree.Root - GenesisTime *common.Timestamp - Subnet string -} - -type BeaconClient struct { - Client - Logger utils.Logging - Config BeaconClientConfig - Builder builder.Builder - - api *eth2api.Eth2HttpClient -} - -func (bn *BeaconClient) Logf(format string, values ...interface{}) { - if l := bn.Logger; l != nil { - l.Logf(format, values...) - } -} - -func (bn *BeaconClient) Start() error { - if !bn.IsRunning() { - if managedClient, ok := bn.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to start an unmanaged client") - } else { - if err := managedClient.Start(); err != nil { - return err - } - } - - } - - return bn.Init(context.Background()) -} - -func (bn *BeaconClient) Init(ctx context.Context) error { - if bn.api == nil { - port := bn.Config.BeaconAPIPort - if port == 0 { - port = PortBeaconAPI - } - bn.api = ð2api.Eth2HttpClient{ - Addr: fmt.Sprintf( - "http://%s:%d", - bn.GetIP(), - port, - ), - Cli: &http.Client{}, - Codec: eth2api.JSONCodec{}, - } - } - - var wg sync.WaitGroup - var errs = make(chan error, 2) - if bn.Config.Spec == nil { - // Try to fetch config directly from the client - wg.Add(1) - go func() { - defer wg.Done() - for { - if cfg, err := bn.BeaconConfig(ctx); err == nil && cfg != nil { - if spec, err := SpecFromConfig(cfg); err != nil { - errs <- err - return - } else { - bn.Config.Spec = spec - return - } - } - select { - case <-ctx.Done(): - errs <- ctx.Err() - return - case <-time.After(time.Second): - } - } - }() - } - - if bn.Config.GenesisTime == nil || bn.Config.GenesisValidatorsRoot == nil { - wg.Add(1) - go func() { - defer wg.Done() - for { - if gen, err := bn.GenesisConfig(ctx); err == nil && - gen != nil { - bn.Config.GenesisTime = &gen.GenesisTime - bn.Config.GenesisValidatorsRoot = &gen.GenesisValidatorsRoot - return - } - select { - case <-ctx.Done(): - errs <- ctx.Err() - return - case <-time.After(time.Second): - } - } - }() - } - wg.Wait() - - select { - case err := <-errs: - return err - default: - return nil - } -} - -func (bn *BeaconClient) Shutdown() error { - if managedClient, ok := bn.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to shutdown an unmanaged client") - } else { - return managedClient.Shutdown() - } -} - -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 - } - bn.Logf("p2p addrs: %v\n", out.P2PAddresses) - bn.Logf("peer id: %s\n", out.PeerID) - bn.Logf("enr: %s\n", out.ENR) - 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 fmt.Sprintf( - "/ip4/%s/tcp/%d/p2p/%s", - bn.GetIP().String(), - PortBeaconTCP, - out.PeerID, - ), nil -} - -func (bn *BeaconClient) BeaconAPIURL() (string, error) { - if bn.api == nil { - return "", fmt.Errorf("api not initialized") - } - return bn.api.Addr, 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 -} - -func (bn *BeaconClient) API() *eth2api.Eth2HttpClient { - return bn.api -} - -func SpecFromConfig(cfg *common.Config) (*common.Spec, error) { - if cfg == nil { - return nil, fmt.Errorf("empty cfg") - } - var spec *common.Spec - if cfg.PRESET_BASE == "mainnet" { - specCpy := *configs.Mainnet - spec = &specCpy - } else if cfg.PRESET_BASE == "minimal" { - specCpy := *configs.Minimal - spec = &specCpy - } else { - return nil, fmt.Errorf("invalid preset base: %s", cfg.PRESET_BASE) - } - spec.Config = *cfg - return spec, nil -} - -// Beacon API wrappers -func (bn *BeaconClient) BeaconConfig( - parentCtx context.Context, -) (*common.Config, error) { - var ( - cfg = new(common.Config) - exists bool - err error - ) - ctx, cancel := utils.ContextTimeoutRPC(parentCtx) - defer cancel() - exists, err = eth2api.SimpleRequest( - ctx, - bn.api, - eth2api.FmtGET("/eth/v1/config/spec"), - eth2api.Wrap(cfg), - ) - - if !exists { - return nil, fmt.Errorf("endpoint not found on beacon client") - } - return cfg, err -} - -func (bn *BeaconClient) GenesisConfig( - parentCtx context.Context, -) (*eth2api.GenesisResponse, error) { - var ( - dest = new(eth2api.GenesisResponse) - exists bool - err error - ) - ctx, cancel := utils.ContextTimeoutRPC(parentCtx) - defer cancel() - - exists, err = beaconapi.Genesis(ctx, bn.api, dest) - - if !exists { - return nil, fmt.Errorf("endpoint not found on beacon client") - } - return dest, err -} - -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 (versionedBlock *VersionedSignedBeaconBlock) Withdrawals() (common.Withdrawals, error) { - switch v := versionedBlock.Data.(type) { - case *capella.SignedBeaconBlock: - return v.Message.Body.ExecutionPayload.Withdrawals, nil - } - return nil, 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) ParentRoot() tree.Root { - switch v := b.Data.(type) { - case *phase0.SignedBeaconBlock: - return v.Message.ParentRoot - case *altair.SignedBeaconBlock: - return v.Message.ParentRoot - case *bellatrix.SignedBeaconBlock: - return v.Message.ParentRoot - case *capella.SignedBeaconBlock: - return v.Message.ParentRoot - } - 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) BlockV2Root( - parentCtx context.Context, - blockId eth2api.BlockId, -) (tree.Root, error) { - var ( - root tree.Root - exists bool - err error - ) - ctx, cancel := utils.ContextTimeoutRPC(parentCtx) - defer cancel() - root, exists, err = beaconapi.BlockRoot(ctx, bn.api, blockId) - if !exists { - return root, fmt.Errorf( - "endpoint not found on beacon client", - ) - } - return root, err -} - -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 - spec *common.Spec -} - -func (vbs *VersionedBeaconStateResponse) Root() tree.Root { - switch state := vbs.Data.(type) { - case *phase0.BeaconState: - return state.HashTreeRoot(vbs.spec, tree.GetHashFn()) - case *altair.BeaconState: - return state.HashTreeRoot(vbs.spec, tree.GetHashFn()) - case *bellatrix.BeaconState: - return state.HashTreeRoot(vbs.spec, tree.GetHashFn()) - case *capella.BeaconState: - return state.HashTreeRoot(vbs.spec, tree.GetHashFn()) - } - panic("badly formatted beacon state") -} - -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) Balance( - id common.ValidatorIndex, -) common.Gwei { - balances := vbs.Balances() - if int(id) >= len(balances) { - panic("invalid validator requested") - } - return balances[id] -} - -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 (vbs *VersionedBeaconStateResponse) RandaoMixes() phase0.RandaoMixes { - switch state := vbs.Data.(type) { - case *phase0.BeaconState: - return state.RandaoMixes - case *altair.BeaconState: - return state.RandaoMixes - case *bellatrix.BeaconState: - return state.RandaoMixes - case *capella.BeaconState: - return state.RandaoMixes - } - panic("badly formatted beacon state") -} - -func (vbs *VersionedBeaconStateResponse) StateSlot() common.Slot { - switch state := vbs.Data.(type) { - case *phase0.BeaconState: - return state.Slot - case *altair.BeaconState: - return state.Slot - case *bellatrix.BeaconState: - return state.Slot - case *capella.BeaconState: - return state.Slot - } - panic("badly formatted beacon state") -} - -func (vbs *VersionedBeaconStateResponse) LatestExecutionPayloadHeaderHash() tree.Root { - switch state := vbs.Data.(type) { - case *phase0.BeaconState: - return tree.Root{} - case *altair.BeaconState: - return tree.Root{} - case *bellatrix.BeaconState: - return state.LatestExecutionPayloadHeader.BlockHash - case *capella.BeaconState: - return state.LatestExecutionPayloadHeader.BlockHash - } - panic("badly formatted beacon state") -} - -func (vbs *VersionedBeaconStateResponse) NextWithdrawalIndex() (common.WithdrawalIndex, error) { - var wIndex common.WithdrawalIndex - switch state := vbs.Data.(type) { - case *capella.BeaconState: - wIndex = state.NextWithdrawalIndex - } - return wIndex, nil -} - -func (vbs *VersionedBeaconStateResponse) NextWithdrawalValidatorIndex() (common.ValidatorIndex, error) { - var wIndex common.ValidatorIndex - switch state := vbs.Data.(type) { - case *capella.BeaconState: - wIndex = state.NextWithdrawalValidatorIndex - } - return wIndex, nil -} - -func (vbs *VersionedBeaconStateResponse) NextWithdrawals( - slot common.Slot, -) (common.Withdrawals, error) { - var ( - withdrawalIndex common.WithdrawalIndex - validatorIndex common.ValidatorIndex - validators phase0.ValidatorRegistry - balances phase0.Balances - epoch = vbs.spec.SlotToEpoch(slot) - ) - switch state := vbs.Data.(type) { - case *bellatrix.BeaconState: - // withdrawalIndex and validatorIndex start at zero - validators = state.Validators - balances = state.Balances - case *capella.BeaconState: - withdrawalIndex = state.NextWithdrawalIndex - validatorIndex = state.NextWithdrawalValidatorIndex - validators = state.Validators - balances = state.Balances - default: - return nil, fmt.Errorf("badly formatted beacon state") - } - validatorCount := uint64(len(validators)) - withdrawals := make(common.Withdrawals, 0) - - i := uint64(0) - for { - if validatorIndex >= common.ValidatorIndex(validatorCount) || - validatorIndex >= common.ValidatorIndex(len(balances)) { - return nil, fmt.Errorf("invalid validator index") - } - validator := validators[validatorIndex] - if validator == nil { - return nil, fmt.Errorf("invalid validator") - } - balance := balances[validatorIndex] - if i >= validatorCount || - i >= uint64(vbs.spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) { - break - } - if IsFullyWithdrawableValidator(validator, balance, epoch) { - withdrawals = append(withdrawals, common.Withdrawal{ - Index: withdrawalIndex, - ValidatorIndex: validatorIndex, - Address: Eth1WithdrawalCredential(validator), - Amount: balance, - }) - withdrawalIndex += 1 - } else if IsPartiallyWithdrawableValidator(vbs.spec, validator, balance, epoch) { - withdrawals = append(withdrawals, common.Withdrawal{ - Index: withdrawalIndex, - ValidatorIndex: validatorIndex, - Address: Eth1WithdrawalCredential(validator), - Amount: balance - vbs.spec.MAX_EFFECTIVE_BALANCE, - }) - withdrawalIndex += 1 - } - if len(withdrawals) == int(vbs.spec.MAX_WITHDRAWALS_PER_PAYLOAD) { - break - } - validatorIndex = common.ValidatorIndex( - uint64(validatorIndex+1) % validatorCount, - ) - i += 1 - } - return withdrawals, nil -} - -func Eth1WithdrawalCredential(validator *phase0.Validator) common.Eth1Address { - var address common.Eth1Address - copy(address[:], validator.WithdrawalCredentials[12:]) - return address -} - -func IsFullyWithdrawableValidator( - validator *phase0.Validator, - balance common.Gwei, - epoch common.Epoch, -) bool { - return HasEth1WithdrawalCredential(validator) && - validator.WithdrawableEpoch <= epoch && - balance > 0 -} - -func IsPartiallyWithdrawableValidator( - spec *common.Spec, - validator *phase0.Validator, - balance common.Gwei, - epoch common.Epoch, -) bool { - effectiveBalance := validator.EffectiveBalance - hasMaxEffectiveBalance := effectiveBalance == spec.MAX_EFFECTIVE_BALANCE - hasExcessBalance := balance > spec.MAX_EFFECTIVE_BALANCE - return HasEth1WithdrawalCredential(validator) && hasMaxEffectiveBalance && - hasExcessBalance -} - -func HasEth1WithdrawalCredential(validator *phase0.Validator) bool { - return bytes.Equal( - validator.WithdrawalCredentials[:1], - []byte{common.ETH1_ADDRESS_WITHDRAWAL_PREFIX}, - ) -} - -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, - spec: bn.Config.Spec, - }, 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 bn.Config.GenesisTime == nil { - panic(fmt.Errorf("init not called yet")) - } - if version != nil { - return common.ComputeDomain( - typ, - *version, - *bn.Config.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.Config.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) { - if b.Config.GenesisTime == nil { - panic(fmt.Errorf("init not called yet")) - } - b.Logf( - "Waiting for execution payload on beacon %d (%s)\n", - b.Config.ClientIndex, - b.ClientName(), - ) - slotDuration := time.Duration(b.Config.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.Config.Spec.TimeToSlot( - common.Timestamp(time.Now().Unix()), - *b.Config.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{} - b.Logf( - "WaitForExecutionPayload: beacon %d (%s): slot=%d, realTimeSlot=%d, head=%s, exec=%s\n", - b.Config.ClientIndex, - 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) { - b.Logf("Waiting for optimistic sync on beacon %d (%s)\n", - b.Config.ClientIndex, - b.ClientName(), - ) - - slotDuration := time.Duration(b.Config.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 { - if !bytes.Equal( - executionPayload.BlockHash[:], - EMPTY_TREE_ROOT[:], - ) { - return versionedBlock, nil - } - } - } - return nil, nil -} - -func (bn *BeaconClient) GetFirstExecutionBeaconBlock( - parentCtx context.Context, -) (*VersionedSignedBeaconBlock, error) { - if bn.Config.GenesisTime == nil { - panic(fmt.Errorf("init not called yet")) - } - lastSlot := bn.Config.Spec.TimeToSlot( - common.Timestamp(time.Now().Unix()), - *bn.Config.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 { - if !bytes.Equal( - executionPayload.BlockHash[:], - EMPTY_TREE_ROOT[:], - ) { - 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 -} - -func (bn *BeaconClient) GetFilledSlotsCountPerEpoch( - parentCtx context.Context, -) (map[common.Epoch]uint64, error) { - headInfo, err := bn.BlockHeader(parentCtx, eth2api.BlockHead) - epochMap := make(map[common.Epoch]uint64) - for { - if err != nil { - return nil, fmt.Errorf("failed to poll head: %v", err) - } - epoch := common.Epoch( - headInfo.Header.Message.Slot / bn.Config.Spec.SLOTS_PER_EPOCH, - ) - if prev, ok := epochMap[epoch]; ok { - epochMap[epoch] = prev + 1 - } else { - epochMap[epoch] = 1 - } - if bytes.Equal( - headInfo.Header.Message.ParentRoot[:], - EMPTY_TREE_ROOT[:], - ) { - break - } - headInfo, err = bn.BlockHeader( - parentCtx, - eth2api.BlockIdRoot(headInfo.Header.Message.ParentRoot), - ) - } - - return epochMap, 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 -} - -// Return subset of clients that are part of an specific subnet -func (all BeaconClients) Subnet(subnet string) BeaconClients { - if subnet == "" { - return all - } - res := make(BeaconClients, 0) - for _, bn := range all { - if bn.Config.Subnet == subnet { - res = append(res, bn) - } - } - 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, -) { - 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(), - ) - } - } - - b.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 deleted file mode 100644 index 9f1e2a4ffe..0000000000 --- a/simulators/eth2/common/clients/execution.go +++ /dev/null @@ -1,672 +0,0 @@ -package clients - -import ( - "context" - "encoding/json" - "fmt" - "math/big" - "net" - "net/http" - "strings" - "sync" - "time" - - api "github.com/ethereum/go-ethereum/beacon/engine" - "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/simulators/eth2/common/spoofing/proxy" - "github.com/ethereum/hive/simulators/eth2/common/utils" - "github.com/golang-jwt/jwt/v4" - spoof "github.com/rauljordan/engine-proxy/proxy" -) - -const ( - PortUserRPC = 8545 - PortEngineRPC = 8551 -) - -var AllForkchoiceUpdatedCalls = []string{ - "engine_forkchoiceUpdatedV1", - "engine_forkchoiceUpdatedV2", -} - -var AllEngineCallsLog = []string{ - "engine_forkchoiceUpdatedV1", - "engine_forkchoiceUpdatedV2", - "engine_getPayloadV1", - "engine_getPayloadV2", - "engine_newPayloadV1", - "engine_newPayloadV2", -} - -type ExecutionProxyConfig struct { - Host net.IP - Port int - LogEngineCalls bool - TrackForkchoiceUpdated bool -} - -type ExecutionClientConfig struct { - ClientIndex int - ProxyConfig *ExecutionProxyConfig - TerminalTotalDifficulty int64 - EngineAPIPort int - RPCPort int - Subnet string - JWTSecret []byte -} - -type ExecutionClient struct { - Client - Logger utils.Logging - Config ExecutionClientConfig - - proxy *proxy.Proxy - latestfcu *api.ForkchoiceStateV1 - - engineRpcClient *rpc.Client - ethRpcClient *rpc.Client - eth *ethclient.Client - - startupComplete bool -} - -func (en *ExecutionClient) Logf(format string, values ...interface{}) { - if l := en.Logger; l != nil { - l.Logf(format, values...) - } -} - -func (en *ExecutionClient) UserRPCAddress() (string, error) { - if !en.Client.IsRunning() { - return "", fmt.Errorf("execution client not yet launched") - } - var port = PortUserRPC - if en.Config.RPCPort != 0 { - port = en.Config.RPCPort - } - return fmt.Sprintf( - "http://%v:%d", - en.Client.GetIP(), - port, - ), nil -} - -func (en *ExecutionClient) EngineRPCAddress() (string, error) { - var port = PortEngineRPC - if en.Config.EngineAPIPort != 0 { - port = en.Config.EngineAPIPort - } - return fmt.Sprintf( - "http://%v:%d", - en.Client.GetIP(), - port, - ), nil -} - -func (en *ExecutionClient) MustGetEnode() string { - if enodeClient, ok := en.Client.(EnodeClient); ok { - addr, err := enodeClient.GetEnodeURL() - if err == nil { - return addr - } - panic(err) - } - panic(fmt.Errorf("invalid client type")) -} - -func (en *ExecutionClient) ConfiguredTTD() *big.Int { - return big.NewInt(en.Config.TerminalTotalDifficulty) -} - -func (en *ExecutionClient) Start() error { - if !en.Client.IsRunning() { - if managedClient, ok := en.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to start an unmanaged client") - } else { - if err := managedClient.Start(); err != nil { - return err - } - } - } - - return en.Init(context.Background()) -} - -func (en *ExecutionClient) Init(ctx context.Context) error { - if !en.startupComplete { - defer func() { - en.startupComplete = true - }() - - // 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 - } - - if en.Config.ProxyConfig != nil { - p := proxy.NewProxy( - en.Config.ProxyConfig.Host, - en.Config.ProxyConfig.Port, - dest, - en.Config.JWTSecret, - ) - - if en.Config.ProxyConfig.TrackForkchoiceUpdated { - logCallback := func(req []byte) *spoof.Spoof { - var ( - fcState api.ForkchoiceStateV1 - pAttr api.PayloadAttributes - err error - ) - err = proxy.UnmarshalFromJsonRPCRequest( - req, - &fcState, - &pAttr, - ) - if err == nil { - en.latestfcu = &fcState - } - return nil - } - for _, c := range AllForkchoiceUpdatedCalls { - p.AddRequestCallback(c, logCallback) - } - } - - if en.Config.ProxyConfig.LogEngineCalls { - logCallback := func(res []byte, req []byte) *spoof.Spoof { - en.Logf( - "DEBUG: execution client %d, request: %s", - en.Config.ClientIndex, - req, - ) - en.Logf( - "DEBUG: execution client %d, response: %s", - en.Config.ClientIndex, - res, - ) - return nil - } - for _, c := range AllEngineCallsLog { - p.AddResponseCallback(c, logCallback) - } - } - - en.proxy = p - } - - } - return nil -} - -func (en *ExecutionClient) Shutdown() error { - if managedClient, ok := en.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to shutdown an unmanaged client") - } else { - return managedClient.Shutdown() - } -} - -func (en *ExecutionClient) IsRunning() bool { - return en.Client.IsRunning() -} - -func (en *ExecutionClient) Proxy() *proxy.Proxy { - return en.proxy -} - -func (en *ExecutionClient) GetLatestForkchoiceUpdated( - ctx context.Context, -) (*api.ForkchoiceStateV1, error) { - if en.latestfcu != nil { - return en.latestfcu, nil - } - // Try to reconstruct by querying it from the client - forkchoiceState := &api.ForkchoiceStateV1{} - errs := make(chan error, 3) - var wg sync.WaitGroup - - type labelBlockHashTask struct { - label string - dest *common.Hash - } - - for _, t := range []*labelBlockHashTask{ - { - label: "latest", - dest: &forkchoiceState.HeadBlockHash, - }, - { - label: "safe", - dest: &forkchoiceState.SafeBlockHash, - }, - { - label: "finalized", - dest: &forkchoiceState.FinalizedBlockHash, - }, - } { - wg.Add(1) - t := t - go func(t *labelBlockHashTask) { - defer wg.Done() - if res, err := en.HeaderByLabel( - ctx, - t.label, - ); err != nil { - en.Logf( - "Error trying to fetch label %s from client: %v", - t.label, - err, - ) - } else if err == nil && res != nil && res.Number != nil { - *t.dest = res.Hash() - } - }(t) - } - wg.Wait() - - select { - case err := <-errs: - return nil, err - default: - } - - return forkchoiceState, 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 { - en.PrepareAuthCallToken(en.Config.JWTSecret, 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, *big.Int, error) { - - var ( - rpcString = fmt.Sprintf("engine_getPayloadV%d", version) - ) - - if err := en.PrepareDefaultAuthCallToken(); err != nil { - return nil, nil, err - } - - ctx, cancel := context.WithTimeout(parentCtx, time.Second*10) - defer cancel() - if version == 2 { - type ExecutionPayloadEnvelope struct { - ExecutionPayload *api.ExecutableData `json:"executionPayload" gencodec:"required"` - BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` - } - var response ExecutionPayloadEnvelope - err := en.engineRpcClient.CallContext( - ctx, - &response, - rpcString, - payloadID, - ) - return response.ExecutionPayload, (*big.Int)(response.BlockValue), err - } else { - var executableData api.ExecutableData - err := en.engineRpcClient.CallContext(ctx, &executableData, rpcString, payloadID) - return &executableData, common.Big0, 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_newPayloadV%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(big.NewInt(ec.Config.TerminalTotalDifficulty)) >= 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) -} - -func (ec *ExecutionClient) SendTransaction( - parentCtx context.Context, - tx *types.Transaction, -) error { - ctx, cancel := utils.ContextTimeoutRPC(parentCtx) - defer cancel() - return ec.eth.SendTransaction(ctx, tx) -} - -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.Config.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() { - if enodeClient, ok := en.Client.(EnodeClient); ok { - enode, err := enodeClient.GetEnodeURL() - if err != nil { - return "", err - } - enodes = append(enodes, enode) - } else { - return "", fmt.Errorf("invalid client type") - } - } - } - 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 ProxyProvider interface { - Proxy() *proxy.Proxy -} -type Proxies []ProxyProvider - -func (all Proxies) Running() []*proxy.Proxy { - res := make([]*proxy.Proxy, 0) - for _, pp := range all { - if p := pp.Proxy(); p != nil { - res = append(res, p) - } - } - return res -} diff --git a/simulators/eth2/common/clients/client.go b/simulators/eth2/common/clients/hive.go similarity index 61% rename from simulators/eth2/common/clients/client.go rename to simulators/eth2/common/clients/hive.go index 32732fb5cc..2df4348826 100644 --- a/simulators/eth2/common/clients/client.go +++ b/simulators/eth2/common/clients/hive.go @@ -3,30 +3,12 @@ package clients import ( "fmt" "net" - "strconv" "github.com/ethereum/hive/hivesim" + "github.com/marioevz/eth-clients/clients" ) -type Client interface { - IsRunning() bool - GetIP() net.IP - ClientType() string -} - -type EnodeClient interface { - Client - GetEnodeURL() (string, error) -} - -type ManagedClient interface { - Client - AddStartOption(...interface{}) - Start() error - Shutdown() error -} - -var _ ManagedClient = &HiveManagedClient{} +var _ clients.ManagedClient = &HiveManagedClient{} type HiveOptionsGenerator func() ([]hivesim.StartOption, error) @@ -103,49 +85,3 @@ func (h *HiveManagedClient) GetEnodeURL() (string, error) { func (h *HiveManagedClient) ClientType() string { return h.HiveClientDefinition.Name } - -var _ Client = &ExternalClient{} - -type ExternalClient struct { - Type string - IP net.IP - Port int - EnodeURL string -} - -func ExternalClientFromURL(url string, typ string) (*ExternalClient, error) { - ip, portStr, err := net.SplitHostPort(url) - if err != nil { - return nil, err - } - port, err := strconv.ParseInt(portStr, 10, 64) - if err != nil { - return nil, err - } - return &ExternalClient{ - Type: typ, - IP: net.ParseIP(ip), - Port: int(port), - }, nil -} - -func (m *ExternalClient) IsRunning() bool { - // We can try pinging a certain port for status - return true -} - -func (m *ExternalClient) GetIP() net.IP { - return m.IP -} - -func (m *ExternalClient) GetPort() int { - return m.Port -} - -func (m *ExternalClient) ClientType() string { - return m.Type -} - -func (m *ExternalClient) GetEnodeURL() (string, error) { - return m.EnodeURL, nil -} diff --git a/simulators/eth2/common/clients/node.go b/simulators/eth2/common/clients/node.go deleted file mode 100644 index 2c12aae4e5..0000000000 --- a/simulators/eth2/common/clients/node.go +++ /dev/null @@ -1,468 +0,0 @@ -package clients - -import ( - "context" - "fmt" - "math/big" - "strings" - - "golang.org/x/exp/slices" - - "github.com/ethereum/go-ethereum/core/types" - cg "github.com/ethereum/hive/simulators/eth2/common/chain_generators" - "github.com/ethereum/hive/simulators/eth2/common/utils" - "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 { - // Client Types - ExecutionClient string - ConsensusClient string - ValidatorClient string - - // Execution Config - ExecutionClientTTD *big.Int - ChainGenerator cg.ChainGenerator - Chain []*types.Block - - // Beacon Config - BeaconNodeTTD *big.Int - - // Validator Config - ValidatorShares uint64 - - // Node Config - TestVerificationNode bool - DisableStartup bool - - // Subnet Configuration - ExecutionSubnet string - ConsensusSubnet string - Subnet 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 n.ConsensusClient -} - -func (n *NodeDefinition) ValidatorClientName() string { - if n.ValidatorClient == "" { - return beaconNodeToValidator(n.ConsensusClient) - } - return n.ValidatorClient -} - -func (n *NodeDefinition) GetExecutionSubnet() string { - if n.ExecutionSubnet != "" { - return n.ExecutionSubnet - } - if n.Subnet != "" { - return n.Subnet - } - return "" -} - -func (n *NodeDefinition) GetConsensusSubnet() string { - if n.ConsensusSubnet != "" { - return n.ConsensusSubnet - } - if n.Subnet != "" { - return n.Subnet - } - return "" -} - -func beaconNodeToValidator(name string) string { - name, branch, hasBranch := strings.Cut(name, "_") - name = strings.TrimSuffix(name, "-bn") - validator := name + "-vc" - if hasBranch { - validator += "_" + branch - } - return validator -} - -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(filters []string) NodeDefinitions { - ret := make(NodeDefinitions, 0) - for _, n := range all { - for _, filter := range filters { - if strings.Contains(n.ConsensusClient, filter) { - ret = append(ret, n) - break - } - } - } - return ret -} - -func (all NodeDefinitions) FilterByEL(filters []string) NodeDefinitions { - ret := make(NodeDefinitions, 0) - for _, n := range all { - for _, filter := range filters { - if strings.Contains(n.ExecutionClient, filter) { - ret = append(ret, n) - break - } - } - } - 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 { - Logging utils.Logging - Index int - ExecutionClient *ExecutionClient - BeaconClient *BeaconClient - ValidatorClient *ValidatorClient - Verification bool -} - -func (n *Node) Logf(format string, values ...interface{}) { - if l := n.Logging; l != nil { - l.Logf(format, values...) - } -} - -// Starts all clients included in the bundle -func (n *Node) Start() error { - n.Logf("Starting validator client bundle %d", n.Index) - if n.ExecutionClient != nil { - if err := n.ExecutionClient.Start(); err != nil { - return err - } - } else { - n.Logf("No execution client started") - } - if n.BeaconClient != nil { - if err := n.BeaconClient.Start(); err != nil { - return err - } - } else { - n.Logf("No beacon client started") - } - if n.ValidatorClient != nil { - if err := n.ValidatorClient.Start(); err != nil { - return err - } - } else { - n.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.Config.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) - } - } - 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(filters []string) Nodes { - ret := make(Nodes, 0) - for _, n := range all { - for _, filter := range filters { - if strings.Contains(n.BeaconClient.ClientName(), filter) { - ret = append(ret, n) - break - } - } - } - return ret -} - -func (all Nodes) FilterByEL(filters []string) Nodes { - ret := make(Nodes, 0) - for _, n := range all { - for _, filter := range filters { - if strings.Contains(n.ExecutionClient.ClientType(), filter) { - ret = append(ret, n) - break - } - } - } - 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/common/clients/node_definition.go b/simulators/eth2/common/clients/node_definition.go new file mode 100644 index 0000000000..b8aeb56d89 --- /dev/null +++ b/simulators/eth2/common/clients/node_definition.go @@ -0,0 +1,141 @@ +package clients + +import ( + "fmt" + "math/big" + "strings" + + "golang.org/x/exp/slices" + + "github.com/ethereum/go-ethereum/core/types" + cg "github.com/ethereum/hive/simulators/eth2/common/chain_generators" +) + +// Describe a node setup, which consists of: +// - Execution Client +// - Beacon Client +// - Validator Client +type NodeDefinition struct { + // Client Types + ExecutionClient string `json:"execution_client"` + ConsensusClient string `json:"consensus_client"` + ValidatorClient string `json:"validator_client"` + + // Execution Config + ExecutionClientTTD *big.Int `json:"execution_client_ttd,omitempty"` + ChainGenerator cg.ChainGenerator `json:"-"` + Chain []*types.Block `json:"chain,omitempty"` + + // Beacon Config + BeaconNodeTTD *big.Int `json:"beacon_node_ttd,omitempty"` + + // Validator Config + ValidatorShares uint64 `json:"validator_shares"` + + // Node Config + TestVerificationNode bool `json:"test_verification_node"` + DisableStartup bool `json:"disable_startup"` + + // Subnet Configuration + ExecutionSubnet string `json:"execution_subnet"` + ConsensusSubnet string `json:"consensus_subnet"` + Subnet string `json:"subnet"` +} + +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 n.ConsensusClient +} + +func (n *NodeDefinition) ValidatorClientName() string { + if n.ValidatorClient == "" { + return beaconNodeToValidator(n.ConsensusClient) + } + return n.ValidatorClient +} + +func (n *NodeDefinition) GetExecutionSubnet() string { + if n.ExecutionSubnet != "" { + return n.ExecutionSubnet + } + if n.Subnet != "" { + return n.Subnet + } + return "" +} + +func (n *NodeDefinition) GetConsensusSubnet() string { + if n.ConsensusSubnet != "" { + return n.ConsensusSubnet + } + if n.Subnet != "" { + return n.Subnet + } + return "" +} + +func beaconNodeToValidator(name string) string { + name, branch, hasBranch := strings.Cut(name, "_") + name = strings.TrimSuffix(name, "-bn") + validator := name + "-vc" + if hasBranch { + validator += "_" + branch + } + return validator +} + +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(filters []string) NodeDefinitions { + ret := make(NodeDefinitions, 0) + for _, n := range all { + for _, filter := range filters { + if strings.Contains(n.ConsensusClient, filter) { + ret = append(ret, n) + break + } + } + } + return ret +} + +func (all NodeDefinitions) FilterByEL(filters []string) NodeDefinitions { + ret := make(NodeDefinitions, 0) + for _, n := range all { + for _, filter := range filters { + if strings.Contains(n.ExecutionClient, filter) { + ret = append(ret, n) + break + } + } + } + return ret +} diff --git a/simulators/eth2/common/clients/validator.go b/simulators/eth2/common/clients/validator.go deleted file mode 100644 index e3980510a9..0000000000 --- a/simulators/eth2/common/clients/validator.go +++ /dev/null @@ -1,180 +0,0 @@ -package clients - -import ( - "fmt" - - consensus_config "github.com/ethereum/hive/simulators/eth2/common/config/consensus" - "github.com/ethereum/hive/simulators/eth2/common/utils" - 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 { - Client - Logger utils.Logging - ClientIndex int - - Keys map[common.ValidatorIndex]*consensus_config.KeyDetails - BeaconClient *BeaconClient -} - -func (vc *ValidatorClient) Logf(format string, values ...interface{}) { - if l := vc.Logger; l != nil { - l.Logf(format, values...) - } -} - -func (vc *ValidatorClient) Start() error { - if !vc.Client.IsRunning() { - if len(vc.Keys) == 0 { - vc.Logf("Skipping validator because it has 0 validator keys") - return nil - } - if managedClient, ok := vc.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to start an unmanaged client") - } else { - return managedClient.Start() - } - } - return nil -} - -func (vc *ValidatorClient) Shutdown() error { - if managedClient, ok := vc.Client.(ManagedClient); !ok { - return fmt.Errorf("attempted to shutdown an unmanaged client") - } else { - return managedClient.Shutdown() - } -} - -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/consensus/genesis.go b/simulators/eth2/common/config/consensus/genesis.go index 1e29b272c6..2288ffef52 100644 --- a/simulators/eth2/common/config/consensus/genesis.go +++ b/simulators/eth2/common/config/consensus/genesis.go @@ -115,7 +115,7 @@ func genesisPayloadHeaderCapella( func createValidators( spec *common.Spec, - keys []*KeyDetails, + keys []*ValidatorDetails, ) []phase0.KickstartValidatorData { validators := make([]phase0.KickstartValidatorData, 0, len(keys)) for _, key := range keys { @@ -136,7 +136,7 @@ func BuildBeaconState( spec *common.Spec, eth1Genesis *core.Genesis, eth2GenesisTime common.Timestamp, - keys []*KeyDetails, + keys []*ValidatorDetails, ) (common.BeaconState, error) { if uint64(len(keys)) < uint64(spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) { return nil, fmt.Errorf( diff --git a/simulators/eth2/common/config/consensus/validator_keys.go b/simulators/eth2/common/config/consensus/validator_keys.go index 1d2842cc22..06988ae394 100644 --- a/simulators/eth2/common/config/consensus/validator_keys.go +++ b/simulators/eth2/common/config/consensus/validator_keys.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/hive/simulators/eth2/common/config" "github.com/google/uuid" hbls "github.com/herumi/bls-eth-go-binary/bls" + "github.com/marioevz/eth-clients/clients/validator" "github.com/pkg/errors" "github.com/protolambda/go-keystorev4" "github.com/protolambda/zrnt/eth2/beacon/common" @@ -31,22 +32,10 @@ func init() { } } -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 +type ValidatorDetails struct { + validator.ValidatorKeys // 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 @@ -57,7 +46,7 @@ type KeyDetails struct { Slashed bool } -func (kd *KeyDetails) WithdrawalCredentials() (out common.Root) { +func (kd *ValidatorDetails) WithdrawalCredentials() (out common.Root) { if kd.WithdrawalCredentialType == common.BLS_WITHDRAWAL_PREFIX { hasher := sha256.New() hasher.Write(kd.WithdrawalPubkey[:]) @@ -71,6 +60,16 @@ func (kd *KeyDetails) WithdrawalCredentials() (out common.Root) { return } +type ValidatorDetailsMap map[common.ValidatorIndex]*ValidatorDetails + +func (m ValidatorDetailsMap) Keys() map[common.ValidatorIndex]*validator.ValidatorKeys { + keys := make(map[common.ValidatorIndex]*validator.ValidatorKeys, len(m)) + for k, v := range m { + keys[k] = &v.ValidatorKeys + } + return keys +} + // 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 @@ -87,7 +86,7 @@ type MnemonicsKeySource struct { WithdrawalCredentialType int // cache loaded validator details - cache []*KeyDetails `yaml:"-"` + cache []*ValidatorDetails `yaml:"-"` } func mnemonicToSeed(mnemonic string) (seed []byte, err error) { @@ -157,7 +156,7 @@ func marshalWeakKeystoreJSON( return json.MarshalIndent(store, "", " ") } -func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) { +func (k *MnemonicsKeySource) Keys() ([]*ValidatorDetails, error) { if k.cache != nil { return k.cache, nil } @@ -176,7 +175,7 @@ func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) { k.To, ) } - out := make([]*KeyDetails, 0, k.To-k.From) + out := make([]*ValidatorDetails, 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) @@ -246,9 +245,11 @@ func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) { if err != nil { return nil, err } - k := &KeyDetails{ - ValidatorKeystoreJSON: jsonData, - ValidatorKeystorePass: passphrase, + k := &ValidatorDetails{ + ValidatorKeys: validator.ValidatorKeys{ + ValidatorKeystoreJSON: jsonData, + ValidatorKeystorePass: passphrase, + }, } copy(k.ValidatorPubkey[:], pub) copy(k.ValidatorSecretKey[:], priv) @@ -261,7 +262,7 @@ func (k *MnemonicsKeySource) Keys() ([]*KeyDetails, error) { return out, nil } -func SecretKeys(keys []*KeyDetails) (*[]blsu.SecretKey, error) { +func SecretKeys(keys []*ValidatorDetails) (*[]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 { @@ -296,13 +297,17 @@ func (shares Shares) ValidatorSplits(validatorTotalCount uint64) []uint64 { } func KeyTranches( - keys []*KeyDetails, + keys []*ValidatorDetails, shares Shares, -) []map[common.ValidatorIndex]*KeyDetails { - tranches := make([]map[common.ValidatorIndex]*KeyDetails, 0, len(shares)) +) []ValidatorDetailsMap { + tranches := make( + []ValidatorDetailsMap, + 0, + len(shares), + ) i := uint64(0) for _, c := range shares.ValidatorSplits(uint64(len(keys))) { - tranche := make(map[common.ValidatorIndex]*KeyDetails) + tranche := make(ValidatorDetailsMap) for j := i; j < (i + c); j++ { tranche[common.ValidatorIndex(j)] = keys[j] } @@ -313,7 +318,7 @@ func KeyTranches( } func KeysBundle( - keys map[common.ValidatorIndex]*KeyDetails, + keys ValidatorDetailsMap, ) hivesim.StartOption { opts := make([]hivesim.StartOption, 0, len(keys)*2) for _, k := range keys { diff --git a/simulators/eth2/common/debug/debug.go b/simulators/eth2/common/debug/debug.go index fc8991de66..e09253648d 100644 --- a/simulators/eth2/common/debug/debug.go +++ b/simulators/eth2/common/debug/debug.go @@ -6,8 +6,8 @@ import ( "sort" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/hive/simulators/eth2/common/clients" "github.com/ethereum/hive/simulators/eth2/common/utils" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" "github.com/protolambda/eth2api" "github.com/protolambda/zrnt/eth2/beacon/common" "github.com/protolambda/ztyp/tree" @@ -17,7 +17,7 @@ import ( func PrintAllBeaconBlocks( parentCtx context.Context, l utils.Logging, - b *clients.BeaconClient, + b *beacon_client.BeaconClient, ) error { headInfo, err := b.BlockHeader(parentCtx, eth2api.BlockHead) @@ -154,7 +154,7 @@ func (bm BeaconBlockMap) Print(l utils.Logging) error { func PrintAllTestnetBeaconBlocks( parentCtx context.Context, l utils.Logging, - runningBeacons clients.BeaconClients, + runningBeacons beacon_client.BeaconClients, ) error { beaconTree := make(BeaconBlockMap) diff --git a/simulators/eth2/common/go.mod b/simulators/eth2/common/go.mod index 2d51656996..a69a55e15b 100644 --- a/simulators/eth2/common/go.mod +++ b/simulators/eth2/common/go.mod @@ -5,11 +5,11 @@ go 1.18 require ( github.com/ethereum/go-ethereum v1.11.5 github.com/ethereum/hive v0.0.0-20230401205547-71595beab31d - github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.3.0 - github.com/gorilla/mux v1.8.0 github.com/herumi/bls-eth-go-binary v1.29.1 github.com/holiman/uint256 v1.2.2 + github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363 + github.com/marioevz/mock-builder v0.0.0-20230515180219-3b0b5c3eefe3 github.com/pkg/errors v0.9.1 github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 github.com/protolambda/eth2api v0.0.0-20230316214135-5f8afbd6d05d @@ -17,7 +17,6 @@ require ( github.com/protolambda/zrnt v0.30.0 github.com/protolambda/ztyp v0.2.2 github.com/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a - github.com/sirupsen/logrus v1.9.0 github.com/tyler-smith/go-bip39 v1.1.0 github.com/wealdtech/go-eth2-util v1.8.1 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 @@ -43,8 +42,10 @@ require ( github.com/go-stack/stack v1.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect @@ -64,9 +65,8 @@ require ( github.com/prometheus/procfs v0.9.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/rs/cors v1.8.3 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/stretchr/testify v1.8.1 // 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 diff --git a/simulators/eth2/common/go.sum b/simulators/eth2/common/go.sum index 818ef17947..afdad59ad9 100644 --- a/simulators/eth2/common/go.sum +++ b/simulators/eth2/common/go.sum @@ -122,13 +122,13 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.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/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 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= @@ -206,10 +206,16 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -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/marioevz/eth2api v0.0.0-20230214151319-641a58f39ae4 h1:CN6XoCl13Dnnwn3I7zjwmn2byw2SW7/MfBX52C9Fa54= -github.com/marioevz/eth2api v0.0.0-20230214151319-641a58f39ae4/go.mod h1:4WbGGB4Bv17hKsiytlJY4IQDNpRS234DvFvIBNLnd60= +github.com/marioevz/eth-clients v0.0.0-20230501225027-135b7d52b617 h1:sk4stg95D93cfiIIYI+XPRhXZQ91QGIPOHNDZjmpXms= +github.com/marioevz/eth-clients v0.0.0-20230501225027-135b7d52b617/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= +github.com/marioevz/eth-clients v0.0.0-20230503000902-6ba8d15dfe6a h1:EbX/rlcGlMXhwlTibd+TWuN2G2mQKiahwH4xBFpzXo0= +github.com/marioevz/eth-clients v0.0.0-20230503000902-6ba8d15dfe6a/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= +github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363 h1:ONwsdY5/heIE0HHxh4+QXkwa69MZuaO+vONXduNBbrM= +github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= +github.com/marioevz/mock-builder v0.0.0-20230501225822-df434a88e375 h1:44F0CrAc81Nzsr/4BhkeKebbrHERHdCjO6jXS9VAE/0= +github.com/marioevz/mock-builder v0.0.0-20230501225822-df434a88e375/go.mod h1:FQIXEFViaQkOqKrqLC91JgqG+6YEvqMVh9D7g6PmFUg= +github.com/marioevz/mock-builder v0.0.0-20230515180219-3b0b5c3eefe3 h1:LbF6BNBYypeF1pjTulvFr4vUSXeeT8B9ZeYCU9KDbuo= +github.com/marioevz/mock-builder v0.0.0-20230515180219-3b0b5c3eefe3/go.mod h1:FQIXEFViaQkOqKrqLC91JgqG+6YEvqMVh9D7g6PmFUg= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -292,17 +298,17 @@ github.com/protolambda/zrnt v0.30.0 h1:pHEn69ZgaDFGpLGGYG1oD7DvYI7RDirbMBPfbC+8p 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/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a h1:ZIfMLprHVdo2vs3WcSqSDEyz2ZsSzDhGeOyxh8VQThA= +github.com/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a/go.mod h1:9OVXfWYnIV+wj1/SqfdREmE5mzN/OANAgdOJRtFtvpo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -329,7 +335,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= diff --git a/simulators/eth2/common/spoofing/beacon/beacon_verification.go b/simulators/eth2/common/spoofing/beacon/beacon_verification.go index 59f010002c..941182c920 100644 --- a/simulators/eth2/common/spoofing/beacon/beacon_verification.go +++ b/simulators/eth2/common/spoofing/beacon/beacon_verification.go @@ -4,7 +4,7 @@ import ( "fmt" api "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/hive/simulators/eth2/common/spoofing/proxy" + exec_client "github.com/marioevz/eth-clients/clients/execution" spoof "github.com/rauljordan/engine-proxy/proxy" "golang.org/x/exp/slices" ) @@ -36,7 +36,7 @@ func GetTimestampFromNewPayload( req []byte, ) (*uint64, error) { var payload api.ExecutableData - if err := proxy.UnmarshalFromJsonRPCRequest(req, &payload); err != nil { + if err := exec_client.UnmarshalFromJsonRPCRequest(req, &payload); err != nil { return nil, err } return &payload.Timestamp, nil @@ -49,7 +49,7 @@ func GetTimestampFromFcU( fcS api.ForkchoiceStateV1 pA *api.PayloadAttributes ) - if err := proxy.UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil { + if err := exec_client.UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil { return nil, err } if pA == nil { @@ -90,14 +90,16 @@ func (v *EngineEndpointMaxTimestampVerify) Verify( return nil } -func (v *EngineEndpointMaxTimestampVerify) AddToProxy(p *proxy.Proxy) error { +func (v *EngineEndpointMaxTimestampVerify) AddToProxy( + p *exec_client.Proxy, +) error { if p == nil { return fmt.Errorf("attempted to add to nil proxy") } if v.Endpoint == "" { return fmt.Errorf("attempted to add to proxy with empty endpoint") } - p.AddRequestCallback(v.Endpoint, v.Verify) + p.AddRequestCallbacks(v.Verify, v.Endpoint) return nil } diff --git a/simulators/eth2/common/spoofing/payload/payload_spoofing.go b/simulators/eth2/common/spoofing/payload/payload_spoofing.go index 665c57dc31..dde16cfd9c 100644 --- a/simulators/eth2/common/spoofing/payload/payload_spoofing.go +++ b/simulators/eth2/common/spoofing/payload/payload_spoofing.go @@ -7,12 +7,12 @@ import ( "strings" "sync" + api "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - api "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/hive/simulators/eth2/common/spoofing/proxy" + exec_client "github.com/marioevz/eth-clients/clients/execution" spoof "github.com/rauljordan/engine-proxy/proxy" ) @@ -627,28 +627,29 @@ func (e *EngineResponseMocker) SetDefaultResponse(r *api.PayloadStatusV1) { } func (e *EngineResponseMocker) AddGetPayloadPassthroughToProxy( - p *proxy.Proxy, + p *exec_client.Proxy, ) { - p.AddResponseCallback( - EngineGetPayloadV1, + p.AddResponseCallbacks( 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) + err := exec_client.UnmarshalFromJsonRPCResponse(res, &payload) if err != nil { panic(err) } e.AddPassthrough(payload.BlockHash, true) return nil }, + exec_client.AllGetPayloadCalls..., ) } -func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy(p *proxy.Proxy) { - p.AddResponseCallback( - EngineNewPayloadV1, +func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy( + p *exec_client.Proxy, +) { + p.AddResponseCallbacks( func(res []byte, req []byte) *spoof.Spoof { var ( payload api.ExecutableData @@ -656,11 +657,11 @@ func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy(p *proxy.Proxy) { spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &payload) + err = exec_client.UnmarshalFromJsonRPCRequest(req, &payload) if err != nil { panic(err) } - err = proxy.UnmarshalFromJsonRPCResponse(res, &status) + err = exec_client.UnmarshalFromJsonRPCResponse(res, &status) if err != nil { panic(err) } @@ -698,14 +699,14 @@ func (e *EngineResponseMocker) AddNewPayloadCallbackToProxy(p *proxy.Proxy) { } return nil }, + exec_client.AllNewPayloadCalls..., ) } func (e *EngineResponseMocker) AddForkchoiceUpdatedCallbackToProxy( - p *proxy.Proxy, + p *exec_client.Proxy, ) { - p.AddResponseCallback( - EngineForkchoiceUpdatedV1, + p.AddResponseCallbacks( func(res []byte, req []byte) *spoof.Spoof { var ( fcState api.ForkchoiceStateV1 @@ -714,11 +715,15 @@ func (e *EngineResponseMocker) AddForkchoiceUpdatedCallbackToProxy( spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr) + err = exec_client.UnmarshalFromJsonRPCRequest( + req, + &fcState, + &pAttr, + ) if err != nil { panic(err) } - err = proxy.UnmarshalFromJsonRPCResponse(res, &fResp) + err = exec_client.UnmarshalFromJsonRPCResponse(res, &fResp) if err != nil { panic(err) } @@ -760,10 +765,11 @@ func (e *EngineResponseMocker) AddForkchoiceUpdatedCallbackToProxy( } return nil }, + exec_client.AllForkchoiceUpdatedCalls..., ) } -func (e *EngineResponseMocker) AddCallbacksToProxy(p *proxy.Proxy) { +func (e *EngineResponseMocker) AddCallbacksToProxy(p *exec_client.Proxy) { e.AddForkchoiceUpdatedCallbackToProxy(p) e.AddNewPayloadCallbackToProxy(p) } @@ -783,7 +789,7 @@ func CheckErrorOnForkchoiceUpdatedPayloadAttributes( fcS api.ForkchoiceStateV1 pA *api.PayloadAttributes ) - if err := proxy.UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil { + if err := exec_client.UnmarshalFromJsonRPCRequest(req, &fcS, &pA); err != nil { panic( fmt.Errorf( "unable to parse ForkchoiceUpdated request: %v", @@ -799,7 +805,7 @@ func CheckErrorOnForkchoiceUpdatedPayloadAttributes( var ( fcResponse api.ForkChoiceResponse ) - err := proxy.UnmarshalFromJsonRPCResponse(res, &fcResponse) + err := exec_client.UnmarshalFromJsonRPCResponse(res, &fcResponse) if err == nil && fcResponse.PayloadID == nil { err = fmt.Errorf( "PayloadID null on ForkchoiceUpdated with attributes", diff --git a/simulators/eth2/common/spoofing/proxy/proxy.go b/simulators/eth2/common/spoofing/proxy/proxy.go deleted file mode 100644 index c728540e10..0000000000 --- a/simulators/eth2/common/spoofing/proxy/proxy.go +++ /dev/null @@ -1,197 +0,0 @@ -package proxy - -import ( - "context" - "encoding/json" - "fmt" - "net" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - "github.com/rauljordan/engine-proxy/proxy" -) - -type Proxy struct { - IP net.IP - port int - proxy *proxy.Proxy - JWTSecret string - config *proxy.SpoofingConfig - callbacks *proxy.SpoofingCallbacks - cancel context.CancelFunc - - rpc *rpc.Client - mu sync.Mutex -} - -func NewProxy( - hostIP net.IP, - port int, - destination string, - jwtSecret []byte, -) *Proxy { - host := "0.0.0.0" - config := proxy.SpoofingConfig{} - callbacks := proxy.SpoofingCallbacks{ - RequestCallbacks: make(map[string]func([]byte) *proxy.Spoof), - ResponseCallbacks: make(map[string]func([]byte, []byte) *proxy.Spoof), - } - options := []proxy.Option{ - proxy.WithHost(host), - proxy.WithPort(port), - proxy.WithDestinationAddress(destination), - proxy.WithSpoofingConfig(&config), - proxy.WithSpoofingCallbacks(&callbacks), - proxy.WithJWTSecret(jwtSecret), - } - proxy, err := proxy.New(options...) - if err != nil { - panic(err) - } - ctx, cancel := context.WithCancel(context.Background()) - go func() { - if err := proxy.Start(ctx); err != nil && err != context.Canceled { - panic(err) - } - }() - 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, - } -} - -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 -} - -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, -) { - log.Info("Adding request spoof callback", "method", method) - requestCallbacks := p.callbacks.RequestCallbacks - requestCallbacks[method] = callback - p.callbacks.RequestCallbacks = requestCallbacks - p.proxy.UpdateSpoofingCallbacks(p.callbacks) -} - -func (p *Proxy) AddRequest(spoof *proxy.Spoof) { - log.Info("Adding spoof request", "method", spoof.Method) - p.config.Requests = append(p.config.Requests, spoof) - p.proxy.UpdateSpoofingConfig(p.config) -} - -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 - p.callbacks.ResponseCallbacks = responseCallbacks - p.proxy.UpdateSpoofingCallbacks(p.callbacks) -} - -func (p *Proxy) AddResponse(spoof *proxy.Spoof) { - log.Info("Adding spoof response", "method", spoof.Method) - p.config.Responses = append(p.config.Responses, spoof) - p.proxy.UpdateSpoofingConfig(p.config) -} - -func (p *Proxy) RPC() *rpc.Client { - p.mu.Lock() - defer p.mu.Unlock() - if p.rpc == nil { - p.rpc, _ = rpc.DialHTTP(fmt.Sprintf("http://%v:%d", p.IP, p.port)) - } - 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 index e357a90bd3..cb8c618cee 100644 --- a/simulators/eth2/common/testnet/config.go +++ b/simulators/eth2/common/testnet/config.go @@ -1,43 +1,55 @@ package testnet import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - mock_builder "github.com/ethereum/hive/simulators/eth2/common/builder/mock" "github.com/ethereum/hive/simulators/eth2/common/clients" execution_config "github.com/ethereum/hive/simulators/eth2/common/config/execution" + mock_builder "github.com/marioevz/mock-builder/mock" ) var ( Big0 = big.NewInt(0) Big1 = big.NewInt(1) + + MAINNET_SLOT_TIME int64 = 12 + MINIMAL_SLOT_TIME int64 = 6 + + // Clients that support the minimal slot time in hive + MINIMAL_SLOT_TIME_CLIENTS = []string{ + "lighthouse", + "teku", + "prysm", + "lodestar", + } ) 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 + AltairForkEpoch *big.Int `json:"altair_fork_epoch,omitempty"` + BellatrixForkEpoch *big.Int `json:"bellatrix_fork_epoch,omitempty"` + CapellaForkEpoch *big.Int `json:"capella_fork_epoch,omitempty"` + ValidatorCount *big.Int `json:"validator_count,omitempty"` + KeyTranches *big.Int `json:"key_tranches,omitempty"` + SlotTime *big.Int `json:"slot_time,omitempty"` + TerminalTotalDifficulty *big.Int `json:"terminal_total_difficulty,omitempty"` + SafeSlotsToImportOptimistically *big.Int `json:"safe_slots_to_import_optimistically,omitempty"` + ExtraShares *big.Int `json:"extra_shares,omitempty"` // Node configurations to launch. Each node as a proportional share of // validators. - NodeDefinitions clients.NodeDefinitions - Eth1Consensus execution_config.ExecutionConsensus + NodeDefinitions clients.NodeDefinitions `json:"node_definitions,omitempty"` + Eth1Consensus execution_config.ExecutionConsensus `json:"eth1_consensus,omitempty"` // Execution Layer specific config - InitialBaseFeePerGas *big.Int - GenesisExecutionAccounts map[common.Address]core.GenesisAccount + InitialBaseFeePerGas *big.Int `json:"initial_base_fee_per_gas,omitempty"` + GenesisExecutionAccounts map[common.Address]core.GenesisAccount `json:"genesis_execution_accounts,omitempty"` // Builders - EnableBuilders bool - BuilderOptions []mock_builder.Option + EnableBuilders bool `json:"enable_builders,omitempty"` + BuilderOptions []mock_builder.Option `json:"builder_options,omitempty"` } // Choose a configuration value. `b` takes precedence @@ -113,3 +125,23 @@ func (c *Config) activeFork() string { return "phase0" } } + +// Check the configuration and its support by the multiple client definitions +func (c *Config) fillDefaults() error { + if c.SlotTime == nil { + allNodeDefinitions := c.NodeDefinitions + if len( + allNodeDefinitions.FilterByCL(MINIMAL_SLOT_TIME_CLIENTS), + ) == len( + allNodeDefinitions, + ) { + // If all clients support using minimal 6 second slot time, use it + c.SlotTime = big.NewInt(MINIMAL_SLOT_TIME) + } else { + // Otherwise, use the mainnet 12 second slot time + c.SlotTime = big.NewInt(MAINNET_SLOT_TIME) + } + fmt.Printf("INFO: using %d second slot time\n", c.SlotTime) + } + return nil +} diff --git a/simulators/eth2/common/testnet/environment.go b/simulators/eth2/common/testnet/environment.go index 0d2509058d..e6adfdb28f 100644 --- a/simulators/eth2/common/testnet/environment.go +++ b/simulators/eth2/common/testnet/environment.go @@ -8,7 +8,7 @@ import ( type Environment struct { Clients *clients.ClientDefinitionsByRole - Keys []*consensus_config.KeyDetails + Keys []*consensus_config.ValidatorDetails Secrets *[]blsu.SecretKey LogEngineCalls bool } diff --git a/simulators/eth2/common/testnet/prepared_testnet.go b/simulators/eth2/common/testnet/prepared_testnet.go index 68e28e77b8..0d7ece7533 100644 --- a/simulators/eth2/common/testnet/prepared_testnet.go +++ b/simulators/eth2/common/testnet/prepared_testnet.go @@ -21,10 +21,14 @@ import ( "github.com/protolambda/zrnt/eth2/configs" "github.com/ethereum/hive/hivesim" - mock_builder "github.com/ethereum/hive/simulators/eth2/common/builder/mock" "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" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" + exec_client "github.com/marioevz/eth-clients/clients/execution" + validator_client "github.com/marioevz/eth-clients/clients/validator" + mock_builder "github.com/marioevz/mock-builder/mock" + builder_types "github.com/marioevz/mock-builder/types" ) var ( @@ -58,17 +62,22 @@ type PreparedTestnet struct { beaconOpts hivesim.StartOption // A tranche is a group of validator keys to run on 1 node - keyTranches []map[common.ValidatorIndex]*cl.KeyDetails + keyTranches []cl.ValidatorDetailsMap } // 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 { +func prepareExecutionForkConfig( + eth2GenesisTime common.Timestamp, + config *Config, +) *params.ChainConfig { chainConfig := params.ChainConfig{} if config.CapellaForkEpoch != nil { shanghai := uint64(eth2GenesisTime) if config.CapellaForkEpoch.Uint64() != 0 { - shanghai += uint64(config.CapellaForkEpoch.Int64() * config.SlotTime.Int64() * 32) + shanghai += uint64( + config.CapellaForkEpoch.Int64() * config.SlotTime.Int64() * 32, + ) } chainConfig.ShanghaiTime = &shanghai } @@ -84,6 +93,17 @@ func prepareTestnet( eth1GenesisTime := common.Timestamp(time.Now().Unix()) eth2GenesisTime := eth1GenesisTime + 30 + // Sanitize configuration according to the clients used + if err := config.fillDefaults(); err != nil { + t.Fatal(fmt.Errorf("FAIL: error filling defaults: %v", err)) + } + + if configJson, err := json.MarshalIndent(config, "", " "); err != nil { + panic(err) + } else { + t.Logf("Testnet config: %s", configJson) + } + // Generate genesis for execution clients eth1Genesis := el.BuildExecutionGenesis( config.TerminalTotalDifficulty, @@ -241,15 +261,15 @@ func prepareTestnet( commonOpts := hivesim.Params{ "HIVE_ETH2_BN_API_PORT": fmt.Sprintf( "%d", - clients.PortBeaconAPI, + beacon_client.PortBeaconAPI, ), "HIVE_ETH2_BN_GRPC_PORT": fmt.Sprintf( "%d", - clients.PortBeaconGRPC, + beacon_client.PortBeaconGRPC, ), "HIVE_ETH2_METRICS_PORT": fmt.Sprintf( "%d", - clients.PortMetrics, + beacon_client.PortMetrics, ), "HIVE_ETH2_CONFIG_DEPOSIT_CONTRACT_ADDRESS": depositAddress.String(), "HIVE_ETH2_DEPOSIT_DEPLOY_BLOCK_HASH": fmt.Sprintf( @@ -262,7 +282,7 @@ func prepareTestnet( hivesim.Params{ "HIVE_CHECK_LIVE_PORT": fmt.Sprintf( "%d", - clients.PortBeaconAPI, + beacon_client.PortBeaconAPI, ), "HIVE_ETH2_MERGE_ENABLED": "1", "HIVE_ETH2_ETH1_GENESIS_TIME": fmt.Sprintf( @@ -320,8 +340,8 @@ func (p *PreparedTestnet) prepareExecutionNode( eth1Def *hivesim.ClientDefinition, consensus el.ExecutionConsensus, chain []*types.Block, - config clients.ExecutionClientConfig, -) *clients.ExecutionClient { + config exec_client.ExecutionClientConfig, +) *exec_client.ExecutionClient { testnet.Logf( "Preparing execution node: %s (%s)", eth1Def.Name, @@ -394,7 +414,7 @@ func (p *PreparedTestnet) prepareExecutionNode( return opts, nil } - return &clients.ExecutionClient{ + return &exec_client.ExecutionClient{ Client: cm, Logger: testnet.T, Config: config, @@ -409,9 +429,9 @@ func (p *PreparedTestnet) prepareBeaconNode( beaconDef *hivesim.ClientDefinition, enableBuilders bool, builderOptions []mock_builder.Option, - config clients.BeaconClientConfig, - eth1Endpoints ...*clients.ExecutionClient, -) *clients.BeaconClient { + config beacon_client.BeaconClientConfig, + eth1Endpoints ...*exec_client.ExecutionClient, +) *beacon_client.BeaconClient { testnet.Logf( "Preparing beacon node: %s (%s)", beaconDef.Name, @@ -427,7 +447,7 @@ func (p *PreparedTestnet) prepareBeaconNode( HiveClientDefinition: beaconDef, } - cl := &clients.BeaconClient{ + cl := &beacon_client.BeaconClient{ Client: cm, Logger: testnet.T, Config: config, @@ -544,9 +564,11 @@ func (p *PreparedTestnet) prepareBeaconNode( ) if cl.Builder != nil { - opts = append(opts, hivesim.Params{ - "HIVE_ETH2_BUILDER_ENDPOINT": cl.Builder.Address(), - }) + if builder, ok := cl.Builder.(builder_types.Builder); ok { + opts = append(opts, hivesim.Params{ + "HIVE_ETH2_BUILDER_ENDPOINT": builder.Address(), + }) + } } // TODO @@ -566,9 +588,9 @@ func (p *PreparedTestnet) prepareValidatorClient( parentCtx context.Context, testnet *Testnet, validatorDef *hivesim.ClientDefinition, - bn *clients.BeaconClient, + bn *beacon_client.BeaconClient, keyIndex int, -) *clients.ValidatorClient { +) *validator_client.ValidatorClient { testnet.Logf( "Preparing validator client: %s (%s)", validatorDef.Name, @@ -604,9 +626,11 @@ func (p *PreparedTestnet) prepareValidatorClient( opts := []hivesim.StartOption{p.validatorOpts, keysOpt, bnAPIOpt} if bn.Builder != nil { - opts = append(opts, hivesim.Params{ - "HIVE_ETH2_BUILDER_ENDPOINT": bn.Builder.Address(), - }) + if builder, ok := bn.Builder.(builder_types.Builder); ok { + opts = append(opts, hivesim.Params{ + "HIVE_ETH2_BUILDER_ENDPOINT": builder.Address(), + }) + } } // TODO @@ -616,11 +640,11 @@ func (p *PreparedTestnet) prepareValidatorClient( return opts, nil } - return &clients.ValidatorClient{ + return &validator_client.ValidatorClient{ Client: cm, Logger: testnet.T, ClientIndex: keyIndex, - Keys: keys, + Keys: keys.Keys(), BeaconClient: bn, } } diff --git a/simulators/eth2/common/testnet/running_testnet.go b/simulators/eth2/common/testnet/running_testnet.go index bea9a6652f..0214ce71dc 100644 --- a/simulators/eth2/common/testnet/running_testnet.go +++ b/simulators/eth2/common/testnet/running_testnet.go @@ -22,9 +22,12 @@ import ( "github.com/protolambda/ztyp/tree" "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" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" + exec_client "github.com/marioevz/eth-clients/clients/execution" + node "github.com/marioevz/eth-clients/clients/node" + builder_types "github.com/marioevz/mock-builder/types" ) const ( @@ -41,7 +44,7 @@ var ( type Testnet struct { *hivesim.T - clients.Nodes + node.Nodes genesisTime common.Timestamp genesisValidatorsRoot common.Root @@ -61,6 +64,8 @@ type ActiveSpec struct { *common.Spec } +const slotsTolerance common.Slot = 2 + func (spec *ActiveSpec) EpochTimeoutContext( parent context.Context, epochs common.Epoch, @@ -68,7 +73,7 @@ func (spec *ActiveSpec) EpochTimeoutContext( return context.WithTimeout( parent, time.Duration( - uint64(spec.SLOTS_PER_EPOCH*common.Slot(epochs))* + uint64((spec.SLOTS_PER_EPOCH*common.Slot(epochs))+slotsTolerance)* uint64(spec.SECONDS_PER_SLOT), )*time.Second, ) @@ -81,7 +86,7 @@ func (spec *ActiveSpec) SlotTimeoutContext( return context.WithTimeout( parent, time.Duration( - uint64(slots)* + uint64(slots+slotsTolerance)* uint64(spec.SECONDS_PER_SLOT))*time.Second, ) } @@ -161,11 +166,11 @@ func StartTestnet( simulatorIP = net.ParseIP(simIPStr) } - testnet.Nodes = make(clients.Nodes, len(config.NodeDefinitions)) + testnet.Nodes = make(node.Nodes, len(config.NodeDefinitions)) // Init all client bundles for nodeIndex := range testnet.Nodes { - testnet.Nodes[nodeIndex] = new(clients.Node) + testnet.Nodes[nodeIndex] = new(node.Node) } // For each key partition, we start a client bundle that consists of: @@ -198,9 +203,13 @@ func StartTestnet( } if node.ExecutionClientTTD != nil { executionTTD = node.ExecutionClientTTD.Int64() + } else if testnet.eth1Genesis.Genesis.Config.TerminalTotalDifficulty != nil { + executionTTD = testnet.eth1Genesis.Genesis.Config.TerminalTotalDifficulty.Int64() } if node.BeaconNodeTTD != nil { beaconTTD = node.BeaconNodeTTD.Int64() + } else if testnet.eth1Genesis.Genesis.Config.TerminalTotalDifficulty != nil { + beaconTTD = testnet.eth1Genesis.Genesis.Config.TerminalTotalDifficulty.Int64() } // Prepare the client objects with all the information necessary to @@ -211,14 +220,14 @@ func StartTestnet( executionDef, config.Eth1Consensus, node.Chain, - clients.ExecutionClientConfig{ + exec_client.ExecutionClientConfig{ ClientIndex: nodeIndex, TerminalTotalDifficulty: executionTTD, Subnet: node.GetExecutionSubnet(), JWTSecret: JWT_SECRET, - ProxyConfig: &clients.ExecutionProxyConfig{ + ProxyConfig: &exec_client.ExecutionProxyConfig{ Host: simulatorIP, - Port: clients.PortEngineRPC + nodeIndex, + Port: exec_client.PortEngineRPC + nodeIndex, TrackForkchoiceUpdated: true, LogEngineCalls: env.LogEngineCalls, }, @@ -232,7 +241,7 @@ func StartTestnet( beaconDef, config.EnableBuilders, config.BuilderOptions, - clients.BeaconClientConfig{ + beacon_client.BeaconClientConfig{ ClientIndex: nodeIndex, TerminalTotalDifficulty: beaconTTD, Spec: testnet.spec, @@ -273,7 +282,9 @@ func (t *Testnet) Stop() { } for _, b := range t.BeaconClients() { if b.Builder != nil { - b.Builder.Cancel() + if builder, ok := b.Builder.(builder_types.Builder); ok { + builder.Cancel() + } } } } @@ -345,19 +356,13 @@ func (t *Testnet) WaitForFork(ctx context.Context, fork string) error { wg.Add(1) go func( ctx context.Context, - n *clients.Node, + n *node.Node, r *result, ) { defer wg.Done() b := n.BeaconClient - headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead) - if err != nil { - r.err = errors.Wrap(err, "failed to poll head") - return - } - checkpoints, err := b.BlockFinalityCheckpoints( ctx, eth2api.BlockHead, @@ -372,7 +377,7 @@ func (t *Testnet) WaitForFork(ctx context.Context, fork string) error { versionedBlock, err := b.BlockV2( ctx, - eth2api.BlockIdRoot(headInfo.Root), + eth2api.BlockHead, ) if err != nil { r.err = errors.Wrap(err, "failed to retrieve block") @@ -384,7 +389,7 @@ func (t *Testnet) WaitForFork(ctx context.Context, fork string) error { execution = executionPayload.BlockHash } - slot := headInfo.Header.Message.Slot + slot := versionedBlock.Slot() if clockSlot > slot && (clockSlot-slot) >= t.spec.SLOTS_PER_EPOCH { r.fatal = fmt.Errorf( @@ -400,7 +405,7 @@ func (t *Testnet) WaitForFork(ctx context.Context, fork string) error { versionedBlock.Version, clockSlot, slot, - utils.Shorten(headInfo.Root.String()), + utils.Shorten(versionedBlock.Root().String()), utils.Shorten(execution.String()), utils.Shorten(checkpoints.CurrentJustified.String()), utils.Shorten(checkpoints.Finalized.String()), @@ -460,17 +465,11 @@ func (t *Testnet) WaitForFinality(ctx context.Context) ( for i, n := range runningNodes { wg.Add(1) - go func(ctx context.Context, n *clients.Node, r *result) { + go func(ctx context.Context, n *node.Node, r *result) { defer wg.Done() b := n.BeaconClient - headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead) - if err != nil { - r.err = errors.Wrap(err, "failed to poll head") - return - } - checkpoints, err := b.BlockFinalityCheckpoints( ctx, eth2api.BlockHead, @@ -485,7 +484,7 @@ func (t *Testnet) WaitForFinality(ctx context.Context) ( versionedBlock, err := b.BlockV2( ctx, - eth2api.BlockIdRoot(headInfo.Root), + eth2api.BlockHead, ) if err != nil { r.err = errors.Wrap(err, "failed to retrieve block") @@ -496,7 +495,7 @@ func (t *Testnet) WaitForFinality(ctx context.Context) ( execution = executionPayload.BlockHash } - slot := headInfo.Header.Message.Slot + slot := versionedBlock.Slot() if clockSlot > slot && (clockSlot-slot) >= t.spec.SLOTS_PER_EPOCH { r.fatal = fmt.Errorf( @@ -516,7 +515,7 @@ func (t *Testnet) WaitForFinality(ctx context.Context) ( versionedBlock.Version, clockSlot, slot, - utils.Shorten(headInfo.Root.String()), + utils.Shorten(versionedBlock.Root().String()), health, utils.Shorten(execution.String()), utils.Shorten(checkpoints.CurrentJustified.String()), @@ -581,19 +580,19 @@ func (t *Testnet) WaitForExecutionFinality( for i, n := range runningNodes { wg.Add(1) - go func(ctx context.Context, n *clients.Node, r *result) { + go func(ctx context.Context, n *node.Node, r *result) { defer wg.Done() var ( - b = n.BeaconClient - version string + b = n.BeaconClient + finalizedFork string ) - headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead) + headBlock, err := b.BlockV2(ctx, eth2api.BlockHead) if err != nil { r.err = errors.Wrap(err, "failed to poll head") return } - slot := headInfo.Header.Message.Slot + slot := headBlock.Slot() if clockSlot > slot && (clockSlot-slot) >= t.spec.SLOTS_PER_EPOCH { r.fatal = fmt.Errorf( @@ -617,8 +616,13 @@ func (t *Testnet) WaitForExecutionFinality( } execution := ethcommon.Hash{} + if exeuctionPayload, err := headBlock.ExecutionPayload(); err == nil { + execution = exeuctionPayload.BlockHash + } + + finalizedExecution := ethcommon.Hash{} if (checkpoints.Finalized != common.Checkpoint{}) { - if versionedBlock, err := b.BlockV2( + if finalizedBlock, err := b.BlockV2( ctx, eth2api.BlockIdRoot(checkpoints.Finalized.Root), ); err != nil { @@ -628,26 +632,31 @@ func (t *Testnet) WaitForExecutionFinality( ) return } else { - version = versionedBlock.Version - if exeuctionPayload, err := versionedBlock.ExecutionPayload(); err == nil { - execution = exeuctionPayload.BlockHash + finalizedFork = finalizedBlock.Version + if exeuctionPayload, err := finalizedBlock.ExecutionPayload(); err == nil { + finalizedExecution = exeuctionPayload.BlockHash } } } r.msg = fmt.Sprintf( - "fork=%s, clock_slot=%s, slot=%d, head=%s, "+ - "exec_payload=%s, justified=%s, finalized=%s", - version, + "fork=%s, finalized_fork=%s, clock_slot=%s, slot=%d, head=%s, "+ + "exec_payload=%s, finalized_exec_payload=%s, justified=%s, finalized=%s", + headBlock.Version, + finalizedFork, clockSlot, slot, - utils.Shorten(headInfo.Root.String()), + utils.Shorten(headBlock.Root().String()), utils.Shorten(execution.Hex()), + utils.Shorten(finalizedExecution.Hex()), utils.Shorten(checkpoints.CurrentJustified.String()), utils.Shorten(checkpoints.Finalized.String()), ) - if !bytes.Equal(execution[:], EMPTY_EXEC_HASH[:]) { + if !bytes.Equal( + finalizedExecution[:], + EMPTY_EXEC_HASH[:], + ) { r.done = true r.result = checkpoints.Finalized } @@ -717,7 +726,7 @@ func (t *Testnet) WaitForCurrentEpochFinalization( for i, n := range runningNodes { i := i wg.Add(1) - go func(ctx context.Context, n *clients.Node, r *result) { + go func(ctx context.Context, n *node.Node, r *result) { defer wg.Done() b := n.BeaconClient @@ -842,18 +851,21 @@ func (t *Testnet) WaitForExecutionPayload( for i, n := range runningNodes { wg.Add(1) - go func(ctx context.Context, n *clients.Node, r *result) { + go func(ctx context.Context, n *node.Node, r *result) { defer wg.Done() b := n.BeaconClient - headInfo, err := b.BlockHeader(ctx, eth2api.BlockHead) + versionedBlock, err := b.BlockV2( + ctx, + eth2api.BlockHead, + ) if err != nil { - r.err = errors.Wrap(err, "failed to poll head") + r.err = errors.Wrap(err, "failed to retrieve block") return } - slot := headInfo.Header.Message.Slot + slot := versionedBlock.Slot() if clockSlot > slot && (clockSlot-slot) >= t.spec.SLOTS_PER_EPOCH { r.fatal = fmt.Errorf( @@ -864,15 +876,6 @@ func (t *Testnet) WaitForExecutionPayload( return } - versionedBlock, err := b.BlockV2( - ctx, - eth2api.BlockIdRoot(headInfo.Root), - ) - if err != nil { - r.err = errors.Wrap(err, "failed to retrieve block") - return - } - executionHash := ethcommon.Hash{} if executionPayload, err := versionedBlock.ExecutionPayload(); err == nil { executionHash = executionPayload.BlockHash @@ -886,7 +889,7 @@ func (t *Testnet) WaitForExecutionPayload( versionedBlock.Version, clockSlot, slot, - utils.Shorten(headInfo.Root.String()), + utils.Shorten(versionedBlock.Root().String()), health, utils.Shorten(executionHash.Hex()), ) @@ -915,7 +918,7 @@ func (t *Testnet) WaitForExecutionPayload( func GetHealth( parentCtx context.Context, - bn *clients.BeaconClient, + bn *beacon_client.BeaconClient, spec *common.Spec, slot common.Slot, ) (float64, error) { diff --git a/simulators/eth2/common/testnet/utils.go b/simulators/eth2/common/testnet/utils.go index e24a3ddcca..cf472025b0 100644 --- a/simulators/eth2/common/testnet/utils.go +++ b/simulators/eth2/common/testnet/utils.go @@ -5,7 +5,7 @@ import ( "github.com/pkg/errors" - "github.com/ethereum/hive/simulators/eth2/common/clients" + "github.com/marioevz/eth-clients/clients/node" ) // result object used to get a result/error from each node @@ -78,7 +78,7 @@ func (rs resultsArr) AllDone() bool { return true } -func makeResults(nodes clients.Nodes, maxErr int) resultsArr { +func makeResults(nodes node.Nodes, maxErr int) resultsArr { res := make(resultsArr, len(nodes)) for i, n := range nodes { r := result{ diff --git a/simulators/eth2/common/testnet/verification.go b/simulators/eth2/common/testnet/verification.go index 356cb77eb1..6ebf3b85e4 100644 --- a/simulators/eth2/common/testnet/verification.go +++ b/simulators/eth2/common/testnet/verification.go @@ -8,8 +8,8 @@ import ( "time" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/hive/simulators/eth2/common/clients" "github.com/ethereum/hive/simulators/eth2/common/utils" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" "github.com/protolambda/eth2api" "github.com/protolambda/zrnt/eth2/beacon/common" "github.com/protolambda/ztyp/tree" @@ -20,7 +20,7 @@ type VerificationSlot interface { Slot( ctx context.Context, t *Testnet, - bn *clients.BeaconClient, + bn *beacon_client.BeaconClient, ) (common.Slot, error) } @@ -32,7 +32,7 @@ type FirstSlotAfterCheckpoint struct { func (c FirstSlotAfterCheckpoint) Slot( ctx context.Context, t *Testnet, - _ *clients.BeaconClient, + _ *beacon_client.BeaconClient, ) (common.Slot, error) { return t.Spec().EpochStartSlot(c.Checkpoint.Epoch + 1) } @@ -45,7 +45,7 @@ type LastSlotAtCheckpoint struct { func (c LastSlotAtCheckpoint) Slot( ctx context.Context, t *Testnet, - _ *clients.BeaconClient, + _ *beacon_client.BeaconClient, ) (common.Slot, error) { return t.Spec().SLOTS_PER_EPOCH * common.Slot(c.Checkpoint.Epoch), nil } @@ -56,7 +56,7 @@ type LastestSlotByTime struct{} func (l LastestSlotByTime) Slot( ctx context.Context, t *Testnet, - _ *clients.BeaconClient, + _ *beacon_client.BeaconClient, ) (common.Slot, error) { return t.Spec(). TimeToSlot(common.Timestamp(time.Now().Unix()), t.GenesisTime()), @@ -69,7 +69,7 @@ type LastestSlotByHead struct{} func (l LastestSlotByHead) Slot( ctx context.Context, t *Testnet, - bn *clients.BeaconClient, + bn *beacon_client.BeaconClient, ) (common.Slot, error) { headInfo, err := bn.BlockHeader(ctx, eth2api.BlockHead) if err != nil { @@ -186,7 +186,7 @@ func (t *Testnet) VerifyExecutionPayloadHashInclusion( parentCtx context.Context, vs VerificationSlot, hash ethcommon.Hash, -) (*clients.VersionedSignedBeaconBlock, error) { +) (*beacon_client.VersionedSignedBeaconBlock, error) { for _, bn := range t.VerificationNodes().BeaconClients().Running() { b, err := t.VerifyExecutionPayloadHashInclusionNode( parentCtx, @@ -204,9 +204,9 @@ func (t *Testnet) VerifyExecutionPayloadHashInclusion( func (t *Testnet) VerifyExecutionPayloadHashInclusionNode( parentCtx context.Context, vs VerificationSlot, - bn *clients.BeaconClient, + bn *beacon_client.BeaconClient, hash ethcommon.Hash, -) (*clients.VersionedSignedBeaconBlock, error) { +) (*beacon_client.VersionedSignedBeaconBlock, error) { lastSlot, err := vs.Slot(parentCtx, t, bn) if err != nil { return nil, err diff --git a/simulators/eth2/engine/go.mod b/simulators/eth2/engine/go.mod index db54512f0a..ba7e118f38 100644 --- a/simulators/eth2/engine/go.mod +++ b/simulators/eth2/engine/go.mod @@ -3,9 +3,10 @@ module github.com/ethereum/hive/simulators/eth2/engine go 1.18 require ( - github.com/ethereum/go-ethereum v1.11.4 + github.com/ethereum/go-ethereum v1.11.5 github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e github.com/ethereum/hive/simulators/eth2/common v0.0.0-20230316220410-1364352c32a6 + github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363 github.com/protolambda/eth2api v0.0.0-20230316214135-5f8afbd6d05d github.com/protolambda/zrnt v0.30.0 github.com/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a @@ -17,7 +18,7 @@ require ( github.com/ferranbt/fastssz v0.1.2 // 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 // indirect + github.com/holiman/uint256 v1.2.2 // 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 @@ -26,8 +27,8 @@ require ( 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.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -48,9 +49,9 @@ require ( github.com/getsentry/sentry-go v0.18.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.4.3 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect diff --git a/simulators/eth2/engine/go.sum b/simulators/eth2/engine/go.sum index 382530b306..3c8aeb83df 100644 --- a/simulators/eth2/engine/go.sum +++ b/simulators/eth2/engine/go.sum @@ -66,8 +66,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.11.4 h1:KG81SnUHXWk8LJB3mBcHg/E2yLvXoiPmRMCIRxgx3cE= -github.com/ethereum/go-ethereum v1.11.4/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= +github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= +github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e h1:3g9cqRqpbZ92tSlGL4PfFoq435axKw6HiZ1Gz3fOkfk= github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e/go.mod h1:PlpDuxHg6q1jU0K8Ouf+RXlHguignJ7k8Eyukc9RCPQ= github.com/ethereum/hive/simulators/eth2/common v0.0.0-20230316220410-1364352c32a6 h1:LcSUNGwQuJyR/gdPcsif57yKX+3MyhpoAuChzR8k6Yk= @@ -111,8 +111,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -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-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -130,8 +130,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 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= @@ -161,8 +162,8 @@ github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwa 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/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= +github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= 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/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= @@ -210,6 +211,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/marioevz/eth-clients v0.0.0-20230503171433-707db4e8bc85 h1:A3UX2d+yP+URXOlirB6ulC6mV6ET54MiMgEdgh29Wj8= +github.com/marioevz/eth-clients v0.0.0-20230503171433-707db4e8bc85/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= +github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363 h1:ONwsdY5/heIE0HHxh4+QXkwa69MZuaO+vONXduNBbrM= +github.com/marioevz/eth-clients v0.0.0-20230503173323-98293c926363/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -463,8 +468,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.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= @@ -473,8 +478,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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= diff --git a/simulators/eth2/engine/helper.go b/simulators/eth2/engine/helper.go index cfc498ec8a..95fec45bed 100644 --- a/simulators/eth2/engine/helper.go +++ b/simulators/eth2/engine/helper.go @@ -7,11 +7,13 @@ import ( "math/big" "time" + api "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/hive/hivesim" "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" + exec_client "github.com/marioevz/eth-clients/clients/execution" beacon "github.com/protolambda/zrnt/eth2/beacon/common" ) @@ -133,7 +135,7 @@ func SlotsUntilBellatrix( func TimeUntilTerminalBlock( parentCtx context.Context, - e *clients.ExecutionClient, + e *exec_client.ExecutionClient, c el.ExecutionConsensus, defaultTTD *big.Int, ) uint64 { @@ -151,3 +153,17 @@ func TimeUntilTerminalBlock( return td.Uint64() } } + +func PayloadFromResponse(res []byte) (*api.ExecutableData, error) { + // First try unmarshalling to the envelope + env := new(api.ExecutionPayloadEnvelope) + if err := exec_client.UnmarshalFromJsonRPCResponse(res, env); err == nil { + return env.ExecutionPayload, nil + } + // If that fails, try unmarshalling directly to the payload + payload := new(api.ExecutableData) + if err := exec_client.UnmarshalFromJsonRPCResponse(res, payload); err != nil { + return nil, err + } + return payload, nil +} diff --git a/simulators/eth2/engine/scenarios.go b/simulators/eth2/engine/scenarios.go index 87b75ee0c5..a44307afc9 100644 --- a/simulators/eth2/engine/scenarios.go +++ b/simulators/eth2/engine/scenarios.go @@ -10,16 +10,17 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/common" api "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/hive/hivesim" "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" + exec_client "github.com/marioevz/eth-clients/clients/execution" + "github.com/marioevz/eth-clients/clients/node" "github.com/protolambda/eth2api" beacon "github.com/protolambda/zrnt/eth2/beacon/common" spoof "github.com/rauljordan/engine-proxy/proxy" @@ -27,7 +28,7 @@ import ( var ( DEFAULT_VALIDATOR_COUNT uint64 = 60 - DEFAULT_SLOT_TIME uint64 = 6 + MAINNET_SLOT_TIME uint64 = 12 DEFAULT_TERMINAL_TOTAL_DIFFICULTY uint64 = 100 EPOCHS_TO_FINALITY beacon.Epoch = 4 @@ -35,7 +36,6 @@ var ( // Default config used for all tests unless a client specific config exists 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), ), @@ -44,29 +44,12 @@ var ( 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 = &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, - "prysm": true, - } - SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY_CLIENT_OVERRIDE = map[string]*big.Int{} ) func getClientConfig(n clients.NodeDefinition) *tn.Config { - config := DEFAULT_CONFIG - if INCREMENTAL_FORKS_CLIENTS[n.ConsensusClient] { - config = config.Join(INCREMENTAL_FORKS_CONFIG) - } - return config + config := *DEFAULT_CONFIG + return &config } func TransitionTestnet(t *hivesim.T, env *tn.Environment, @@ -172,12 +155,11 @@ func TestRPCError(t *hivesim.T, env *tn.Environment, fields := make(map[string]interface{}) fields["headBlockHash"] = "weird error" - spoof := &spoof.Spoof{ - Method: EngineForkchoiceUpdatedV1, - Fields: fields, - } - testnet.Proxies().Running()[0].AddRequest(spoof) + testnet.Proxies().Running()[0].AddRequests( + exec_client.MakeSpoofs( + fields, + exec_client.AllForkchoiceUpdatedCalls...)...) time.Sleep(24 * time.Second) @@ -263,12 +245,8 @@ func UnknownPoWParent(t *hivesim.T, env *tn.Environment, getPayloadCount++ // Invalidate the transition payload if getPayloadCount == 1 { - var ( - payload api.ExecutableData - spoof *spoof.Spoof - err error - ) - err = proxy.UnmarshalFromJsonRPCResponse(res, &payload) + var spoof *spoof.Spoof + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } @@ -279,7 +257,7 @@ func UnknownPoWParent(t *hivesim.T, env *tn.Environment, ) invalidPayloadHash, spoof, err = payload_spoof.GenerateInvalidPayloadSpoof( EngineGetPayloadV1, - &payload, + payload, payload_spoof.InvalidParentHash, VaultSigner, ) @@ -306,7 +284,7 @@ func UnknownPoWParent(t *hivesim.T, env *tn.Environment, spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &payload) + err = exec_client.UnmarshalFromJsonRPCRequest(req, &payload) if err != nil { panic(err) } @@ -346,7 +324,11 @@ func UnknownPoWParent(t *hivesim.T, env *tn.Environment, spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr) + err = exec_client.UnmarshalFromJsonRPCRequest( + req, + &fcState, + &pAttr, + ) if err != nil { panic(err) } @@ -378,9 +360,15 @@ func UnknownPoWParent(t *hivesim.T, env *tn.Environment, } } for n, p := range testnet.Proxies().Running() { - p.AddResponseCallback(EngineGetPayloadV1, getPayloadCallbackGen(n)) - p.AddResponseCallback(EngineNewPayloadV1, newPayloadCallbackGen(n)) - p.AddResponseCallback(EngineForkchoiceUpdatedV1, fcUCallbackGen(n)) + p.AddResponseCallbacks( + getPayloadCallbackGen(n), + exec_client.AllGetPayloadCalls...) + p.AddResponseCallbacks( + newPayloadCallbackGen(n), + exec_client.AllNewPayloadCalls...) + p.AddResponseCallbacks( + fcUCallbackGen(n), + exec_client.AllForkchoiceUpdatedCalls...) } // Network should recover from this @@ -471,10 +459,7 @@ func InvalidPayloadGen( if getPayloadCount == invalidPayloadNumber { // 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 api.ExecutableData - ) - err := proxy.UnmarshalFromJsonRPCResponse(res, &payload) + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } @@ -496,7 +481,7 @@ func InvalidPayloadGen( spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &payload) + err = exec_client.UnmarshalFromJsonRPCRequest(req, &payload) if err != nil { panic(err) } @@ -542,8 +527,12 @@ func InvalidPayloadGen( callback */ for i, p := range testnet.Proxies().Running() { - p.AddResponseCallback(EngineGetPayloadV1, getPayloadCallbackGen(i)) - p.AddResponseCallback(EngineNewPayloadV1, newPayloadCallbackGen(i)) + p.AddResponseCallbacks( + getPayloadCallbackGen(i), + exec_client.AllGetPayloadCalls...) + p.AddResponseCallbacks( + newPayloadCallbackGen(i), + exec_client.AllNewPayloadCalls...) } execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext( @@ -611,19 +600,15 @@ func IncorrectHeaderPrevRandaoPayload( getPayloadCount++ // Invalidate a payload after the transition payload if getPayloadCount == 2 { - var ( - payload api.ExecutableData - spoof *spoof.Spoof - err error - ) - err = proxy.UnmarshalFromJsonRPCResponse(res, &payload) + var spoof *spoof.Spoof + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } t.Logf("INFO (%v): Invalidating payload: %s", t.TestID, res) invalidPayloadHash, spoof, err = payload_spoof.GenerateInvalidPayloadSpoof( EngineGetPayloadV1, - &payload, + payload, payload_spoof.InvalidPrevRandao, VaultSigner, ) @@ -640,7 +625,7 @@ func IncorrectHeaderPrevRandaoPayload( return nil } for _, p := range testnet.Proxies().Running() { - p.AddResponseCallback(EngineGetPayloadV1, c) + p.AddResponseCallbacks(c, exec_client.AllGetPayloadCalls...) } execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext( @@ -686,7 +671,7 @@ func Timeouts(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) { n, }, // Use the default mainnet slot time to allow the timeout value to make sense - SlotTime: big.NewInt(int64(12)), + SlotTime: big.NewInt(int64(MAINNET_SLOT_TIME)), }) testnet := tn.StartTestnet(ctx, t, env, config) @@ -710,13 +695,13 @@ func Timeouts(t *hivesim.T, env *tn.Environment, n clients.NodeDefinition) { p0 = testnet.Proxies().Running()[0] p1 = testnet.Proxies().Running()[1] ) - p0.AddResponseCallback( - EngineNewPayloadV1, + p0.AddResponseCallbacks( gen(NewPayloadTimeoutSeconds-ToleranceSeconds), + exec_client.AllNewPayloadCalls..., ) - p1.AddResponseCallback( - EngineForkchoiceUpdatedV1, + p1.AddResponseCallbacks( gen(ForkchoiceUpdatedTimeoutSeconds-ToleranceSeconds), + exec_client.AllForkchoiceUpdatedCalls..., ) // Finality should be reached anyway because the time limit is not reached on the engine calls @@ -766,16 +751,14 @@ func InvalidTimestampPayload( defer getPayloadLock.Unlock() getPayloadCount++ var ( - payload api.ExecutableData - payloadID api.PayloadID + payloadID = new(api.PayloadID) spoof *spoof.Spoof - err error ) - err = proxy.UnmarshalFromJsonRPCResponse(res, &payload) + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } - err = proxy.UnmarshalFromJsonRPCRequest(req, &payloadID) + err = exec_client.UnmarshalFromJsonRPCRequest(req, payloadID) if err != nil { panic(err) } @@ -795,7 +778,7 @@ func InvalidTimestampPayload( extraData := []byte("alt") invalidPayloadHash, spoof, err = payload_spoof.CustomizePayloadSpoof( EngineGetPayloadV1, - &payload, + payload, &payload_spoof.CustomPayloadData{ Timestamp: &newTimestamp, ExtraData: &extraData, @@ -827,15 +810,15 @@ func InvalidTimestampPayload( ) for _, p := range testnet.Proxies().Running() { - p.AddResponseCallback(EngineGetPayloadV1, c) - p.AddResponseCallback( - EngineForkchoiceUpdatedV1, + p.AddResponseCallbacks(c, exec_client.AllGetPayloadCalls...) + p.AddResponseCallbacks( payload_spoof.CheckErrorOnForkchoiceUpdatedPayloadAttributes( &fcuLock, fcUCountLimit, &fcUAttrCount, fcudone, ), + exec_client.AllForkchoiceUpdatedCalls..., ) } @@ -1103,7 +1086,7 @@ func SyncingWithInvalidChain( spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &payload) + err = exec_client.UnmarshalFromJsonRPCRequest(req, &payload) if err != nil { panic(err) } @@ -1160,7 +1143,7 @@ func SyncingWithInvalidChain( spoof *spoof.Spoof err error ) - err = proxy.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr) + err = exec_client.UnmarshalFromJsonRPCRequest(req, &fcState, &pAttr) if err != nil { panic(err) } @@ -1217,10 +1200,12 @@ func SyncingWithInvalidChain( importerProxy := testnet.Proxies().Running()[2] // Add the callback to the last proxy which will not produce blocks - importerProxy.AddResponseCallback(EngineNewPayloadV1, newPayloadCallback) - importerProxy.AddResponseCallback( - EngineForkchoiceUpdatedV1, + importerProxy.AddResponseCallbacks( + newPayloadCallback, + exec_client.AllNewPayloadCalls...) + importerProxy.AddResponseCallbacks( forkchoiceUpdatedCallback, + exec_client.AllForkchoiceUpdatedCalls..., ) <-done @@ -1375,14 +1360,14 @@ func EqualTimestampTerminalTransitionBlock( ) for _, p := range testnet.Proxies().Running() { - p.AddResponseCallback( - EngineForkchoiceUpdatedV1, + p.AddResponseCallbacks( payload_spoof.CheckErrorOnForkchoiceUpdatedPayloadAttributes( &fcuLock, fcUCountLimit, &fcUAttrCount, fcudone, ), + exec_client.AllForkchoiceUpdatedCalls..., ) } @@ -1484,7 +1469,7 @@ func InvalidQuantityPayloadFields( invalidateQuantityType := func(id int, method string, response []byte, q QuantityType, invType InvalidationType) *spoof.Spoof { responseFields := make(map[string]json.RawMessage) - if err := proxy.UnmarshalFromJsonRPCResponse(response, &responseFields); err != nil { + if err := exec_client.UnmarshalFromJsonRPCResponse(response, &responseFields); err != nil { panic( fmt.Errorf("unable to unmarshal: %v. json: %s", err, response), ) @@ -1579,8 +1564,7 @@ func InvalidQuantityPayloadFields( defer func() { getPayloadCount++ }() - var payload api.ExecutableData - err := proxy.UnmarshalFromJsonRPCResponse(res, &payload) + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } @@ -1607,13 +1591,13 @@ func InvalidQuantityPayloadFields( ) newHash, spoof, _ := payload_spoof.CustomizePayloadSpoof( EngineGetPayloadV1, - &payload, + payload, &payload_spoof.CustomPayloadData{ ExtraData: &customExtraData, }, ) invalidPayloadHashes = append(invalidPayloadHashes, newHash) - return proxy.Combine( + return exec_client.Combine( spoof, invalidateQuantityType( id, @@ -1628,7 +1612,9 @@ func InvalidQuantityPayloadFields( // 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.AddResponseCallbacks( + getPayloadCallbackGen(i), + exec_client.AllGetPayloadCalls...) } // Wait until we are done @@ -2224,8 +2210,8 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock( // because they are not interconnected. // Therefore only one client pair will end up in optimistic sync mode. type BuilderImporterInfo struct { - Builder *clients.Node - Importer *clients.Node + Builder *node.Node + Importer *node.Node ChainGenerator *pow.ChainGenerator } builderImporterPairs := []BuilderImporterInfo{ @@ -2345,7 +2331,7 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock( } // Verify the heads match - optimisticClients := clients.ExecutionClients{ + optimisticClients := exec_client.ExecutionClients{ optimisticPair.Builder.ExecutionClient, optimisticPair.Importer.ExecutionClient, } @@ -2360,7 +2346,7 @@ func ReOrgSyncWithChainHavingInvalidTerminalBlock( } // Verify heads of the two client pairs are different - forkedClients := clients.ExecutionClients{ + forkedClients := exec_client.ExecutionClients{ testnet.ExecutionClients().Running()[0], testnet.ExecutionClients().Running()[2], } @@ -2438,7 +2424,7 @@ func NoViableHeadDueToOptimisticSync( importerProxy = testnet.Proxies().Running()[1] // Not yet started builder2 = testnet.BeaconClients()[2] - builder2Proxy *proxy.Proxy + builder2Proxy *exec_client.Proxy ) importerNewPayloadResponseMocker := payload_spoof.NewEngineResponseMocker( @@ -2462,11 +2448,7 @@ func NoViableHeadDueToOptimisticSync( ) getPayloadCallback := func(res []byte, req []byte) *spoof.Spoof { getPayloadCount++ - var ( - payload api.ExecutableData - err error - ) - err = proxy.UnmarshalFromJsonRPCResponse(res, &payload) + payload, err := PayloadFromResponse(res) if err != nil { panic(err) } @@ -2532,7 +2514,9 @@ func NoViableHeadDueToOptimisticSync( } return nil } - builder1Proxy.AddResponseCallback(EngineGetPayloadV1, getPayloadCallback) + builder1Proxy.AddResponseCallbacks( + getPayloadCallback, + exec_client.AllGetPayloadCalls...) execPayloadCtx, cancel := testnet.Spec().SlotTimeoutContext( ctx, diff --git a/simulators/eth2/go.work.sum b/simulators/eth2/go.work.sum index 85bfe33a66..a5d4d9c1f7 100644 --- a/simulators/eth2/go.work.sum +++ b/simulators/eth2/go.work.sum @@ -774,6 +774,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.3/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/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= @@ -819,6 +820,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= diff --git a/simulators/eth2/withdrawals/go.mod b/simulators/eth2/withdrawals/go.mod index 864dc57a6a..a010a2151b 100644 --- a/simulators/eth2/withdrawals/go.mod +++ b/simulators/eth2/withdrawals/go.mod @@ -3,7 +3,7 @@ module github.com/ethereum/hive/simulators/eth2/withdrawals go 1.18 require ( - github.com/ethereum/go-ethereum v1.11.4 + github.com/ethereum/go-ethereum v1.11.5 github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e github.com/ethereum/hive/simulators/eth2/common v0.0.0-20230316220410-1364352c32a6 github.com/protolambda/eth2api v0.0.0-20230316214135-5f8afbd6d05d @@ -12,12 +12,12 @@ require ( ) require ( - github.com/VictoriaMetrics/fastcache v1.12.0 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/ferranbt/fastssz v0.1.2 // 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 // indirect + github.com/holiman/uint256 v1.2.2 // 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 @@ -26,8 +26,8 @@ require ( 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.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.8.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -38,18 +38,18 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect + github.com/cockroachdb/pebble v0.0.0-20230404150825-93eff0a72e22 // indirect github.com/cockroachdb/redact v1.1.3 // indirect - github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/fjl/memsize v0.0.1 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getsentry/sentry-go v0.20.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.4.3 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -58,20 +58,22 @@ require ( 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/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.2.2 // indirect + github.com/klauspost/compress v1.16.3 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/marioevz/eth-clients v0.0.0-20230501225027-135b7d52b617 // indirect + github.com/marioevz/mock-builder v0.0.0-20230501225822-df434a88e375 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/protolambda/go-keystorev4 v0.0.0-20211007151826-f20444f6d564 // indirect github.com/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a // indirect - github.com/rivo/uniseg v0.4.3 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect @@ -80,9 +82,9 @@ require ( github.com/wealdtech/go-eth2-types/v2 v2.8.0 // indirect github.com/wealdtech/go-eth2-util v1.8.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - golang.org/x/crypto v0.4.0 // indirect - golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/time v0.3.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect ) diff --git a/simulators/eth2/withdrawals/go.sum b/simulators/eth2/withdrawals/go.sum index f4dcd26061..3de52d5233 100644 --- a/simulators/eth2/withdrawals/go.sum +++ b/simulators/eth2/withdrawals/go.sum @@ -9,6 +9,8 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= 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/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= @@ -37,6 +39,8 @@ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/pebble v0.0.0-20230404150825-93eff0a72e22 h1:2Nwgec/S3FkQW3r807JL9+D2xb2XU9zbRCotvQWLIfY= +github.com/cockroachdb/pebble v0.0.0-20230404150825-93eff0a72e22/go.mod h1:9lRMC4XN3/BLPtIp6kAKwIaHu369NOf2rMucPzipz50= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -52,6 +56,8 @@ 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/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= +github.com/deckarep/golang-set/v2 v2.3.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= @@ -67,6 +73,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.11.4 h1:KG81SnUHXWk8LJB3mBcHg/E2yLvXoiPmRMCIRxgx3cE= github.com/ethereum/go-ethereum v1.11.4/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= +github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= +github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e h1:3g9cqRqpbZ92tSlGL4PfFoq435axKw6HiZ1Gz3fOkfk= github.com/ethereum/hive v0.0.0-20230313141339-8e3200bfc09e/go.mod h1:PlpDuxHg6q1jU0K8Ouf+RXlHguignJ7k8Eyukc9RCPQ= github.com/ethereum/hive/simulators/eth2/common v0.0.0-20230316220410-1364352c32a6 h1:LcSUNGwQuJyR/gdPcsif57yKX+3MyhpoAuChzR8k6Yk= @@ -87,6 +95,8 @@ github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ= +github.com/getsentry/sentry-go v0.20.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -112,6 +122,8 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 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-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -128,9 +140,13 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.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/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 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= @@ -162,6 +178,8 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU 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/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= +github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= 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/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= @@ -193,10 +211,14 @@ github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 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/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -209,6 +231,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/marioevz/eth-clients v0.0.0-20230501225027-135b7d52b617 h1:sk4stg95D93cfiIIYI+XPRhXZQ91QGIPOHNDZjmpXms= +github.com/marioevz/eth-clients v0.0.0-20230501225027-135b7d52b617/go.mod h1:LnzXFKyMw3wF/3eaTfPhKiwkWkZJXokOWcUI02Ioi4s= +github.com/marioevz/mock-builder v0.0.0-20230501225822-df434a88e375 h1:44F0CrAc81Nzsr/4BhkeKebbrHERHdCjO6jXS9VAE/0= +github.com/marioevz/mock-builder v0.0.0-20230501225822-df434a88e375/go.mod h1:FQIXEFViaQkOqKrqLC91JgqG+6YEvqMVh9D7g6PmFUg= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -279,6 +305,8 @@ github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvq github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/protolambda/bls12-381-util v0.0.0-20210720105258-a772f2aac13e/go.mod h1:MPZvj2Pr0N8/dXyTPS5REeg2sdLG7t8DRzC1rLv925w= @@ -299,10 +327,14 @@ github.com/rauljordan/engine-proxy v0.0.0-20230316220057-4c80c36c4c3a/go.mod h1: 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/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -383,9 +415,13 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/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/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -464,6 +500,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.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= @@ -474,6 +512,8 @@ 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.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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= @@ -522,6 +562,8 @@ 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= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/simulators/eth2/withdrawals/helper.go b/simulators/eth2/withdrawals/helper.go index 0cdccbf0a0..c246ab0583 100644 --- a/simulators/eth2/withdrawals/helper.go +++ b/simulators/eth2/withdrawals/helper.go @@ -10,9 +10,11 @@ import ( "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" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" + exec_client "github.com/marioevz/eth-clients/clients/execution" + "github.com/pkg/errors" blsu "github.com/protolambda/bls12-381-util" "github.com/protolambda/eth2api" beacon "github.com/protolambda/zrnt/eth2/beacon/common" @@ -72,8 +74,8 @@ func WithdrawalsContainValidator( } type BeaconBlockState struct { - *clients.VersionedBeaconStateResponse - *clients.VersionedSignedBeaconBlock + *beacon_client.VersionedBeaconStateResponse + *beacon_client.VersionedSignedBeaconBlock } type BeaconCache map[tree.Root]BeaconBlockState @@ -94,7 +96,7 @@ func (c BeaconCache) Clear() error { func (c BeaconCache) GetBlockStateByRoot( ctx context.Context, - bc *clients.BeaconClient, + bc *beacon_client.BeaconClient, blockroot tree.Root, ) (BeaconBlockState, error) { if s, ok := c[blockroot]; ok { @@ -125,7 +127,7 @@ func (c BeaconCache) GetBlockStateByRoot( func (c BeaconCache) GetBlockStateBySlotFromHeadRoot( ctx context.Context, - bc *clients.BeaconClient, + bc *beacon_client.BeaconClient, headblockroot tree.Root, slot beacon.Slot, ) (*BeaconBlockState, error) { @@ -195,7 +197,7 @@ type Validator struct { Exited bool ExitCondition string ExactWithdrawableBalance *big.Int - Keys *cl.KeyDetails + Keys *cl.ValidatorDetails BLSToExecutionChangeDomain *beacon.BLSDomain Verified bool InitialBalance beacon.Gwei @@ -205,8 +207,8 @@ type Validator struct { func (v *Validator) VerifyWithdrawnBalance( ctx context.Context, - bc *clients.BeaconClient, - ec *clients.ExecutionClient, + bc *beacon_client.BeaconClient, + ec *exec_client.ExecutionClient, headBlockRoot tree.Root, ) (bool, error) { if v.Verified { @@ -228,7 +230,7 @@ func (v *Validator) VerifyWithdrawnBalance( headBlockRoot, ) if err != nil { - return false, err + return false, errors.Wrap(err, "failed to get head block state") } fmt.Printf( "INFO: Verifying balance validator %d on slot %d\n", @@ -239,7 +241,10 @@ func (v *Validator) VerifyWithdrawnBalance( // Then get the balance execPayload, err := headBlockState.ExecutionPayload() if err != nil { - return false, err + return false, errors.Wrap( + err, + "failed to get execution payload from head", + ) } balance, err := ec.BalanceAt( ctx, @@ -247,7 +252,7 @@ func (v *Validator) VerifyWithdrawnBalance( big.NewInt(int64(execPayload.Number)), ) if err != nil { - return false, err + return false, errors.Wrap(err, "failed to get balance") } fmt.Printf( @@ -285,7 +290,7 @@ func (v *Validator) VerifyWithdrawnBalance( for slot := beacon.Slot(0); slot <= headBlockState.Slot(); slot++ { blockState, err := v.BlockStateCache.GetBlockStateBySlotFromHeadRoot(ctx, bc, headBlockRoot, slot) if err != nil { - return false, err + return false, errors.Wrapf(err, "failed to get block state, slot %d", slot) } if blockState == nil { // Probably a skipped slot @@ -294,7 +299,7 @@ func (v *Validator) VerifyWithdrawnBalance( execPayload, err := blockState.ExecutionPayload() if err != nil { - return false, err + return false, errors.Wrapf(err, "failed to get execution payload, slot %d", slot) } if WithdrawalsContainValidator(execPayload.Withdrawals, v.Index) { @@ -392,7 +397,7 @@ func (v *Validator) SignBLSToExecutionChange( // Also internally update the withdraw address. func (v *Validator) SignSendBLSToExecutionChange( ctx context.Context, - bc *clients.BeaconClient, + bc *beacon_client.BeaconClient, executionAddress common.Address, ) error { signedBLS, err := v.SignBLSToExecutionChange(executionAddress) @@ -423,8 +428,8 @@ func (vs Validators) GetValidatorByIndex(i beacon.ValidatorIndex) *Validator { // Verify all validators have withdrawn func (vs Validators) VerifyWithdrawnBalance( ctx context.Context, - bc *clients.BeaconClient, - ec *clients.ExecutionClient, + bc *beacon_client.BeaconClient, + ec *exec_client.ExecutionClient, headBlockRoot tree.Root, ) (bool, error) { for i, v := range vs { @@ -499,7 +504,7 @@ func ValidatorFromBeaconValidator( index beacon.ValidatorIndex, source beacon.Validator, balance beacon.Gwei, - keys *cl.KeyDetails, + keys *cl.ValidatorDetails, domain *beacon.BLSDomain, beaconCache BeaconCache, ) (*Validator, error) { @@ -562,7 +567,7 @@ func ValidatorFromBeaconState( spec beacon.Spec, state beacon.BeaconState, index beacon.ValidatorIndex, - keys *cl.KeyDetails, + keys *cl.ValidatorDetails, domain *beacon.BLSDomain, beaconCache BeaconCache, ) (*Validator, error) { @@ -596,7 +601,7 @@ func ValidatorFromBeaconState( func ValidatorsFromBeaconState( state beacon.BeaconState, spec beacon.Spec, - keys []*cl.KeyDetails, + keys []*cl.ValidatorDetails, domain *beacon.BLSDomain, ) (Validators, error) { stateVals, err := state.Validators() diff --git a/simulators/eth2/withdrawals/main.go b/simulators/eth2/withdrawals/main.go index d060bf86c7..966935fe0c 100644 --- a/simulators/eth2/withdrawals/main.go +++ b/simulators/eth2/withdrawals/main.go @@ -8,10 +8,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/hive/hivesim" - mock_builder "github.com/ethereum/hive/simulators/eth2/common/builder/mock" "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" + mock_builder "github.com/marioevz/mock-builder/mock" ) var ( @@ -29,7 +29,7 @@ type TestSpec interface { GetName() string GetDescription() string Execute(*hivesim.T, *testnet.Environment, []clients.NodeDefinition) - GetValidatorKeys(string) []*consensus_config.KeyDetails + GetValidatorKeys(string) []*consensus_config.ValidatorDetails } var tests = []TestSpec{ diff --git a/simulators/eth2/withdrawals/scenarios.go b/simulators/eth2/withdrawals/scenarios.go index 06c2019c4f..9465d26b95 100644 --- a/simulators/eth2/withdrawals/scenarios.go +++ b/simulators/eth2/withdrawals/scenarios.go @@ -8,11 +8,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/hive/hivesim" - mock_builder "github.com/ethereum/hive/simulators/eth2/common/builder/mock" "github.com/ethereum/hive/simulators/eth2/common/clients" + mock_builder "github.com/marioevz/mock-builder/mock" beacon_verification "github.com/ethereum/hive/simulators/eth2/common/spoofing/beacon" tn "github.com/ethereum/hive/simulators/eth2/common/testnet" + beacon_client "github.com/marioevz/eth-clients/clients/beacon" "github.com/protolambda/eth2api" beacon "github.com/protolambda/zrnt/eth2/beacon/common" ) @@ -160,7 +161,7 @@ func (ts BaseWithdrawalsTestSpec) Execute( } // Get the beacon state and verify the credentials were updated - var versionedBeaconState *clients.VersionedBeaconStateResponse + var versionedBeaconState *beacon_client.VersionedBeaconStateResponse for _, bn := range testnet.BeaconClients().Running() { versionedBeaconState, err = bn.BeaconStateV2( ctx, @@ -399,7 +400,14 @@ func (ts BuilderWithdrawalsTestSpec) Execute( // Check that the builder was working properly until now for i, b := range testnet.BeaconClients().Running() { - builder := b.Builder + builder, ok := b.Builder.(*mock_builder.MockBuilder) + if !ok { + t.Fatalf( + "FAIL: client %d (%s) is not a mock builder", + i, + b.ClientName(), + ) + } if builder.GetBuiltPayloadsCount() == 0 { t.Fatalf("FAIL: builder %d did not build any payloads", i) } @@ -454,7 +462,14 @@ func (ts BuilderWithdrawalsTestSpec) Execute( // Simply verify that builder's capella payloads were included in the // canonical chain for i, n := range testnet.Nodes.Running() { - b := n.BeaconClient.Builder + b, ok := n.BeaconClient.Builder.(*mock_builder.MockBuilder) + if !ok { + t.Fatalf( + "FAIL: client %d (%s) is not a mock builder", + i, + n.BeaconClient.ClientName(), + ) + } ec := n.ExecutionClient includedPayloads := 0 for _, p := range b.GetBuiltPayloads() { @@ -482,7 +497,15 @@ func (ts BuilderWithdrawalsTestSpec) Execute( } } else if ts.InvalidatePayloadAttributes != "" { for i, n := range testnet.VerificationNodes().Running() { - modifiedPayloads := n.BeaconClient.Builder.GetModifiedPayloads() + b, ok := n.BeaconClient.Builder.(*mock_builder.MockBuilder) + if !ok { + t.Fatalf( + "FAIL: client %d (%s) is not a mock builder", + i, + n.BeaconClient.ClientName(), + ) + } + modifiedPayloads := b.GetModifiedPayloads() if len(modifiedPayloads) == 0 { t.Fatalf("FAIL: No payloads were modified by builder %d", i) } @@ -552,7 +575,14 @@ func (ts BuilderWithdrawalsTestSpec) Execute( spec := testnet.Spec().Spec genesisValsRoot := testnet.GenesisValidatorsRoot() for i, n := range testnet.Nodes.Running() { - b := n.BeaconClient.Builder + b, ok := n.BeaconClient.Builder.(*mock_builder.MockBuilder) + if !ok { + t.Fatalf( + "FAIL: client %d (%s) is not a mock builder", + i, + n.BeaconClient.ClientName(), + ) + } for slot, b := range b.GetSignedBeaconBlocks() { if slot != b.Slot() { t.Fatalf( diff --git a/simulators/eth2/withdrawals/specs.go b/simulators/eth2/withdrawals/specs.go index c8b1246c9a..8d39f93ae2 100644 --- a/simulators/eth2/withdrawals/specs.go +++ b/simulators/eth2/withdrawals/specs.go @@ -8,11 +8,11 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" - mock_builder "github.com/ethereum/hive/simulators/eth2/common/builder/mock" "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" + mock_builder "github.com/marioevz/mock-builder/mock" beacon "github.com/protolambda/zrnt/eth2/beacon/common" ) @@ -47,15 +47,12 @@ type BaseWithdrawalsTestSpec struct { var ( DEFAULT_VALIDATOR_COUNT uint64 = 128 - MAINNET_SLOT_TIME int64 = 12 - MINIMAL_SLOT_TIME int64 = 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(MAINNET_SLOT_TIME), TerminalTotalDifficulty: common.Big0, AltairForkEpoch: common.Big0, BellatrixForkEpoch: common.Big0, @@ -63,27 +60,6 @@ var ( Eth1Consensus: &el.ExecutionPostMergeGenesis{}, } - MINIMAL_SLOT_TIME_CLIENTS = []string{ - "lighthouse", - "teku", - "prysm", - "lodestar", - } - - // 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, - } - */ - // This is the account that sends vault funding transactions. VaultAccountAddress = common.HexToAddress( "0xcf49fda3be353c69b41ed96333cd24302da4556f", @@ -109,22 +85,6 @@ func (ts BaseWithdrawalsTestSpec) GetTestnetConfig( ) *testnet.Config { config := *DEFAULT_CONFIG - /* - if INCREMENTAL_FORKS_CLIENTS[n.ConsensusClient] { - config = config.Join(INCREMENTAL_FORKS_CONFIG) - } - */ - - if len( - allNodeDefinitions.FilterByCL(MINIMAL_SLOT_TIME_CLIENTS), - ) == len( - allNodeDefinitions, - ) { - // If all clients support using minimal 6 second slot time, use it - config.SlotTime = big.NewInt(MINIMAL_SLOT_TIME) - } - fmt.Printf("INFO: using %d second slot time\n", config.SlotTime) - if ts.CapellaGenesis { config.CapellaForkEpoch = common.Big0 } @@ -192,7 +152,7 @@ func (ts BaseWithdrawalsTestSpec) GetValidatorCount() uint64 { func (ts BaseWithdrawalsTestSpec) GetValidatorKeys( mnemonic string, -) []*cl.KeyDetails { +) []*cl.ValidatorDetails { keySrc := &cl.MnemonicsKeySource{ From: 0, To: ts.GetValidatorCount(),