Skip to content

Commit d370206

Browse files
committed
capella upgrade
1 parent 88e8c06 commit d370206

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1634
-734
lines changed

README.md

Lines changed: 58 additions & 305 deletions
Large diffs are not rendered by default.

README.original.md

Lines changed: 36 additions & 35 deletions
Large diffs are not rendered by default.

accounts/abi/bind/backends/simulated.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,11 @@ func NewSimulatedBackendChain(database ethdb.Database, blockchain *core.BlockCha
119119
filterBackend := &filterBackend{database, blockchain, backend}
120120
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
121121
backend.events = filters.NewEventSystem(backend.filterSystem, false)
122-
backend.rollback(blockchain.CurrentBlock())
122+
123+
header := backend.blockchain.CurrentBlock()
124+
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
123125

126+
backend.rollback(block)
124127
return backend
125128
}
126129

beacon/engine/types.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"math/big"
2222

23+
"github.com/attestantio/go-eth2-client/spec/capella"
2324
"github.com/ethereum/go-ethereum/common"
2425
"github.com/ethereum/go-ethereum/common/hexutil"
2526
"github.com/ethereum/go-ethereum/core/types"
@@ -37,6 +38,8 @@ type PayloadAttributes struct {
3738
Random common.Hash `json:"prevRandao" gencodec:"required"`
3839
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
3940
Withdrawals []*types.Withdrawal `json:"withdrawals"`
41+
GasLimit uint64
42+
Slot uint64
4043
}
4144

4245
// JSON type overrides for PayloadAttributes.
@@ -237,3 +240,87 @@ type ExecutionPayloadBodyV1 struct {
237240
TransactionData []hexutil.Bytes `json:"transactions"`
238241
Withdrawals []*types.Withdrawal `json:"withdrawals"`
239242
}
243+
244+
func ExecutionPayloadToBlock(payload *boostTypes.ExecutionPayload) (*types.Block, error) {
245+
// TODO: separate decode function to avoid allocating twice
246+
transactionBytes := make([][]byte, len(payload.Transactions))
247+
for i, txHexBytes := range payload.Transactions {
248+
transactionBytes[i] = txHexBytes[:]
249+
}
250+
txs, err := decodeTransactions(transactionBytes)
251+
if err != nil {
252+
return nil, err
253+
}
254+
255+
header := &types.Header{
256+
ParentHash: common.Hash(payload.ParentHash),
257+
UncleHash: types.EmptyUncleHash,
258+
Coinbase: common.Address(payload.FeeRecipient),
259+
Root: common.Hash(payload.StateRoot),
260+
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
261+
ReceiptHash: common.Hash(payload.ReceiptsRoot),
262+
Bloom: types.BytesToBloom(payload.LogsBloom[:]),
263+
Difficulty: common.Big0,
264+
Number: new(big.Int).SetUint64(payload.BlockNumber),
265+
GasLimit: payload.GasLimit,
266+
GasUsed: payload.GasUsed,
267+
Time: payload.Timestamp,
268+
BaseFee: payload.BaseFeePerGas.BigInt(),
269+
Extra: payload.ExtraData,
270+
MixDigest: common.Hash(payload.Random),
271+
}
272+
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
273+
return block, nil
274+
}
275+
276+
func ExecutionPayloadV2ToBlock(payload *capella.ExecutionPayload) (*types.Block, error) {
277+
// TODO: separate decode function to avoid allocating twice
278+
transactionBytes := make([][]byte, len(payload.Transactions))
279+
for i, txHexBytes := range payload.Transactions {
280+
transactionBytes[i] = txHexBytes[:]
281+
}
282+
txs, err := decodeTransactions(transactionBytes)
283+
if err != nil {
284+
return nil, err
285+
}
286+
287+
withdrawals := make([]*types.Withdrawal, len(payload.Withdrawals))
288+
for i, withdrawal := range payload.Withdrawals {
289+
withdrawals[i] = &types.Withdrawal{
290+
Index: uint64(withdrawal.Index),
291+
Validator: uint64(withdrawal.ValidatorIndex),
292+
Address: common.Address(withdrawal.Address),
293+
Amount: uint64(withdrawal.Amount),
294+
}
295+
}
296+
withdrawalsHash := types.DeriveSha(types.Withdrawals(withdrawals), trie.NewStackTrie(nil))
297+
298+
// base fee per gas is stored little-endian but we need it
299+
// big-endian for big.Int.
300+
var baseFeePerGasBytes [32]byte
301+
for i := 0; i < 32; i++ {
302+
baseFeePerGasBytes[i] = payload.BaseFeePerGas[32-1-i]
303+
}
304+
baseFeePerGas := new(big.Int).SetBytes(baseFeePerGasBytes[:])
305+
306+
header := &types.Header{
307+
ParentHash: common.Hash(payload.ParentHash),
308+
UncleHash: types.EmptyUncleHash,
309+
Coinbase: common.Address(payload.FeeRecipient),
310+
Root: common.Hash(payload.StateRoot),
311+
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
312+
ReceiptHash: common.Hash(payload.ReceiptsRoot),
313+
Bloom: types.BytesToBloom(payload.LogsBloom[:]),
314+
Difficulty: common.Big0,
315+
Number: new(big.Int).SetUint64(payload.BlockNumber),
316+
GasLimit: payload.GasLimit,
317+
GasUsed: payload.GasUsed,
318+
Time: payload.Timestamp,
319+
BaseFee: baseFeePerGas,
320+
Extra: payload.ExtraData,
321+
MixDigest: common.Hash(payload.PrevRandao),
322+
WithdrawalsHash: &withdrawalsHash,
323+
}
324+
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(withdrawals)
325+
return block, nil
326+
}

