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

Merge changes from validation #4

Merged
merged 7 commits into from
Nov 22, 2022
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
10 changes: 5 additions & 5 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (b *Builder) Stop() error {
return nil
}

func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, proposerFeeRecipient boostTypes.Address, attrs *BuilderPayloadAttributes) error {
func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, proposerFeeRecipient boostTypes.Address, proposerRegisteredGasLimit uint64, attrs *BuilderPayloadAttributes) error {
executableData := beacon.BlockToExecutableData(block)
payload, err := executableDataToExecutionPayload(executableData)
if err != nil {
Expand Down Expand Up @@ -137,7 +137,7 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
}

if b.dryRun {
err = b.validator.ValidateBuilderSubmissionV1(&blockSubmitReq)
err = b.validator.ValidateBuilderSubmissionV1(&blockvalidation.BuilderBlockValidationRequest{blockSubmitReq, proposerRegisteredGasLimit})
if err != nil {
log.Error("could not validate block", "err", err)
}
Expand Down Expand Up @@ -208,7 +208,7 @@ func (b *Builder) OnPayloadAttribute(attrs *BuilderPayloadAttributes) error {
}
b.slotAttrs = append(b.slotAttrs, *attrs)

go b.runBuildingJob(b.slotCtx, proposerPubkey, vd.FeeRecipient, attrs)
go b.runBuildingJob(b.slotCtx, proposerPubkey, vd.FeeRecipient, vd.GasLimit, attrs)
return nil
}

Expand All @@ -220,7 +220,7 @@ type blockQueueEntry struct {
allBundles []types.SimulatedBundle
}

func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTypes.PublicKey, feeRecipient boostTypes.Address, attrs *BuilderPayloadAttributes) {
func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTypes.PublicKey, feeRecipient boostTypes.Address, proposerRegisteredGasLimit uint64, attrs *BuilderPayloadAttributes) {
ctx, cancel := context.WithTimeout(slotCtx, 12*time.Second)
defer cancel()

Expand All @@ -245,7 +245,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
submitBestBlock := func() {
queueMu.Lock()
if queueLastSubmittedProfit.Cmp(queueBestProfit) < 0 {
err := b.onSealedBlock(queueBestEntry.block, queueBestEntry.ordersCloseTime, queueBestEntry.sealedAt, queueBestEntry.commitedBundles, queueBestEntry.allBundles, proposerPubkey, feeRecipient, attrs)
err := b.onSealedBlock(queueBestEntry.block, queueBestEntry.ordersCloseTime, queueBestEntry.sealedAt, queueBestEntry.commitedBundles, queueBestEntry.allBundles, proposerPubkey, feeRecipient, proposerRegisteredGasLimit, attrs)

if err != nil {
log.Error("could not run sealed block hook", "err", err)
Expand Down
7 changes: 6 additions & 1 deletion cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,12 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
// Configure log filter RPC API.
filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth)

if err := blockvalidationapi.Register(stack, eth, ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)); err != nil {
bvConfig := blockvalidationapi.BlockValidationConfig{}
if ctx.IsSet(utils.BuilderBlockValidationBlacklistSourceFilePath.Name) {
bvConfig.BlacklistSourceFilePath = ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)
}

if err := blockvalidationapi.Register(stack, eth, bvConfig); err != nil {
utils.Fatalf("Failed to register the Block Validation API: %v", err)
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1075,8 +1075,8 @@ var (
// Builder API flags
BuilderBlockValidationBlacklistSourceFilePath = &cli.StringFlag{
Name: "builder.validation_blacklist",
Usage: "Path to file containing blacklisted addresses, json-encoded list of strings. Default assumes no blacklist",
Value: "",
Usage: "Path to file containing blacklisted addresses, json-encoded list of strings. Default assumes CWD is repo's root",
Value: "ofac_blacklist.json",
Category: flags.EthCategory,
}
)
Expand Down
25 changes: 2 additions & 23 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/utils"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)
Expand Down Expand Up @@ -102,28 +103,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil
}

// CalcGasLimit computes the gas limit of the next block after parent. It aims
// to keep the baseline gas close to the provided target, and increase it towards
// the target if the baseline gas is lower.
func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
delta := parentGasLimit/params.GasLimitBoundDivisor - 1
limit := parentGasLimit
if desiredLimit < params.MinGasLimit {
desiredLimit = params.MinGasLimit
}
// If we're outside our allowed gas range, we try to hone towards them
if limit < desiredLimit {
limit = parentGasLimit + delta
if limit > desiredLimit {
limit = desiredLimit
}
return limit
}
if limit > desiredLimit {
limit = parentGasLimit - delta
if limit < desiredLimit {
limit = desiredLimit
}
}
return limit
return utils.CalcGasLimit(parentGasLimit, desiredLimit)
}
24 changes: 23 additions & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/utils"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
Expand Down Expand Up @@ -2422,7 +2423,7 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro
bc.processor = p
}

