diff --git a/devnet-sdk/system/txprocessor.go b/devnet-sdk/system/txprocessor.go index c6c4438fe6bb5..1279aadffc1b6 100644 --- a/devnet-sdk/system/txprocessor.go +++ b/devnet-sdk/system/txprocessor.go @@ -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: diff --git a/devnet-sdk/system/wallet.go b/devnet-sdk/system/wallet.go index 0f7e1ee3c1cda..966aa2c7cbf19 100644 --- a/devnet-sdk/system/wallet.go +++ b/devnet-sdk/system/wallet.go @@ -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: diff --git a/op-chain-ops/cmd/check-derivation/main.go b/op-chain-ops/cmd/check-derivation/main.go index 71c0fec1b9a18..026e821c01eff 100644 --- a/op-chain-ops/cmd/check-derivation/main.go +++ b/op-chain-ops/cmd/check-derivation/main.go @@ -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" @@ -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{} @@ -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: @@ -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 { diff --git a/op-chain-ops/cmd/check-ecotone/main.go b/op-chain-ops/cmd/check-ecotone/main.go index b49bb0de33160..37e590c47fa11 100644 --- a/op-chain-ops/cmd/check-ecotone/main.go +++ b/op-chain-ops/cmd/check-ecotone/main.go @@ -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) } diff --git a/op-e2e/actions/helpers/user.go b/op-e2e/actions/helpers/user.go index d7215b80650f7..f85368baaaa1f 100644 --- a/op-e2e/actions/helpers/user.go +++ b/op-e2e/actions/helpers/user.go @@ -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, diff --git a/op-e2e/actions/proofs/isthmus_setcode_tx_test.go b/op-e2e/actions/proofs/isthmus_setcode_tx_test.go new file mode 100644 index 0000000000000..bd63698a3ee43 --- /dev/null +++ b/op-e2e/actions/proofs/isthmus_setcode_tx_test.go @@ -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, + ) +} diff --git a/op-node/rollup/derive/batch_queue_test.go b/op-node/rollup/derive/batch_queue_test.go index 54ae9abc63703..99e833d338093 100644 --- a/op-node/rollup/derive/batch_queue_test.go +++ b/op-node/rollup/derive/batch_queue_test.go @@ -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{ diff --git a/op-node/rollup/derive/batch_test.go b/op-node/rollup/derive/batch_test.go index 9e48f265d745d..c206739c979ae 100644 --- a/op-node/rollup/derive/batch_test.go +++ b/op-node/rollup/derive/batch_test.go @@ -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 { diff --git a/op-node/rollup/derive/batch_test_utils.go b/op-node/rollup/derive/batch_test_utils.go index 5783b5ec39bfa..bf28c1e00e656 100644 --- a/op-node/rollup/derive/batch_test_utils.go +++ b/op-node/rollup/derive/batch_test_utils.go @@ -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 diff --git a/op-node/rollup/derive/batches_test.go b/op-node/rollup/derive/batches_test.go index a50773c71d754..dbb86aec22024 100644 --- a/op-node/rollup/derive/batches_test.go +++ b/op-node/rollup/derive/batches_test.go @@ -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() diff --git a/op-node/rollup/derive/channel_out_test.go b/op-node/rollup/derive/channel_out_test.go index e82653cfd985f..f3097318ac508 100644 --- a/op-node/rollup/derive/channel_out_test.go +++ b/op-node/rollup/derive/channel_out_test.go @@ -360,7 +360,7 @@ 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, @@ -368,14 +368,14 @@ func TestSpanChannelOut_MaxBlocksPerSpanBatch(t *testing.T) { 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, @@ -383,14 +383,14 @@ func TestSpanChannelOut_MaxBlocksPerSpanBatch(t *testing.T) { 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, @@ -398,7 +398,7 @@ func TestSpanChannelOut_MaxBlocksPerSpanBatch(t *testing.T) { expLastNumBlocks: 1, }, { - outputSize: 12_000, + outputSize: 10_000, numBatches: 18, maxBlocks: 4, expNumSpanBatches: 5, diff --git a/op-node/rollup/derive/span_batch_test.go b/op-node/rollup/derive/span_batch_test.go index 4c02c46b2de46..96628c92c10ba 100644 --- a/op-node/rollup/derive/span_batch_test.go +++ b/op-node/rollup/derive/span_batch_test.go @@ -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{} } diff --git a/op-node/rollup/derive/span_batch_tx.go b/op-node/rollup/derive/span_batch_tx.go index 5f5bffb02b8b6..81c9f24e0b6a7 100644 --- a/op-node/rollup/derive/span_batch_tx.go +++ b/op-node/rollup/derive/span_batch_tx.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" ) type spanBatchTxData interface { @@ -45,6 +46,17 @@ type spanBatchDynamicFeeTxData struct { func (txData *spanBatchDynamicFeeTxData) txType() byte { return types.DynamicFeeTxType } +type spanBatchSetCodeTxData struct { + Value *uint256.Int + GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas + GasFeeCap *uint256.Int // a.k.a. maxFeePerGas + Data []byte + AccessList types.AccessList + AuthorizationList []types.SetCodeAuthorization +} + +func (txData *spanBatchSetCodeTxData) txType() byte { return types.SetCodeTxType } + // Type returns the transaction type. func (tx *spanBatchTx) Type() uint8 { return tx.inner.txType() @@ -93,6 +105,13 @@ func (tx *spanBatchTx) decodeTyped(b []byte) (spanBatchTxData, error) { return nil, fmt.Errorf("failed to decode spanBatchDynamicFeeTxData: %w", err) } return &inner, nil + case types.SetCodeTxType: + var inner spanBatchSetCodeTxData + err := rlp.DecodeBytes(b[1:], &inner) + if err != nil { + return nil, fmt.Errorf("failed to decode spanBatchSetCodeTxData: %w", err) + } + return &inner, nil default: return nil, types.ErrTxTypeNotSupported } @@ -168,6 +187,23 @@ func (tx *spanBatchTx) convertToFullTx(nonce, gas uint64, to *common.Address, ch R: R, S: S, } + case types.SetCodeTxType: + setCodeTxInner := tx.inner.(*spanBatchSetCodeTxData) + inner = &types.SetCodeTx{ + ChainID: uint256.MustFromBig(chainID), + Nonce: nonce, + GasTipCap: setCodeTxInner.GasTipCap, + GasFeeCap: setCodeTxInner.GasFeeCap, + Gas: gas, + To: *to, + Value: setCodeTxInner.Value, + Data: setCodeTxInner.Data, + AccessList: setCodeTxInner.AccessList, + AuthList: setCodeTxInner.AuthorizationList, + V: uint256.MustFromBig(V), + R: uint256.MustFromBig(R), + S: uint256.MustFromBig(S), + } default: return nil, fmt.Errorf("invalid tx type: %d", tx.Type()) } @@ -199,6 +235,15 @@ func newSpanBatchTx(tx *types.Transaction) (*spanBatchTx, error) { Data: tx.Data(), AccessList: tx.AccessList(), } + case types.SetCodeTxType: + inner = &spanBatchSetCodeTxData{ + GasTipCap: uint256.MustFromBig(tx.GasTipCap()), + GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()), + Value: uint256.MustFromBig(tx.Value()), + Data: tx.Data(), + AccessList: tx.AccessList(), + AuthorizationList: tx.SetCodeAuthorizations(), + } default: return nil, fmt.Errorf("invalid tx type: %d", tx.Type()) } diff --git a/op-node/rollup/derive/span_batch_tx_test.go b/op-node/rollup/derive/span_batch_tx_test.go index 55a9101da5e7c..cd405bf09f04e 100644 --- a/op-node/rollup/derive/span_batch_tx_test.go +++ b/op-node/rollup/derive/span_batch_tx_test.go @@ -24,13 +24,14 @@ func TestSpanBatchTxConvert(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(0x1331 + i))) chainID := big.NewInt(rng.Int63n(1000)) - signer := types.NewLondonSigner(chainID) + signer := types.NewIsthmusSigner(chainID) if !testCase.protected { signer = types.HomesteadSigner{} } @@ -63,13 +64,14 @@ func TestSpanBatchTxRoundTrip(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(0x1332 + i))) chainID := big.NewInt(rng.Int63n(1000)) - signer := types.NewLondonSigner(chainID) + signer := types.NewIsthmusSigner(chainID) if !testCase.protected { signer = types.HomesteadSigner{} } diff --git a/op-node/rollup/derive/span_batch_txs.go b/op-node/rollup/derive/span_batch_txs.go index e4bc73d0f9874..7c354430fc30e 100644 --- a/op-node/rollup/derive/span_batch_txs.go +++ b/op-node/rollup/derive/span_batch_txs.go @@ -271,6 +271,8 @@ func (btx *spanBatchTxs) recoverV(chainID *big.Int) error { v = bit case types.DynamicFeeTxType: v = bit + case types.SetCodeTxType: + v = bit default: return fmt.Errorf("invalid tx type: %d", txType) } @@ -386,6 +388,8 @@ func convertVToYParity(v uint64, txType int) (uint, error) { yParityBit = uint(v) case types.DynamicFeeTxType: yParityBit = uint(v) + case types.SetCodeTxType: + yParityBit = uint(v) default: return 0, fmt.Errorf("invalid tx type: %d", txType) } diff --git a/op-node/rollup/derive/span_batch_txs_test.go b/op-node/rollup/derive/span_batch_txs_test.go index 20f03899413dc..5cd5ee966dc82 100644 --- a/op-node/rollup/derive/span_batch_txs_test.go +++ b/op-node/rollup/derive/span_batch_txs_test.go @@ -332,14 +332,15 @@ func TestSpanBatchTxsRecoverV(t *testing.T) { rng := rand.New(rand.NewSource(0x123)) chainID := big.NewInt(rng.Int63n(1000)) - londonSigner := types.NewLondonSigner(chainID) + isthmusSigner := types.NewIsthmusSigner(chainID) totalblockTxCount := 20 + rng.Intn(100) cases := []txTypeTest{ {"unprotected legacy tx", testutils.RandomLegacyTx, types.HomesteadSigner{}}, - {"legacy tx", testutils.RandomLegacyTx, londonSigner}, - {"access list tx", testutils.RandomAccessListTx, londonSigner}, - {"dynamic fee tx", testutils.RandomDynamicFeeTx, londonSigner}, + {"legacy tx", testutils.RandomLegacyTx, isthmusSigner}, + {"access list tx", testutils.RandomAccessListTx, isthmusSigner}, + {"dynamic fee tx", testutils.RandomDynamicFeeTx, isthmusSigner}, + {"setcode tx", testutils.RandomSetCodeTx, isthmusSigner}, } for _, testCase := range cases { @@ -423,13 +424,14 @@ func TestSpanBatchTxsRoundTrip(t *testing.T) { func TestSpanBatchTxsRoundTripFullTxs(t *testing.T) { rng := rand.New(rand.NewSource(0x13377331)) chainID := big.NewInt(rng.Int63n(1000)) - londonSigner := types.NewLondonSigner(chainID) + isthmusSigner := types.NewIsthmusSigner(chainID) cases := []txTypeTest{ {"unprotected legacy tx", testutils.RandomLegacyTx, types.HomesteadSigner{}}, - {"legacy tx", testutils.RandomLegacyTx, londonSigner}, - {"access list tx", testutils.RandomAccessListTx, londonSigner}, - {"dynamic fee tx", testutils.RandomDynamicFeeTx, londonSigner}, + {"legacy tx", testutils.RandomLegacyTx, isthmusSigner}, + {"access list tx", testutils.RandomAccessListTx, isthmusSigner}, + {"dynamic fee tx", testutils.RandomDynamicFeeTx, isthmusSigner}, + {"setcode tx", testutils.RandomSetCodeTx, isthmusSigner}, } for _, testCase := range cases { @@ -473,13 +475,14 @@ func TestSpanBatchTxsRecoverVInvalidTxType(t *testing.T) { func TestSpanBatchTxsFullTxNotEnoughTxTos(t *testing.T) { rng := rand.New(rand.NewSource(0x13572468)) chainID := big.NewInt(rng.Int63n(1000)) - londonSigner := types.NewLondonSigner(chainID) + isthmusSigner := types.NewIsthmusSigner(chainID) cases := []txTypeTest{ {"unprotected legacy tx", testutils.RandomLegacyTx, types.HomesteadSigner{}}, - {"legacy tx", testutils.RandomLegacyTx, londonSigner}, - {"access list tx", testutils.RandomAccessListTx, londonSigner}, - {"dynamic fee tx", testutils.RandomDynamicFeeTx, londonSigner}, + {"legacy tx", testutils.RandomLegacyTx, isthmusSigner}, + {"access list tx", testutils.RandomAccessListTx, isthmusSigner}, + {"dynamic fee tx", testutils.RandomDynamicFeeTx, isthmusSigner}, + {"setcode tx", testutils.RandomSetCodeTx, isthmusSigner}, } for _, testCase := range cases { diff --git a/op-node/rollup/derive/test/random.go b/op-node/rollup/derive/test/random.go index c4e1b011ea6ea..8502855d01463 100644 --- a/op-node/rollup/derive/test/random.go +++ b/op-node/rollup/derive/test/random.go @@ -40,7 +40,7 @@ func RandomL2BlockWithChainId(rng *rand.Rand, txCount int, chainId *big.Int) *ty } func RandomL2BlockWithChainIdAndTime(rng *rand.Rand, txCount int, chainId *big.Int, t time.Time) *types.Block { - signer := types.NewLondonSigner(chainId) + signer := types.NewIsthmusSigner(chainId) block, _ := RandomL2Block(rng, 0, t) txs := []*types.Transaction{block.Transactions()[0]} // L1 info deposit TX for i := 0; i < txCount; i++ { diff --git a/op-service/testutils/random.go b/op-service/testutils/random.go index a18ad020d1f86..c7e37ef85ab16 100644 --- a/op-service/testutils/random.go +++ b/op-service/testutils/random.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" ) func RandomBool(rng *rand.Rand) bool { @@ -141,7 +142,7 @@ func RandomTo(rng *rand.Rand) *common.Address { } func RandomTx(rng *rand.Rand, baseFee *big.Int, signer types.Signer) *types.Transaction { - txTypeList := []int{types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType} + txTypeList := []int{types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.SetCodeTxType} txType := txTypeList[rng.Intn(len(txTypeList))] var tx *types.Transaction switch txType { @@ -151,6 +152,8 @@ func RandomTx(rng *rand.Rand, baseFee *big.Int, signer types.Signer) *types.Tran tx = RandomAccessListTx(rng, signer) case types.DynamicFeeTxType: tx = RandomDynamicFeeTxWithBaseFee(rng, baseFee, signer) + case types.SetCodeTxType: + tx = RandomSetCodeTx(rng, signer) default: panic("invalid tx type") } @@ -225,6 +228,49 @@ func RandomDynamicFeeTx(rng *rand.Rand, signer types.Signer) *types.Transaction return RandomDynamicFeeTxWithBaseFee(rng, baseFee, signer) } +func RandomSetCodeAuth(rng *rand.Rand) types.SetCodeAuthorization { + key := InsecureRandomKey(rng) + + auth := types.SetCodeAuthorization{ + ChainID: *uint256.MustFromHex("0x0"), + Address: RandomAddress(rng), + Nonce: rng.Uint64(), + } + + authSigned, err := types.SignSetCode(key, auth) + if err != nil { + panic(err) + } + + return authSigned +} + +func RandomSetCodeTx(rng *rand.Rand, signer types.Signer) *types.Transaction { + baseFee := new(big.Int).SetUint64(rng.Uint64()) + key := InsecureRandomKey(rng) + tip := big.NewInt(rng.Int63n(10 * params.GWei)) + to := RandomAddress(rng) + txData := &types.SetCodeTx{ + ChainID: uint256.MustFromBig(signer.ChainID()), + Nonce: rng.Uint64(), + GasTipCap: uint256.MustFromBig(tip), + GasFeeCap: uint256.MustFromBig(new(big.Int).Add(baseFee, tip)), + Gas: params.TxGas + uint64(rng.Int63n(2_000_000)), + To: to, + Value: uint256.MustFromBig(RandomETH(rng, 10)), + Data: RandomData(rng, rng.Intn(RandomDataSize)), + AccessList: nil, + AuthList: []types.SetCodeAuthorization{ + RandomSetCodeAuth(rng), + }, + } + tx, err := types.SignNewTx(key, signer, txData) + if err != nil { + panic(err) + } + return tx +} + func RandomReceipt(rng *rand.Rand, signer types.Signer, tx *types.Transaction, txIndex uint64, cumulativeGasUsed uint64) *types.Receipt { gasUsed := params.TxGas + uint64(rng.Int63n(int64(tx.Gas()-params.TxGas+1))) logs := make([]*types.Log, rng.Intn(10)) @@ -285,7 +331,7 @@ func RandomBlock(rng *rand.Rand, txCount uint64) (*types.Block, []*types.Receipt func RandomBlockPrependTxsWithTime(rng *rand.Rand, txCount int, t uint64, ptxs ...*types.Transaction) (*types.Block, []*types.Receipt) { header := RandomHeaderWithTime(rng, t) chainID := big.NewInt(rng.Int63n(1000)) - signer := types.NewLondonSigner(chainID) + signer := types.NewIsthmusSigner(chainID) txs := make([]*types.Transaction, 0, txCount+len(ptxs)) txs = append(txs, ptxs...) for i := 0; i < txCount; i++ {