builder/builder.go

Lines changed: 144 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,28 @@ package builder
33
import (
44
"context"
55
"errors"
6+
"math/big"
67
_ "os"
78
"sync"
89
"time"
910

11+
"github.com/attestantio/go-eth2-client/spec/bellatrix"
12+
"github.com/attestantio/go-eth2-client/spec/capella"
13+
"github.com/attestantio/go-eth2-client/spec/phase0"
1014
"github.com/ethereum/go-ethereum/common"
1115
blockvalidation "github.com/ethereum/go-ethereum/eth/block-validation"
16+
"github.com/holiman/uint256"
1217
"golang.org/x/time/rate"
1318

19+
"github.com/ethereum/go-ethereum/beacon/engine"
1420
"github.com/ethereum/go-ethereum/common/hexutil"
15-
"github.com/ethereum/go-ethereum/core/beacon"
1621
"github.com/ethereum/go-ethereum/core/types"
1722
"github.com/ethereum/go-ethereum/flashbotsextra"
1823
"github.com/ethereum/go-ethereum/log"
1924

25+
capellaapi "github.com/attestantio/go-builder-client/api/capella"
26+
apiv1 "github.com/attestantio/go-builder-client/api/v1"
27+
2028
"github.com/flashbots/go-boost-utils/bls"
2129
boostTypes "github.com/flashbots/go-boost-utils/types"
2230
)
@@ -38,6 +46,7 @@ type IBeaconClient interface {
3846

3947
type IRelay interface {
4048
SubmitBlock(msg *boostTypes.BuilderSubmitBlockRequest, vd ValidatorData) error
49+
SubmitBlockCapella(msg *capellaapi.SubmitBlockRequest, vd ValidatorData) error
4150
GetValidatorForSlot(nextSlot uint64) (ValidatorData, error)
4251
Start() error
4352
Stop()
@@ -99,16 +108,32 @@ func (b *Builder) Stop() error {
99108
return nil
100109
}
101110

102-
func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
103-
executableData := beacon.BlockToExecutableData(block)
104-
payload, err := executableDataToExecutionPayload(executableData)
111+
func (b *Builder) onSealedBlock(block *types.Block, blockValue *big.Int, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
112+
if b.eth.Config().IsShanghai(block.Time()) {
113+
if err := b.submitCapellaBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, proposerPubkey, vd, attrs); err != nil {
114+
return err
115+
}
116+
} else {
117+
if err := b.submitBellatrixBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, proposerPubkey, vd, attrs); err != nil {
118+
return err
119+
}
120+
}
121+
122+
log.Info("submitted block", "slot", attrs.Slot, "value", blockValue.String(), "parent", block.ParentHash, "hash", block.Hash(), "#commitedBundles", len(commitedBundles))
123+
124+
return nil
125+
}
126+
127+
func (b *Builder) submitBellatrixBlock(block *types.Block, blockValue *big.Int, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
128+
executableData := engine.BlockToExecutableData(block, blockValue)
129+
payload, err := executableDataToExecutionPayload(executableData.ExecutionPayload)
105130
if err != nil {
106131
log.Error("could not format execution payload", "err", err)
107132
return err
108133
}
109134

110135
value := new(boostTypes.U256Str)
111-
err = value.FromBig(block.Profit)
136+
err = value.FromBig(blockValue)
112137
if err != nil {
113138
log.Error("could not set block value", "err", err)
114139
return err
@@ -121,8 +146,8 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
121146
BuilderPubkey: b.builderPublicKey,
122147
ProposerPubkey: proposerPubkey,
123148
ProposerFeeRecipient: vd.FeeRecipient,
124-
GasLimit: executableData.GasLimit,
125-
GasUsed: executableData.GasUsed,
149+
GasLimit: executableData.ExecutionPayload.GasLimit,
150+
GasUsed: executableData.ExecutionPayload.GasUsed,
126151
Value: *value,
127152
}
128153

@@ -144,7 +169,7 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
144169
log.Error("could not validate block", "err", err)
145170
}
146171
} else {
147-
go b.ds.ConsumeBuiltBlock(block, ordersClosedAt, sealedAt, commitedBundles, allBundles, &blockBidMsg)
172+
go b.ds.ConsumeBuiltBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, &blockBidMsg)
148173
err = b.relay.SubmitBlock(&blockSubmitReq, vd)
149174
if err != nil {
150175
log.Error("could not submit block", "err", err, "#commitedBundles", len(commitedBundles))
@@ -157,6 +182,56 @@ func (b *Builder) onSealedBlock(block *types.Block, ordersClosedAt time.Time, se
157182
return nil
158183
}
159184

185+
func (b *Builder) submitCapellaBlock(block *types.Block, blockValue *big.Int, ordersClosedAt time.Time, sealedAt time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle, proposerPubkey boostTypes.PublicKey, vd ValidatorData, attrs *types.BuilderPayloadAttributes) error {
186+
executableData := engine.BlockToExecutableData(block, blockValue)
187+
payload, err := executableDataToCapellaExecutionPayload(executableData.ExecutionPayload)
188+
if err != nil {
189+
log.Error("could not format execution payload", "err", err)
190+
return err
191+
}
192+
193+
value := new(boostTypes.U256Str)
194+
err = value.FromBig(blockValue)
195+
if err != nil {
196+
log.Error("could not set block value", "err", err)
197+
return err
198+
}
199+
200+
blockBidMsg := apiv1.BidTrace{
201+
Slot: attrs.Slot,
202+
ParentHash: payload.ParentHash,
203+
BlockHash: payload.BlockHash,
204+
BuilderPubkey: phase0.BLSPubKey(b.builderPublicKey),
205+
ProposerPubkey: phase0.BLSPubKey(proposerPubkey),
206+
ProposerFeeRecipient: bellatrix.ExecutionAddress(vd.FeeRecipient),
207+
GasLimit: executableData.ExecutionPayload.GasLimit,
208+
GasUsed: executableData.ExecutionPayload.GasUsed,
209+
Value: uint256.NewInt(value.BigInt().Uint64()),
210+
}
211+
212+
boostBidTrace := convertBidTrace(blockBidMsg)
213+
214+
signature, err := boostTypes.SignMessage(&blockBidMsg, b.builderSigningDomain, b.builderSecretKey)
215+
if err != nil {
216+
log.Error("could not sign builder bid", "err", err)
217+
return err
218+
}
219+
220+
blockSubmitReq := capellaapi.SubmitBlockRequest{
221+
Signature: phase0.BLSSignature(signature),
222+
Message: &blockBidMsg,
223+
ExecutionPayload: payload,
224+
}
225+
226+
go b.ds.ConsumeBuiltBlock(block, blockValue, ordersClosedAt, sealedAt, commitedBundles, allBundles, &boostBidTrace)
227+
err = b.relay.SubmitBlockCapella(&blockSubmitReq, vd)
228+
if err != nil {
229+
log.Error("could not submit block", "err", err, "#commitedBundles", len(commitedBundles))
230+
return err
231+
}
232+
return nil
233+
}
234+
160235
func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) error {
161236
if attrs == nil {
162237
return nil
@@ -203,7 +278,7 @@ func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) erro
203278
}
204279

