@@ -50,6 +50,7 @@ type environment struct {
50
50
signer types.Signer
51
51
state * state.StateDB // apply state changes here
52
52
tcount int // tx count in cycle
53
+ size uint64 // size of the block we are building
53
54
gasPool * core.GasPool // available gas used to pack transactions
54
55
coinbase common.Address
55
56
evm * vm.EVM
@@ -63,13 +64,23 @@ type environment struct {
63
64
witness * stateless.Witness
64
65
}
65
66
67
+ // txFits reports whether the transaction fits into the block size limit.
68
+ func (env * environment ) txFitsSize (tx * types.Transaction ) bool {
69
+ return env .size + tx .Size () < params .MaxBlockSize - maxBlockSizeBufferZone
70
+ }
71
+
66
72
const (
67
73
commitInterruptNone int32 = iota
68
74
commitInterruptNewHead
69
75
commitInterruptResubmit
70
76
commitInterruptTimeout
71
77
)
72
78
79
+ // Block size is capped by the protocol at params.MaxBlockSize. When producing blocks, we
80
+ // try to say below the size including a buffer zone, this is to avoid going over the
81
+ // maximum size with auxiliary data added into the block.
82
+ const maxBlockSizeBufferZone = 1_000_000
83
+
73
84
// newPayloadResult is the result of payload generation.
74
85
type newPayloadResult struct {
75
86
err error
@@ -95,12 +106,23 @@ type generateParams struct {
95
106
}
96
107
97
108
// generateWork generates a sealing block based on the given parameters.
98
- func (miner * Miner ) generateWork (params * generateParams , witness bool ) * newPayloadResult {
99
- work , err := miner .prepareWork (params , witness )
109
+ func (miner * Miner ) generateWork (genParam * generateParams , witness bool ) * newPayloadResult {
110
+ work , err := miner .prepareWork (genParam , witness )
100
111
if err != nil {
101
112
return & newPayloadResult {err : err }
102
113
}
103
- if ! params .noTxs {
114
+
115
+ // Check withdrawals fit max block size.
116
+ // Due to the cap on withdrawal count, this can actually never happen, but we still need to
117
+ // check to ensure the CL notices there's a problem if the withdrawal cap is ever lifted.
118
+ maxBlockSize := params .MaxBlockSize - maxBlockSizeBufferZone
119
+ if genParam .withdrawals .Size () > maxBlockSize {
120
+ return & newPayloadResult {err : errors .New ("withdrawals exceed max block size" )}
121
+ }
122
+ // Also add size of withdrawals to work block size.
123
+ work .size += uint64 (genParam .withdrawals .Size ())
124
+
125
+ if ! genParam .noTxs {
104
126
interrupt := new (atomic.Int32 )
105
127
timer := time .AfterFunc (miner .config .Recommit , func () {
106
128
interrupt .Store (commitInterruptTimeout )
@@ -112,8 +134,8 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
112
134
log .Warn ("Block building is interrupted" , "allowance" , common .PrettyDuration (miner .config .Recommit ))
113
135
}
114
136
}
137
+ body := types.Body {Transactions : work .txs , Withdrawals : genParam .withdrawals }
115
138
116
- body := types.Body {Transactions : work .txs , Withdrawals : params .withdrawals }
117
139
allLogs := make ([]* types.Log , 0 )
118
140
for _ , r := range work .receipts {
119
141
allLogs = append (allLogs , r .Logs ... )
@@ -256,6 +278,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
256
278
return & environment {
257
279
signer : types .MakeSigner (miner .chainConfig , header .Number , header .Time ),
258
280
state : state ,
281
+ size : uint64 (header .Size ()),
259
282
coinbase : coinbase ,
260
283
header : header ,
261
284
witness : state .Witness (),
@@ -273,6 +296,7 @@ func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) e
273
296
}
274
297
env .txs = append (env .txs , tx )
275
298
env .receipts = append (env .receipts , receipt )
299
+ env .size += tx .Size ()
276
300
env .tcount ++
277
301
return nil
278
302
}
@@ -294,10 +318,12 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
294
318
if err != nil {
295
319
return err
296
320
}
297
- env .txs = append (env .txs , tx .WithoutBlobTxSidecar ())
321
+ txNoBlob := tx .WithoutBlobTxSidecar ()
322
+ env .txs = append (env .txs , txNoBlob )
298
323
env .receipts = append (env .receipts , receipt )
299
324
env .sidecars = append (env .sidecars , sc )
300
325
env .blobs += len (sc .Blobs )
326
+ env .size += txNoBlob .Size ()
301
327
* env .header .BlobGasUsed += receipt .BlobGasUsed
302
328
env .tcount ++
303
329
return nil
@@ -318,7 +344,11 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
318
344
}
319
345
320
346
func (miner * Miner ) commitTransactions (env * environment , plainTxs , blobTxs * transactionsByPriceAndNonce , interrupt * atomic.Int32 ) error {
321
- gasLimit := env .header .GasLimit
347
+ var (
348
+ isOsaka = miner .chainConfig .IsOsaka (env .header .Number , env .header .Time )
349
+ isCancun = miner .chainConfig .IsCancun (env .header .Number , env .header .Time )
350
+ gasLimit = env .header .GasLimit
351
+ )
322
352
if env .gasPool == nil {
323
353
env .gasPool = new (core.GasPool ).AddGas (gasLimit )
324
354
}
@@ -374,7 +404,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
374
404
// Most of the blob gas logic here is agnostic as to if the chain supports
375
405
// blobs or not, however the max check panics when called on a chain without
376
406
// a defined schedule, so we need to verify it's safe to call.
377
- if miner . chainConfig . IsCancun ( env . header . Number , env . header . Time ) {
407
+ if isCancun {
378
408
left := eip4844 .MaxBlobsPerBlock (miner .chainConfig , env .header .Time ) - env .blobs
379
409
if left < int (ltx .BlobGas / params .BlobTxBlobGasPerBlob ) {
380
410
log .Trace ("Not enough blob space left for transaction" , "hash" , ltx .Hash , "left" , left , "needed" , ltx .BlobGas / params .BlobTxBlobGasPerBlob )
@@ -391,8 +421,14 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
391
421
continue
392
422
}
393
423
424
+ // if inclusion of the transaction would put the block size over the
425
+ // maximum we allow, don't add any more txs to the payload.
426
+ if ! env .txFitsSize (tx ) {
427
+ break
428
+ }
429
+
394
430
// Make sure all transactions after osaka have cell proofs
395
- if miner . chainConfig . IsOsaka ( env . header . Number , env . header . Time ) {
431
+ if isOsaka {
396
432
if sidecar := tx .BlobTxSidecar (); sidecar != nil {
397
433
if sidecar .Version == 0 {
398
434
log .Info ("Including blob tx with v0 sidecar, recomputing proofs" , "hash" , ltx .Hash )
0 commit comments