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

Commit 85ce2f9

Browse files
committed
Add block value to validation api
1 parent df9c765 commit 85ce2f9

File tree

4 files changed

+73
-52
lines changed

4 files changed

+73
-52
lines changed

builder/builder.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ func (b *Builder) onSealedBlock(opts SubmitBlockOpts) error {
279279
case spec.DataVersionCapella:
280280
err = b.validator.ValidateBuilderSubmissionV2(&blockvalidation.BuilderBlockValidationRequestV2{SubmitBlockRequest: *versionedBlockRequest.Capella, RegisteredGasLimit: opts.ValidatorData.GasLimit})
281281
case spec.DataVersionDeneb:
282-
err = b.validator.ValidateBuilderSubmissionV3(&blockvalidation.BuilderBlockValidationRequestV3{SubmitBlockRequest: *versionedBlockRequest.Deneb, RegisteredGasLimit: opts.ValidatorData.GasLimit, ParentBeaconBlockRoot: *opts.Block.BeaconRoot()})
282+
_, err = b.validator.ValidateBuilderSubmissionV3(&blockvalidation.BuilderBlockValidationRequestV3{SubmitBlockRequest: *versionedBlockRequest.Deneb, RegisteredGasLimit: opts.ValidatorData.GasLimit, ParentBeaconBlockRoot: *opts.Block.BeaconRoot()})
283283
}
284284
if err != nil {
285285
log.Error("could not validate block", "version", dataVersion.String(), "err", err)

core/blockchain.go

+29-24
Original file line numberDiff line numberDiff line change
@@ -2454,31 +2454,31 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro
24542454
// - `useBalanceDiffProfit` if set to false, proposer payment is assumed to be in the last transaction of the block
24552455
// otherwise we use proposer balance changes after the block to calculate proposer payment (see details in the code)
24562456
// - `excludeWithdrawals` if set to true, withdrawals to the fee recipient are excluded from the balance change
2457-
func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config, useBalanceDiffProfit, excludeWithdrawals bool) error {
2457+
func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config, useBalanceDiffProfit, excludeWithdrawals bool) (*uint256.Int, error) {
24582458
header := block.Header()
24592459
if err := bc.engine.VerifyHeader(bc, header); err != nil {
2460-
return err
2460+
return nil, err
24612461
}
24622462

24632463
current := bc.CurrentBlock()
24642464
reorg, err := bc.forker.ReorgNeeded(current, header)
24652465
if err == nil && reorg {
2466-
return errors.New("block requires a reorg")
2466+
return nil, errors.New("block requires a reorg")
24672467
}
24682468

24692469
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
24702470
if parent == nil {
2471-
return errors.New("parent not found")
2471+
return nil, errors.New("parent not found")
24722472
}
24732473

24742474
calculatedGasLimit := CalcGasLimit(parent.GasLimit, registeredGasLimit)
24752475
if calculatedGasLimit != header.GasLimit {
2476-
return errors.New("incorrect gas limit set")
2476+
return nil, errors.New("incorrect gas limit set")
24772477
}
24782478

24792479
statedb, err := bc.StateAt(parent.Root)
24802480
if err != nil {
2481-
return err
2481+
return nil, err
24822482
}
24832483

24842484
// The chain importer is starting and stopping trie prefetchers. If a bad
@@ -2491,7 +2491,7 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
24912491

24922492
receipts, _, usedGas, err := bc.processor.Process(block, statedb, vmConfig)
24932493
if err != nil {
2494-
return err
2494+
return nil, err
24952495
}
24962496

24972497
feeRecipientBalanceAfter := new(uint256.Int).Set(statedb.GetBalance(feeRecipient))
@@ -2508,24 +2508,24 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
25082508

25092509
if bc.Config().IsShanghai(header.Number, header.Time) {
25102510
if header.WithdrawalsHash == nil {
2511-
return fmt.Errorf("withdrawals hash is missing")
2511+
return nil, fmt.Errorf("withdrawals hash is missing")
25122512
}
25132513
// withdrawals hash and withdrawals validated later in ValidateBody
25142514
} else {
25152515
if header.WithdrawalsHash != nil {
2516-
return fmt.Errorf("withdrawals hash present before shanghai")
2516+
return nil, fmt.Errorf("withdrawals hash present before shanghai")
25172517
}
25182518
if block.Withdrawals() != nil {
2519-
return fmt.Errorf("withdrawals list present in block body before shanghai")
2519+
return nil, fmt.Errorf("withdrawals list present in block body before shanghai")
25202520
}
25212521
}
25222522

25232523
if err := bc.validator.ValidateBody(block); err != nil {
2524-
return err
2524+
return nil, err
25252525
}
25262526

25272527
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
2528-
return err
2528+
return nil, err
25292529
}
25302530

