From 4f67099d22730b4eb0e06429c539f8858ac5d0cf Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:35:44 +0000 Subject: [PATCH 1/6] op-node: validate EIP-1559 params in derivation pipeline Add redundant validation for zero elasticity multiplier in EIP-1559 parameters during derivation, providing defense-in-depth against contract-level checks being accidentally removed. The SystemConfig contract already enforces denominator >= 1 and elasticity >= 1, but this adds the same check in the derivation pipeline for redundancy. Closes #18625 Co-Authored-By: Kelvin Fichter --- op-node/rollup/derive/system_config.go | 16 ++++- op-node/rollup/derive/system_config_test.go | 68 +++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/op-node/rollup/derive/system_config.go b/op-node/rollup/derive/system_config.go index 773a1c6f51772..ce2951482522b 100644 --- a/op-node/rollup/derive/system_config.go +++ b/op-node/rollup/derive/system_config.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/hashicorp/go-multierror" @@ -33,8 +34,9 @@ var ( ) var ( - ErrUnknownEventVersion = errors.New("unknown SystemConfig event version") - ErrUnknownEventType = errors.New("unknown SystemConfig event type") + ErrUnknownEventVersion = errors.New("unknown SystemConfig event version") + ErrUnknownEventType = errors.New("unknown SystemConfig event type") + ErrInvalidEIP1559Params = errors.New("invalid EIP-1559 parameters") ) // UpdateSystemConfigWithL1Receipts filters all L1 receipts to find config updates and applies the config updates to the given sysCfg @@ -128,7 +130,15 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L if err != nil { return err } - copy(destSysCfg.EIP1559Params[:], params[24:32]) + eip1559Params := params[24:32] + denominator, elasticity := eip1559.DecodeHolocene1559Params(eip1559Params) + if denominator == 0 && elasticity != 0 { + return fmt.Errorf("%w: denominator is 0 but elasticity is %d", ErrInvalidEIP1559Params, elasticity) + } + if elasticity == 0 && denominator != 0 { + return fmt.Errorf("%w: elasticity is 0 but denominator is %d", ErrInvalidEIP1559Params, denominator) + } + copy(destSysCfg.EIP1559Params[:], eip1559Params) return nil case SystemConfigUpdateOperatorFeeParams: params, err := parseSystemConfigUpdateOperatorFeeParams(ev.Data) diff --git a/op-node/rollup/derive/system_config_test.go b/op-node/rollup/derive/system_config_test.go index 8317587543a8e..f4c3f2c18b3e8 100644 --- a/op-node/rollup/derive/system_config_test.go +++ b/op-node/rollup/derive/system_config_test.go @@ -214,6 +214,74 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { }, err: false, }, + { + name: "EIP1559Params_ZeroDenominatorNonZeroElasticity", + log: &types.Log{ + Topics: []common.Hash{ + ConfigUpdateEventABIHash, + ConfigUpdateEventVersion0, + SystemConfigUpdateEIP1559Params, + }, + }, + hook: func(t *testing.T, log *types.Log) *types.Log { + // denominator = 0, elasticity = 1 (invalid combination) + params := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1} + numberData, err := oneUint256.Pack(new(big.Int).SetBytes(params)) + require.NoError(t, err) + data, err := bytesArgs.Pack(numberData) + require.NoError(t, err) + log.Data = data + return log + }, + config: eth.SystemConfig{}, + err: true, + }, + { + name: "EIP1559Params_NonZeroDenominatorZeroElasticity", + log: &types.Log{ + Topics: []common.Hash{ + ConfigUpdateEventABIHash, + ConfigUpdateEventVersion0, + SystemConfigUpdateEIP1559Params, + }, + }, + hook: func(t *testing.T, log *types.Log) *types.Log { + // denominator = 1, elasticity = 0 (invalid combination) + params := []byte{0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0} + numberData, err := oneUint256.Pack(new(big.Int).SetBytes(params)) + require.NoError(t, err) + data, err := bytesArgs.Pack(numberData) + require.NoError(t, err) + log.Data = data + return log + }, + config: eth.SystemConfig{}, + err: true, + }, + { + name: "EIP1559Params_BothZero", + log: &types.Log{ + Topics: []common.Hash{ + ConfigUpdateEventABIHash, + ConfigUpdateEventVersion0, + SystemConfigUpdateEIP1559Params, + }, + }, + hook: func(t *testing.T, log *types.Log) *types.Log { + // denominator = 0, elasticity = 0 (valid - uses pre-Holocene constants) + params := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} + numberData, err := oneUint256.Pack(new(big.Int).SetBytes(params)) + require.NoError(t, err) + data, err := bytesArgs.Pack(numberData) + require.NoError(t, err) + log.Data = data + return log + }, + config: eth.SystemConfig{ + EIP1559Params: eth.Bytes8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + err: false, + }, { name: "OperatorFeeParams", log: &types.Log{ From b2a18313171e4de19d2792308e0f134949a5d0b2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:49:46 +0000 Subject: [PATCH 2/6] op-node: use ValidateHolocene1559Params for EIP-1559 validation - Move validation from ProcessSystemConfigUpdateLogEvent into parseSystemConfigUpdateEIP1559Params - Use eip1559.ValidateHolocene1559Params instead of manual checks - Update op-geth dependency to include elasticity validation (PR #743) Co-Authored-By: Kelvin Fichter --- go.mod | 2 +- go.sum | 4 ++-- op-node/rollup/derive/system_config.go | 14 +++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 791784f4b8572..909c7b7852759 100644 --- a/go.mod +++ b/go.mod @@ -310,7 +310,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.0-synctest.0.0.20251208094937-ba6bdcfef423 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index d4297507e1cf6..689a888c431d4 100644 --- a/go.sum +++ b/go.sum @@ -240,8 +240,8 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e h1:iy1vBIzACYUyOVyoADUwvAiq2eOPC0yVsDUdolPwQjk= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e/go.mod h1:DYj7+vYJ4cIB7zera9mv4LcAynCL5u4YVfoeUu6Wa+w= -github.com/ethereum-optimism/op-geth v1.101604.0-synctest.0.0.20251208094937-ba6bdcfef423 h1:5xVkCCBRWkOt+bzVWL1p3mOwrpZLjxi/+yWUsja0E48= -github.com/ethereum-optimism/op-geth v1.101604.0-synctest.0.0.20251208094937-ba6bdcfef423/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09 h1:9mRtRuYsVMgjch1FSYX6MIshf/Nd0RgiRj2RjRWnvKM= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00 h1:TR5Y7B+5m63V0Dno7MHcFqv/XZByQzx/4THV1T1A7+U= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= diff --git a/op-node/rollup/derive/system_config.go b/op-node/rollup/derive/system_config.go index ce2951482522b..8e145d144ffae 100644 --- a/op-node/rollup/derive/system_config.go +++ b/op-node/rollup/derive/system_config.go @@ -130,15 +130,7 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L if err != nil { return err } - eip1559Params := params[24:32] - denominator, elasticity := eip1559.DecodeHolocene1559Params(eip1559Params) - if denominator == 0 && elasticity != 0 { - return fmt.Errorf("%w: denominator is 0 but elasticity is %d", ErrInvalidEIP1559Params, elasticity) - } - if elasticity == 0 && denominator != 0 { - return fmt.Errorf("%w: elasticity is 0 but denominator is %d", ErrInvalidEIP1559Params, denominator) - } - copy(destSysCfg.EIP1559Params[:], eip1559Params) + copy(destSysCfg.EIP1559Params[:], params[24:32]) return nil case SystemConfigUpdateOperatorFeeParams: params, err := parseSystemConfigUpdateOperatorFeeParams(ev.Data) @@ -244,6 +236,10 @@ func parseSystemConfigUpdateEIP1559Params(data []byte) (eth.Bytes32, error) { if !solabi.EmptyReader(reader) { return eth.Bytes32{}, fmt.Errorf("%w: too many bytes", ErrParsingSystemConfig) } + // Validate the EIP-1559 params (last 8 bytes of the 32-byte value) + if err := eip1559.ValidateHolocene1559Params(params[24:32]); err != nil { + return eth.Bytes32{}, fmt.Errorf("%w: %w", ErrInvalidEIP1559Params, err) + } return params, nil } From 3c5a11a4dfa67adb8b91b19246c535d2709ff13a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 16:15:40 +0000 Subject: [PATCH 3/6] op-node: fix test to use valid EIP-1559 params The createMismatchedEIP1559Params test was creating invalid params (denominator=1, elasticity=0) which now triggers validation error from op-geth PR #743. Fix by using valid but mismatched params (999, 999). Co-Authored-By: Kelvin Fichter --- op-node/rollup/attributes/engine_consolidate_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/op-node/rollup/attributes/engine_consolidate_test.go b/op-node/rollup/attributes/engine_consolidate_test.go index 7c57ef3cb6dc9..c5bd0b9649d73 100644 --- a/op-node/rollup/attributes/engine_consolidate_test.go +++ b/op-node/rollup/attributes/engine_consolidate_test.go @@ -214,7 +214,8 @@ func createMismatchedFeeRecipient() matchArgs { func createMismatchedEIP1559Params() matchArgs { args := holoceneArgs() - args.attrs.EIP1559Params[0]++ // so denominator is != 0 + // Create valid but mismatched EIP-1559 params (both denominator and elasticity must be non-zero or both zero) + copy((*args.attrs.EIP1559Params)[:], eip1559.EncodeHolocene1559Params(999, 999)) return args } From 19ab613c0f3e2b95bca7fdb5c3e5a41901f172b6 Mon Sep 17 00:00:00 2001 From: Sebastian Stammler Date: Thu, 8 Jan 2026 20:34:35 +0100 Subject: [PATCH 4/6] update go.mod --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 909c7b7852759..f80bc52751cbf 100644 --- a/go.mod +++ b/go.mod @@ -310,7 +310,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index 689a888c431d4..f96b79e8a7f05 100644 --- a/go.sum +++ b/go.sum @@ -240,8 +240,8 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e h1:iy1vBIzACYUyOVyoADUwvAiq2eOPC0yVsDUdolPwQjk= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e/go.mod h1:DYj7+vYJ4cIB7zera9mv4LcAynCL5u4YVfoeUu6Wa+w= -github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09 h1:9mRtRuYsVMgjch1FSYX6MIshf/Nd0RgiRj2RjRWnvKM= -github.com/ethereum-optimism/op-geth v1.101604.1-0.20260106153129-7dfdde14fe09/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277 h1:j9lXFMwvKjhKTXjUhOIdL/sI0ZR9bjjfEMeb5F0BIw4= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00 h1:TR5Y7B+5m63V0Dno7MHcFqv/XZByQzx/4THV1T1A7+U= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= From 8e514ae88a2c650bb445483904bc73a9f0606e47 Mon Sep 17 00:00:00 2001 From: Sebastian Stammler Date: Thu, 8 Jan 2026 21:20:30 +0100 Subject: [PATCH 5/6] fix test --- op-node/rollup/attributes/engine_consolidate_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/op-node/rollup/attributes/engine_consolidate_test.go b/op-node/rollup/attributes/engine_consolidate_test.go index c5bd0b9649d73..cc5c0c6522b77 100644 --- a/op-node/rollup/attributes/engine_consolidate_test.go +++ b/op-node/rollup/attributes/engine_consolidate_test.go @@ -576,7 +576,7 @@ func TestCheckEIP1559ParamsMatch(t *testing.T) { desc: "err-both-zero", attrParams: new(eth.Bytes8), blockExtraData: make(eth.BytesMax32, 9), - err: "eip1559 parameters do not match, attributes: 250, 6 (translated from 0,0), block: 0, 0", + err: "invalid block extraData: holocene extraData must encode a non-zero denominator", }, { desc: "err-invalid-params", @@ -610,7 +610,8 @@ func TestCheckEIP1559ParamsMatch(t *testing.T) { HoloceneTime: &pastTime, IsthmusTime: &pastTime, JovianTime: &futureTime, - ChainOpConfig: defaultOpConfig} + ChainOpConfig: defaultOpConfig, + } err := checkExtraDataParamsMatch(cfg, uint64(2), test.attrParams, nil, test.blockExtraData) if test.err == "" { require.NoError(t, err) From 62b34cb342c2cb803a3ee9f47df8234cfa35472d Mon Sep 17 00:00:00 2001 From: Sebastian Stammler Date: Fri, 9 Jan 2026 14:31:25 +0100 Subject: [PATCH 6/6] update go.mod (after merging op-geth PR) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f80bc52751cbf..bb25b0644b7e8 100644 --- a/go.mod +++ b/go.mod @@ -310,7 +310,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101604.1-0.20260109132258-733bb5b623f7 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index f96b79e8a7f05..df1eebcbd2516 100644 --- a/go.sum +++ b/go.sum @@ -240,8 +240,8 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e h1:iy1vBIzACYUyOVyoADUwvAiq2eOPC0yVsDUdolPwQjk= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e/go.mod h1:DYj7+vYJ4cIB7zera9mv4LcAynCL5u4YVfoeUu6Wa+w= -github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277 h1:j9lXFMwvKjhKTXjUhOIdL/sI0ZR9bjjfEMeb5F0BIw4= -github.com/ethereum-optimism/op-geth v1.101604.1-0.20260108163134-5ddfe8964277/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260109132258-733bb5b623f7 h1:VQM98S1gNqKAFGlsqwr1TvHtYgNPM+RUkSH4ia1TG0c= +github.com/ethereum-optimism/op-geth v1.101604.1-0.20260109132258-733bb5b623f7/go.mod h1:fCNAwDynfAP6EKsmLqwSDUDgi+GtJIir74Ui3fXXMps= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00 h1:TR5Y7B+5m63V0Dno7MHcFqv/XZByQzx/4THV1T1A7+U= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251121143344-5ac16e0fbb00/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=