func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, vmConfig vm.Config) error {
func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config) error {
header := block.Header()
if err := bc.engine.VerifyHeader(bc, header, true); err != nil {
return err
Expand All @@ -2439,6 +2440,11 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
return errors.New("parent not found")
}

calculatedGasLimit := utils.CalcGasLimit(parent.GasLimit, registeredGasLimit)
if calculatedGasLimit != header.GasLimit {
return errors.New("incorrect gas limit set")
}

statedb, err := bc.StateAt(parent.Root)
if err != nil {
return err
Expand Down Expand Up @@ -2490,5 +2496,21 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
return fmt.Errorf("inaccurate payment %s, expected %s", paymentTx.Value().String(), expectedProfit.String())
}

if len(paymentTx.Data()) != 0 {
return fmt.Errorf("malformed proposer payment, contains calldata")
}

if paymentTx.GasPrice().Cmp(block.BaseFee()) != 0 {
return fmt.Errorf("malformed proposer payment, gas price not equal to base fee")
}

if paymentTx.GasTipCap().Cmp(block.BaseFee()) != 0 && paymentTx.GasTipCap().Sign() != 0 {
return fmt.Errorf("malformed proposer payment, unexpected gas tip cap")
}

if paymentTx.GasFeeCap().Cmp(block.BaseFee()) != 0 {
return fmt.Errorf("malformed proposer payment, unexpected gas fee cap")
}

return nil
}
29 changes: 29 additions & 0 deletions core/utils/gas_limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package utils

import "github.com/ethereum/go-ethereum/params"

// CalcGasLimit computes the gas limit of the next block after parent. It aims
// to keep the baseline gas close to the provided target, and increase it towards
// the target if the baseline gas is lower.
func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
delta := parentGasLimit/params.GasLimitBoundDivisor - 1
limit := parentGasLimit
if desiredLimit < params.MinGasLimit {
desiredLimit = params.MinGasLimit
}
// If we're outside our allowed gas range, we try to hone towards them
if limit < desiredLimit {
limit = parentGasLimit + delta
if limit > desiredLimit {
limit = desiredLimit
}
return limit
}
if limit > desiredLimit {
limit = parentGasLimit - delta
if limit < desiredLimit {
limit = desiredLimit
}
}
return limit
}
35 changes: 29 additions & 6 deletions eth/block-validation/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"

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

Expand All @@ -26,7 +27,7 @@ type AccessVerifier struct {
}