25312531
// Validate proposer payment
@@ -2540,56 +2540,61 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
25402540
if feeRecipientBalanceDelta.Cmp(uint256ExpectedProfit) > 0 {
25412541
log.Warn("builder claimed profit is lower than calculated profit", "expected", expectedProfit, "actual", feeRecipientBalanceDelta)
25422542
}
2543-
return nil
2543+
return feeRecipientBalanceDelta, nil
25442544
}
25452545
log.Warn("proposer payment not enough, trying last tx payment validation", "expected", expectedProfit, "actual", feeRecipientBalanceDelta)
25462546
}
25472547
}
25482548

25492549
if len(receipts) == 0 {
2550-
return errors.New("no proposer payment receipt")
2550+
return nil, errors.New("no proposer payment receipt")
25512551
}
25522552

25532553
lastReceipt := receipts[len(receipts)-1]
25542554
if lastReceipt.Status != types.ReceiptStatusSuccessful {
2555-
return errors.New("proposer payment not successful")
2555+
return nil, errors.New("proposer payment not successful")
25562556
}
25572557
txIndex := lastReceipt.TransactionIndex
25582558
if txIndex+1 != uint(len(block.Transactions())) {
2559-
return fmt.Errorf("proposer payment index not last transaction in the block (%d of %d)", txIndex, len(block.Transactions())-1)
2559+
return nil, fmt.Errorf("proposer payment index not last transaction in the block (%d of %d)", txIndex, len(block.Transactions())-1)
25602560
}
25612561

25622562
paymentTx := block.Transaction(lastReceipt.TxHash)
25632563
if paymentTx == nil {
2564-
return errors.New("payment tx not in the block")
2564+
return nil, errors.New("payment tx not in the block")
25652565
}
25662566

25672567
paymentTo := paymentTx.To()
25682568
if paymentTo == nil || *paymentTo != feeRecipient {
2569-
return fmt.Errorf("payment tx not to the proposers fee recipient (%v)", paymentTo)
2569+
return nil, fmt.Errorf("payment tx not to the proposers fee recipient (%v)", paymentTo)
25702570
}
25712571

25722572
if paymentTx.Value().Cmp(expectedProfit) != 0 {
2573-
return fmt.Errorf("inaccurate payment %s, expected %s", paymentTx.Value().String(), expectedProfit.String())
2573+
return nil, fmt.Errorf("inaccurate payment %s, expected %s", paymentTx.Value().String(), expectedProfit.String())
25742574
}
25752575

25762576
if len(paymentTx.Data()) != 0 {
2577-
return fmt.Errorf("malformed proposer payment, contains calldata")
2577+
return nil, fmt.Errorf("malformed proposer payment, contains calldata")
25782578
}
25792579

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

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

25882588
if paymentTx.GasFeeCap().Cmp(block.BaseFee()) != 0 {
2589-
return fmt.Errorf("malformed proposer payment, unexpected gas fee cap")
2589+
return nil, fmt.Errorf("malformed proposer payment, unexpected gas fee cap")
25902590
}
25912591

2592-
return nil
2592+
blockValue, ok := uint256.FromBig(paymentTx.Value())
2593+
if !ok {
2594+
return nil, fmt.Errorf("malformed proposer payment, value too large")
2595+
}
2596+
2597+
return blockValue, nil
25932598
}
25942599

25952600
// SetTrieFlushInterval configures how often in-memory tries are persisted to disk.

eth/block-validation/api.go

+27-20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/ethereum/go-ethereum/log"
2323
"github.com/ethereum/go-ethereum/node"
2424
"github.com/ethereum/go-ethereum/rpc"
25+
"github.com/holiman/uint256"
2526
)
2627

2728
type BlacklistedAddresses []common.Address
@@ -153,7 +154,8 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *BuilderBlockV
153154
return err
154155
}
155156

156-
return api.validateBlock(block, params.Message, params.RegisteredGasLimit)
157+
_, err = api.validateBlock(block, params.Message, params.RegisteredGasLimit)
158+
return err
157159
}
158160

159161
type BuilderBlockValidationRequestV2 struct {
@@ -192,7 +194,8 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV2(params *BuilderBlockV
192194
return err
193195
}
194196

195-
return api.validateBlock(block, params.Message, params.RegisteredGasLimit)
197+
_, err = api.validateBlock(block, params.Message, params.RegisteredGasLimit)
198+
return err
196199
}
197200

