From 9bffd16e3151d7391408cf9149d739b9d3de091f Mon Sep 17 00:00:00 2001 From: Kolby Moroz Liebl <31669092+KolbyML@users.noreply.github.com> Date: Thu, 16 Oct 2025 16:01:29 -0600 Subject: [PATCH 1/3] Add ``arbdebug_overwriteContractCode`` method to ArbDebug precompile --- arbos/tx_processor.go | 4 +++ contracts-local/src/precompiles | 2 +- precompiles/ArbDebug.go | 6 ++++ system_tests/precompile_test.go | 53 +++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arbos/tx_processor.go b/arbos/tx_processor.go index fa9af8d758..74074ca9c5 100644 --- a/arbos/tx_processor.go +++ b/arbos/tx_processor.go @@ -814,3 +814,7 @@ func (p *TxProcessor) IsCalldataPricingIncreaseEnabled() bool { } return enabled } + +func (p *TxProcessor) EVM() *vm.EVM { + return p.evm +} diff --git a/contracts-local/src/precompiles b/contracts-local/src/precompiles index 0202f1f1c8..c7b5bf44de 160000 --- a/contracts-local/src/precompiles +++ b/contracts-local/src/precompiles @@ -1 +1 @@ -Subproject commit 0202f1f1c88cd8bb125672ffb140ac466ee7e265 +Subproject commit c7b5bf44de99207de2b9db881e7cef0359276929 diff --git a/precompiles/ArbDebug.go b/precompiles/ArbDebug.go index 54c3ec0ecd..1a70822f1c 100644 --- a/precompiles/ArbDebug.go +++ b/precompiles/ArbDebug.go @@ -7,6 +7,7 @@ import ( "errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" ) // All calls to this precompile are authorized by the DebugPrecompile wrapper, @@ -59,6 +60,11 @@ func (con ArbDebug) BecomeChainOwner(c ctx, evm mech) error { return c.State.ChainOwners().Add(c.caller) } +// Overwrite an existing contract's code +func (con ArbDebug) OverwriteContractCode(c ctx, evm mech, addr addr, code []byte) ([]byte, error) { + return c.txProcessor.EVM().StateDB.SetCode(addr, code, tracing.CodeChangeUnspecified), nil +} + // Halts the chain by panicking in the STF func (con ArbDebug) Panic(c ctx, evm mech) error { panic("called ArbDebug's debug-only Panic method") diff --git a/system_tests/precompile_test.go b/system_tests/precompile_test.go index 7b1461259a..35443d7768 100644 --- a/system_tests/precompile_test.go +++ b/system_tests/precompile_test.go @@ -4,6 +4,7 @@ package arbtest import ( + "bytes" "context" "fmt" "math/big" @@ -1312,3 +1313,55 @@ func TestArbAggregatorGetPreferredAggregator(t *testing.T) { Fatal(t, "expected default preferred aggregator to be", l1pricing.BatchPosterAddress, "got", prefAgg) } } + +func TestArbDebugOverwriteContractCode(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + builder := NewNodeBuilder(ctx).DefaultConfig(t, false) + cleanup := builder.Build(t) + defer cleanup() + + // Become chain owner + auth := builder.L2Info.GetDefaultTransactOpts("Owner", ctx) + arbDebug, err := precompilesgen.NewArbDebug(types.ArbDebugAddress, builder.L2.Client) + Require(t, err) + tx, err := arbDebug.BecomeChainOwner(&auth) + Require(t, err) + _, err = builder.L2.EnsureTxSucceeded(tx) + Require(t, err) + + // create EOA to test against + addr := common.BytesToAddress(crypto.Keccak256([]byte{})[:20]) + + // test that code is empty + code, err := builder.L2.Client.CodeAt(ctx, addr, nil) + Require(t, err) + if len(code) != 0 { + t.Fatal("expected code to be empty") + } + + // overwrite with some code + testCodeA := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + tx, err = arbDebug.OverwriteContractCode(&auth, addr, testCodeA) + Require(t, err) + _, err = builder.L2.EnsureTxSucceeded(tx) + Require(t, err) + code, err = builder.L2.Client.CodeAt(ctx, addr, nil) + Require(t, err) + if !bytes.Equal(code, testCodeA) { + t.Fatal("expected code A to be", testCodeA, "got", code) + } + + // overwrite with some other code + testCodeB := []byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + tx, err = arbDebug.OverwriteContractCode(&auth, addr, testCodeB) + Require(t, err) + _, err = builder.L2.EnsureTxSucceeded(tx) + Require(t, err) + code, err = builder.L2.Client.CodeAt(ctx, addr, nil) + Require(t, err) + if !bytes.Equal(code, testCodeB) { + t.Fatal("expected code B to be", testCodeB, "got", code) + } +} From a4a3249566c34b8502f490894b6ff21b37d8ea6f Mon Sep 17 00:00:00 2001 From: Kolby Moroz Liebl <31669092+KolbyML@users.noreply.github.com> Date: Tue, 21 Oct 2025 08:42:38 -0600 Subject: [PATCH 2/3] Update submodule to latest of upstream --- contracts-local/src/precompiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts-local/src/precompiles b/contracts-local/src/precompiles index c7b5bf44de..c395f7b686 160000 --- a/contracts-local/src/precompiles +++ b/contracts-local/src/precompiles @@ -1 +1 @@ -Subproject commit c7b5bf44de99207de2b9db881e7cef0359276929 +Subproject commit c395f7b6860bdccce940b27d79f2e08b04de6dd5 From fb0aee52446789ff09efd3ea6156f67d29933867 Mon Sep 17 00:00:00 2001 From: Kolby Moroz Liebl <31669092+KolbyML@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:30:54 -0600 Subject: [PATCH 3/3] fix CI by stubing non-implemented precompiles --- precompiles/ArbGasInfo.go | 13 +++++++++++++ precompiles/ArbOwner.go | 6 ++++++ precompiles/precompile_test.go | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/precompiles/ArbGasInfo.go b/precompiles/ArbGasInfo.go index c5db8d29c3..eeffc02196 100644 --- a/precompiles/ArbGasInfo.go +++ b/precompiles/ArbGasInfo.go @@ -4,6 +4,7 @@ package precompiles import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -284,3 +285,15 @@ func (con ArbGasInfo) GetL1PricingUnitsSinceUpdate(c ctx, evm mech) (uint64, err func (con ArbGasInfo) GetLastL1PricingSurplus(c ctx, evm mech) (*big.Int, error) { return c.State.L1PricingState().LastSurplus() } + +// GetMaxBlockGasLimit gets the maximum block gas limit +func (con ArbGasInfo) GetMaxBlockGasLimit(c ctx, evm mech) (uint64, error) { + // todo: update with real code once https://github.com/OffchainLabs/nitro/pull/3860 is merged + return 0, fmt.Errorf("GetMaxBlockGasLimit is a stub implementation, since definitions were upstreamed, but implementations not done") +} + +// GetGasPricingConstraints gets the current gas pricing constraints used by the Multi-Constraint Pricer. +func (con ArbGasInfo) GetGasPricingConstraints(c ctx, evm mech) ([][3]uint64, error) { + // todo: update with real code once https://github.com/OffchainLabs/nitro/pull/3860 is merged + return nil, fmt.Errorf("GetGasPricingConstraints is a stub implementation, since definitions were upstreamed, but implementations not done") +} diff --git a/precompiles/ArbOwner.go b/precompiles/ArbOwner.go index 65b2ec5367..7ececacde3 100644 --- a/precompiles/ArbOwner.go +++ b/precompiles/ArbOwner.go @@ -453,3 +453,9 @@ func (con ArbOwner) SetChainConfig(c ctx, evm mech, serializedChainConfig []byte func (con ArbOwner) SetCalldataPriceIncrease(c ctx, _ mech, enable bool) error { return c.State.Features().SetCalldataPriceIncrease(enable) } + +// SetGasPricingConstraints sets the gas pricing constraints used by the Multi-Constraint Pricer. +func (con ArbOwner) SetGasPricingConstraints(c ctx, evm mech, constraints [][3]uint64) error { + // todo: update with real code once https://github.com/OffchainLabs/nitro/pull/3860 is merged + return fmt.Errorf("SetGasPricingConstraints is a stub implementation, since definitions were upstreamed, but implementations not done") +} diff --git a/precompiles/precompile_test.go b/precompiles/precompile_test.go index 0612b9c994..400df63e7b 100644 --- a/precompiles/precompile_test.go +++ b/precompiles/precompile_test.go @@ -182,7 +182,7 @@ func TestPrecompilesPerArbosVersion(t *testing.T) { // Each new precompile contract and each method on new or existing precompile // contracts should be counted. expectedNewEntriesPerArbosVersion := map[uint64]int{ - 0: 99, + 0: 102, params.ArbosVersion_5: 3, params.ArbosVersion_10: 2, params.ArbosVersion_11: 4,