205280
for _, currentAttrs := range b.slotAttrs {
206-
if *attrs == currentAttrs {
281+
if attrs.Equal(&currentAttrs) {
207282
log.Debug("ignoring known payload attribute", "slot", attrs.Slot, "hash", attrs.HeadHash)
208283
return nil
209284
}
@@ -216,6 +291,7 @@ func (b *Builder) OnPayloadAttribute(attrs *types.BuilderPayloadAttributes) erro
216291

217292
type blockQueueEntry struct {
218293
block *types.Block
294+
blockValue *big.Int
219295
ordersCloseTime time.Time
220296
sealedAt time.Time
221297
commitedBundles []types.SimulatedBundle
@@ -246,7 +322,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
246322
submitBestBlock := func() {
247323
queueMu.Lock()
248324
if queueBestEntry.block.Hash() != queueLastSubmittedHash {
249-
err := b.onSealedBlock(queueBestEntry.block, queueBestEntry.ordersCloseTime, queueBestEntry.sealedAt, queueBestEntry.commitedBundles, queueBestEntry.allBundles, proposerPubkey, vd, attrs)
325+
err := b.onSealedBlock(queueBestEntry.block, queueBestEntry.blockValue, queueBestEntry.ordersCloseTime, queueBestEntry.sealedAt, queueBestEntry.commitedBundles, queueBestEntry.allBundles, proposerPubkey, vd, attrs)
250326

251327
if err != nil {
252328
log.Error("could not run sealed block hook", "err", err)
@@ -261,7 +337,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
261337
go runResubmitLoop(ctx, b.limiter, queueSignal, submitBestBlock)
262338

263339
// Populates queue with submissions that increase block profit
264-
blockHook := func(block *types.Block, ordersCloseTime time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle) {
340+
blockHook := func(block *types.Block, blockValue *big.Int, ordersCloseTime time.Time, commitedBundles []types.SimulatedBundle, allBundles []types.SimulatedBundle) {
265341
if ctx.Err() != nil {
266342
return
267343
}
@@ -273,6 +349,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
273349
if block.Hash() != queueLastSubmittedHash {
274350
queueBestEntry = blockQueueEntry{
275351
block: block,
352+
blockValue: new(big.Int).Set(blockValue),
276353
ordersCloseTime: ordersCloseTime,
277354
sealedAt: sealedAt,
278355
commitedBundles: commitedBundles,
@@ -296,7 +373,7 @@ func (b *Builder) runBuildingJob(slotCtx context.Context, proposerPubkey boostTy
296373
})
297374
}
298375

299-
func executableDataToExecutionPayload(data *beacon.ExecutableDataV1) (*boostTypes.ExecutionPayload, error) {
376+
func executableDataToExecutionPayload(data *engine.ExecutableData) (*boostTypes.ExecutionPayload, error) {
300377
transactionData := make([]hexutil.Bytes, len(data.Transactions))
301378
for i, tx := range data.Transactions {
302379
transactionData[i] = hexutil.Bytes(tx)
@@ -325,3 +402,58 @@ func executableDataToExecutionPayload(data *beacon.ExecutableDataV1) (*boostType
325402
Transactions: transactionData,
326403
}, nil
327404
}
405+
406+
func executableDataToCapellaExecutionPayload(data *engine.ExecutableData) (*capella.ExecutionPayload, error) {
407+
transactionData := make([]bellatrix.Transaction, len(data.Transactions))
408+
for i, tx := range data.Transactions {
409+
transactionData[i] = bellatrix.Transaction(tx)
410+
}
411+
412+
withdrawalData := make([]*capella.Withdrawal, len(data.Withdrawals))
413+
for i, wd := range data.Withdrawals {
414+
withdrawalData[i] = &capella.Withdrawal{
415+
Index: capella.WithdrawalIndex(wd.Index),
416+
ValidatorIndex: phase0.ValidatorIndex(wd.Validator),
417+
Address: bellatrix.ExecutionAddress(wd.Address),
418+
Amount: phase0.Gwei(wd.Amount),
419+
}
420+
}
421+
422+
baseFeePerGas := new(boostTypes.U256Str)
423+
err := baseFeePerGas.FromBig(data.BaseFeePerGas)
424+
if err != nil {
425+
return nil, err
426+
}
427+
428+
return &capella.ExecutionPayload{
429+
ParentHash: [32]byte(data.ParentHash),
430+
FeeRecipient: [20]byte(data.FeeRecipient),
431+
StateRoot: [32]byte(data.StateRoot),
432+
ReceiptsRoot: [32]byte(data.ReceiptsRoot),
433+
LogsBloom: boostTypes.Bloom(types.BytesToBloom(data.LogsBloom)),
434+
PrevRandao: [32]byte(data.Random),
435+
BlockNumber: data.Number,
436+
GasLimit: data.GasLimit,
437+
GasUsed: data.GasUsed,
438+
Timestamp: data.Timestamp,
439+
ExtraData: data.ExtraData,
440+
BaseFeePerGas: *baseFeePerGas,
441+
BlockHash: [32]byte(data.BlockHash),
442+
Transactions: transactionData,
443+
Withdrawals: withdrawalData,
444+
}, nil
445+
}
446+
447+
func convertBidTrace(bidTrace apiv1.BidTrace) boostTypes.BidTrace {
448+
return boostTypes.BidTrace{
449+
Slot: bidTrace.Slot,
450+
ParentHash: boostTypes.Hash(bidTrace.ParentHash),
451+
BlockHash: boostTypes.Hash(bidTrace.BlockHash),
452+
BuilderPubkey: boostTypes.PublicKey(bidTrace.BuilderPubkey),
453+
ProposerPubkey: boostTypes.PublicKey(bidTrace.ProposerPubkey),
454+
ProposerFeeRecipient: boostTypes.Address(bidTrace.ProposerFeeRecipient),
455+
GasLimit: bidTrace.GasLimit,
456+
GasUsed: bidTrace.GasUsed,
457+
Value: boostTypes.IntToU256(bidTrace.Value.Uint64()),
458+
}
459+
}

0 commit comments

Comments
 (0)