diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index ca79d7a004..7941e9724b 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -415,16 +415,17 @@ func TestTransactionByHash(t *testing.T) { func TestEstimateGas(t *testing.T) { /* - pragma solidity ^0.6.4; + pragma solidity =0.6.12; contract GasEstimation { function PureRevert() public { revert(); } function Revert() public { revert("revert reason");} function OOG() public { for (uint i = 0; ; i++) {}} function Assert() public { assert(false);} + function SelfDestruct() public { selfdestruct(msg.sender); } function Valid() public {} }*/ - const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" - const contractBin = "0x60806040523480156100115760006000fd5b50610017565b61016e806100266000396000f3fe60806040523480156100115760006000fd5b506004361061005c5760003560e01c806350f6fe3414610062578063aa8b1d301461006c578063b9b046f914610076578063d8b9839114610080578063e09fface1461008a5761005c565b60006000fd5b61006a610094565b005b6100746100ad565b005b61007e6100b5565b005b6100886100c2565b005b610092610135565b005b6000600090505b5b808060010191505061009b565b505b565b60006000fd5b565b600015156100bf57fe5b5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f72657665727420726561736f6e0000000000000000000000000000000000000081526020015060200191505060405180910390fd5b565b5b56fea2646970667358221220345bbcbb1a5ecf22b53a78eaebf95f8ee0eceff6d10d4b9643495084d2ec934a64736f6c63430006040033" + const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SelfDestruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + const contractBin = "0x608060405234801561001057600080fd5b50610181806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806350f6fe3414610067578063aa8b1d3014610071578063b9b046f91461007b578063d8b9839114610085578063dba5e9171461008f578063e09fface14610099575b600080fd5b61006f6100a3565b005b6100796100b3565b005b6100836100b8565b005b61008d6100c2565b005b610097610130565b005b6100a1610149565b005b60005b80806001019150506100a6565b600080fd5b60006100c057fe5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f72657665727420726561736f6e0000000000000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff16ff5b56fea2646970667358221220381c1672ed4be389ed2337c96f8e2fccf83479ec05cb9dd10362e8819e7ca38f64736f6c634300060c0033" key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) @@ -498,6 +499,15 @@ func TestEstimateGas(t *testing.T) { Data: common.Hex2Bytes("b9b046f9"), }, 0, errors.New("invalid opcode: INVALID"), nil}, + {"SelfDestruct", ethereum.CallMsg{ + From: addr, + To: &contractAddr, + Gas: 100000, + GasPrice: big.NewInt(0), + Value: nil, + Data: common.Hex2Bytes("dba5e917"), + }, 0, errors.New("invalid opcode: SELFDESTRUCT"), nil}, + {"Valid", ethereum.CallMsg{ From: addr, To: &contractAddr, @@ -505,7 +515,7 @@ func TestEstimateGas(t *testing.T) { GasPrice: big.NewInt(0), Value: nil, Data: common.Hex2Bytes("e09fface"), - }, 21275, nil, nil}, + }, 21296, nil, nil}, } for _, c := range cases { got, err := sim.EstimateGas(context.Background(), c.message) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 4aca8e4bca..6f7ebdb227 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2511,6 +2511,52 @@ func TestSideImportPrunedBlocks(t *testing.T) { } } +// TestSelfDestructDisabled +// If a transaction's execution triggers SELFDESTRUCT, it will fail. +func TestSelfDestructDisabled(t *testing.T) { + var ( + // Generate a canonical chain to act as the main dataset + engine = ethash.NewFaker() + db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + + aa = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f43") + aaStorage = make(map[common.Hash]common.Hash) // Initial storage in AA + aaCode = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) + ) + + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + // The address 0xAAAAA selfdestructs if called + aa: { + // Code needs to just selfdestruct + Code: aaCode, + Nonce: 1, + Balance: big.NewInt(0), + Storage: aaStorage, + }, + }, + } + genesis := gspec.MustCommit(db) + + _, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + // One transaction to AA, to kill it + tx, _ := types.SignTx(types.NewTransaction(0, aa, + big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) + b.AddTx(tx) + }) + + if receipts[0][0].Status != types.ReceiptStatusFailed { + t.Fatalf("Expected transaction triggering SELFDESTRUCT to fail") + } +} + // TestDeleteCreateRevert tests a weird state transition corner case that we hit // while changing the internals of statedb. The workflow is that a contract is // self destructed, then in a followup transaction (but same block) it's created @@ -2586,402 +2632,6 @@ func TestDeleteCreateRevert(t *testing.T) { } } -// TestDeleteRecreateSlots tests a state-transition that contains both deletion -// and recreation of contract state. -// Contract A exists, has slots 1 and 2 set -// Tx 1: Selfdestruct A -// Tx 2: Re-create A, set slots 3 and 4 -// Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, -// and then the new slots exist -func TestDeleteRecreateSlots(t *testing.T) { - var ( - // Generate a canonical chain to act as the main dataset - engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() - // A sender who makes transactions, has some funds - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000000000) - bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") - aaStorage = make(map[common.Hash]common.Hash) // Initial storage in AA - aaCode = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) - ) - // Populate two slots - aaStorage[common.HexToHash("01")] = common.HexToHash("01") - aaStorage[common.HexToHash("02")] = common.HexToHash("02") - - // The bb-code needs to CREATE2 the aa contract. It consists of - // both initcode and deployment code - // initcode: - // 1. Set slots 3=3, 4=4, - // 2. Return aaCode - - initCode := []byte{ - byte(vm.PUSH1), 0x3, // value - byte(vm.PUSH1), 0x3, // location - byte(vm.SSTORE), // Set slot[3] = 1 - byte(vm.PUSH1), 0x4, // value - byte(vm.PUSH1), 0x4, // location - byte(vm.SSTORE), // Set slot[4] = 1 - // Slots are set, now return the code - byte(vm.PUSH2), byte(vm.PC), byte(vm.SELFDESTRUCT), // Push code on stack - byte(vm.PUSH1), 0x0, // memory start on stack - byte(vm.MSTORE), - // Code is now in memory. - byte(vm.PUSH1), 0x2, // size - byte(vm.PUSH1), byte(32 - 2), // offset - byte(vm.RETURN), - } - if l := len(initCode); l > 32 { - t.Fatalf("init code is too long for a pushx, need a more elaborate deployer") - } - bbCode := []byte{ - // Push initcode onto stack - byte(vm.PUSH1) + byte(len(initCode)-1)} - bbCode = append(bbCode, initCode...) - bbCode = append(bbCode, []byte{ - byte(vm.PUSH1), 0x0, // memory start on stack - byte(vm.MSTORE), - byte(vm.PUSH1), 0x00, // salt - byte(vm.PUSH1), byte(len(initCode)), // size - byte(vm.PUSH1), byte(32 - len(initCode)), // offset - byte(vm.PUSH1), 0x00, // endowment - byte(vm.CREATE2), - }...) - - initHash := crypto.Keccak256Hash(initCode) - aa := crypto.CreateAddress2(bb, [32]byte{}, initHash[:]) - t.Logf("Destination address: %x\n", aa) - - gspec := &Genesis{ - Config: params.TestChainConfig, - Alloc: GenesisAlloc{ - address: {Balance: funds}, - // The address 0xAAAAA selfdestructs if called - aa: { - // Code needs to just selfdestruct - Code: aaCode, - Nonce: 1, - Balance: big.NewInt(0), - Storage: aaStorage, - }, - // The contract BB recreates AA - bb: { - Code: bbCode, - Balance: big.NewInt(1), - }, - }, - } - genesis := gspec.MustCommit(db) - - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { - b.SetCoinbase(common.Address{1}) - // One transaction to AA, to kill it - tx, _ := types.SignTx(types.NewTransaction(0, aa, - big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - b.AddTx(tx) - // One transaction to BB, to recreate AA - tx, _ = types.SignTx(types.NewTransaction(1, bb, - big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - b.AddTx(tx) - }) - // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ - Debug: true, - Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - if n, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", n, err) - } - statedb, _ := chain.State() - - // If all is correct, then slot 1 and 2 are zero - if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { - t.Errorf("got %x exp %x", got, exp) - } - if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { - t.Errorf("got %x exp %x", got, exp) - } - // Also, 3 and 4 should be set - if got, exp := statedb.GetState(aa, common.HexToHash("03")), common.HexToHash("03"); got != exp { - t.Fatalf("got %x exp %x", got, exp) - } - if got, exp := statedb.GetState(aa, common.HexToHash("04")), common.HexToHash("04"); got != exp { - t.Fatalf("got %x exp %x", got, exp) - } -} - -// TestDeleteRecreateAccount tests a state-transition that contains deletion of a -// contract with storage, and a recreate of the same contract via a -// regular value-transfer -// Expected outcome is that _all_ slots are cleared from A -func TestDeleteRecreateAccount(t *testing.T) { - var ( - // Generate a canonical chain to act as the main dataset - engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() - // A sender who makes transactions, has some funds - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000000000) - - aa = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f43") - aaStorage = make(map[common.Hash]common.Hash) // Initial storage in AA - aaCode = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) - ) - // Populate two slots - aaStorage[common.HexToHash("01")] = common.HexToHash("01") - aaStorage[common.HexToHash("02")] = common.HexToHash("02") - - gspec := &Genesis{ - Config: params.TestChainConfig, - Alloc: GenesisAlloc{ - address: {Balance: funds}, - // The address 0xAAAAA selfdestructs if called - aa: { - // Code needs to just selfdestruct - Code: aaCode, - Nonce: 1, - Balance: big.NewInt(0), - Storage: aaStorage, - }, - }, - } - genesis := gspec.MustCommit(db) - - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { - b.SetCoinbase(common.Address{1}) - // One transaction to AA, to kill it - tx, _ := types.SignTx(types.NewTransaction(0, aa, - big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - b.AddTx(tx) - // One transaction to AA, to recreate it (but without storage - tx, _ = types.SignTx(types.NewTransaction(1, aa, - big.NewInt(1), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - b.AddTx(tx) - }) - // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ - Debug: true, - Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - if n, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", n, err) - } - statedb, _ := chain.State() - - // If all is correct, then both slots are zero - if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { - t.Errorf("got %x exp %x", got, exp) - } - if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { - t.Errorf("got %x exp %x", got, exp) - } -} - -// TestDeleteRecreateSlotsAcrossManyBlocks tests multiple state-transition that contains both deletion -// and recreation of contract state. -// Contract A exists, has slots 1 and 2 set -// Tx 1: Selfdestruct A -// Tx 2: Re-create A, set slots 3 and 4 -// Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, -// and then the new slots exist -func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { - var ( - // Generate a canonical chain to act as the main dataset - engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() - // A sender who makes transactions, has some funds - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000000000) - bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") - aaStorage = make(map[common.Hash]common.Hash) // Initial storage in AA - aaCode = []byte{byte(vm.PC), byte(vm.SELFDESTRUCT)} // Code for AA (simple selfdestruct) - ) - // Populate two slots - aaStorage[common.HexToHash("01")] = common.HexToHash("01") - aaStorage[common.HexToHash("02")] = common.HexToHash("02") - - // The bb-code needs to CREATE2 the aa contract. It consists of - // both initcode and deployment code - // initcode: - // 1. Set slots 3=blocknum+1, 4=4, - // 2. Return aaCode - - initCode := []byte{ - byte(vm.PUSH1), 0x1, // - byte(vm.NUMBER), // value = number + 1 - byte(vm.ADD), // - byte(vm.PUSH1), 0x3, // location - byte(vm.SSTORE), // Set slot[3] = number + 1 - byte(vm.PUSH1), 0x4, // value - byte(vm.PUSH1), 0x4, // location - byte(vm.SSTORE), // Set slot[4] = 4 - // Slots are set, now return the code - byte(vm.PUSH2), byte(vm.PC), byte(vm.SELFDESTRUCT), // Push code on stack - byte(vm.PUSH1), 0x0, // memory start on stack - byte(vm.MSTORE), - // Code is now in memory. - byte(vm.PUSH1), 0x2, // size - byte(vm.PUSH1), byte(32 - 2), // offset - byte(vm.RETURN), - } - if l := len(initCode); l > 32 { - t.Fatalf("init code is too long for a pushx, need a more elaborate deployer") - } - bbCode := []byte{ - // Push initcode onto stack - byte(vm.PUSH1) + byte(len(initCode)-1)} - bbCode = append(bbCode, initCode...) - bbCode = append(bbCode, []byte{ - byte(vm.PUSH1), 0x0, // memory start on stack - byte(vm.MSTORE), - byte(vm.PUSH1), 0x00, // salt - byte(vm.PUSH1), byte(len(initCode)), // size - byte(vm.PUSH1), byte(32 - len(initCode)), // offset - byte(vm.PUSH1), 0x00, // endowment - byte(vm.CREATE2), - }...) - - initHash := crypto.Keccak256Hash(initCode) - aa := crypto.CreateAddress2(bb, [32]byte{}, initHash[:]) - t.Logf("Destination address: %x\n", aa) - gspec := &Genesis{ - Config: params.TestChainConfig, - Alloc: GenesisAlloc{ - address: {Balance: funds}, - // The address 0xAAAAA selfdestructs if called - aa: { - // Code needs to just selfdestruct - Code: aaCode, - Nonce: 1, - Balance: big.NewInt(0), - Storage: aaStorage, - }, - // The contract BB recreates AA - bb: { - Code: bbCode, - Balance: big.NewInt(1), - }, - }, - } - genesis := gspec.MustCommit(db) - var nonce uint64 - - type expectation struct { - exist bool - blocknum int - values map[int]int - } - var current = &expectation{ - exist: true, // exists in genesis - blocknum: 0, - values: map[int]int{1: 1, 2: 2}, - } - var expectations []*expectation - var newDestruct = func(e *expectation, b *BlockGen) *types.Transaction { - tx, _ := types.SignTx(types.NewTransaction(nonce, aa, - big.NewInt(0), 50000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - nonce++ - if e.exist { - e.exist = false - e.values = nil - } - t.Logf("block %d; adding destruct\n", e.blocknum) - return tx - } - var newResurrect = func(e *expectation, b *BlockGen) *types.Transaction { - tx, _ := types.SignTx(types.NewTransaction(nonce, bb, - big.NewInt(0), 100000, b.header.BaseFee, nil), types.HomesteadSigner{}, key) - nonce++ - if !e.exist { - e.exist = true - e.values = map[int]int{3: e.blocknum + 1, 4: 4} - } - t.Logf("block %d; adding resurrect\n", e.blocknum) - return tx - } - - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 150, func(i int, b *BlockGen) { - var exp = new(expectation) - exp.blocknum = i + 1 - exp.values = make(map[int]int) - for k, v := range current.values { - exp.values[k] = v - } - exp.exist = current.exist - - b.SetCoinbase(common.Address{1}) - if i%2 == 0 { - b.AddTx(newDestruct(exp, b)) - } - if i%3 == 0 { - b.AddTx(newResurrect(exp, b)) - } - if i%5 == 0 { - b.AddTx(newDestruct(exp, b)) - } - if i%7 == 0 { - b.AddTx(newResurrect(exp, b)) - } - expectations = append(expectations, exp) - current = exp - }) - // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ - //Debug: true, - //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - var asHash = func(num int) common.Hash { - return common.BytesToHash([]byte{byte(num)}) - } - for i, block := range blocks { - blockNum := i + 1 - if n, err := chain.InsertChain([]*types.Block{block}); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", n, err) - } - statedb, _ := chain.State() - // If all is correct, then slot 1 and 2 are zero - if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { - t.Errorf("block %d, got %x exp %x", blockNum, got, exp) - } - if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { - t.Errorf("block %d, got %x exp %x", blockNum, got, exp) - } - exp := expectations[i] - if exp.exist { - if !statedb.Exist(aa) { - t.Fatalf("block %d, expected %v to exist, it did not", blockNum, aa) - } - for slot, val := range exp.values { - if gotValue, expValue := statedb.GetState(aa, asHash(slot)), asHash(val); gotValue != expValue { - t.Fatalf("block %d, slot %d, got %x exp %x", blockNum, slot, gotValue, expValue) - } - } - } else { - if statedb.Exist(aa) { - t.Fatalf("block %d, expected %v to not exist, it did", blockNum, aa) - } - } - } -} - // TestInitThenFailCreateContract tests a pretty notorious case that happened // on mainnet over blocks 7338108, 7338110 and 7338115. // - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated diff --git a/core/vm/eips.go b/core/vm/eips.go index 0af12970ca..a3acfbe999 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -142,10 +142,9 @@ func enable2929(jt *JumpTable) { jt[DELEGATECALL].constantGas = params.WarmStorageReadCostEIP2929 jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP2929 - // This was previously part of the dynamic cost, but we're using it as a constantGas - // factor here - jt[SELFDESTRUCT].constantGas = params.SelfdestructGasEIP150 - jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP2929 + // SELFDESTRUCT is disabled in Scroll + // jt[SELFDESTRUCT].constantGas = params.SelfdestructGasEIP150 + // jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP2929 } // enable3529 enabled "EIP-3529: Reduction in refunds": @@ -154,7 +153,9 @@ func enable2929(jt *JumpTable) { // - Reduces max refunds to 20% gas func enable3529(jt *JumpTable) { jt[SSTORE].dynamicGas = gasSStoreEIP3529 - jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP3529 + + // SELFDESTRUCT is disabled in Scroll + // jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP3529 } // enable3198 applies EIP-3198 (BASEFEE Opcode) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 6ebd8b2ec8..8d985e3ac5 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -416,26 +416,3 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo } return gas, nil } - -func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var gas uint64 - // EIP150 homestead gas reprice fork: - if evm.chainRules.IsEIP150 { - gas = params.SelfdestructGasEIP150 - var address = common.Address(stack.Back(0).Bytes20()) - - if evm.chainRules.IsEIP158 { - // if empty and transfers value - if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { - gas += params.CreateBySelfdestructGas - } - } else if !evm.StateDB.Exist(address) { - gas += params.CreateBySelfdestructGas - } - } - - if !evm.StateDB.HasSuicided(contract.Address()) { - evm.StateDB.AddRefund(params.SelfdestructRefundGas) - } - return gas, nil -} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 00288eaac7..1b319cc1a0 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -787,18 +787,6 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt return nil, nil } -func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - beneficiary := scope.Stack.pop() - balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) - interpreter.evm.StateDB.Suicide(scope.Contract.Address()) - if interpreter.cfg.Debug { - interpreter.cfg.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil) - } - return nil, nil -} - // following functions are used by the instruction jump table // make log instruction function diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 6933549f8b..526a5a0a2d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -1021,13 +1021,8 @@ func newFrontierInstructionSet() JumpTable { memorySize: memoryReturn, halts: true, }, - SELFDESTRUCT: { - execute: opSuicide, - dynamicGas: gasSelfdestruct, - minStack: minStack(1, 0), - maxStack: maxStack(1, 0), - halts: true, - writes: true, - }, + // SELFDESTRUCT is disabled in Scroll. + // SELFDESTRUCT has the same behavior as INVALID. + SELFDESTRUCT: nil, } } diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index ae70d79243..3dbccbd97c 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -196,9 +196,6 @@ var ( gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929(gasDelegateCall) gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall) gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode) - gasSelfdestructEIP2929 = makeSelfdestructGasFn(true) - // gasSelfdestructEIP3529 implements the changes in EIP-2539 (no refunds) - gasSelfdestructEIP3529 = makeSelfdestructGasFn(false) // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929 // @@ -218,27 +215,3 @@ var ( // Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800) gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529) ) - -// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-2539 -func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { - gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var ( - gas uint64 - address = common.Address(stack.peek().Bytes20()) - ) - if !evm.StateDB.AddressInAccessList(address) { - // If the caller cannot afford the cost, this change will be rolled back - evm.StateDB.AddAddressToAccessList(address) - gas = params.ColdAccountAccessCostEIP2929 - } - // if empty and transfers value - if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { - gas += params.CreateBySelfdestructGas - } - if refundsEnabled && !evm.StateDB.HasSuicided(contract.Address()) { - evm.StateDB.AddRefund(params.SelfdestructRefundGas) - } - return gas, nil - } - return gasFunc -}