@@ -49,12 +49,18 @@ func init() {
49
49
}
50
50
51
51
var (
52
- // BedrockL1AttributesSelector is the function selector indicating Bedrock style L1 gas
53
- // attributes.
54
- BedrockL1AttributesSelector = []byte {0x01 , 0x5d , 0x8e , 0xb9 }
52
+ // BedrockL1AttributesSelector is the function selector indicating Bedrock style L1 gas attributes.
53
+ // keccak256("setL1BlockValues(uint64,uint64,uint256,bytes32,uint64,bytes32,uint256,uint256)")[:4]
54
+ BedrockL1AttributesSelector = [4 ]byte {0x01 , 0x5d , 0x8e , 0xb9 }
55
55
// EcotoneL1AttributesSelector is the selector indicating Ecotone style L1 gas attributes.
56
- EcotoneL1AttributesSelector = []byte {0x44 , 0x0a , 0x5e , 0x20 }
57
-
56
+ // keccak256("setL1BlockValuesEcotone()")[:4]
57
+ EcotoneL1AttributesSelector = [4 ]byte {0x44 , 0x0a , 0x5e , 0x20 }
58
+ // IsthmusL1AttributesSelector is the selector indicating Isthmus style L1 gas attributes.
59
+ // keccak256("setL1BlockValuesIsthmus()")[:4]
60
+ IsthmusL1AttributesSelector = [4 ]byte {0x09 , 0x89 , 0x99 , 0xbe }
61
+ // InteropL1AttributesSelector is the selector indicating Interop style L1 gas attributes.
62
+ // keccak256("setL1BlockValuesInterop()")[:4]
63
+ InteropL1AttributesSelector = [4 ]byte {0x76 , 0x0e , 0xe0 , 0x4d }
58
64
// L1BlockAddr is the address of the L1Block contract which stores the L1 gas attributes.
59
65
L1BlockAddr = common .HexToAddress ("0x4200000000000000000000000000000000000015" )
60
66
@@ -259,35 +265,60 @@ func intToScaledFloat(scalar *big.Int) *big.Float {
259
265
260
266
// extractL1GasParams extracts the gas parameters necessary to compute gas costs from L1 block info
261
267
func extractL1GasParams (config * params.ChainConfig , time uint64 , data []byte ) (gasParams , error ) {
262
- // edge case: for the very first Ecotone block we still need to use the Bedrock
263
- // function. We detect this edge case by seeing if the function selector is the old one
264
- // If so, fall through to the pre-ecotone format
265
- // Both Ecotone and Fjord use the same function selector
266
- if config .IsEcotone (time ) && len (data ) >= 4 && ! bytes .Equal (data [0 :4 ], BedrockL1AttributesSelector ) {
267
- p , err := extractL1GasParamsPostEcotone (data )
268
- if err != nil {
269
- return gasParams {}, err
270
- }
268
+ if len (data ) < 4 {
269
+ return gasParams {}, fmt .Errorf ("unexpected L1 info data length, got %d" , len (data ))
270
+ }
271
271
272
- if config .IsFjord (time ) {
273
- p .costFunc = NewL1CostFuncFjord (
274
- p .l1BaseFee ,
275
- p .l1BlobBaseFee ,
276
- big .NewInt (int64 (* p .l1BaseFeeScalar )),
277
- big .NewInt (int64 (* p .l1BlobBaseFeeScalar )),
278
- )
279
- } else {
280
- p .costFunc = newL1CostFuncEcotone (
281
- p .l1BaseFee ,
282
- p .l1BlobBaseFee ,
283
- big .NewInt (int64 (* p .l1BaseFeeScalar )),
284
- big .NewInt (int64 (* p .l1BlobBaseFeeScalar )),
285
- )
272
+ var p gasParams
273
+ var err error
274
+ var signature [4 ]byte
275
+ copy (signature [:], data )
276
+ // Note: for Ecotone + Isthmus, the new L1Block method selector is used in the block after
277
+ // activation, so we use the selector for the switch block rather than the fork time.
278
+ switch signature {
279
+ case BedrockL1AttributesSelector :
280
+ return extractL1GasParamsPreEcotone (config , time , data )
281
+ case EcotoneL1AttributesSelector :
282
+ if ! config .IsEcotone (time ) {
283
+ return gasParams {}, fmt .Errorf ("setL1BlockValuesEcotone called before Ecotone active" )
284
+ }
285
+ p , err = extractL1GasParamsPostEcotone (data )
286
+ case IsthmusL1AttributesSelector :
287
+ if ! config .IsIsthmus (time ) {
288
+ return gasParams {}, fmt .Errorf ("setL1BlockValuesIsthmus called before Isthmus active" )
286
289
}
290
+ p , err = extractL1GasParamsPostIsthmus (data )
291
+ case InteropL1AttributesSelector :
292
+ if ! config .IsInterop (time ) {
293
+ return gasParams {}, fmt .Errorf ("setL1BlockValuesInterop called before Interop active" )
294
+ }
295
+ // Interop uses the same tx calldata size/format as Isthmus
296
+ p , err = extractL1GasParamsPostIsthmus (data )
297
+ default :
298
+ return gasParams {}, fmt .Errorf ("unknown L1Block function signature: 0x%s" , common .Bytes2Hex (signature [:]))
299
+ }
287
300
288
- return p , nil
301
+ if err != nil {
302
+ return gasParams {}, err
289
303
}
290
- return extractL1GasParamsPreEcotone (config , time , data )
304
+
305
+ if config .IsFjord (time ) {
306
+ p .costFunc = NewL1CostFuncFjord (
307
+ p .l1BaseFee ,
308
+ p .l1BlobBaseFee ,
309
+ big .NewInt (int64 (* p .l1BaseFeeScalar )),
310
+ big .NewInt (int64 (* p .l1BlobBaseFeeScalar )),
311
+ )
312
+ } else {
313
+ p .costFunc = newL1CostFuncEcotone (
314
+ p .l1BaseFee ,
315
+ p .l1BlobBaseFee ,
316
+ big .NewInt (int64 (* p .l1BaseFeeScalar )),
317
+ big .NewInt (int64 (* p .l1BlobBaseFeeScalar )),
318
+ )
319
+ }
320
+
321
+ return p , nil
291
322
}
292
323
293
324
func extractL1GasParamsPreEcotone (config * params.ChainConfig , time uint64 , data []byte ) (gasParams , error ) {
@@ -314,6 +345,19 @@ func extractL1GasParamsPostEcotone(data []byte) (gasParams, error) {
314
345
if len (data ) != 164 {
315
346
return gasParams {}, fmt .Errorf ("expected 164 L1 info bytes, got %d" , len (data ))
316
347
}
348
+ return extractL1GasParamsPostEcotoneIsthmus (data )
349
+ }
350
+
351
+ // extractL1GasParamsPostIsthmus extracts the gas parameters necessary to compute gas from L1 attribute
352
+ // info calldata after the Isthmus upgrade, but not for the very first Isthmus block.
353
+ func extractL1GasParamsPostIsthmus (data []byte ) (gasParams , error ) {
354
+ if len (data ) != 180 {
355
+ return gasParams {}, fmt .Errorf ("expected 180 L1 info bytes, got %d" , len (data ))
356
+ }
357
+ return extractL1GasParamsPostEcotoneIsthmus (data )
358
+ }
359
+
360
+ func extractL1GasParamsPostEcotoneIsthmus (data []byte ) (gasParams , error ) {
317
361
// data layout assumed for Ecotone:
318
362
// offset type varname
319
363
// 0 <selector>
@@ -326,6 +370,9 @@ func extractL1GasParamsPostEcotone(data []byte) (gasParams, error) {
326
370
// 68 uint256 _blobBaseFee,
327
371
// 100 bytes32 _hash,
328
372
// 132 bytes32 _batcherHash,
373
+ // Isthmus adds two more uint64s, which are ignored by this function:
374
+ // 164 uint64 _depositNonce
375
+ // 172 uint64 _configUpdateNonce
329
376
l1BaseFee := new (big.Int ).SetBytes (data [36 :68 ])
330
377
l1BlobBaseFee := new (big.Int ).SetBytes (data [68 :100 ])
331
378
l1BaseFeeScalar := binary .BigEndian .Uint32 (data [4 :8 ])
0 commit comments