Skip to content

Commit 41f77d8

Browse files
Ruteriavalonche
authored andcommitted
Merge changes from validation (ethereum#4)
* Implement block validation API * Validate proposer payment assuming its the last transaction in the block (ethereum#4) * Validate that the coinbase and feeRecipient are not blacklisted (ethereum#5) * Validate that the proposer payment has no calldata and its gas usage (ethereum#6) * Validate gas limit is set correctly wrt registered (ethereum#8) * Pass validation-specific config (ethereum#9)
1 parent 4f1f997 commit 41f77d8

File tree

9 files changed

+107
-55
lines changed

9 files changed

+107
-55
lines changed

builder/builder.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (b *Builder) Stop() error {
9797
return nil
9898
}
9999

100-
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 {
100+
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 {
101101
executableData := beacon.BlockToExecutableData(block)
102102
payload, err := executableDataToExecutionPayload(executableData)
103103
if err != nil {
@@ -137,7 +137,7 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
137137
}
138138

139139
if b.dryRun {
140-
err = b.validator.ValidateBuilderSubmissionV1(&blockSubmitReq)
140+
err = b.validator.ValidateBuilderSubmissionV1(&blockvalidation.BuilderBlockValidationRequest{blockSubmitReq, proposerRegisteredGasLimit})
141141
if err != nil {
142142
log.Error("could not validate block", "err", err)
143143
}
@@ -208,7 +208,7 @@ func (b *Builder) OnPayloadAttribute(attrs *BuilderPayloadAttributes) error {
208208
}
209209
b.slotAttrs = append(b.slotAttrs, *attrs)
210210

211-
go b.runBuildingJob(b.slotCtx, proposerPubkey, vd.FeeRecipient, attrs)
211+
go b.runBuildingJob(b.slotCtx, proposerPubkey, vd.FeeRecipient, vd.GasLimit, attrs)
212212
return nil
213213
}
214214

@@ -220,7 +220,7 @@ type blockQueueEntry struct {
220220
allBundles []types.SimulatedBundle
221221
}
222222

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

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

250250
if err != nil {
251251
log.Error("could not run sealed block hook", "err", err)

cmd/geth/config.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,12 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
168168
// Configure log filter RPC API.
169169
filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth)
170170

171-
if err := blockvalidationapi.Register(stack, eth, ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)); err != nil {
171+
bvConfig := blockvalidationapi.BlockValidationConfig{}
172+
if ctx.IsSet(utils.BuilderBlockValidationBlacklistSourceFilePath.Name) {
173+
bvConfig.BlacklistSourceFilePath = ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)
174+
}
175+
176+
if err := blockvalidationapi.Register(stack, eth, bvConfig); err != nil {
172177
utils.Fatalf("Failed to register the Block Validation API: %v", err)
173178
}
174179

cmd/utils/flags.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,8 +1085,8 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
10851085
// Builder API flags
10861086
BuilderBlockValidationBlacklistSourceFilePath = &cli.StringFlag{
10871087
Name: "builder.validation_blacklist",
1088-
Usage: "Path to file containing blacklisted addresses, json-encoded list of strings. Default assumes no blacklist",
1089-
Value: "",
1088+
Usage: "Path to file containing blacklisted addresses, json-encoded list of strings. Default assumes CWD is repo's root",
1089+
Value: "ofac_blacklist.json",
10901090
Category: flags.EthCategory,
10911091
}
10921092
)

core/block_validator.go

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/ethereum/go-ethereum/consensus"
2323
"github.com/ethereum/go-ethereum/core/state"
2424
"github.com/ethereum/go-ethereum/core/types"
25+
"github.com/ethereum/go-ethereum/core/utils"
2526
"github.com/ethereum/go-ethereum/params"
2627
"github.com/ethereum/go-ethereum/trie"
2728
)
@@ -118,28 +119,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
118119
return nil
119120
}
120121

121-
// CalcGasLimit computes the gas limit of the next block after parent. It aims
122-
// to keep the baseline gas close to the provided target, and increase it towards
123-
// the target if the baseline gas is lower.
124122
func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
125-
delta := parentGasLimit/params.GasLimitBoundDivisor - 1
126-
limit := parentGasLimit
127-
if desiredLimit < params.MinGasLimit {
128-
desiredLimit = params.MinGasLimit
129-
}
130-
// If we're outside our allowed gas range, we try to hone towards them
131-
if limit < desiredLimit {
132-
limit = parentGasLimit + delta
133-
if limit > desiredLimit {
134-
limit = desiredLimit
135-
}
136-
return limit
137-
}
138-
if limit > desiredLimit {
139-
limit = parentGasLimit - delta
140-
if limit < desiredLimit {
141-
limit = desiredLimit
142-
}
143-
}
144-
return limit
123+
return utils.CalcGasLimit(parentGasLimit, desiredLimit)
145124
}

