Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Commit

Permalink
Add flashbots block validation endpoint v3
Browse files Browse the repository at this point in the history
  • Loading branch information
avalonche committed Aug 26, 2023
1 parent 11c541e commit 268a07a
Show file tree
Hide file tree
Showing 24 changed files with 331 additions and 287 deletions.
154 changes: 95 additions & 59 deletions beacon/engine/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
package engine

import (
"crypto/sha256"
"fmt"
"math/big"

denebapi "github.com/attestantio/go-builder-client/api/deneb"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
"github.com/attestantio/go-eth2-client/spec/capella"
"github.com/attestantio/go-eth2-client/spec/deneb"
"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/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)

Expand Down Expand Up @@ -279,17 +283,39 @@ type ExecutionPayloadBodyV1 struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"`
}

func ExecutionPayloadToBlock(payload *bellatrix.ExecutionPayload) (*types.Block, error) {
// TODO: consolidate this into one function that handles all forks
transactionBytes := make([][]byte, len(payload.Transactions))
func ExecutionPayloadV1ToBlock(payload *bellatrix.ExecutionPayload) (*types.Block, error) {
// 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[:])

txs := make([][]byte, len(payload.Transactions))
for i, txHexBytes := range payload.Transactions {
transactionBytes[i] = txHexBytes[:]
txs[i] = txHexBytes
}
txs, err := decodeTransactions(transactionBytes)
if err != nil {
return nil, err
executableData := ExecutableData{
ParentHash: common.Hash(payload.ParentHash),
FeeRecipient: common.Address(payload.FeeRecipient),
StateRoot: common.Hash(payload.StateRoot),
ReceiptsRoot: common.Hash(payload.ReceiptsRoot),
LogsBloom: payload.LogsBloom[:],
Random: common.Hash(payload.PrevRandao),
Number: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Timestamp: payload.Timestamp,
ExtraData: payload.ExtraData,
BaseFeePerGas: baseFeePerGas,
BlockHash: common.Hash(payload.BlockHash),
Transactions: txs,
}
return ExecutableDataToBlock(executableData, nil)
}

func ExecutionPayloadV2ToBlock(payload *capella.ExecutionPayload) (*types.Block, error) {
// base fee per gas is stored little-endian but we need it
// big-endian for big.Int.
var baseFeePerGasBytes [32]byte
Expand All @@ -298,36 +324,44 @@ func ExecutionPayloadToBlock(payload *bellatrix.ExecutionPayload) (*types.Block,
}
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBytes[:])

header := &types.Header{
ParentHash: common.Hash(payload.ParentHash),
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address(payload.FeeRecipient),
Root: common.Hash(payload.StateRoot),
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: common.Hash(payload.ReceiptsRoot),
Bloom: types.BytesToBloom(payload.LogsBloom[:]),
Difficulty: common.Big0,
Number: new(big.Int).SetUint64(payload.BlockNumber),
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Time: payload.Timestamp,
BaseFee: baseFeePerGas,
Extra: payload.ExtraData,
MixDigest: common.Hash(payload.PrevRandao),
txs := make([][]byte, len(payload.Transactions))
for i, txHexBytes := range payload.Transactions {
txs[i] = txHexBytes
}
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
return block, nil

withdrawals := make([]*types.Withdrawal, len(payload.Withdrawals))
for i, withdrawal := range payload.Withdrawals {
withdrawals[i] = &types.Withdrawal{
Index: uint64(withdrawal.Index),
Validator: uint64(withdrawal.ValidatorIndex),
Address: common.Address(withdrawal.Address),
Amount: uint64(withdrawal.Amount),
}
}
executableData := ExecutableData{
ParentHash: common.Hash(payload.ParentHash),
FeeRecipient: common.Address(payload.FeeRecipient),
StateRoot: common.Hash(payload.StateRoot),
ReceiptsRoot: common.Hash(payload.ReceiptsRoot),
LogsBloom: payload.LogsBloom[:],
Random: common.Hash(payload.PrevRandao),
Number: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Timestamp: payload.Timestamp,
ExtraData: payload.ExtraData,
BaseFeePerGas: baseFeePerGas,
BlockHash: common.Hash(payload.BlockHash),
Transactions: txs,
Withdrawals: withdrawals,
}
return ExecutableDataToBlock(executableData, nil)
}

func ExecutionPayloadV2ToBlock(payload *capella.ExecutionPayload) (*types.Block, error) {
// TODO: separate decode function to avoid allocating twice
transactionBytes := make([][]byte, len(payload.Transactions))
func ExecutionPayloadV3ToBlock(payload *deneb.ExecutionPayload, blobsBundle *denebapi.BlobsBundle) (*types.Block, error) {
txs := make([][]byte, len(payload.Transactions))
for i, txHexBytes := range payload.Transactions {
transactionBytes[i] = txHexBytes[:]
}
txs, err := decodeTransactions(transactionBytes)
if err != nil {
return nil, err
txs[i] = txHexBytes
}

withdrawals := make([]*types.Withdrawal, len(payload.Withdrawals))
Expand All @@ -339,34 +373,36 @@ func ExecutionPayloadV2ToBlock(payload *capella.ExecutionPayload) (*types.Block,
Amount: uint64(withdrawal.Amount),
}
}
withdrawalsHash := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil))

// 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]
hasher := sha256.New()
versionedHashes := make([]common.Hash, len(blobsBundle.Commitments))
for i, commitment := range blobsBundle.Commitments {
hasher.Write(commitment[:])
hash := hasher.Sum(nil)
hasher.Reset()

var vhash common.Hash
vhash[0] = params.BlobTxHashVersion
copy(vhash[1:], hash[1:])
versionedHashes[i] = vhash
}
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBytes[:])

