Skip to content

Commit 283d9eb

Browse files
committed
miner: preserve builder vanity in BidBlock extra-data
1 parent 2c1e042 commit 283d9eb

3 files changed

Lines changed: 36 additions & 49 deletions

File tree

consensus/parlia/parlia.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,18 +1179,39 @@ func (p *Parlia) prepareHeader(chain consensus.ChainHeaderReader, header *types.
11791179
header.MixDigest = common.Hash{}
11801180
}
11811181

1182+
p.fillExtraDataVanity(chain, header)
11821183
return p.SetExtraData(chain, header)
11831184
}
11841185

1185-
// SetExtraData rebuilds the validator-controlled extra-data section.
1186-
func (p *Parlia) SetExtraData(chain consensus.ChainHeaderReader, header *types.Header) error {
1186+
// fillExtraDataVanity pads vanity and writes nextForkHash to produce the 32-byte vanity prefix.
1187+
func (p *Parlia) fillExtraDataVanity(chain consensus.ChainHeaderReader, header *types.Header) {
11871188
if len(header.Extra) < extraVanity-nextForkHashSize {
11881189
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-nextForkHashSize-len(header.Extra))...)
11891190
}
1190-
11911191
header.Extra = header.Extra[:extraVanity-nextForkHashSize]
11921192
nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, chain.GenesisHeader().Time, header.Number.Uint64(), header.Time)
11931193
header.Extra = append(header.Extra, nextForkHash[:]...)
1194+
}
1195+
1196+
// VerifyExtraDataVanity checks the nextForkHash inside the 32-byte vanity prefix.
1197+
func (p *Parlia) VerifyExtraDataVanity(chain consensus.ChainHeaderReader, header *types.Header) error {
1198+
if len(header.Extra) < extraVanity {
1199+
return fmt.Errorf("extra data too short for vanity prefix: %d < %d", len(header.Extra), extraVanity)
1200+
}
1201+
expected := forkid.NextForkHash(p.chainConfig, p.genesisHash, chain.GenesisHeader().Time, header.Number.Uint64(), header.Time)
1202+
got := header.Extra[extraVanity-nextForkHashSize : extraVanity]
1203+
if !bytes.Equal(got, expected[:]) {
1204+
return fmt.Errorf("invalid nextForkHash: got %x, want %x", got, expected)
1205+
}
1206+
return nil
1207+
}
1208+
1209+
// SetExtraData appends validator-set, turnLength and reserved seal space after the 32-byte vanity prefix.
1210+
func (p *Parlia) SetExtraData(chain consensus.ChainHeaderReader, header *types.Header) error {
1211+
if len(header.Extra) < extraVanity {
1212+
return fmt.Errorf("extra data too short for vanity prefix: %d < %d", len(header.Extra), extraVanity)
1213+
}
1214+
header.Extra = header.Extra[:extraVanity]
11941215

11951216
if err := p.prepareValidators(chain, header); err != nil {
11961217
return err

miner/bid_block.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@ func bindSignBidBlockSystemTxs(
8888
}
8989

9090
// prepareBidBlockTask signs system txs and assembles a BidBlock task.
91-
// Validator computes only Extra (SetExtraData here + seal signature in engine.Seal)
92-
// and TxHash (re-derived after bind-signing the trailing system txs). All other
93-
// header fields flow from decoded.Header via CopyHeader; any lie is caught by
94-
// InsertChain.
91+
// Validator rewrites only the post-vanity portion of Extra (via SetExtraData,
92+
// + seal signature in Seal) and recomputes TxHash; all other header fields
93+
// flow verbatim from decoded.Header.
9594
func (w *worker) prepareBidBlockTask(
9695
decoded *types.DecodedBidBlock,
9796
start time.Time,
@@ -100,20 +99,16 @@ func (w *worker) prepareBidBlockTask(
10099
return nil, errors.New("worker is not running")
101100
}
102101

103-
// preSealVerifyBidBlock already enforced engine == parlia.
104102
p := w.engine.(*parlia.Parlia)
105103

106-
// Shallow-copy the tx slice so bind-signing does not mutate the cached BidBlock.
104+
// Copy the tx slice so bind-signing does not mutate the cached BidBlock.
107105
allTxs := make([]*types.Transaction, len(decoded.Txs))
108106
copy(allTxs, decoded.Txs)
109107
if err := bindSignBidBlockSystemTxs(allTxs[decoded.SystemTxStart:], w.chainConfig.ChainID, p); err != nil {
110108
return nil, err
111109
}
112110

113111
header := types.CopyHeader(decoded.Header)
114-
w.confMu.RLock()
115-
header.Extra = common.CopyBytes(w.extra)
116-
w.confMu.RUnlock()
117112
if err := p.SetExtraData(w.chain, header); err != nil {
118113
return nil, err
119114
}

miner/bid_simulator.go

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/ethereum/go-ethereum/common"
1818
"github.com/ethereum/go-ethereum/common/bidutil"
1919
"github.com/ethereum/go-ethereum/consensus"
20-
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
2120
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
2221
"github.com/ethereum/go-ethereum/consensus/parlia"
2322
"github.com/ethereum/go-ethereum/core"
@@ -670,59 +669,31 @@ func (b *bidSimulator) GetBestBidBlock(parentHash common.Hash) *types.DecodedBid
670669
return b.bestBidBlock[parentHash]
671670
}
672671

673-
// preSealVerifyBidBlock validates deterministic header fields before selection.
674-
// Execution-result fields are deferred to InsertChain.
675-
// TODO: extract shared deterministic Parlia header checks when this path grows.
672+
// preSealVerifyBidBlock validates a BidBlock before admission.
676673
func (b *bidSimulator) preSealVerifyBidBlock(decoded *types.DecodedBidBlock) error {
677674
parliaEngine, ok := b.engine.(*parlia.Parlia)
678675
if !ok {
679676
return errors.New("consensus engine is not parlia")
680677
}
681-
682678
header := decoded.Header
683-
// RPC admission checks the parent hash, but pre-seal must not assume the lookup succeeds.
684-
parent := b.chain.GetHeaderByHash(header.ParentHash)
685-
if parent == nil {
686-
return fmt.Errorf("parent header not found: %s", header.ParentHash.Hex())
687-
}
688679

689-
// 1. Coinbase must be the in-turn validator (this node).
690-
expectedCoinbase := b.bidWorker.etherbase()
691-
if header.Coinbase != expectedCoinbase {
680+
if header.Coinbase != b.bidWorker.etherbase() {
692681
return fmt.Errorf("invalid coinbase: got %s, want %s",
693-
header.Coinbase.Hex(), expectedCoinbase.Hex())
682+
header.Coinbase.Hex(), b.bidWorker.etherbase().Hex())
694683
}
695-
696-
// 2. TODO: add full GasLimit bounds check when BidBlock pre-seal rules define it.
697-
698-
// 3. GasUsed must not exceed GasLimit (consensus hard rule).
699-
if header.GasUsed > header.GasLimit {
700-
return fmt.Errorf("invalid gasUsed: %d > gasLimit %d", header.GasUsed, header.GasLimit)
684+
if err := parliaEngine.VerifyUnsealedHeader(b.chain, header, nil); err != nil {
685+
return fmt.Errorf("invalid header: %v", err)
701686
}
702-
703-
// 4. BaseFee must match the EIP-1559 derived value.
704-
expectedBaseFee := eip1559.CalcBaseFee(b.chainConfig, parent)
705-
if header.BaseFee == nil || header.BaseFee.Cmp(expectedBaseFee) != 0 {
706-
return fmt.Errorf("invalid baseFee: got %v, want %v", header.BaseFee, expectedBaseFee)
687+
if err := parliaEngine.VerifyExtraDataVanity(b.chain, header); err != nil {
688+
return fmt.Errorf("invalid extra-data vanity: %v", err)
707689
}
708690

709-
// 5. Difficulty must be in-turn.
710-
if header.Difficulty == nil || header.Difficulty.Cmp(diffInTurn) != 0 {
711-
return fmt.Errorf("invalid difficulty: got %v, want %v", header.Difficulty, diffInTurn)
712-
}
713-
714-
// 6. Timestamp must match the deterministic BidBlock time.
715-
if err := parliaEngine.VerifyBlockTime(b.chain, header, parent); err != nil {
716-
return fmt.Errorf("invalid block time: %v", err)
717-
}
718-
719-
// 7. GasFee is derived from the unsigned deposit tx.
720691
decoded.GasFee = parliaEngine.ExtractBidBlockDepositValue(decoded.Txs)
721692
if decoded.GasFee.Sign() <= 0 {
722693
return errors.New("empty gasFee")
723694
}
724695

725-
// 8. Validate and locate the trailing unsigned system-tx region.
696+
parent := b.chain.GetHeaderByHash(header.ParentHash)
726697
systemTxStart, err := parliaEngine.VerifyBidBlockSystemTxs(decoded, parent)
727698
if err != nil {
728699
return err

0 commit comments

Comments
 (0)