Skip to content

Commit

Permalink
Add support for the new Isthmus block info tx
Browse files Browse the repository at this point in the history
  • Loading branch information
mdehoog committed Jan 1, 2025
1 parent 928070c commit 91ba056
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 32 deletions.
98 changes: 68 additions & 30 deletions core/types/rollup_cost.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ func init() {
}

var (
// BedrockL1AttributesSelector is the function selector indicating Bedrock style L1 gas
// attributes.
BedrockL1AttributesSelector = []byte{0x01, 0x5d, 0x8e, 0xb9}
// BedrockL1AttributesSelector is the function selector indicating Bedrock style L1 gas attributes.
// keccak256("setL1BlockValues(uint64,uint64,uint256,bytes32,uint64,bytes32,uint256,uint256)")[:4]
BedrockL1AttributesSelector = [4]byte{0x01, 0x5d, 0x8e, 0xb9}
// EcotoneL1AttributesSelector is the selector indicating Ecotone style L1 gas attributes.
EcotoneL1AttributesSelector = []byte{0x44, 0x0a, 0x5e, 0x20}

// keccak256("setL1BlockValuesEcotone()")[:4]
EcotoneL1AttributesSelector = [4]byte{0x44, 0x0a, 0x5e, 0x20}
// IsthmusL1AttributesSelector is the selector indicating Isthmus style L1 gas attributes.
// keccak256("setL1BlockValuesIsthmus()")[:4]
IsthmusL1AttributesSelector = [4]byte{0x09, 0x89, 0x99, 0xbe}
// L1BlockAddr is the address of the L1Block contract which stores the L1 gas attributes.
L1BlockAddr = common.HexToAddress("0x4200000000000000000000000000000000000015")

Expand Down Expand Up @@ -259,35 +262,54 @@ func intToScaledFloat(scalar *big.Int) *big.Float {

// extractL1GasParams extracts the gas parameters necessary to compute gas costs from L1 block info
func extractL1GasParams(config *params.ChainConfig, time uint64, data []byte) (gasParams, error) {
// edge case: for the very first Ecotone block we still need to use the Bedrock
// function. We detect this edge case by seeing if the function selector is the old one
// If so, fall through to the pre-ecotone format
// Both Ecotone and Fjord use the same function selector
if config.IsEcotone(time) && len(data) >= 4 && !bytes.Equal(data[0:4], BedrockL1AttributesSelector) {
p, err := extractL1GasParamsPostEcotone(data)
if err != nil {
return gasParams{}, err
}
if len(data) < 4 {
return gasParams{}, fmt.Errorf("unexpected L1 info data length, got %d", len(data))
}

if config.IsFjord(time) {
p.costFunc = NewL1CostFuncFjord(
p.l1BaseFee,
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
)
} else {
p.costFunc = newL1CostFuncEcotone(
p.l1BaseFee,
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
)
var p gasParams
var err error
var signature [4]byte
copy(signature[:], data)
// Note: for Ecotone + Isthmus, the new L1Block method selector is used in the block after
// activation, so we use the selector for the switch block rather than the fork time.
switch signature {
case BedrockL1AttributesSelector:
return extractL1GasParamsPreEcotone(config, time, data)
case EcotoneL1AttributesSelector:
if !config.IsEcotone(time) {
return gasParams{}, fmt.Errorf("setL1BlockValuesEcotone called before Ecotone active")
}
p, err = extractL1GasParamsPostEcotone(data)
case IsthmusL1AttributesSelector:
if !config.IsIsthmus(time) {
return gasParams{}, fmt.Errorf("setL1BlockValuesIsthmus called before Isthmus active")
}
p, err = extractL1GasParamsPostIsthmus(data)
default:
return gasParams{}, fmt.Errorf("unknown L1Block function signature: 0x%s", common.Bytes2Hex(signature[:]))
}

return p, nil
if err != nil {
return gasParams{}, err
}
return extractL1GasParamsPreEcotone(config, time, data)

if config.IsFjord(time) {
p.costFunc = NewL1CostFuncFjord(
p.l1BaseFee,
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
)
} else {
p.costFunc = newL1CostFuncEcotone(
p.l1BaseFee,
p.l1BlobBaseFee,
big.NewInt(int64(*p.l1BaseFeeScalar)),
big.NewInt(int64(*p.l1BlobBaseFeeScalar)),
)
}

return p, nil
}

func extractL1GasParamsPreEcotone(config *params.ChainConfig, time uint64, data []byte) (gasParams, error) {
Expand All @@ -314,6 +336,19 @@ func extractL1GasParamsPostEcotone(data []byte) (gasParams, error) {
if len(data) != 164 {
return gasParams{}, fmt.Errorf("expected 164 L1 info bytes, got %d", len(data))
}
return extractL1GasParamsPostEcotoneIsthmus(data)
}

// extractL1GasParamsPostIsthmus extracts the gas parameters necessary to compute gas from L1 attribute
// info calldata after the Isthmus upgrade, but not for the very first Isthmus block.
func extractL1GasParamsPostIsthmus(data []byte) (gasParams, error) {
if len(data) != 180 {
return gasParams{}, fmt.Errorf("expected 180 L1 info bytes, got %d", len(data))
}
return extractL1GasParamsPostEcotoneIsthmus(data)
}

func extractL1GasParamsPostEcotoneIsthmus(data []byte) (gasParams, error) {
// data layout assumed for Ecotone:
// offset type varname
// 0 <selector>
Expand All @@ -326,6 +361,9 @@ func extractL1GasParamsPostEcotone(data []byte) (gasParams, error) {
// 68 uint256 _blobBaseFee,
// 100 bytes32 _hash,
// 132 bytes32 _batcherHash,
// Isthmus adds two more uint64s, which are ignored by this function:
// 164 uint64 _depositNonce
// 172 uint64 _configUpdateNonce
l1BaseFee := new(big.Int).SetBytes(data[36:68])
l1BlobBaseFee := new(big.Int).SetBytes(data[68:100])
l1BaseFeeScalar := binary.BigEndian.Uint32(data[4:8])
Expand Down
4 changes: 2 additions & 2 deletions core/types/rollup_cost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func getBedrockL1Attributes(baseFee, overhead, scalar *big.Int) []byte {
uint256 := make([]byte, 32)
ignored := big.NewInt(1234)
data := []byte{}
data = append(data, BedrockL1AttributesSelector...)
data = append(data, BedrockL1AttributesSelector[:]...)
data = append(data, ignored.FillBytes(uint256)...) // arg 0
data = append(data, ignored.FillBytes(uint256)...) // arg 1
data = append(data, baseFee.FillBytes(uint256)...) // arg 2
Expand All @@ -250,7 +250,7 @@ func getEcotoneL1Attributes(baseFee, blobBaseFee, baseFeeScalar, blobBaseFeeScal
uint256Slice := make([]byte, 32)
uint64Slice := make([]byte, 8)
uint32Slice := make([]byte, 4)
data = append(data, EcotoneL1AttributesSelector...)
data = append(data, EcotoneL1AttributesSelector[:]...)
data = append(data, baseFeeScalar.FillBytes(uint32Slice)...)
data = append(data, blobBaseFeeScalar.FillBytes(uint32Slice)...)
data = append(data, ignored.FillBytes(uint64Slice)...)
Expand Down

0 comments on commit 91ba056

Please sign in to comment.