Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions beacon/engine/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ import (
"fmt"
"math/big"

"github.com/attestantio/go-eth2-client/spec/bellatrix"
"github.com/attestantio/go-eth2-client/spec/capella"
"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/trie"

boostTypes "github.com/flashbots/go-boost-utils/types"
)

//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
Expand Down Expand Up @@ -241,8 +240,8 @@ type ExecutionPayloadBodyV1 struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
}

func ExecutionPayloadToBlock(payload *boostTypes.ExecutionPayload) (*types.Block, error) {
// TODO: separate decode function to avoid allocating twice
func ExecutionPayloadToBlock(payload *bellatrix.ExecutionPayload) (*types.Block, error) {
// TODO: consolidate this into one function that handles all forks
transactionBytes := make([][]byte, len(payload.Transactions))
for i, txHexBytes := range payload.Transactions {
transactionBytes[i] = txHexBytes[:]
Expand All @@ -252,6 +251,14 @@ func ExecutionPayloadToBlock(payload *boostTypes.ExecutionPayload) (*types.Block
return nil, err
}

// base fee per gas is stored little-endian but we need it
// big-endian for big.Int.
var baseFeePerGasBytes [32]byte
for i := 0; i < 32; i++ {
baseFeePerGasBytes[i] = payload.BaseFeePerGas[32-1-i]
}
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBytes[:])

header := &types.Header{
ParentHash: common.Hash(payload.ParentHash),
UncleHash: types.EmptyUncleHash,
Expand All @@ -265,9 +272,9 @@ func ExecutionPayloadToBlock(payload *boostTypes.ExecutionPayload) (*types.Block
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Time: payload.Timestamp,
BaseFee: payload.BaseFeePerGas.BigInt(),
BaseFee: baseFeePerGas,
Extra: payload.ExtraData,
MixDigest: common.Hash(payload.Random),
MixDigest: common.Hash(payload.PrevRandao),
}
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
return block, nil
Expand Down
108 changes: 44 additions & 64 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import (
"sync"
"time"

bellatrixapi "github.com/attestantio/go-builder-client/api/bellatrix"
capellaapi "github.com/attestantio/go-builder-client/api/capella"
apiv1 "github.com/attestantio/go-builder-client/api/v1"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
"github.com/attestantio/go-eth2-client/spec/capella"
"github.com/attestantio/go-eth2-client/spec/phase0"
"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"
blockvalidation "github.com/ethereum/go-ethereum/eth/block-validation"
"github.com/ethereum/go-ethereum/flashbotsextra"
"github.com/ethereum/go-ethereum/log"
"github.com/flashbots/go-boost-utils/bls"
"github.com/flashbots/go-boost-utils/ssz"
boostTypes "github.com/flashbots/go-boost-utils/types"
"github.com/flashbots/go-boost-utils/utils"
"github.com/holiman/uint256"
"golang.org/x/time/rate"
)
Expand All @@ -39,12 +41,12 @@ type PubkeyHex string

type ValidatorData struct {
Pubkey PubkeyHex
FeeRecipient boostTypes.Address
FeeRecipient bellatrix.ExecutionAddress
GasLimit uint64
}

type IRelay interface {
SubmitBlock(msg *boostTypes.BuilderSubmitBlockRequest, vd ValidatorData) error
SubmitBlock(msg *bellatrixapi.SubmitBlockRequest, vd ValidatorData) error
SubmitBlockCapella(msg *capellaapi.SubmitBlockRequest, vd ValidatorData) error
GetValidatorForSlot(nextSlot uint64) (ValidatorData, error)
Config() RelayConfig
Expand All @@ -67,8 +69,8 @@ type Builder struct {
validator *blockvalidation.BlockValidationAPI
beaconClient IBeaconClient
builderSecretKey *bls.SecretKey
builderPublicKey boostTypes.PublicKey
builderSigningDomain boostTypes.Domain
builderPublicKey phase0.BLSPubKey
builderSigningDomain phase0.Domain
builderResubmitInterval time.Duration

limiter *rate.Limiter
Expand All @@ -86,7 +88,7 @@ type BuilderArgs struct {
sk *bls.SecretKey
ds flashbotsextra.IDatabaseService
relay IRelay
builderSigningDomain boostTypes.Domain
builderSigningDomain phase0.Domain
builderBlockResubmitInterval time.Duration
eth IEthereumService
dryRun bool
Expand All @@ -97,10 +99,15 @@ type BuilderArgs struct {
limiter *rate.Limiter
}

func NewBuilder(args BuilderArgs) *Builder {
pkBytes := bls.PublicKeyFromSecretKey(args.sk).Compress()
pk := boostTypes.PublicKey{}
pk.FromSlice(pkBytes)
func NewBuilder(args BuilderArgs) (*Builder, error) {
blsPk, err := bls.PublicKeyFromSecretKey(args.sk)
if err != nil {
return nil, err
}
pk, err := utils.BlsPublicKeyToPublicKey(blsPk)
if err != nil {
return nil, err
}

if args.limiter == nil {
args.limiter = rate.NewLimiter(rate.Every(RateLimitIntervalDefault), RateLimitBurstDefault)
Expand Down Expand Up @@ -129,7 +136,7 @@ func NewBuilder(args BuilderArgs) *Builder {
slotCtxCancel: slotCtxCancel,

stop: make(chan struct{}, 1),
}
}, nil
}

func (b *Builder) Start() error {
Expand Down Expand Up @@ -185,7 +192,7 @@ func (b *Builder) Stop() error {

func (b *Builder) onSealedBlock(block *types.Block, blockValue *big.Int, ordersClosedAt, sealedAt time.Time,
commitedBundles, allBundles []types.SimulatedBundle, usedSbundles []types.UsedSBundle,
proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
proposerPubkey phase0.BLSPubKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
if b.eth.Config().IsShanghai(block.Time()) {
if err := b.submitCapellaBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, usedSbundles, proposerPubkey, vd, attrs); err != nil {
return err
Expand All @@ -204,22 +211,21 @@ func (b *Builder) onSealedBlock(block *types.Block, blockValue *big.Int, ordersC

func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int, ordersClosedAt, sealedAt time.Time,
commitedBundles, allBundles []types.SimulatedBundle, usedSbundles []types.UsedSBundle,
proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
proposerPubkey phase0.BLSPubKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
executableData := engine.BlockToExecutableData(block, blockValue)
payload, err := executableDataToExecutionPayload(executableData.ExecutionPayload)
if err != nil {
log.Error("could not format execution payload", "err", err)
return err
}

value := new(boostTypes.U256Str)
err = value.FromBig(blockValue)
if err != nil {
log.Error("could not set block value", "err", err)
value, overflow := uint256.FromBig(blockValue)
if overflow {
log.Error("could not set block value due to value overflow")
return err
}

blockBidMsg := boostTypes.BidTrace{
blockBidMsg := apiv1.BidTrace{
Slot: attrs.Slot,
ParentHash: payload.ParentHash,
BlockHash: payload.BlockHash,
Expand All @@ -228,23 +234,23 @@ func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int,
ProposerFeeRecipient: vd.FeeRecipient,
GasLimit: executableData.ExecutionPayload.GasLimit,
GasUsed: executableData.ExecutionPayload.GasUsed,
Value: *value,
Value: value,
}

signature, err := boostTypes.SignMessage(&blockBidMsg, b.builderSigningDomain, b.builderSecretKey)
signature, err := ssz.SignMessage(&blockBidMsg, b.builderSigningDomain, b.builderSecretKey)
if err != nil {
log.Error("could not sign builder bid", "err", err)
return err
}

blockSubmitReq := boostTypes.BuilderSubmitBlockRequest{
blockSubmitReq := bellatrixapi.SubmitBlockRequest{
Signature: signature,
Message: &blockBidMsg,
ExecutionPayload: payload,
}

if b.dryRun {
err = b.validator.ValidateBuilderSubmissionV1(&blockvalidation.BuilderBlockValidationRequest{BuilderSubmitBlockRequest: blockSubmitReq, RegisteredGasLimit: vd.GasLimit})
err = b.validator.ValidateBuilderSubmissionV1(&blockvalidation.BuilderBlockValidationRequest{SubmitBlockRequest: blockSubmitReq, RegisteredGasLimit: vd.GasLimit})
if err != nil {
log.Error("could not validate bellatrix block", "err", err)
}
Expand All @@ -264,7 +270,7 @@ func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int,

func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, ordersClosedAt, sealedAt time.Time,
commitedBundles, allBundles []types.SimulatedBundle, usedSbundles []types.UsedSBundle,
proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
proposerPubkey phase0.BLSPubKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
executableData := engine.BlockToExecutableData(block, blockValue)
payload, err := executableDataToCapellaExecutionPayload(executableData.ExecutionPayload)
if err != nil {
Expand All @@ -282,28 +288,22 @@ func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, or
Slot: attrs.Slot,
ParentHash: payload.ParentHash,
BlockHash: payload.BlockHash,
BuilderPubkey: phase0.BLSPubKey(b.builderPublicKey),
ProposerPubkey: phase0.BLSPubKey(proposerPubkey),
ProposerFeeRecipient: bellatrix.ExecutionAddress(vd.FeeRecipient),
BuilderPubkey: b.builderPublicKey,
ProposerPubkey: proposerPubkey,
ProposerFeeRecipient: vd.FeeRecipient,
GasLimit: executableData.ExecutionPayload.GasLimit,
GasUsed: executableData.ExecutionPayload.GasUsed,
Value: value,
}

boostBidTrace, err := convertBidTrace(blockBidMsg)
if err != nil {
log.Error("could not convert bid trace", "err", err)
return err
}

signature, err := boostTypes.SignMessage(&blockBidMsg, b.builderSigningDomain, b.builderSecretKey)
signature, err := ssz.SignMessage(&blockBidMsg, b.builderSigningDomain, b.builderSecretKey)
if err != nil {
log.Error("could not sign builder bid", "err", err)
return err
}

blockSubmitReq := capellaapi.SubmitBlockRequest{
Signature: phase0.BLSSignature(signature),
Signature: signature,
Message: &blockBidMsg,
ExecutionPayload: payload,
}
Expand All @@ -314,7 +314,7 @@ func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, or
log.Error("could not validate block for capella", "err", err)
}
} else {
go b.ds.ConsumeBuiltBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, usedSbundles, &boostBidTrace)
go b.ds.ConsumeBuiltBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, usedSbundles, &blockBidMsg)
err = b.relay.SubmitBlockCapella(&blockSubmitReq, vd)
if err != nil {
log.Error("could not submit capella block", "err", err, "#commitedBundles", len(commitedBundles))
Expand All @@ -339,7 +339,7 @@ func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) erro
attrs.SuggestedFeeRecipient = [20]byte(vd.FeeRecipient)
attrs.GasLimit = vd.GasLimit

proposerPubkey, err := boostTypes.HexToPubkey(string(vd.Pubkey))
proposerPubkey, err := utils.HexToPubkey(string(vd.Pubkey))
if err != nil {
return fmt.Errorf("could not parse pubkey (%s) - %w", vd.Pubkey, err)
}
Expand Down Expand Up @@ -384,7 +384,7 @@ type blockQueueEntry struct {
usedSbundles []types.UsedSBundle
}

func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) {
func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey phase0.BLSPubKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) {
ctx, cancel := context.WithTimeout(slotCtx, 12*time.Second)
defer cancel()

Expand Down Expand Up @@ -471,10 +471,10 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
})
}

func executableDataToExecutionPayload(data *engine.ExecutableData) (*boostTypes.ExecutionPayload, error) {
transactionData := make([]hexutil.Bytes, len(data.Transactions))
func executableDataToExecutionPayload(data *engine.ExecutableData) (*bellatrix.ExecutionPayload, error) {
transactionData := make([]bellatrix.Transaction, len(data.Transactions))
for i, tx := range data.Transactions {
transactionData[i] = hexutil.Bytes(tx)
transactionData[i] = bellatrix.Transaction(tx)
}

baseFeePerGas := new(boostTypes.U256Str)
Expand All @@ -483,13 +483,13 @@ func executableDataToExecutionPayload(data *engine.ExecutableData) (*boostTypes.
return nil, err
}

return &boostTypes.ExecutionPayload{
return &bellatrix.ExecutionPayload{
ParentHash: [32]byte(data.ParentHash),
FeeRecipient: [20]byte(data.FeeRecipient),
StateRoot: [32]byte(data.StateRoot),
ReceiptsRoot: [32]byte(data.ReceiptsRoot),
LogsBloom: boostTypes.Bloom(types.BytesToBloom(data.LogsBloom)),
Random: [32]byte(data.Random),
LogsBloom: types.BytesToBloom(data.LogsBloom),
PrevRandao: [32]byte(data.Random),
BlockNumber: data.Number,
GasLimit: data.GasLimit,
GasUsed: data.GasUsed,
Expand Down Expand Up @@ -528,7 +528,7 @@ func executableDataToCapellaExecutionPayload(data *engine.ExecutableData) (*cape
FeeRecipient: [20]byte(data.FeeRecipient),
StateRoot: [32]byte(data.StateRoot),
ReceiptsRoot: [32]byte(data.ReceiptsRoot),
LogsBloom: boostTypes.Bloom(types.BytesToBloom(data.LogsBloom)),
LogsBloom: types.BytesToBloom(data.LogsBloom),
PrevRandao: [32]byte(data.Random),
BlockNumber: data.Number,
GasLimit: data.GasLimit,
Expand All @@ -541,23 +541,3 @@ func executableDataToCapellaExecutionPayload(data *engine.ExecutableData) (*cape
Withdrawals: withdrawalData,
}, nil
}

func convertBidTrace(bidTrace apiv1.BidTrace) (boostTypes.BidTrace, error) {
value := new(boostTypes.U256Str)
err := value.FromBig(bidTrace.Value.ToBig())
if err != nil {
return boostTypes.BidTrace{}, err
}

return boostTypes.BidTrace{
Slot: bidTrace.Slot,
ParentHash: boostTypes.Hash(bidTrace.ParentHash),
BlockHash: boostTypes.Hash(bidTrace.BlockHash),
BuilderPubkey: boostTypes.PublicKey(bidTrace.BuilderPubkey),
ProposerPubkey: boostTypes.PublicKey(bidTrace.ProposerPubkey),
ProposerFeeRecipient: boostTypes.Address(bidTrace.ProposerFeeRecipient),
GasLimit: bidTrace.GasLimit,
GasUsed: bidTrace.GasUsed,
Value: *value,
}, nil
}
Loading