header := &types.Header{
ParentHash: common.Hash(payload.ParentHash),
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address(payload.FeeRecipient),
Root: common.Hash(payload.StateRoot),
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: common.Hash(payload.ReceiptsRoot),
Bloom: types.BytesToBloom(payload.LogsBloom[:]),
Difficulty: common.Big0,
Number: new(big.Int).SetUint64(payload.BlockNumber),
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Time: payload.Timestamp,
BaseFee: baseFeePerGas,
Extra: payload.ExtraData,
MixDigest: common.Hash(payload.PrevRandao),
WithdrawalsHash: &withdrawalsHash,
executableData := ExecutableData{
ParentHash: common.Hash(payload.ParentHash),
FeeRecipient: common.Address(payload.FeeRecipient),
StateRoot: common.Hash(payload.StateRoot),
ReceiptsRoot: common.Hash(payload.ReceiptsRoot),
LogsBloom: payload.LogsBloom[:],
Random: common.Hash(payload.PrevRandao),
Number: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Timestamp: payload.Timestamp,
ExtraData: payload.ExtraData,
BaseFeePerGas: payload.BaseFeePerGas.ToBig(),
BlockHash: common.Hash(payload.BlockHash),
Transactions: txs,
Withdrawals: withdrawals,
}
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(withdrawals)
return block, nil
return ExecutableDataToBlock(executableData, versionedHashes)
}
18 changes: 9 additions & 9 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ 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"
builderApiBellatrix "github.com/attestantio/go-builder-client/api/bellatrix"
builderApiCapella "github.com/attestantio/go-builder-client/api/capella"
builderApiV1 "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"
Expand Down Expand Up @@ -46,8 +46,8 @@ type ValidatorData struct {
}

type IRelay interface {
SubmitBlock(msg *bellatrixapi.SubmitBlockRequest, vd ValidatorData) error
SubmitBlockCapella(msg *capellaapi.SubmitBlockRequest, vd ValidatorData) error
SubmitBlock(msg *builderApiBellatrix.SubmitBlockRequest, vd ValidatorData) error
SubmitBlockCapella(msg *builderApiCapella.SubmitBlockRequest, vd ValidatorData) error
GetValidatorForSlot(nextSlot uint64) (ValidatorData, error)
Config() RelayConfig
Start() error
Expand Down Expand Up @@ -235,7 +235,7 @@ func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int,
return err
}

blockBidMsg := apiv1.BidTrace{
blockBidMsg := builderApiV1.BidTrace{
Slot: attrs.Slot,
ParentHash: payload.ParentHash,
BlockHash: payload.BlockHash,
Expand All @@ -253,7 +253,7 @@ func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int,
return err
}

blockSubmitReq := bellatrixapi.SubmitBlockRequest{
blockSubmitReq := builderApiBellatrix.SubmitBlockRequest{
Signature: signature,
Message: &blockBidMsg,
ExecutionPayload: payload,
Expand Down Expand Up @@ -294,7 +294,7 @@ func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, or
return err
}

blockBidMsg := apiv1.BidTrace{
blockBidMsg := builderApiV1.BidTrace{
Slot: attrs.Slot,
ParentHash: payload.ParentHash,
BlockHash: payload.BlockHash,
Expand All @@ -312,7 +312,7 @@ func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, or
return err
}

blockSubmitReq := capellaapi.SubmitBlockRequest{
blockSubmitReq := builderApiCapella.SubmitBlockRequest{
Signature: signature,
Message: &blockBidMsg,
ExecutionPayload: payload,
Expand Down
4 changes: 2 additions & 2 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"testing"
"time"

apiv1 "github.com/attestantio/go-builder-client/api/v1"
builderApiV1 "github.com/attestantio/go-builder-client/api/v1"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/ethereum/go-ethereum/beacon/engine"
Expand Down Expand Up @@ -102,7 +102,7 @@ func TestOnPayloadAttributes(t *testing.T) {
expectedProposerPubkey, err := utils.HexToPubkey(testBeacon.validator.Pk.String())
require.NoError(t, err)

expectedMessage := apiv1.BidTrace{
expectedMessage := builderApiV1.BidTrace{
Slot: uint64(25),
ParentHash: phase0.Hash32{0x02, 0x03},
BuilderPubkey: builder.builderPublicKey,
Expand Down
42 changes: 21 additions & 21 deletions builder/local_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import (
"sync"
"time"

"github.com/attestantio/go-builder-client/api"
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-builder-client/spec"
apiv1bellatrix "github.com/attestantio/go-eth2-client/api/v1/bellatrix"
consensusspec "github.com/attestantio/go-eth2-client/spec"
builderApi "github.com/attestantio/go-builder-client/api"
builderApiBellatrix "github.com/attestantio/go-builder-client/api/bellatrix"
builderCapellaApi "github.com/attestantio/go-builder-client/api/capella"
builderApiV1 "github.com/attestantio/go-builder-client/api/v1"
builderSpec "github.com/attestantio/go-builder-client/spec"
eth2ApiV1Bellatrix "github.com/attestantio/go-eth2-client/api/v1/bellatrix"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
"github.com/attestantio/go-eth2-client/spec/phase0"
bellatrixutil "github.com/attestantio/go-eth2-client/util/bellatrix"
eth2UtilBellatrix "github.com/attestantio/go-eth2-client/util/bellatrix"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/flashbots/go-boost-utils/bls"
Expand Down Expand Up @@ -110,12 +110,12 @@ func (r *LocalRelay) Stop() {
r.beaconClient.Stop()
}

func (r *LocalRelay) SubmitBlock(msg *bellatrixapi.SubmitBlockRequest, _ ValidatorData) error {
func (r *LocalRelay) SubmitBlock(msg *builderApiBellatrix.SubmitBlockRequest, _ ValidatorData) error {
log.Info("submitting block to local relay", "block", msg.ExecutionPayload.BlockHash.String())
return r.submitBlock(msg)
}

func (r *LocalRelay) SubmitBlockCapella(msg *capellaapi.SubmitBlockRequest, _ ValidatorData) error {
func (r *LocalRelay) SubmitBlockCapella(msg *builderCapellaApi.SubmitBlockRequest, _ ValidatorData) error {
log.Info("submitting block to local relay", "block", msg.ExecutionPayload.BlockHash.String())

return r.submitBlockCapella(msg)
Expand All @@ -127,11 +127,11 @@ func (r *LocalRelay) Config() RelayConfig {
}

// TODO: local relay support for capella
func (r *LocalRelay) submitBlockCapella(msg *capellaapi.SubmitBlockRequest) error {
func (r *LocalRelay) submitBlockCapella(msg *builderCapellaApi.SubmitBlockRequest) error {
return nil
}

func (r *LocalRelay) submitBlock(msg *bellatrixapi.SubmitBlockRequest) error {
func (r *LocalRelay) submitBlock(msg *builderApiBellatrix.SubmitBlockRequest) error {
header, err := PayloadToPayloadHeader(msg.ExecutionPayload)
if err != nil {
log.Error("could not convert payload to header", "err", err)
Expand All @@ -148,7 +148,7 @@ func (r *LocalRelay) submitBlock(msg *bellatrixapi.SubmitBlockRequest) error {
}

func (r *LocalRelay) handleRegisterValidator(w http.ResponseWriter, req *http.Request) {
payload := []apiv1.SignedValidatorRegistration{}
payload := []builderApiV1.SignedValidatorRegistration{}
if err := json.NewDecoder(req.Body).Decode(&payload); err != nil {
log.Error("could not decode payload", "err", err)
respondError(w, http.StatusBadRequest, "invalid payload")
Expand Down Expand Up @@ -278,7 +278,7 @@ func (r *LocalRelay) handleGetHeader(w http.ResponseWriter, req *http.Request) {
return
}

bid := bellatrixapi.BuilderBid{
bid := builderApiBellatrix.BuilderBid{
Header: bestHeader,
Value: profit,
Pubkey: r.relayPublicKey,
Expand All @@ -289,9 +289,9 @@ func (r *LocalRelay) handleGetHeader(w http.ResponseWriter, req *http.Request) {
return
}

response := &spec.VersionedSignedBuilderBid{
Version: consensusspec.DataVersionBellatrix,
Bellatrix: &bellatrixapi.SignedBuilderBid{Message: &bid, Signature: signature},
response := &builderSpec.VersionedSignedBuilderBid{
Version: spec.DataVersionBellatrix,
Bellatrix: &builderApiBellatrix.SignedBuilderBid{Message: &bid, Signature: signature},
}

w.Header().Set("Content-Type", "application/json")
Expand All @@ -303,7 +303,7 @@ func (r *LocalRelay) handleGetHeader(w http.ResponseWriter, req *http.Request) {
}

func (r *LocalRelay) handleGetPayload(w http.ResponseWriter, req *http.Request) {
payload := new(apiv1bellatrix.SignedBlindedBeaconBlock)
payload := new(eth2ApiV1Bellatrix.SignedBlindedBeaconBlock)
if err := json.NewDecoder(req.Body).Decode(&payload); err != nil {
log.Error("failed to decode payload", "error", err)
respondError(w, http.StatusBadRequest, "invalid payload")
Expand Down Expand Up @@ -356,8 +356,8 @@ func (r *LocalRelay) handleGetPayload(w http.ResponseWriter, req *http.Request)
return
}

response := &api.VersionedExecutionPayload{
Version: consensusspec.DataVersionBellatrix,
response := &builderApi.VersionedExecutionPayload{
Version: spec.DataVersionBellatrix,
Bellatrix: bestPayload,
}

Expand Down Expand Up @@ -442,7 +442,7 @@ func PayloadToPayloadHeader(p *bellatrix.ExecutionPayload) (*bellatrix.Execution
var txs []bellatrix.Transaction
txs = append(txs, p.Transactions...)

transactions := bellatrixutil.ExecutionPayloadTransactions{Transactions: txs}
transactions := eth2UtilBellatrix.ExecutionPayloadTransactions{Transactions: txs}
txroot, err := transactions.HashTreeRoot()
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 268a07a

Please sign in to comment.