func (a *AccessVerifier) verifyTraces(tracer *logger.AccessListTracer) error {
log.Info("x", "tracer.AccessList()", tracer.AccessList())
log.Trace("x", "tracer.AccessList()", tracer.AccessList())
for _, accessTuple := range tracer.AccessList() {
// TODO: should we ignore common.Address{}?
if _, found := a.blacklistedAddresses[accessTuple.Address]; found {
Expand All @@ -38,6 +39,13 @@ func (a *AccessVerifier) verifyTraces(tracer *logger.AccessListTracer) error {
return nil
}

func (a *AccessVerifier) isBlacklisted(addr common.Address) error {
if _, present := a.blacklistedAddresses[addr]; present {
return fmt.Errorf("transaction from blacklisted address %s", addr.String())
}
return nil
}

func (a *AccessVerifier) verifyTransactions(signer types.Signer, txs types.Transactions) error {
for _, tx := range txs {
from, err := signer.Sender(tx)
Expand Down Expand Up @@ -77,12 +85,16 @@ func NewAccessVerifierFromFile(path string) (*AccessVerifier, error) {
}, nil
}

type BlockValidationConfig struct {
BlacklistSourceFilePath string
}

// Register adds catalyst APIs to the full node.
func Register(stack *node.Node, backend *eth.Ethereum, blockValidationBlocklistFile string) error {
func Register(stack *node.Node, backend *eth.Ethereum, cfg BlockValidationConfig) error {
var accessVerifier *AccessVerifier
if blockValidationBlocklistFile != "" {
if cfg.BlacklistSourceFilePath != "" {
var err error
accessVerifier, err = NewAccessVerifierFromFile(blockValidationBlocklistFile)
accessVerifier, err = NewAccessVerifierFromFile(cfg.BlacklistSourceFilePath)
if err != nil {
return err
}
Expand Down Expand Up @@ -111,7 +123,12 @@ func NewBlockValidationAPI(eth *eth.Ethereum, accessVerifier *AccessVerifier) *B
}
}

func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.BuilderSubmitBlockRequest) error {
type BuilderBlockValidationRequest struct {
boostTypes.BuilderSubmitBlockRequest
RegisteredGasLimit uint64 `json:"registered_gas_limit,string"`
}

func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *BuilderBlockValidationRequest) error {
// TODO: fuzztest, make sure the validation is sound
// TODO: handle context!

Expand Down Expand Up @@ -146,6 +163,12 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.Bu
var vmconfig vm.Config
var tracer *logger.AccessListTracer = nil
if api.accessVerifier != nil {
if err := api.accessVerifier.isBlacklisted(block.Coinbase()); err != nil {
return err
}
if err := api.accessVerifier.isBlacklisted(feeRecipient); err != nil {
return err
}
if err := api.accessVerifier.verifyTransactions(types.LatestSigner(api.eth.BlockChain().Config()), block.Transactions()); err != nil {
return err
}
Expand All @@ -155,7 +178,7 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.Bu
vmconfig = vm.Config{Tracer: tracer, Debug: true}
}

err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, vmconfig)
err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig)
if err != nil {
log.Error("invalid payload", "hash", payload.BlockHash.String(), "number", payload.BlockNumber, "parentHash", payload.ParentHash.String(), "err", err)
return err
Expand Down
49 changes: 31 additions & 18 deletions eth/block-validation/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/rawdb"
Expand All @@ -20,7 +21,6 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -68,14 +68,14 @@ func TestValidateBuilderSubmissionV1(t *testing.T) {
cc, _ := types.SignTx(types.NewContractCreation(nonce+1, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().AddLocal(cc)

tx2, _ := types.SignTx(types.NewTransaction(nonce+2, testAddr, big.NewInt(10), 21000, big.NewInt(2*params.InitialBaseFee), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
baseFee := misc.CalcBaseFee(params.AllEthashProtocolChanges, preMergeBlocks[len(preMergeBlocks)-1].Header())
tx2, _ := types.SignTx(types.NewTransaction(nonce+2, testAddr, big.NewInt(10), 21000, baseFee, nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().AddLocal(tx2)

execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
Timestamp: parent.Time() + 5,
SuggestedFeeRecipient: testValidatorAddr,
})
require.NoError(t, err)
require.EqualValues(t, len(execData.Transactions), 4)
require.NoError(t, err)

Expand All @@ -85,22 +85,37 @@ func TestValidateBuilderSubmissionV1(t *testing.T) {
proposerAddr := boostTypes.Address{}
proposerAddr.FromSlice(testValidatorAddr[:])

blockRequest := &boostTypes.BuilderSubmitBlockRequest{
Signature: boostTypes.Signature{},
Message: &boostTypes.BidTrace{
ParentHash: boostTypes.Hash(execData.ParentHash),
BlockHash: boostTypes.Hash(execData.BlockHash),
ProposerFeeRecipient: proposerAddr,
GasLimit: execData.GasLimit,
GasUsed: execData.GasUsed,
blockRequest := &BuilderBlockValidationRequest{
BuilderSubmitBlockRequest: boostTypes.BuilderSubmitBlockRequest{
Signature: boostTypes.Signature{},
Message: &boostTypes.BidTrace{
ParentHash: boostTypes.Hash(execData.ParentHash),
BlockHash: boostTypes.Hash(execData.BlockHash),
ProposerFeeRecipient: proposerAddr,
GasLimit: execData.GasLimit,
GasUsed: execData.GasUsed,
},
ExecutionPayload: payload,
},
ExecutionPayload: payload,
RegisteredGasLimit: execData.GasLimit,
}

blockRequest.Message.Value = boostTypes.IntToU256(190526394825529)
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "inaccurate payment")
blockRequest.Message.Value = boostTypes.IntToU256(190526394825530)
blockRequest.Message.Value = boostTypes.IntToU256(149830884438530)
require.NoError(t, api.ValidateBuilderSubmissionV1(blockRequest))

blockRequest.Message.GasLimit += 1
blockRequest.ExecutionPayload.GasLimit += 1

oldHash := blockRequest.Message.BlockHash
copy(blockRequest.Message.BlockHash[:], hexutil.MustDecode("0x56cbdd508966f89cfb6ba16535e3676b59ae3ac3774478b631466bc99c1033c9")[:32])
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "incorrect gas limit set")

blockRequest.Message.GasLimit -= 1
blockRequest.ExecutionPayload.GasLimit -= 1
blockRequest.Message.BlockHash = oldHash

// TODO: test with contract calling blacklisted address
// Test tx from blacklisted address
api.accessVerifier = &AccessVerifier{
Expand Down Expand Up @@ -130,17 +145,16 @@ func TestValidateBuilderSubmissionV1(t *testing.T) {

txData, err := invalidTx.MarshalBinary()
require.NoError(t, err)
execData.Transactions = append(execData.Transactions, execData.Transactions[3])
execData.Transactions[3] = txData
execData.Transactions = append(execData.Transactions, txData)

invalidPayload, err := ExecutableDataToExecutionPayload(execData)
require.NoError(t, err)
invalidPayload.GasUsed = execData.GasUsed
invalidPayload.LogsBloom = boostTypes.Bloom{}
copy(invalidPayload.ReceiptsRoot[:], hexutil.MustDecode("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")[:32])
blockRequest.ExecutionPayload = invalidPayload
copy(blockRequest.Message.BlockHash[:], hexutil.MustDecode("0x2ff468dee2e05f1f58744d5496f3ab22fdc23c8141f86f907b4b0f2c8e22afc4")[:32])
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "could not apply tx 3", "insufficient funds for gas * price + value")
copy(blockRequest.Message.BlockHash[:], hexutil.MustDecode("0x595cba7ab70a18b7e11ae7541661cb6692909a0acd3eba3f1cf6ae694f85a8bd")[:32])
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "could not apply tx 4", "insufficient funds for gas * price + value")
}

func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
Expand Down Expand Up @@ -211,7 +225,6 @@ func assembleBlock(api *BlockValidationAPI, parentHash common.Hash, params *beac
if err != nil {
return nil, err
}
log.Info("b", "block", block)
return beacon.BlockToExecutableData(block), nil
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ require (
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading