mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-09 12:31:21 +00:00
cda14447ad
Co-authored-by: Giulio <giulio.rebuffo@gmail.com>
149 lines
4.5 KiB
Go
149 lines
4.5 KiB
Go
package execution_client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/holiman/uint256"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/types"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
|
"github.com/ledgerwatch/erigon/ethdb/privateapi"
|
|
)
|
|
|
|
var errContextExceeded = "rpc error: code = DeadlineExceeded desc = context deadline exceeded"
|
|
|
|
// ExecutionEngine is used only for syncing up very close to chain tip and to stay in sync.
|
|
// It pretty much mimics engine API.
|
|
type ExecutionEngine interface {
|
|
NewPayload(payload *cltypes.Eth1Block) error
|
|
ForkChoiceUpdate(finalized libcommon.Hash, head libcommon.Hash) error
|
|
}
|
|
|
|
// ExecutionEnginePhase1 is just the normal engine api.
|
|
type ExecutionEnginePhase1 struct {
|
|
// Either execution server or client
|
|
executionServer remote.ETHBACKENDServer
|
|
executionClient remote.ETHBACKENDClient
|
|
|
|
ctx context.Context
|
|
}
|
|
|
|
// NewExecutionEnginePhase1FromServer use ethbackend server
|
|
func NewExecutionEnginePhase1FromServer(ctx context.Context, executionServer remote.ETHBACKENDServer) *ExecutionEnginePhase1 {
|
|
return &ExecutionEnginePhase1{
|
|
executionServer: executionServer,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
// NewExecutionEnginePhase1FromServer use ethbackend client
|
|
func NewExecutionEnginePhase1FromClient(ctx context.Context, executionClient remote.ETHBACKENDClient) *ExecutionEnginePhase1 {
|
|
return &ExecutionEnginePhase1{
|
|
executionClient: executionClient,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
func (e *ExecutionEnginePhase1) NewPayload(payload *cltypes.Eth1Block) error {
|
|
grpcMessage, err := convertPayloadToGrpc(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ctx, cancel := context.WithTimeout(e.ctx, 3*time.Second)
|
|
defer cancel()
|
|
|
|
var status *remote.EnginePayloadStatus
|
|
if e.executionServer != nil {
|
|
status, err = e.executionServer.EngineNewPayload(ctx, grpcMessage)
|
|
} else if e.executionClient != nil {
|
|
status, err = e.executionClient.EngineNewPayload(ctx, grpcMessage)
|
|
}
|
|
// Ignore timeouts
|
|
if err != nil {
|
|
if err.Error() == errContextExceeded {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
if status.Status == remote.EngineStatus_INVALID {
|
|
return fmt.Errorf("invalid block")
|
|
}
|
|
if status.Status == remote.EngineStatus_INVALID_BLOCK_HASH {
|
|
return fmt.Errorf("invalid block hash")
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (e *ExecutionEnginePhase1) ForkChoiceUpdate(finalized libcommon.Hash, head libcommon.Hash) error {
|
|
grpcMessage := &remote.EngineForkChoiceUpdatedRequest{
|
|
ForkchoiceState: &remote.EngineForkChoiceState{
|
|
HeadBlockHash: gointerfaces.ConvertHashToH256(head),
|
|
SafeBlockHash: gointerfaces.ConvertHashToH256(head),
|
|
FinalizedBlockHash: gointerfaces.ConvertHashToH256(finalized),
|
|
},
|
|
}
|
|
var err error
|
|
ctx, cancel := context.WithTimeout(e.ctx, 3*time.Second)
|
|
defer cancel()
|
|
if e.executionClient != nil {
|
|
_, err = e.executionClient.EngineForkChoiceUpdated(ctx, grpcMessage)
|
|
} else if e.executionServer != nil {
|
|
_, err = e.executionServer.EngineForkChoiceUpdated(ctx, grpcMessage)
|
|
}
|
|
// Ignore timeouts
|
|
if err != nil && err.Error() == errContextExceeded {
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// ExecutionEnginePhase2 is "real merge" (TODO).
|
|
type ExecutionEnginePhase2 struct {
|
|
}
|
|
|
|
func convertPayloadToGrpc(e *cltypes.Eth1Block) (*types.ExecutionPayload, error) {
|
|
var baseFee *uint256.Int
|
|
header, err := e.RlpHeader()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if header.BaseFee != nil {
|
|
var overflow bool
|
|
baseFee, overflow = uint256.FromBig(header.BaseFee)
|
|
if overflow {
|
|
panic("NewPayload BaseFeePerGas overflow")
|
|
}
|
|
}
|
|
|
|
res := &types.ExecutionPayload{
|
|
Version: 1,
|
|
ParentHash: gointerfaces.ConvertHashToH256(header.ParentHash),
|
|
Coinbase: gointerfaces.ConvertAddressToH160(header.Coinbase),
|
|
StateRoot: gointerfaces.ConvertHashToH256(header.Root),
|
|
ReceiptRoot: gointerfaces.ConvertHashToH256(header.ReceiptHash),
|
|
LogsBloom: gointerfaces.ConvertBytesToH2048(header.Bloom[:]),
|
|
PrevRandao: gointerfaces.ConvertHashToH256(header.MixDigest),
|
|
BlockNumber: header.Number.Uint64(),
|
|
GasLimit: header.GasLimit,
|
|
GasUsed: header.GasUsed,
|
|
Timestamp: header.Time,
|
|
ExtraData: header.Extra,
|
|
BaseFeePerGas: gointerfaces.ConvertUint256IntToH256(baseFee),
|
|
BlockHash: gointerfaces.ConvertHashToH256(e.BlockHash),
|
|
Transactions: e.Transactions,
|
|
Withdrawals: privateapi.ConvertWithdrawalsToRpc(e.Withdrawals),
|
|
}
|
|
if e.Withdrawals != nil {
|
|
res.Version = 2
|
|
res.Withdrawals = privateapi.ConvertWithdrawalsToRpc(e.Withdrawals)
|
|
}
|
|
|
|
return res, nil
|
|
}
|