core/blockchain.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/ethereum/go-ethereum/core/state"
3939
"github.com/ethereum/go-ethereum/core/state/snapshot"
4040
"github.com/ethereum/go-ethereum/core/types"
41+
"github.com/ethereum/go-ethereum/core/utils"
4142
"github.com/ethereum/go-ethereum/core/vm"
4243
"github.com/ethereum/go-ethereum/ethdb"
4344
"github.com/ethereum/go-ethereum/event"

core/utils/gas_limit.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package utils
2+
3+
import "github.com/ethereum/go-ethereum/params"
4+
5+
// CalcGasLimit computes the gas limit of the next block after parent. It aims
6+
// to keep the baseline gas close to the provided target, and increase it towards
7+
// the target if the baseline gas is lower.
8+
func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
9+
delta := parentGasLimit/params.GasLimitBoundDivisor - 1
10+
limit := parentGasLimit
11+
if desiredLimit < params.MinGasLimit {
12+
desiredLimit = params.MinGasLimit
13+
}
14+
// If we're outside our allowed gas range, we try to hone towards them
15+
if limit < desiredLimit {
16+
limit = parentGasLimit + delta
17+
if limit > desiredLimit {
18+
limit = desiredLimit
19+
}
20+
return limit
21+
}
22+
if limit > desiredLimit {
23+
limit = parentGasLimit - delta
24+
if limit < desiredLimit {
25+
limit = desiredLimit
26+
}
27+
}
28+
return limit
29+
}

eth/block-validation/api.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/ethereum/go-ethereum/log"
1717
"github.com/ethereum/go-ethereum/node"
1818
"github.com/ethereum/go-ethereum/rpc"
19+
1920
boostTypes "github.com/flashbots/go-boost-utils/types"
2021
)
2122

@@ -26,7 +27,7 @@ type AccessVerifier struct {
2627
}
2728

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

