Skip to content
2 changes: 2 additions & 0 deletions devnet-sdk/system/txprocessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func (p *transactionProcessor) Sign(tx Transaction) (Transaction, error) {

var signer types.Signer
switch tx.Type() {
case types.SetCodeTxType:
signer = types.NewIsthmusSigner(p.chainID)
case types.DynamicFeeTxType:
signer = types.NewLondonSigner(p.chainID)
case types.AccessListTxType:
Expand Down
2 changes: 2 additions & 0 deletions devnet-sdk/system/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ func (w *wallet) Sign(tx Transaction) (Transaction, error) {

var signer coreTypes.Signer
switch tx.Type() {
case coreTypes.SetCodeTxType:
signer = coreTypes.NewIsthmusSigner(w.chain.ID())
case coreTypes.DynamicFeeTxType:
signer = coreTypes.NewLondonSigner(w.chain.ID())
case coreTypes.AccessListTxType:
Expand Down
27 changes: 25 additions & 2 deletions op-chain-ops/cmd/check-derivation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/holiman/uint256"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
Expand Down Expand Up @@ -275,13 +276,33 @@ func getRandomSignedTransaction(ctx context.Context, ethClient *ethclient.Client
Value: amount,
Data: data,
}

case types.SetCodeTxType:
gasLimit, err := core.FloorDataGas(data)
if err != nil {
return nil, fmt.Errorf("failed to get intrinsicGas: %w", err)
}
gasTipCap, err := ethClient.SuggestGasTipCap(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get gas tip cap: %w", err)
}
txData = &types.SetCodeTx{
ChainID: uint256.MustFromBig(chainId),
Nonce: nonce,
GasTipCap: uint256.MustFromBig(gasTipCap),
GasFeeCap: uint256.MustFromBig(gasPrice),
Gas: gasLimit,
To: randomAddress,
Value: uint256.MustFromBig(amount),
Data: data,
}
default:
return nil, fmt.Errorf("unsupported tx type: %d", txType)
}

tx := types.NewTx(txData)

signer := types.NewLondonSigner(chainId)
signer := types.NewIsthmusSigner(chainId)
if !protected {
if txType == types.LegacyTxType {
signer = types.HomesteadSigner{}
Expand Down Expand Up @@ -359,7 +380,7 @@ func checkConsolidation(cliCtx *cli.Context) error {
txType := types.LegacyTxType
protected := true
// Generate all tx types alternately
switch i % 4 {
switch i % 5 {
case 0:
protected = false // legacy unprotected TX (Homestead)
case 1:
Expand All @@ -368,6 +389,8 @@ func checkConsolidation(cliCtx *cli.Context) error {
txType = types.AccessListTxType
case 3:
txType = types.DynamicFeeTxType
case 4:
txType = types.SetCodeTxType
}
tx, err := getRandomSignedTransaction(ctx, cl, rng, from, privateKey, l2ChainID, txType, protected)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion op-chain-ops/cmd/check-ecotone/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ func checkL1Fees(ctx context.Context, env *actionEnv) error {
Data: []byte("hello"),
AccessList: nil,
}
tx, err := types.SignNewTx(env.key, types.NewLondonSigner(txData.ChainID), txData)
tx, err := types.SignNewTx(env.key, types.NewIsthmusSigner(txData.ChainID), txData)
if err != nil {
return fmt.Errorf("failed to sign test tx: %w", err)
}
Expand Down
4 changes: 4 additions & 0 deletions op-e2e/actions/helpers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ func (s *BasicUser[B]) LastTxReceipt(t Testing) *types.Receipt {
return receipt
}

func (s *BasicUser[B]) Secret() *ecdsa.PrivateKey {
return s.account
}

func (s *BasicUser[B]) MakeTransaction(t Testing) *types.Transaction {
gas, err := s.env.EthCl.EstimateGas(t.Ctx(), ethereum.CallMsg{
From: s.address,
Expand Down
139 changes: 139 additions & 0 deletions op-e2e/actions/proofs/isthmus_setcode_tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package proofs_test

import (
"bytes"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm/program"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"

actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
)

var (
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
)

func runSetCodeTxTypeTest(gt *testing.T, testCfg *helpers.TestCfg[any]) {
t := actionsHelpers.NewDefaultTesting(gt)

// hardcoded because it's not available until after we need it
bobAddr := common.HexToAddress("0x14dC79964da2C08b23698B3D3cc7Ca32193d9955")

// Create 2 contracts, (1) writes 42 to slot 42, (2) calls (1)
store42Program := program.New().Sstore(0x42, 0x42)
callBobProgram := program.New().Call(nil, bobAddr, 1, 0, 0, 0, 0)

alloc := *actionsHelpers.DefaultAlloc
alloc.L2Alloc = make(map[common.Address]types.Account)
alloc.L2Alloc[aa] = types.Account{
Code: store42Program.Bytes(),
}
alloc.L2Alloc[bb] = types.Account{
Code: callBobProgram.Bytes(),
}

testCfg.Allocs = &alloc

tp := helpers.NewTestParams()
env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg())
require.Equal(gt, env.Bob.Address(), bobAddr)

cl := env.Engine.EthClient()

env.Sequencer.ActL2PipelineFull(t)
env.Miner.ActEmptyBlock(t)
env.Sequencer.ActL2StartBlock(t)

aliceSecret := env.Alice.L2.Secret()
bobSecret := env.Bob.L2.Secret()

chainID := env.Sequencer.RollupCfg.L2ChainID

// Sign authorization tuples.
// The way the auths are combined, it becomes
// 1. tx -> addr1 which is delegated to 0xaaaa
// 2. addr1:0xaaaa calls into addr2:0xbbbb
// 3. addr2:0xbbbb writes to storage
auth1, err := types.SignSetCode(aliceSecret, types.SetCodeAuthorization{
ChainID: *uint256.MustFromBig(chainID),
Address: bb,
Nonce: 1,
})
require.NoError(gt, err, "failed to sign auth1")
auth2, err := types.SignSetCode(bobSecret, types.SetCodeAuthorization{
Address: aa,
Nonce: 0,
})
require.NoError(gt, err, "failed to sign auth2")

txdata := &types.SetCodeTx{
ChainID: uint256.MustFromBig(chainID),
Nonce: 0,
To: env.Alice.Address(),
Gas: 500000,
GasFeeCap: uint256.NewInt(5000000000),
GasTipCap: uint256.NewInt(2),
AuthList: []types.SetCodeAuthorization{auth1, auth2},
}
signer := types.NewIsthmusSigner(chainID)
tx := types.MustSignNewTx(aliceSecret, signer, txdata)

err = cl.SendTransaction(t.Ctx(), tx)
require.NoError(gt, err, "failed to send set code tx")

_, err = env.Engine.EngineApi.IncludeTx(tx, env.Alice.Address())
require.NoError(t, err, "failed to include set code tx")

env.Sequencer.ActL2EndBlock(t)

// Verify delegation designations were deployed.
bobCode, err := cl.PendingCodeAt(t.Ctx(), env.Bob.Address())
require.NoError(gt, err, "failed to get bob code")
want := types.AddressToDelegation(auth2.Address)
if !bytes.Equal(bobCode, want) {
t.Fatalf("addr1 code incorrect: got %s, want %s", common.Bytes2Hex(bobCode), common.Bytes2Hex(want))
}
aliceCode, err := cl.PendingCodeAt(t.Ctx(), env.Alice.Address())
require.NoError(gt, err, "failed to get alice code")
want = types.AddressToDelegation(auth1.Address)
if !bytes.Equal(aliceCode, want) {
t.Fatalf("addr2 code incorrect: got %s, want %s", common.Bytes2Hex(aliceCode), common.Bytes2Hex(want))
}

// Verify delegation executed the correct code.
fortyTwo := common.BytesToHash([]byte{0x42})
actual, err := cl.PendingStorageAt(t.Ctx(), env.Bob.Address(), fortyTwo)
require.NoError(gt, err, "failed to get addr1 storage")

if !bytes.Equal(actual, fortyTwo[:]) {
t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual)
}

// batch submit to L1. batcher should submit span batches.
env.BatchAndMine(t)

env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)

latestBlock, err := cl.BlockByNumber(t.Ctx(), nil)
require.NoError(t, err, "error fetching latest block")

env.RunFaultProofProgram(t, latestBlock.NumberU64(), testCfg.CheckResult, testCfg.InputParams...)
}

func TestSetCodeTx(gt *testing.T) {
matrix := helpers.NewMatrix[any]()
defer matrix.Run(gt)

matrix.AddDefaultTestCases(
nil,
helpers.LatestForkOnly,
runSetCodeTxTypeTest,
)
}
2 changes: 1 addition & 1 deletion op-node/rollup/derive/batch_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func mockHash(time uint64, layer uint8) common.Hash {

func b(chainId *big.Int, timestamp uint64, epoch eth.L1BlockRef) *SingularBatch {
rng := rand.New(rand.NewSource(int64(timestamp)))
signer := types.NewLondonSigner(chainId)
signer := types.NewIsthmusSigner(chainId)
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
txData, _ := tx.MarshalBinary()
return &SingularBatch{
Expand Down
12 changes: 7 additions & 5 deletions op-node/rollup/derive/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,21 @@ func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
blockTxCounts = append(blockTxCounts, blockTxCount)
totalblockTxCounts += blockTxCount
}
londonSigner := types.NewLondonSigner(chainId)
signer := types.NewIsthmusSigner(chainId)
var txs [][]byte
for i := 0; i < int(totalblockTxCounts); i++ {
var tx *types.Transaction
switch i % 4 {
switch i % 5 {
case 0:
tx = testutils.RandomLegacyTx(rng, types.HomesteadSigner{})
case 1:
tx = testutils.RandomLegacyTx(rng, londonSigner)
tx = testutils.RandomLegacyTx(rng, signer)
case 2:
tx = testutils.RandomAccessListTx(rng, londonSigner)
tx = testutils.RandomAccessListTx(rng, signer)
case 3:
tx = testutils.RandomDynamicFeeTx(rng, londonSigner)
tx = testutils.RandomDynamicFeeTx(rng, signer)
case 4:
tx = testutils.RandomSetCodeTx(rng, signer)
}
rawTx, err := tx.MarshalBinary()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion op-node/rollup/derive/batch_test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func RandomSingularBatch(rng *rand.Rand, txCount int, chainID *big.Int) *SingularBatch {
signer := types.NewLondonSigner(chainID)
signer := types.NewIsthmusSigner(chainID)
baseFee := big.NewInt(rng.Int63n(300_000_000_000))
txsEncoded := make([]hexutil.Bytes, 0, txCount)
// force each tx to have equal chainID
Expand Down
2 changes: 1 addition & 1 deletion op-node/rollup/derive/batches_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestValidBatch(t *testing.T) {
rng := rand.New(rand.NewSource(1234))

chainId := new(big.Int).SetUint64(rng.Uint64())
signer := types.NewLondonSigner(chainId)
signer := types.NewIsthmusSigner(chainId)
randTx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
randTxData, _ := randTx.MarshalBinary()

Expand Down
12 changes: 6 additions & 6 deletions op-node/rollup/derive/channel_out_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,45 +360,45 @@ type maxBlocksTest struct {
func TestSpanChannelOut_MaxBlocksPerSpanBatch(t *testing.T) {
for i, tt := range []maxBlocksTest{
{
outputSize: 10_751,
outputSize: 9_109,
exactFull: true,
numBatches: 15,
maxBlocks: 4,
expNumSpanBatches: 4,
expLastNumBlocks: 3,
},
{
outputSize: 11_000,
outputSize: 9_200,
numBatches: 16,
maxBlocks: 4,
expNumSpanBatches: 4,
expLastNumBlocks: 3,
},
{
outputSize: 11_154,
outputSize: 9_310,
exactFull: true,
numBatches: 16,
maxBlocks: 4,
expNumSpanBatches: 4,
expLastNumBlocks: 4,
},
{
outputSize: 11_500,
outputSize: 9_400,
numBatches: 17,
maxBlocks: 4,
expNumSpanBatches: 4,
expLastNumBlocks: 4,
},
{
outputSize: 11_801,
outputSize: 9_933,
exactFull: true,
numBatches: 17,
maxBlocks: 4,
expNumSpanBatches: 5,
expLastNumBlocks: 1,
},
{
outputSize: 12_000,
outputSize: 10_000,
numBatches: 18,
maxBlocks: 4,
expNumSpanBatches: 5,
Expand Down
3 changes: 2 additions & 1 deletion op-node/rollup/derive/span_batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,13 +478,14 @@ func TestSpanBatchReadTxData(t *testing.T) {
{"legacy tx", 32, testutils.RandomLegacyTx, true},
{"access list tx", 32, testutils.RandomAccessListTx, true},
{"dynamic fee tx", 32, testutils.RandomDynamicFeeTx, true},
{"setcode tx", 32, testutils.RandomSetCodeTx, true},
}

for i, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
rng := rand.New(rand.NewSource(int64(0x109550 + i)))
chainID := new(big.Int).SetUint64(rng.Uint64())
signer := types.NewLondonSigner(chainID)
signer := types.NewIsthmusSigner(chainID)
if !testCase.protected {
signer = types.HomesteadSigner{}
}
Expand Down
Loading