diff --git a/cl/phase1/execution_client/execution_client.go b/cl/phase1/execution_client/execution_client.go index a1583d108eb..fdfbb3aa6c3 100644 --- a/cl/phase1/execution_client/execution_client.go +++ b/cl/phase1/execution_client/execution_client.go @@ -22,7 +22,7 @@ import ( "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/phase1/execution_client/rpc_helper" "github.com/ledgerwatch/erigon/core/types" - "github.com/ledgerwatch/erigon/turbo/engineapi" + "github.com/ledgerwatch/erigon/turbo/engineapi/engine_types" ) const fcuTimeout = 12 * time.Second @@ -155,7 +155,7 @@ func (ec *ExecutionClient) InsertBodies(bodies []*types.RawBody, blockHashes []l BlockHash: gointerfaces.ConvertHashToH256(blockHashes[i]), BlockNumber: blockNumbers[i], Transactions: body.Transactions, - Withdrawals: engineapi.ConvertWithdrawalsToRpc(body.Withdrawals), + Withdrawals: engine_types.ConvertWithdrawalsToRpc(body.Withdrawals), }) } _, err := ec.client.InsertBodies(ec.ctx, &execution.InsertBodiesRequest{Bodies: grpcBodies}) @@ -246,6 +246,6 @@ func (ec *ExecutionClient) ReadBody(number uint64, blockHash libcommon.Hash) (*t return &types.RawBody{ Transactions: resp.Body.Transactions, Uncles: uncles, - Withdrawals: engineapi.ConvertWithdrawalsFromRpc(resp.Body.Withdrawals), + Withdrawals: engine_types.ConvertWithdrawalsFromRpc(resp.Body.Withdrawals), }, nil } diff --git a/cmd/erigon-el-mock/server.go b/cmd/erigon-el-mock/server.go index 7dc429e07a3..453c82ce7cb 100644 --- a/cmd/erigon-el-mock/server.go +++ b/cmd/erigon-el-mock/server.go @@ -14,7 +14,7 @@ import ( "github.com/ledgerwatch/erigon-lib/gointerfaces/execution" types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon/turbo/engineapi" + "github.com/ledgerwatch/erigon/turbo/engineapi/engine_types" "github.com/ledgerwatch/erigon/turbo/services" "github.com/ledgerwatch/erigon/core/rawdb" @@ -201,7 +201,7 @@ func (e *Eth1Execution) GetBody(ctx context.Context, req *execution.GetSegmentRe if err != nil { return nil, err } - rpcWithdrawals := engineapi.ConvertWithdrawalsToRpc(body.Withdrawals) + rpcWithdrawals := engine_types.ConvertWithdrawalsToRpc(body.Withdrawals) unclesRpc := make([]*execution.Header, 0, len(body.Uncles)) for _, uncle := range body.Uncles { unclesRpc = append(unclesRpc, HeaderToHeaderRPC(uncle)) diff --git a/eth/backend.go b/eth/backend.go index ee9e09916c1..6dff78b39ec 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -41,6 +41,7 @@ import ( "github.com/ledgerwatch/erigon/turbo/builder" "github.com/ledgerwatch/erigon/turbo/engineapi" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers" + "github.com/ledgerwatch/erigon/turbo/execution/eth1" "github.com/ledgerwatch/erigon/turbo/jsonrpc" "github.com/ledgerwatch/erigon/turbo/rpchelper" "github.com/ledgerwatch/erigon/turbo/snapshotsync/freezeblocks" @@ -568,15 +569,16 @@ func New(stack *node.Node, config *ethconfig.Config, logger log.Logger) (*Ethere // intiialize engine backend var engine *execution_client.ExecutionClientDirect + executionRpc := direct.NewExecutionClientDirect(eth1.NewEthereumExecutionModule(blockReader, chainKv, nil, backend.forkValidator, chainConfig, assembleBlockPOS, logger)) if config.ExperimentalConsensusSeparation { log.Info("Using experimental Engine API") - engineBackendRPC := engineapi.NewEngineServerExperimental(ctx, logger, chainConfig, assembleBlockPOS, backend.chainDB, blockReader, backend.sentriesClient.Hd, config.Miner.EnabledPOS) + engineBackendRPC := engineapi.NewEngineServerExperimental(ctx, logger, chainConfig, executionRpc, backend.chainDB, blockReader, backend.sentriesClient.Hd, config.Miner.EnabledPOS) backend.engineBackendRPC = engineBackendRPC engine, err = execution_client.NewExecutionClientDirect(ctx, engineBackendRPC, ) } else { - engineBackendRPC := engineapi.NewEngineServer(ctx, logger, chainConfig, assembleBlockPOS, backend.chainDB, blockReader, backend.sentriesClient.Hd, config.Miner.EnabledPOS) + engineBackendRPC := engineapi.NewEngineServer(ctx, logger, chainConfig, executionRpc, backend.chainDB, blockReader, backend.sentriesClient.Hd, config.Miner.EnabledPOS) backend.engineBackendRPC = engineBackendRPC engine, err = execution_client.NewExecutionClientDirect(ctx, engineBackendRPC, diff --git a/go.mod b/go.mod index 5fd2c7a8254..3d031f6e3ee 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ledgerwatch/erigon go 1.19 require ( - github.com/ledgerwatch/erigon-lib v0.0.0-20230723163836-9e08d02f75b8 + github.com/ledgerwatch/erigon-lib v0.0.0-20230726204453-940c82dc2341 github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2 github.com/ledgerwatch/log/v3 v3.8.0 github.com/ledgerwatch/secp256k1 v1.0.0 diff --git a/go.sum b/go.sum index 961a7446b1f..fc58f921232 100644 --- a/go.sum +++ b/go.sum @@ -499,8 +499,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/ledgerwatch/erigon-lib v0.0.0-20230723163836-9e08d02f75b8 h1:P8CdtNh0DDKhzTVnwuCQY1lg8Jn1N21nmSHGOl4Kjxo= -github.com/ledgerwatch/erigon-lib v0.0.0-20230723163836-9e08d02f75b8/go.mod h1:ZkH1giM9x/HgdvjWzeCiOIx2lLDo98T/uvmRkG6xet0= +github.com/ledgerwatch/erigon-lib v0.0.0-20230726204453-940c82dc2341 h1:uKE4wYKbBrzBdrEV7gB2hQZ+snGkMobooU6on1/MRpo= +github.com/ledgerwatch/erigon-lib v0.0.0-20230726204453-940c82dc2341/go.mod h1:k8pDfuQxOA2IJvgJVbw0iEmro2ri3jLUyDANMhPIbWk= github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2 h1:Ls2itRGHMOr2PbHRDA4g1HH8HQdwfJhRVfMPEaLQe94= github.com/ledgerwatch/erigon-snapshot v1.2.1-0.20230622075030-1d69651854c2/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= github.com/ledgerwatch/log/v3 v3.8.0 h1:gCpp7uGtIerEz1jKVPeDnbIopFPud9ZnCpBLlLBGqPU= diff --git a/turbo/engineapi/engine_server.go b/turbo/engineapi/engine_server.go index 39e5eb2626b..74c484ff3a3 100644 --- a/turbo/engineapi/engine_server.go +++ b/turbo/engineapi/engine_server.go @@ -1,28 +1,26 @@ package engineapi import ( - "bytes" "context" "encoding/binary" + "errors" "fmt" "math/big" - "reflect" "sync" "time" + "github.com/ledgerwatch/erigon-lib/gointerfaces" libstate "github.com/ledgerwatch/erigon-lib/state" - "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" + "github.com/ledgerwatch/erigon-lib/gointerfaces/execution" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" - types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/log/v3" - "github.com/ledgerwatch/erigon-lib/gointerfaces" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg" @@ -30,11 +28,9 @@ import ( "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/consensus/merge" - "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/rpc" - "github.com/ledgerwatch/erigon/turbo/builder" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_types" "github.com/ledgerwatch/erigon/turbo/jsonrpc" @@ -43,24 +39,12 @@ import ( "github.com/ledgerwatch/erigon/turbo/stages/headerdownload" ) -// Configure network related parameters for the config. -type EngineServerConfig struct { - // Authentication - JwtSecret []byte - // Network related - Address string - Port int -} - type EngineServer struct { hd *headerdownload.HeaderDownload config *chain.Config // Block proposing for proof-of-stake - payloadId uint64 - lastParameters *core.BlockBuilderParameters - builders map[uint64]*builder.BlockBuilder - builderFunc builder.BlockBuilderFunc - proposing bool + proposing bool + executionService execution.ExecutionClient ctx context.Context lock sync.Mutex @@ -70,18 +54,17 @@ type EngineServer struct { blockReader services.FullBlockReader } -func NewEngineServer(ctx context.Context, logger log.Logger, config *chain.Config, builderFunc builder.BlockBuilderFunc, +func NewEngineServer(ctx context.Context, logger log.Logger, config *chain.Config, executionService execution.ExecutionClient, db kv.RoDB, blockReader services.FullBlockReader, hd *headerdownload.HeaderDownload, proposing bool) *EngineServer { return &EngineServer{ - ctx: ctx, - logger: logger, - config: config, - builderFunc: builderFunc, - db: db, - blockReader: blockReader, - proposing: proposing, - hd: hd, - builders: make(map[uint64]*builder.BlockBuilder), + ctx: ctx, + logger: logger, + config: config, + executionService: executionService, + db: db, + blockReader: blockReader, + proposing: proposing, + hd: hd, } } @@ -377,19 +360,6 @@ func (s *EngineServer) getQuickPayloadStatusIfPossible(blockHash libcommon.Hash, return nil, nil } -// The expected value to be received by the feeRecipient in wei -func blockValue(br *types.BlockWithReceipts, baseFee *uint256.Int) *uint256.Int { - blockValue := uint256.NewInt(0) - txs := br.Block.Transactions() - for i := range txs { - gas := new(uint256.Int).SetUint64(br.Receipts[i].GasUsed) - effectiveTip := txs[i].GetEffectiveGasTip(baseFee) - txValue := new(uint256.Int).Mul(gas, effectiveTip) - blockValue.Add(blockValue, txValue) - } - return blockValue -} - // EngineGetPayload retrieves previously assembled payload (Validators only) func (s *EngineServer) getPayload(ctx context.Context, payloadId uint64) (*engine_types.GetPayloadResponse, error) { if !s.proposing { @@ -404,90 +374,28 @@ func (s *EngineServer) getPayload(ctx context.Context, payloadId uint64) (*engin s.lock.Lock() defer s.lock.Unlock() s.logger.Debug("[GetPayload] lock acquired") - - builder, ok := s.builders[payloadId] - if !ok { - log.Warn("Payload not stored", "payloadId", payloadId) - return nil, &engine_helpers.UnknownPayloadErr - } - - blockWithReceipts, err := builder.Stop() + resp, err := s.executionService.GetAssembledBlock(ctx, &execution.GetAssembledBlockRequest{ + Id: payloadId, + }) if err != nil { - s.logger.Error("Failed to build PoS block", "err", err) return nil, err } - block := blockWithReceipts.Block - header := block.Header() - - baseFee := new(uint256.Int) - baseFee.SetFromBig(header.BaseFee) - - encodedTransactions, err := types.MarshalTransactionsBinary(block.Transactions()) - if err != nil { - return nil, err - } - txs := []hexutility.Bytes{} - for _, tx := range encodedTransactions { - txs = append(txs, tx) - } - - payload := &engine_types.ExecutionPayload{ - ParentHash: header.ParentHash, - FeeRecipient: header.Coinbase, - Timestamp: hexutil.Uint64(header.Time), - PrevRandao: header.MixDigest, - StateRoot: block.Root(), - ReceiptsRoot: block.ReceiptHash(), - LogsBloom: block.Bloom().Bytes(), - GasLimit: hexutil.Uint64(block.GasLimit()), - GasUsed: hexutil.Uint64(block.GasUsed()), - BlockNumber: hexutil.Uint64(block.NumberU64()), - ExtraData: block.Extra(), - BaseFeePerGas: (*hexutil.Big)(header.BaseFee), - BlockHash: block.Hash(), - Transactions: txs, - } - if block.Withdrawals() != nil { - payload.Withdrawals = block.Withdrawals() - } - - if header.DataGasUsed != nil && header.ExcessDataGas != nil { - payload.DataGasUsed = (*hexutil.Uint64)(header.DataGasUsed) - payload.ExcessDataGas = (*hexutil.Uint64)(header.ExcessDataGas) + if resp.Busy { + log.Warn("Cannot build payload, execution is busy", "payloadId", payloadId) + return nil, &engine_helpers.UnknownPayloadErr } + // If the service is busy or there is no data for the given id then respond accordingly. + if resp.Data == nil { + log.Warn("Payload not stored", "payloadId", payloadId) + return nil, &engine_helpers.UnknownPayloadErr - blockValue := blockValue(blockWithReceipts, baseFee) - - blobsBundle := &engine_types.BlobsBundleV1{} - for i, tx := range block.Transactions() { - if tx.Type() != types.BlobTxType { - continue - } - blobTx, ok := tx.(*types.BlobTxWrapper) - if !ok { - return nil, fmt.Errorf("expected blob transaction to be type BlobTxWrapper, got: %T", blobTx) - } - versionedHashes, commitments, proofs, blobs := blobTx.GetDataHashes(), blobTx.Commitments, blobTx.Proofs, blobTx.Blobs - lenCheck := len(versionedHashes) - if lenCheck != len(commitments) || lenCheck != len(proofs) || lenCheck != len(blobs) { - return nil, fmt.Errorf("tx %d in block %s has inconsistent commitments (%d) / proofs (%d) / blobs (%d) / "+ - "versioned hashes (%d)", i, block.Hash(), len(commitments), len(proofs), len(blobs), lenCheck) - } - for _, commitment := range commitments { - blobsBundle.Commitments = append(blobsBundle.Commitments, commitment) - } - for _, proof := range proofs { - blobsBundle.Proofs = append(blobsBundle.Proofs, proof) - } - for _, blob := range blobs { - blobsBundle.Blobs = append(blobsBundle.Blobs, blob) - } } + data := resp.Data return &engine_types.GetPayloadResponse{ - ExecutionPayload: payload, - BlockValue: (*hexutil.Big)(blockValue.ToBig()), - BlobsBundle: blobsBundle, + ExecutionPayload: engine_types.ConvertPayloadFromRpc(data.ExecutionPayload), + BlockValue: (*hexutil.Big)(gointerfaces.ConvertH256ToUint256Int(data.BlockValue).ToBig()), + BlobsBundle: engine_types.ConvertBlobsFromRpc(data.BlobsBundle), }, nil } @@ -557,58 +465,33 @@ func (s *EngineServer) forkchoiceUpdated(ctx context.Context, forkchoiceState *e return nil, &engine_helpers.InvalidPayloadAttributesErr } - param := core.BlockBuilderParameters{ - ParentHash: forkChoice.HeadHash, - Timestamp: uint64(payloadAttributes.Timestamp), - PrevRandao: payloadAttributes.PrevRandao, - SuggestedFeeRecipient: payloadAttributes.SuggestedFeeRecipient, - PayloadId: s.payloadId, + req := &execution.AssembleBlockRequest{ + ParentHash: gointerfaces.ConvertHashToH256(forkChoice.HeadHash), + Timestamp: uint64(payloadAttributes.Timestamp), + MixDigest: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao), + SuggestedFeeRecipent: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient), } + if version >= clparams.CapellaVersion { - param.Withdrawals = payloadAttributes.Withdrawals + req.Withdrawals = engine_types.ConvertWithdrawalsToRpc(payloadAttributes.Withdrawals) } - if err := s.checkWithdrawalsPresence(uint64(payloadAttributes.Timestamp), param.Withdrawals); err != nil { + + resp, err := s.executionService.AssembleBlock(ctx, req) + if err != nil { return nil, err } - - // First check if we're already building a block with the requested parameters - if reflect.DeepEqual(s.lastParameters, ¶m) { - s.logger.Info("[ForkChoiceUpdated] duplicate build request") - return &engine_types.ForkChoiceUpdatedResponse{ - PayloadStatus: &engine_types.PayloadStatus{ - Status: engine_types.ValidStatus, - LatestValidHash: &headHash, - }, - PayloadId: convertPayloadId(s.payloadId), - }, nil + if resp.Busy { + return nil, errors.New("[ForkChoiceUpdated]: execution service is busy, cannot assemble blocks") } - - // Initiate payload building - s.evictOldBuilders() - - s.payloadId++ - param.PayloadId = s.payloadId - s.lastParameters = ¶m - - s.builders[s.payloadId] = builder.NewBlockBuilder(s.builderFunc, ¶m) - s.logger.Info("[ForkChoiceUpdated] BlockBuilder added", "payload", s.payloadId) - return &engine_types.ForkChoiceUpdatedResponse{ PayloadStatus: &engine_types.PayloadStatus{ Status: engine_types.ValidStatus, LatestValidHash: &headHash, }, - PayloadId: convertPayloadId(s.payloadId), + PayloadId: engine_types.ConvertPayloadId(resp.Id), }, nil } -func convertPayloadId(payloadId uint64) *hexutility.Bytes { - encodedPayloadId := make([]byte, 8) - binary.BigEndian.PutUint64(encodedPayloadId, payloadId) - ret := hexutility.Bytes(encodedPayloadId) - return &ret -} - func (s *EngineServer) getPayloadBodiesByHash(ctx context.Context, request []libcommon.Hash, _ clparams.StateVersion) ([]*engine_types.ExecutionPayloadBodyV1, error) { tx, err := s.db.BeginRo(ctx) if err != nil { @@ -666,66 +549,6 @@ func (s *EngineServer) getPayloadBodiesByRange(ctx context.Context, start, count return bodies, nil } -func extractPayloadBodyFromBlock(block *types.Block) (*engine_types.ExecutionPayloadBodyV1, error) { - if block == nil { - return nil, nil - } - - txs := block.Transactions() - bdTxs := make([]hexutility.Bytes, len(txs)) - for idx, tx := range txs { - var buf bytes.Buffer - if err := tx.MarshalBinary(&buf); err != nil { - return nil, err - } else { - bdTxs[idx] = buf.Bytes() - } - } - - return &engine_types.ExecutionPayloadBodyV1{Transactions: bdTxs, Withdrawals: block.Withdrawals()}, nil -} - -func (s *EngineServer) evictOldBuilders() { - ids := common.SortedKeys(s.builders) - - // remove old builders so that at most MaxBuilders - 1 remain - for i := 0; i <= len(s.builders)-engine_helpers.MaxBuilders; i++ { - delete(s.builders, ids[i]) - } -} - -func ConvertWithdrawalsFromRpc(in []*types2.Withdrawal) []*types.Withdrawal { - if in == nil { - return nil - } - out := make([]*types.Withdrawal, 0, len(in)) - for _, w := range in { - out = append(out, &types.Withdrawal{ - Index: w.Index, - Validator: w.ValidatorIndex, - Address: gointerfaces.ConvertH160toAddress(w.Address), - Amount: w.Amount, - }) - } - return out -} - -func ConvertWithdrawalsToRpc(in []*types.Withdrawal) []*types2.Withdrawal { - if in == nil { - return nil - } - out := make([]*types2.Withdrawal, 0, len(in)) - for _, w := range in { - out = append(out, &types2.Withdrawal{ - Index: w.Index, - ValidatorIndex: w.Validator, - Address: gointerfaces.ConvertAddressToH160(w.Address), - Amount: w.Amount, - }) - } - return out -} - func (e *EngineServer) GetPayloadV1(ctx context.Context, payloadId hexutility.Bytes) (*engine_types.ExecutionPayload, error) { decodedPayloadId := binary.BigEndian.Uint64(payloadId) @@ -819,20 +642,6 @@ func (e *EngineServer) GetPayloadBodiesByRangeV1(ctx context.Context, start, cou return e.getPayloadBodiesByRange(ctx, uint64(start), uint64(count), clparams.CapellaVersion) } -var ourCapabilities = []string{ - "engine_forkchoiceUpdatedV1", - "engine_forkchoiceUpdatedV2", - "engine_newPayloadV1", - "engine_newPayloadV2", - // "engine_newPayloadV3", - "engine_getPayloadV1", - "engine_getPayloadV2", - // "engine_getPayloadV3", - "engine_exchangeTransitionConfigurationV1", - "engine_getPayloadBodiesByHashV1", - "engine_getPayloadBodiesByRangeV1", -} - func (e *EngineServer) ExchangeCapabilities(fromCl []string) []string { missingOurs := compareCapabilities(fromCl, ourCapabilities) missingCl := compareCapabilities(ourCapabilities, fromCl) @@ -843,21 +652,3 @@ func (e *EngineServer) ExchangeCapabilities(fromCl []string) []string { return ourCapabilities } - -func compareCapabilities(from []string, to []string) []string { - result := make([]string, 0) - for _, f := range from { - found := false - for _, t := range to { - if f == t { - found = true - break - } - } - if !found { - result = append(result, f) - } - } - - return result -} diff --git a/turbo/engineapi/engine_server_experimental.go b/turbo/engineapi/engine_server_experimental.go index ca85f383279..5c23757e20d 100644 --- a/turbo/engineapi/engine_server_experimental.go +++ b/turbo/engineapi/engine_server_experimental.go @@ -1,20 +1,22 @@ package engineapi import ( + "bytes" "context" "encoding/binary" + "errors" "fmt" "math/big" - "reflect" "sync" "time" + "github.com/ledgerwatch/erigon-lib/gointerfaces" libstate "github.com/ledgerwatch/erigon-lib/state" - "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" + "github.com/ledgerwatch/erigon-lib/gointerfaces/execution" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/kvcache" @@ -27,11 +29,9 @@ import ( "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/consensus/merge" - "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/rpc" - "github.com/ledgerwatch/erigon/turbo/builder" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_types" "github.com/ledgerwatch/erigon/turbo/jsonrpc" @@ -44,11 +44,8 @@ type EngineServerExperimental struct { hd *headerdownload.HeaderDownload config *chain.Config // Block proposing for proof-of-stake - payloadId uint64 - lastParameters *core.BlockBuilderParameters - builders map[uint64]*builder.BlockBuilder - builderFunc builder.BlockBuilderFunc - proposing bool + proposing bool + executionService execution.ExecutionClient ctx context.Context lock sync.Mutex @@ -58,18 +55,17 @@ type EngineServerExperimental struct { blockReader services.FullBlockReader } -func NewEngineServerExperimental(ctx context.Context, logger log.Logger, config *chain.Config, builderFunc builder.BlockBuilderFunc, +func NewEngineServerExperimental(ctx context.Context, logger log.Logger, config *chain.Config, executionService execution.ExecutionClient, db kv.RoDB, blockReader services.FullBlockReader, hd *headerdownload.HeaderDownload, proposing bool) *EngineServerExperimental { return &EngineServerExperimental{ - ctx: ctx, - logger: logger, - config: config, - builderFunc: builderFunc, - db: db, - blockReader: blockReader, - proposing: proposing, - hd: hd, - builders: make(map[uint64]*builder.BlockBuilder), + ctx: ctx, + logger: logger, + config: config, + executionService: executionService, + db: db, + blockReader: blockReader, + proposing: proposing, + hd: hd, } } @@ -379,90 +375,28 @@ func (s *EngineServerExperimental) getPayload(ctx context.Context, payloadId uin s.lock.Lock() defer s.lock.Unlock() s.logger.Debug("[GetPayload] lock acquired") - - builder, ok := s.builders[payloadId] - if !ok { - log.Warn("Payload not stored", "payloadId", payloadId) - return nil, &engine_helpers.UnknownPayloadErr - } - - blockWithReceipts, err := builder.Stop() - if err != nil { - s.logger.Error("Failed to build PoS block", "err", err) - return nil, err - } - block := blockWithReceipts.Block - header := block.Header() - - baseFee := new(uint256.Int) - baseFee.SetFromBig(header.BaseFee) - - encodedTransactions, err := types.MarshalTransactionsBinary(block.Transactions()) + resp, err := s.executionService.GetAssembledBlock(ctx, &execution.GetAssembledBlockRequest{ + Id: payloadId, + }) if err != nil { return nil, err } - txs := []hexutility.Bytes{} - for _, tx := range encodedTransactions { - txs = append(txs, tx) - } - - payload := &engine_types.ExecutionPayload{ - ParentHash: header.ParentHash, - FeeRecipient: header.Coinbase, - Timestamp: hexutil.Uint64(header.Time), - PrevRandao: header.MixDigest, - StateRoot: block.Root(), - ReceiptsRoot: block.ReceiptHash(), - LogsBloom: block.Bloom().Bytes(), - GasLimit: hexutil.Uint64(block.GasLimit()), - GasUsed: hexutil.Uint64(block.GasUsed()), - BlockNumber: hexutil.Uint64(block.NumberU64()), - ExtraData: block.Extra(), - BaseFeePerGas: (*hexutil.Big)(header.BaseFee), - BlockHash: block.Hash(), - Transactions: txs, - } - if block.Withdrawals() != nil { - payload.Withdrawals = block.Withdrawals() - } - - if header.DataGasUsed != nil && header.ExcessDataGas != nil { - payload.DataGasUsed = (*hexutil.Uint64)(header.DataGasUsed) - payload.ExcessDataGas = (*hexutil.Uint64)(header.ExcessDataGas) + if resp.Busy { + log.Warn("Cannot build payload, execution is busy", "payloadId", payloadId) + return nil, &engine_helpers.UnknownPayloadErr } + // If the service is busy or there is no data for the given id then respond accordingly. + if resp.Data == nil { + log.Warn("Payload not stored", "payloadId", payloadId) + return nil, &engine_helpers.UnknownPayloadErr - blockValue := blockValue(blockWithReceipts, baseFee) - - blobsBundle := &engine_types.BlobsBundleV1{} - for i, tx := range block.Transactions() { - if tx.Type() != types.BlobTxType { - continue - } - blobTx, ok := tx.(*types.BlobTxWrapper) - if !ok { - return nil, fmt.Errorf("expected blob transaction to be type BlobTxWrapper, got: %T", blobTx) - } - versionedHashes, commitments, proofs, blobs := blobTx.GetDataHashes(), blobTx.Commitments, blobTx.Proofs, blobTx.Blobs - lenCheck := len(versionedHashes) - if lenCheck != len(commitments) || lenCheck != len(proofs) || lenCheck != len(blobs) { - return nil, fmt.Errorf("tx %d in block %s has inconsistent commitments (%d) / proofs (%d) / blobs (%d) / "+ - "versioned hashes (%d)", i, block.Hash(), len(commitments), len(proofs), len(blobs), lenCheck) - } - for _, commitment := range commitments { - blobsBundle.Commitments = append(blobsBundle.Commitments, commitment) - } - for _, proof := range proofs { - blobsBundle.Proofs = append(blobsBundle.Proofs, proof) - } - for _, blob := range blobs { - blobsBundle.Blobs = append(blobsBundle.Blobs, blob) - } } + data := resp.Data return &engine_types.GetPayloadResponse{ - ExecutionPayload: payload, - BlockValue: (*hexutil.Big)(blockValue.ToBig()), - BlobsBundle: blobsBundle, + ExecutionPayload: engine_types.ConvertPayloadFromRpc(data.ExecutionPayload), + BlockValue: (*hexutil.Big)(gointerfaces.ConvertH256ToUint256Int(data.BlockValue).ToBig()), + BlobsBundle: engine_types.ConvertBlobsFromRpc(data.BlobsBundle), }, nil } @@ -532,48 +466,30 @@ func (s *EngineServerExperimental) forkchoiceUpdated(ctx context.Context, forkch return nil, &engine_helpers.InvalidPayloadAttributesErr } - param := core.BlockBuilderParameters{ - ParentHash: forkChoice.HeadHash, - Timestamp: uint64(payloadAttributes.Timestamp), - PrevRandao: payloadAttributes.PrevRandao, - SuggestedFeeRecipient: payloadAttributes.SuggestedFeeRecipient, - PayloadId: s.payloadId, + req := &execution.AssembleBlockRequest{ + ParentHash: gointerfaces.ConvertHashToH256(forkChoice.HeadHash), + Timestamp: uint64(payloadAttributes.Timestamp), + MixDigest: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao), + SuggestedFeeRecipent: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient), } + if version >= clparams.CapellaVersion { - param.Withdrawals = payloadAttributes.Withdrawals + req.Withdrawals = engine_types.ConvertWithdrawalsToRpc(payloadAttributes.Withdrawals) } - if err := s.checkWithdrawalsPresence(uint64(payloadAttributes.Timestamp), param.Withdrawals); err != nil { + + resp, err := s.executionService.AssembleBlock(ctx, req) + if err != nil { return nil, err } - - // First check if we're already building a block with the requested parameters - if reflect.DeepEqual(s.lastParameters, ¶m) { - s.logger.Info("[ForkChoiceUpdated] duplicate build request") - return &engine_types.ForkChoiceUpdatedResponse{ - PayloadStatus: &engine_types.PayloadStatus{ - Status: engine_types.ValidStatus, - LatestValidHash: &headHash, - }, - PayloadId: convertPayloadId(s.payloadId), - }, nil + if resp.Busy { + return nil, errors.New("[ForkChoiceUpdated]: execution service is busy, cannot assemble blocks") } - - // Initiate payload building - s.evictOldBuilders() - - s.payloadId++ - param.PayloadId = s.payloadId - s.lastParameters = ¶m - - s.builders[s.payloadId] = builder.NewBlockBuilder(s.builderFunc, ¶m) - s.logger.Info("[ForkChoiceUpdated] BlockBuilder added", "payload", s.payloadId) - return &engine_types.ForkChoiceUpdatedResponse{ PayloadStatus: &engine_types.PayloadStatus{ Status: engine_types.ValidStatus, LatestValidHash: &headHash, }, - PayloadId: convertPayloadId(s.payloadId), + PayloadId: engine_types.ConvertPayloadId(resp.Id), }, nil } @@ -601,6 +517,25 @@ func (s *EngineServerExperimental) getPayloadBodiesByHash(ctx context.Context, r return bodies, nil } +func extractPayloadBodyFromBlock(block *types.Block) (*engine_types.ExecutionPayloadBodyV1, error) { + if block == nil { + return nil, nil + } + + txs := block.Transactions() + bdTxs := make([]hexutility.Bytes, len(txs)) + for idx, tx := range txs { + var buf bytes.Buffer + if err := tx.MarshalBinary(&buf); err != nil { + return nil, err + } else { + bdTxs[idx] = buf.Bytes() + } + } + + return &engine_types.ExecutionPayloadBodyV1{Transactions: bdTxs, Withdrawals: block.Withdrawals()}, nil +} + func (s *EngineServerExperimental) getPayloadBodiesByRange(ctx context.Context, start, count uint64, _ clparams.StateVersion) ([]*engine_types.ExecutionPayloadBodyV1, error) { tx, err := s.db.BeginRo(ctx) if err != nil { @@ -634,15 +569,6 @@ func (s *EngineServerExperimental) getPayloadBodiesByRange(ctx context.Context, return bodies, nil } -func (s *EngineServerExperimental) evictOldBuilders() { - ids := common.SortedKeys(s.builders) - - // remove old builders so that at most MaxBuilders - 1 remain - for i := 0; i <= len(s.builders)-engine_helpers.MaxBuilders; i++ { - delete(s.builders, ids[i]) - } -} - func (e *EngineServerExperimental) GetPayloadV1(ctx context.Context, payloadId hexutility.Bytes) (*engine_types.ExecutionPayload, error) { decodedPayloadId := binary.BigEndian.Uint64(payloadId) @@ -736,6 +662,20 @@ func (e *EngineServerExperimental) GetPayloadBodiesByRangeV1(ctx context.Context return e.getPayloadBodiesByRange(ctx, uint64(start), uint64(count), clparams.CapellaVersion) } +var ourCapabilities = []string{ + "engine_forkchoiceUpdatedV1", + "engine_forkchoiceUpdatedV2", + "engine_newPayloadV1", + "engine_newPayloadV2", + // "engine_newPayloadV3", + "engine_getPayloadV1", + "engine_getPayloadV2", + // "engine_getPayloadV3", + "engine_exchangeTransitionConfigurationV1", + "engine_getPayloadBodiesByHashV1", + "engine_getPayloadBodiesByRangeV1", +} + func (e *EngineServerExperimental) ExchangeCapabilities(fromCl []string) []string { missingOurs := compareCapabilities(fromCl, ourCapabilities) missingCl := compareCapabilities(ourCapabilities, fromCl) @@ -746,3 +686,21 @@ func (e *EngineServerExperimental) ExchangeCapabilities(fromCl []string) []strin return ourCapabilities } + +func compareCapabilities(from []string, to []string) []string { + result := make([]string, 0) + for _, f := range from { + found := false + for _, t := range to { + if f == t { + found = true + break + } + } + if !found { + result = append(result, f) + } + } + + return result +} diff --git a/turbo/engineapi/engine_types/jsonrpc.go b/turbo/engineapi/engine_types/jsonrpc.go index 9c9f8511eec..e99ad72b94a 100644 --- a/turbo/engineapi/engine_types/jsonrpc.go +++ b/turbo/engineapi/engine_types/jsonrpc.go @@ -1,11 +1,14 @@ package engine_types import ( + "encoding/binary" "encoding/json" "errors" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" + "github.com/ledgerwatch/erigon-lib/gointerfaces" + types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/core/types" ) @@ -103,3 +106,101 @@ func (e StringifiedError) MarshalJSON() ([]byte, error) { func (e StringifiedError) Error() error { return e.err } + +func ConvertPayloadFromRpc(payload *types2.ExecutionPayload) *ExecutionPayload { + var bloom types.Bloom = gointerfaces.ConvertH2048ToBloom(payload.LogsBloom) + baseFee := gointerfaces.ConvertH256ToUint256Int(payload.BaseFeePerGas).ToBig() + + // Convert slice of hexutility.Bytes to a slice of slice of bytes + transactions := make([]hexutility.Bytes, len(payload.Transactions)) + for i, transaction := range payload.Transactions { + transactions[i] = transaction + } + + res := &ExecutionPayload{ + ParentHash: gointerfaces.ConvertH256ToHash(payload.ParentHash), + FeeRecipient: gointerfaces.ConvertH160toAddress(payload.Coinbase), + StateRoot: gointerfaces.ConvertH256ToHash(payload.StateRoot), + ReceiptsRoot: gointerfaces.ConvertH256ToHash(payload.ReceiptRoot), + LogsBloom: bloom[:], + PrevRandao: gointerfaces.ConvertH256ToHash(payload.PrevRandao), + BlockNumber: hexutil.Uint64(payload.BlockNumber), + GasLimit: hexutil.Uint64(payload.GasLimit), + GasUsed: hexutil.Uint64(payload.GasUsed), + Timestamp: hexutil.Uint64(payload.Timestamp), + ExtraData: payload.ExtraData, + BaseFeePerGas: (*hexutil.Big)(baseFee), + BlockHash: gointerfaces.ConvertH256ToHash(payload.BlockHash), + Transactions: transactions, + } + if payload.Version >= 2 { + res.Withdrawals = ConvertWithdrawalsFromRpc(payload.Withdrawals) + } + if payload.Version >= 3 { + dataGasUsed := *payload.DataGasUsed + res.DataGasUsed = (*hexutil.Uint64)(&dataGasUsed) + excessDataGas := *payload.ExcessDataGas + res.ExcessDataGas = (*hexutil.Uint64)(&excessDataGas) + } + return res +} + +func ConvertBlobsFromRpc(bundle *types2.BlobsBundleV1) *BlobsBundleV1 { + if bundle == nil { + return nil + } + res := &BlobsBundleV1{ + Commitments: make([]types.KZGCommitment, len(bundle.Commitments)), + Proofs: make([]types.KZGProof, len(bundle.Proofs)), + Blobs: make([]types.Blob, len(bundle.Blobs)), + } + for i, commitment := range bundle.Commitments { + copy(res.Commitments[i][:], commitment) + } + for i, proof := range bundle.Proofs { + copy(res.Proofs[i][:], proof) + } + for i, blob := range bundle.Blobs { + copy(res.Blobs[i][:], blob) + } + return res +} + +func ConvertWithdrawalsToRpc(in []*types.Withdrawal) []*types2.Withdrawal { + if in == nil { + return nil + } + out := make([]*types2.Withdrawal, 0, len(in)) + for _, w := range in { + out = append(out, &types2.Withdrawal{ + Index: w.Index, + ValidatorIndex: w.Validator, + Address: gointerfaces.ConvertAddressToH160(w.Address), + Amount: w.Amount, + }) + } + return out +} + +func ConvertWithdrawalsFromRpc(in []*types2.Withdrawal) []*types.Withdrawal { + if in == nil { + return nil + } + out := make([]*types.Withdrawal, 0, len(in)) + for _, w := range in { + out = append(out, &types.Withdrawal{ + Index: w.Index, + Validator: w.ValidatorIndex, + Address: gointerfaces.ConvertH160toAddress(w.Address), + Amount: w.Amount, + }) + } + return out +} + +func ConvertPayloadId(payloadId uint64) *hexutility.Bytes { + encodedPayloadId := make([]byte, 8) + binary.BigEndian.PutUint64(encodedPayloadId, payloadId) + ret := hexutility.Bytes(encodedPayloadId) + return &ret +} diff --git a/turbo/execution/eth1/block_building.go b/turbo/execution/eth1/block_building.go new file mode 100644 index 00000000000..a2e4a07a9ab --- /dev/null +++ b/turbo/execution/eth1/block_building.go @@ -0,0 +1,193 @@ +package eth1 + +import ( + "context" + "fmt" + "reflect" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/gointerfaces" + "github.com/ledgerwatch/erigon-lib/gointerfaces/execution" + types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/builder" + "github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers" +) + +func (e *EthereumExecutionModule) checkWithdrawalsPresence(time uint64, withdrawals []*types.Withdrawal) error { + if !e.config.IsShanghai(time) && withdrawals != nil { + return &rpc.InvalidParamsError{Message: "withdrawals before shanghai"} + } + if e.config.IsShanghai(time) && withdrawals == nil { + return &rpc.InvalidParamsError{Message: "missing withdrawals list"} + } + return nil +} + +func (e *EthereumExecutionModule) evictOldBuilders() { + ids := common.SortedKeys(e.builders) + + // remove old builders so that at most MaxBuilders - 1 remain + for i := 0; i <= len(e.builders)-engine_helpers.MaxBuilders; i++ { + delete(e.builders, ids[i]) + } +} + +// Missing: NewPayload, AssembleBlock +func (e *EthereumExecutionModule) AssembleBlock(ctx context.Context, req *execution.AssembleBlockRequest) (*execution.AssembleBlockResponse, error) { + if !e.semaphore.TryAcquire(1) { + return &execution.AssembleBlockResponse{ + Id: 0, + Busy: true, + }, nil + } + defer e.semaphore.Release(1) + param := core.BlockBuilderParameters{ + ParentHash: gointerfaces.ConvertH256ToHash(req.ParentHash), + Timestamp: req.Timestamp, + PrevRandao: gointerfaces.ConvertH256ToHash(req.MixDigest), + SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(req.SuggestedFeeRecipent), + Withdrawals: ConvertWithdrawalsFromRpc(req.Withdrawals), + } + + if err := e.checkWithdrawalsPresence(param.Timestamp, param.Withdrawals); err != nil { + return nil, err + } + + // First check if we're already building a block with the requested parameters + if reflect.DeepEqual(e.lastParameters, ¶m) { + e.logger.Info("[ForkChoiceUpdated] duplicate build request") + return &execution.AssembleBlockResponse{ + Id: e.nextPayloadId, + Busy: false, + }, nil + } + + // Initiate payload building + e.evictOldBuilders() + + e.nextPayloadId++ + param.PayloadId = e.nextPayloadId + e.lastParameters = ¶m + + e.builders[e.nextPayloadId] = builder.NewBlockBuilder(e.builderFunc, ¶m) + e.logger.Info("[ForkChoiceUpdated] BlockBuilder added", "payload", e.nextPayloadId) + + return &execution.AssembleBlockResponse{ + Id: e.nextPayloadId, + Busy: false, + }, nil +} + +// The expected value to be received by the feeRecipient in wei +func blockValue(br *types.BlockWithReceipts, baseFee *uint256.Int) *uint256.Int { + blockValue := uint256.NewInt(0) + txs := br.Block.Transactions() + for i := range txs { + gas := new(uint256.Int).SetUint64(br.Receipts[i].GasUsed) + effectiveTip := txs[i].GetEffectiveGasTip(baseFee) + txValue := new(uint256.Int).Mul(gas, effectiveTip) + blockValue.Add(blockValue, txValue) + } + return blockValue +} + +func (e *EthereumExecutionModule) GetAssembledBlock(ctx context.Context, req *execution.GetAssembledBlockRequest) (*execution.GetAssembledBlockResponse, error) { + if !e.semaphore.TryAcquire(1) { + return &execution.GetAssembledBlockResponse{ + Busy: true, + }, nil + } + defer e.semaphore.Release(1) + payloadId := req.Id + builder, ok := e.builders[payloadId] + if !ok { + return &execution.GetAssembledBlockResponse{ + Busy: false, + }, nil + } + + blockWithReceipts, err := builder.Stop() + if err != nil { + e.logger.Error("Failed to build PoS block", "err", err) + return nil, err + } + block := blockWithReceipts.Block + header := block.Header() + + baseFee := new(uint256.Int) + baseFee.SetFromBig(header.BaseFee) + + encodedTransactions, err := types.MarshalTransactionsBinary(block.Transactions()) + if err != nil { + return nil, err + } + + payload := &types2.ExecutionPayload{ + Version: 1, + ParentHash: gointerfaces.ConvertHashToH256(header.ParentHash), + Coinbase: gointerfaces.ConvertAddressToH160(header.Coinbase), + Timestamp: header.Time, + PrevRandao: gointerfaces.ConvertHashToH256(header.MixDigest), + StateRoot: gointerfaces.ConvertHashToH256(block.Root()), + ReceiptRoot: gointerfaces.ConvertHashToH256(block.ReceiptHash()), + LogsBloom: gointerfaces.ConvertBytesToH2048(block.Bloom().Bytes()), + GasLimit: block.GasLimit(), + GasUsed: block.GasUsed(), + BlockNumber: block.NumberU64(), + ExtraData: block.Extra(), + BaseFeePerGas: gointerfaces.ConvertUint256IntToH256(baseFee), + BlockHash: gointerfaces.ConvertHashToH256(block.Hash()), + Transactions: encodedTransactions, + } + if block.Withdrawals() != nil { + payload.Version = 2 + payload.Withdrawals = ConvertWithdrawalsToRpc(block.Withdrawals()) + } + + if header.DataGasUsed != nil && header.ExcessDataGas != nil { + payload.Version = 3 + payload.DataGasUsed = header.DataGasUsed + payload.ExcessDataGas = header.ExcessDataGas + } + + blockValue := blockValue(blockWithReceipts, baseFee) + + blobsBundle := &types2.BlobsBundleV1{} + for i, tx := range block.Transactions() { + if tx.Type() != types.BlobTxType { + continue + } + blobTx, ok := tx.(*types.BlobTxWrapper) + if !ok { + return nil, fmt.Errorf("expected blob transaction to be type BlobTxWrapper, got: %T", blobTx) + } + versionedHashes, commitments, proofs, blobs := blobTx.GetDataHashes(), blobTx.Commitments, blobTx.Proofs, blobTx.Blobs + lenCheck := len(versionedHashes) + if lenCheck != len(commitments) || lenCheck != len(proofs) || lenCheck != len(blobs) { + return nil, fmt.Errorf("tx %d in block %s has inconsistent commitments (%d) / proofs (%d) / blobs (%d) / "+ + "versioned hashes (%d)", i, block.Hash(), len(commitments), len(proofs), len(blobs), lenCheck) + } + for _, commitment := range commitments { + blobsBundle.Commitments = append(blobsBundle.Commitments, commitment[:]) + } + for _, proof := range proofs { + blobsBundle.Proofs = append(blobsBundle.Proofs, proof[:]) + } + for _, blob := range blobs { + blobsBundle.Blobs = append(blobsBundle.Blobs, blob[:]) + } + } + + return &execution.GetAssembledBlockResponse{ + Data: &execution.AssembledBlockData{ + ExecutionPayload: payload, + BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue), + BlobsBundle: blobsBundle, + }, + Busy: false, + }, nil +} diff --git a/turbo/execution/eth1/eth1_test.go b/turbo/execution/eth1/eth1_test.go index 14c155520d4..b0d06410b58 100644 --- a/turbo/execution/eth1/eth1_test.go +++ b/turbo/execution/eth1/eth1_test.go @@ -25,7 +25,7 @@ func TestInsertGetterHeader(t *testing.T) { tx, _ := db.BeginRw(context.TODO()) rawdb.WriteTd(tx, libcommon.Hash{}, 1, libcommon.Big0) tx.Commit() - e := eth1.NewEthereumExecutionModule(nil, db, nil, nil, nil) + e := eth1.NewEthereumExecutionModule(nil, db, nil, nil, nil, nil, nil) _, err := e.InsertHeaders(context.TODO(), &execution.InsertHeadersRequest{ Headers: []*execution.Header{ eth1.HeaderToHeaderRPC(header), @@ -46,7 +46,7 @@ func TestInsertGetterBody(t *testing.T) { body := &types.RawBody{ Transactions: txs, } - e := eth1.NewEthereumExecutionModule(nil, memdb.NewTestDB(t), nil, nil, nil) + e := eth1.NewEthereumExecutionModule(nil, memdb.NewTestDB(t), nil, nil, nil, nil, nil) _, err := e.InsertBodies(context.TODO(), &execution.InsertBodiesRequest{ Bodies: []*execution.BlockBody{ eth1.ConvertRawBlockBodyToRpc(body, bn, bhash), diff --git a/turbo/execution/eth1/ethereum_execution.go b/turbo/execution/eth1/ethereum_execution.go index 9e9f1d8656d..bf7533a90ea 100644 --- a/turbo/execution/eth1/ethereum_execution.go +++ b/turbo/execution/eth1/ethereum_execution.go @@ -3,6 +3,7 @@ package eth1 import ( "context" + "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/gointerfaces" "github.com/ledgerwatch/erigon-lib/gointerfaces/execution" @@ -11,10 +12,12 @@ import ( "golang.org/x/sync/semaphore" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/eth/stagedsync" "github.com/ledgerwatch/erigon/eth/stagedsync/stages" + "github.com/ledgerwatch/erigon/turbo/builder" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers" "github.com/ledgerwatch/erigon/turbo/engineapi/engine_types" "github.com/ledgerwatch/erigon/turbo/services" @@ -32,17 +35,28 @@ type EthereumExecutionModule struct { forkValidator *engine_helpers.ForkValidator logger log.Logger + // Block building + nextPayloadId uint64 + lastParameters *core.BlockBuilderParameters + builderFunc builder.BlockBuilderFunc + builders map[uint64]*builder.BlockBuilder + + // configuration + config *chain.Config execution.UnimplementedExecutionServer } -func NewEthereumExecutionModule(blockReader services.FullBlockReader, db kv.RwDB, executionPipeline *stagedsync.Sync, forkValidator *engine_helpers.ForkValidator, logger log.Logger) *EthereumExecutionModule { +func NewEthereumExecutionModule(blockReader services.FullBlockReader, db kv.RwDB, executionPipeline *stagedsync.Sync, forkValidator *engine_helpers.ForkValidator, config *chain.Config, builderFunc builder.BlockBuilderFunc, logger log.Logger) *EthereumExecutionModule { return &EthereumExecutionModule{ blockReader: blockReader, db: db, executionPipeline: executionPipeline, logger: logger, forkValidator: forkValidator, + builders: make(map[uint64]*builder.BlockBuilder), + builderFunc: builderFunc, + config: config, semaphore: semaphore.NewWeighted(1), } } @@ -71,7 +85,7 @@ func (e *EthereumExecutionModule) canonicalHash(ctx context.Context, tx kv.Tx, b // Remaining -func (e *EthereumExecutionModule) UpdateForkChoice(ctx context.Context, req *types2.H256) (*execution.ForkChoiceReceipt, error) { +func (e *EthereumExecutionModule) UpdateForkChoice(ctx context.Context, req *execution.ForkChoice) (*execution.ForkChoiceReceipt, error) { type canonicalEntry struct { hash libcommon.Hash number uint64 @@ -90,7 +104,7 @@ func (e *EthereumExecutionModule) UpdateForkChoice(ctx context.Context, req *typ } defer tx.Rollback() - blockHash := gointerfaces.ConvertH256ToHash(req) + blockHash := gointerfaces.ConvertH256ToHash(req.HeadBlockHash) // Step one, find reconnection point, and mark all of those headers as canonical. fcuHeader, err := e.blockReader.HeaderByHash(ctx, tx, blockHash) if err != nil { @@ -228,5 +242,3 @@ func (e *EthereumExecutionModule) ValidateChain(ctx context.Context, req *execut MissingHash: gointerfaces.ConvertHashToH256(libcommon.Hash{}), // TODO: implement }, nil } - -// Missing: NewPayload, AssembleBlock