mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 11:41:19 +00:00
a54939633e
Corresponds to Item 3 of https://github.com/maticnetwork/bor/pull/1055
208 lines
6.7 KiB
Go
208 lines
6.7 KiB
Go
package eth1
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/holiman/uint256"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"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/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"
|
|
"github.com/ledgerwatch/erigon/turbo/execution/eth1/eth1_utils"
|
|
)
|
|
|
|
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 := libcommon.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.PrevRandao),
|
|
SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(req.SuggestedFeeRecipient),
|
|
Withdrawals: eth1_utils.ConvertWithdrawalsFromRpc(req.Withdrawals),
|
|
}
|
|
|
|
if err := e.checkWithdrawalsPresence(param.Timestamp, param.Withdrawals); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if req.ParentBeaconBlockRoot != nil {
|
|
pbbr := libcommon.Hash(gointerfaces.ConvertH256ToHash(req.ParentBeaconBlockRoot))
|
|
param.ParentBeaconBlockRoot = &pbbr
|
|
}
|
|
|
|
// 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 = eth1_utils.ConvertWithdrawalsToRpc(block.Withdrawals())
|
|
}
|
|
|
|
if header.BlobGasUsed != nil && header.ExcessBlobGas != nil {
|
|
payload.Version = 3
|
|
payload.BlobGasUsed = header.BlobGasUsed
|
|
payload.ExcessBlobGas = header.ExcessBlobGas
|
|
}
|
|
|
|
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.GetBlobHashes(), 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 {
|
|
c := types.KZGCommitment{}
|
|
copy(c[:], commitment[:])
|
|
blobsBundle.Commitments = append(blobsBundle.Commitments, c[:])
|
|
}
|
|
for _, proof := range proofs {
|
|
p := types.KZGProof{}
|
|
copy(p[:], proof[:])
|
|
blobsBundle.Proofs = append(blobsBundle.Proofs, p[:])
|
|
}
|
|
for _, blob := range blobs {
|
|
b := types.Blob{}
|
|
copy(b[:], blob[:])
|
|
blobsBundle.Blobs = append(blobsBundle.Blobs, b[:])
|
|
}
|
|
}
|
|
|
|
return &execution.GetAssembledBlockResponse{
|
|
Data: &execution.AssembledBlockData{
|
|
ExecutionPayload: payload,
|
|
BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue),
|
|
BlobsBundle: blobsBundle,
|
|
},
|
|
Busy: false,
|
|
}, nil
|
|
}
|