42+
func (a *AccessVerifier) isBlacklisted(addr common.Address) error {
43+
if _, present := a.blacklistedAddresses[addr]; present {
44+
return fmt.Errorf("transaction from blacklisted address %s", addr.String())
45+
}
46+
return nil
47+
}
48+
4149
func (a *AccessVerifier) verifyTransactions(signer types.Signer, txs types.Transactions) error {
4250
for _, tx := range txs {
4351
from, err := signer.Sender(tx)
@@ -77,12 +85,16 @@ func NewAccessVerifierFromFile(path string) (*AccessVerifier, error) {
7785
}, nil
7886
}
7987

88+
type BlockValidationConfig struct {
89+
BlacklistSourceFilePath string
90+
}
91+
8092
// Register adds catalyst APIs to the full node.
81-
func Register(stack *node.Node, backend *eth.Ethereum, blockValidationBlocklistFile string) error {
93+
func Register(stack *node.Node, backend *eth.Ethereum, cfg BlockValidationConfig) error {
8294
var accessVerifier *AccessVerifier
83-
if blockValidationBlocklistFile != "" {
95+
if cfg.BlacklistSourceFilePath != "" {
8496
var err error
85-
accessVerifier, err = NewAccessVerifierFromFile(blockValidationBlocklistFile)
97+
accessVerifier, err = NewAccessVerifierFromFile(cfg.BlacklistSourceFilePath)
8698
if err != nil {
8799
return err
88100
}
@@ -111,7 +123,12 @@ func NewBlockValidationAPI(eth *eth.Ethereum, accessVerifier *AccessVerifier) *B
111123
}
112124
}
113125

114-
func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.BuilderSubmitBlockRequest) error {
126+
type BuilderBlockValidationRequest struct {
127+
boostTypes.BuilderSubmitBlockRequest
128+
RegisteredGasLimit uint64 `json:"registered_gas_limit,string"`
129+
}
130+
131+
func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *BuilderBlockValidationRequest) error {
115132
// TODO: fuzztest, make sure the validation is sound
116133
// TODO: handle context!
117134

@@ -146,6 +163,12 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.Bu
146163
var vmconfig vm.Config
147164
var tracer *logger.AccessListTracer = nil
148165
if api.accessVerifier != nil {
166+
if err := api.accessVerifier.isBlacklisted(block.Coinbase()); err != nil {
167+
return err
168+
}
169+
if err := api.accessVerifier.isBlacklisted(feeRecipient); err != nil {
170+
return err
171+
}
149172
if err := api.accessVerifier.verifyTransactions(types.LatestSigner(api.eth.BlockChain().Config()), block.Transactions()); err != nil {
150173
return err
151174
}
@@ -155,7 +178,7 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *boostTypes.Bu
155178
vmconfig = vm.Config{Tracer: tracer, Debug: true}
156179
}
157180

158-
err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, vmconfig)
181+
err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig)
159182
if err != nil {
160183
log.Error("invalid payload", "hash", payload.BlockHash.String(), "number", payload.BlockNumber, "parentHash", payload.ParentHash.String(), "err", err)
161184
return err

eth/block-validation/api_test.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/ethereum/go-ethereum/common"
1212
"github.com/ethereum/go-ethereum/common/hexutil"
1313
"github.com/ethereum/go-ethereum/consensus/ethash"
14+
"github.com/ethereum/go-ethereum/consensus/misc"
1415
"github.com/ethereum/go-ethereum/core"
1516
"github.com/ethereum/go-ethereum/core/beacon"
1617
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -20,7 +21,6 @@ import (
2021
"github.com/ethereum/go-ethereum/eth/downloader"
2122
"github.com/ethereum/go-ethereum/eth/ethconfig"
2223
"github.com/ethereum/go-ethereum/eth/tracers/logger"
23-
"github.com/ethereum/go-ethereum/log"
2424
"github.com/ethereum/go-ethereum/node"
2525
"github.com/ethereum/go-ethereum/p2p"
2626
"github.com/ethereum/go-ethereum/params"
@@ -68,14 +68,14 @@ func TestValidateBuilderSubmissionV1(t *testing.T) {
6868
cc, _ := types.SignTx(types.NewContractCreation(nonce+1, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
6969
ethservice.TxPool().AddLocal(cc)
7070

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

7475
execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
7576
Timestamp: parent.Time() + 5,
7677
SuggestedFeeRecipient: testValidatorAddr,
7778
})
78-
require.NoError(t, err)
7979
require.EqualValues(t, len(execData.Transactions), 4)
8080
require.NoError(t, err)
8181

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

88-
blockRequest := &boostTypes.BuilderSubmitBlockRequest{
89-
Signature: boostTypes.Signature{},
90-
Message: &boostTypes.BidTrace{
91-
ParentHash: boostTypes.Hash(execData.ParentHash),
92-
BlockHash: boostTypes.Hash(execData.BlockHash),
93-
ProposerFeeRecipient: proposerAddr,
94-
GasLimit: execData.GasLimit,
95-
GasUsed: execData.GasUsed,
88+
blockRequest := &BuilderBlockValidationRequest{
89+
BuilderSubmitBlockRequest: boostTypes.BuilderSubmitBlockRequest{
90+
Signature: boostTypes.Signature{},
91+
Message: &boostTypes.BidTrace{
92+
ParentHash: boostTypes.Hash(execData.ParentHash),
93+
BlockHash: boostTypes.Hash(execData.BlockHash),
94+
ProposerFeeRecipient: proposerAddr,
95+
GasLimit: execData.GasLimit,
96+
GasUsed: execData.GasUsed,
97+
},
98+
ExecutionPayload: payload,
9699
},
97-
ExecutionPayload: payload,
100+
RegisteredGasLimit: execData.GasLimit,
98101
}
102+
99103
blockRequest.Message.Value = boostTypes.IntToU256(190526394825529)
100104
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "inaccurate payment")
101-
blockRequest.Message.Value = boostTypes.IntToU256(190526394825530)
105+
blockRequest.Message.Value = boostTypes.IntToU256(149830884438530)
102106
require.NoError(t, api.ValidateBuilderSubmissionV1(blockRequest))
103107

108+
blockRequest.Message.GasLimit += 1
109+
blockRequest.ExecutionPayload.GasLimit += 1
110+
111+
oldHash := blockRequest.Message.BlockHash
112+
copy(blockRequest.Message.BlockHash[:], hexutil.MustDecode("0x56cbdd508966f89cfb6ba16535e3676b59ae3ac3774478b631466bc99c1033c9")[:32])
113+
require.ErrorContains(t, api.ValidateBuilderSubmissionV1(blockRequest), "incorrect gas limit set")
114+
115+
blockRequest.Message.GasLimit -= 1
116+
blockRequest.ExecutionPayload.GasLimit -= 1
117+
blockRequest.Message.BlockHash = oldHash
118+
104119
// TODO: test with contract calling blacklisted address
105120
// Test tx from blacklisted address
106121
api.accessVerifier = &AccessVerifier{
@@ -130,17 +145,16 @@ func TestValidateBuilderSubmissionV1(t *testing.T) {
130145

131146
txData, err := invalidTx.MarshalBinary()
132147
require.NoError(t, err)
133-
execData.Transactions = append(execData.Transactions, execData.Transactions[3])
134-
execData.Transactions[3] = txData
148+
execData.Transactions = append(execData.Transactions, txData)
135149

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

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

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,8 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7
877877
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
878878
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
879879
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
880+
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
881+
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
880882
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
881883
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
882884
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 commit comments

Comments
 (0)