198201
type BuilderBlockValidationRequestV3 struct {
@@ -201,6 +204,10 @@ type BuilderBlockValidationRequestV3 struct {
201204
RegisteredGasLimit uint64 `json:"registered_gas_limit,string"`
202205
}
203206

207+
type BuilderBlockValidationResponse struct {
208+
BlockValue *uint256.Int `json:"block_value"`
209+
}
210+
204211
func (r *BuilderBlockValidationRequestV3) UnmarshalJSON(data []byte) error {
205212
params := &struct {
206213
ParentBeaconBlockRoot common.Hash `json:"parent_beacon_block_root"`
@@ -222,44 +229,44 @@ func (r *BuilderBlockValidationRequestV3) UnmarshalJSON(data []byte) error {
222229
return nil
223230
}
224231

225-
func (api *BlockValidationAPI) ValidateBuilderSubmissionV3(params *BuilderBlockValidationRequestV3) error {
232+
func (api *BlockValidationAPI) ValidateBuilderSubmissionV3(params *BuilderBlockValidationRequestV3) (*BuilderBlockValidationResponse, error) {
226233
// TODO: fuzztest, make sure the validation is sound
227234
payload := params.ExecutionPayload
228235
blobsBundle := params.BlobsBundle
229236
log.Info("blobs bundle", "blobs", len(blobsBundle.Blobs), "commits", len(blobsBundle.Commitments), "proofs", len(blobsBundle.Proofs))
230237
block, err := engine.ExecutionPayloadV3ToBlock(payload, blobsBundle, params.ParentBeaconBlockRoot)
231238
if err != nil {
232-
return err
239+
return nil, err
233240
}
234241

235-
err = api.validateBlock(block, params.Message, params.RegisteredGasLimit)
242+
blockValue, err := api.validateBlock(block, params.Message, params.RegisteredGasLimit)
236243
if err != nil {
237244
log.Error("invalid payload", "hash", block.Hash, "number", block.NumberU64(), "parentHash", block.ParentHash, "err", err)
238-
return err
245+
return nil, err
239246
}
240247
err = validateBlobsBundle(block.Transactions(), blobsBundle)
241248
if err != nil {
242249
log.Error("invalid blobs bundle", "err", err)
243-
return err
250+
return nil, err
244251
}
245-
return nil
252+
return &BuilderBlockValidationResponse{blockValue}, nil
246253
}
247254

248-
func (api *BlockValidationAPI) validateBlock(block *types.Block, msg *builderApiV1.BidTrace, registeredGasLimit uint64) error {
255+
func (api *BlockValidationAPI) validateBlock(block *types.Block, msg *builderApiV1.BidTrace, registeredGasLimit uint64) (*uint256.Int, error) {
249256
if msg.ParentHash != phase0.Hash32(block.ParentHash()) {
250-
return fmt.Errorf("incorrect ParentHash %s, expected %s", msg.ParentHash.String(), block.ParentHash().String())
257+
return nil, fmt.Errorf("incorrect ParentHash %s, expected %s", msg.ParentHash.String(), block.ParentHash().String())
251258
}
252259

253260
if msg.BlockHash != phase0.Hash32(block.Hash()) {
254-
return fmt.Errorf("incorrect BlockHash %s, expected %s", msg.BlockHash.String(), block.Hash().String())
261+
return nil, fmt.Errorf("incorrect BlockHash %s, expected %s", msg.BlockHash.String(), block.Hash().String())
255262
}
256263

257264
if msg.GasLimit != block.GasLimit() {
258-
return fmt.Errorf("incorrect GasLimit %d, expected %d", msg.GasLimit, block.GasLimit())
265+
return nil, fmt.Errorf("incorrect GasLimit %d, expected %d", msg.GasLimit, block.GasLimit())
259266
}
260267

261268
if msg.GasUsed != block.GasUsed() {
262-
return fmt.Errorf("incorrect GasUsed %d, expected %d", msg.GasUsed, block.GasUsed())
269+
return nil, fmt.Errorf("incorrect GasUsed %d, expected %d", msg.GasUsed, block.GasUsed())
263270
}
264271

265272
feeRecipient := common.BytesToAddress(msg.ProposerFeeRecipient[:])
@@ -269,33 +276,33 @@ func (api *BlockValidationAPI) validateBlock(block *types.Block, msg *builderApi
269276
var tracer *logger.AccessListTracer = nil
270277
if api.accessVerifier != nil {
271278
if err := api.accessVerifier.isBlacklisted(block.Coinbase()); err != nil {
272-
return err
279+
return nil, err
273280
}
274281
if err := api.accessVerifier.isBlacklisted(feeRecipient); err != nil {
275-
return err
282+
return nil, err
276283
}
277284
if err := api.accessVerifier.verifyTransactions(types.LatestSigner(api.eth.BlockChain().Config()), block.Transactions()); err != nil {
278-
return err
285+
return nil, err
279286
}
280287
isPostMerge := true // the call is PoS-native
281288
precompiles := vm.ActivePrecompiles(api.eth.APIBackend.ChainConfig().Rules(new(big.Int).SetUint64(block.NumberU64()), isPostMerge, block.Time()))
282289
tracer = logger.NewAccessListTracer(nil, common.Address{}, common.Address{}, precompiles)
283290
vmconfig = vm.Config{Tracer: tracer}
284291
}
285292

286-
err := api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, registeredGasLimit, vmconfig, api.useBalanceDiffProfit, api.excludeWithdrawals)
293+
blockValue, err := api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, registeredGasLimit, vmconfig, api.useBalanceDiffProfit, api.excludeWithdrawals)
287294
if err != nil {
288-
return err
295+
return nil, err
289296
}
290297

291298
if api.accessVerifier != nil && tracer != nil {
292299
if err := api.accessVerifier.verifyTraces(tracer); err != nil {
293-
return err
300+
return nil, err
294301
}
295302
}
296303

297304
log.Info("validated block", "hash", block.Hash(), "number", block.NumberU64(), "parentHash", block.ParentHash())
298-
return nil
305+
return blockValue, nil
299306
}
300307

301308
func validateBlobsBundle(txs types.Transactions, blobsBundle *builderApiDeneb.BlobsBundle) error {

eth/block-validation/api_test.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,20 @@ func TestValidateBuilderSubmissionV3(t *testing.T) {
390390
ParentBeaconBlockRoot: common.Hash{42},
391391
}
392392

393-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "inaccurate payment")
393+
response, err := api.ValidateBuilderSubmissionV3(blockRequest)
394+
require.ErrorContains(t, err, "inaccurate payment")
395+
require.Nil(t, response)
394396
blockRequest.Message.Value = uint256.NewInt(132912184722468)
395-
require.NoError(t, api.ValidateBuilderSubmissionV3(blockRequest))
397+
response, err = api.ValidateBuilderSubmissionV3(blockRequest)
398+
require.NoError(t, err)
399+
require.Equal(t, response.BlockValue, uint256.NewInt(132912184722468))
396400

397401
blockRequest.Message.GasLimit += 1
398402
blockRequest.ExecutionPayload.GasLimit += 1
399403
updatePayloadHashV3(t, blockRequest)
400404

401-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "incorrect gas limit set")
405+
_, err = api.ValidateBuilderSubmissionV3(blockRequest)
406+
require.ErrorContains(t, err, "incorrect gas limit set")
402407

403408
blockRequest.Message.GasLimit -= 1
404409
blockRequest.ExecutionPayload.GasLimit -= 1
@@ -411,20 +416,23 @@ func TestValidateBuilderSubmissionV3(t *testing.T) {
411416
testAddr: {},
412417
},
413418
}
414-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "transaction from blacklisted address 0x71562b71999873DB5b286dF957af199Ec94617F7")
419+
_, err = api.ValidateBuilderSubmissionV3(blockRequest)
420+
require.ErrorContains(t, err, "transaction from blacklisted address 0x71562b71999873DB5b286dF957af199Ec94617F7")
415421

416422
// Test tx to blacklisted address
417423
api.accessVerifier = &AccessVerifier{
418424
blacklistedAddresses: map[common.Address]struct{}{
419425
{0x16}: {},
420426
},
421427
}
422-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "transaction to blacklisted address 0x1600000000000000000000000000000000000000")
428+
_, err = api.ValidateBuilderSubmissionV3(blockRequest)
429+
require.ErrorContains(t, err, "transaction to blacklisted address 0x1600000000000000000000000000000000000000")
423430

424431
api.accessVerifier = nil
425432

426433
blockRequest.Message.GasUsed = 10
427-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "incorrect GasUsed 10, expected 119996")
434+
_, err = api.ValidateBuilderSubmissionV3(blockRequest)
435+
require.ErrorContains(t, err, "incorrect GasUsed 10, expected 119996")
428436
blockRequest.Message.GasUsed = execData.GasUsed
429437

430438
newTestKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f290")
@@ -441,7 +449,8 @@ func TestValidateBuilderSubmissionV3(t *testing.T) {
441449
copy(invalidPayload.ReceiptsRoot[:], hexutil.MustDecode("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")[:32])
442450
blockRequest.ExecutionPayload = invalidPayload
443451
updatePayloadHashV3(t, blockRequest)
444-
require.ErrorContains(t, api.ValidateBuilderSubmissionV3(blockRequest), "could not apply tx 4", "insufficient funds for gas * price + value")
452+
_, err = api.ValidateBuilderSubmissionV3(blockRequest)
453+
require.ErrorContains(t, err, "could not apply tx 4", "insufficient funds for gas * price + value")
445454
}
446455

447456
func updatePayloadHash(t *testing.T, blockRequest *BuilderBlockValidationRequest) {

0 commit comments

Comments
 (0)