bsc/core/blockchain_eip3529_test.go
Mister-EA 1036dc70be
core: port several London EIPs on BSC(#1422)
Here is the list:
 a.BEP-227: Implement EIP-3198: BASEFEE opcode
 b.BEP-226: Implement EIP-1559 with base fee of 0
 c.BEP-228: Implement EIP-3541: Prevent deploying contracts starting with 0xEF
 d.BEP-212: Implement EIP-3529: Reduction in Refunds
2023-05-25 17:34:04 +08:00

166 lines
6.1 KiB
Go

package core
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
func postLondonConfig() *params.ChainConfig {
config := *params.TestChainConfig
config.LondonBlock = big.NewInt(0)
return &config
}
func preLondonConfig() *params.ChainConfig {
config := *params.TestChainConfig
config.LondonBlock = nil
return &config
}
func TestSelfDestructGasPreEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PC),
byte(vm.SELFDESTRUCT),
}
// Expected gas is (intrinsic + pc + cold load (due to legacy tx) + selfdestruct cost ) / 2
// The refund of 24000 gas (i.e. params.SelfdestructRefundGas) is not applied since refunds pre-EIP3529 are
// capped to half of the transaction's gas.
expectedGasUsed := (params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150) / 2
testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}
func TestSstoreGasPreEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x3, // location
byte(vm.SSTORE), // Set slot[3] = 3
}
// // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200
testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}
func TestSelfDestructGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PC),
byte(vm.SELFDESTRUCT),
}
// Expected gas is intrinsic + pc + cold load (due to legacy tx) + SelfDestructGas
expectedGasUsed := params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}
func TestSstoreGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x3, // location
byte(vm.SSTORE), // Set slot[3] = 3
}
// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}
func TestSstoreModifyGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x1, // location
byte(vm.SSTORE), // Set slot[1] = 3
}
// initialize contract storage
initialStorage := make(map[common.Hash]common.Hash)
// Populate two slots
initialStorage[common.HexToHash("01")] = common.HexToHash("01")
initialStorage[common.HexToHash("02")] = common.HexToHash("02")
// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0)
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929)
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsed)
}
func TestSstoreClearGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x0, // value
byte(vm.PUSH1), 0x1, // location
byte(vm.SSTORE), // Set slot[1] = 0
}
// initialize contract storage
initialStorage := make(map[common.Hash]common.Hash)
// Populate two slots
initialStorage[common.HexToHash("01")] = common.HexToHash("01")
initialStorage[common.HexToHash("02")] = common.HexToHash("02")
// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0) - sstoreClearGasRefund
expectedGasUsage := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.SstoreClearsScheduleRefundEIP3529
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsage)
}
// Test the gas used by running a transaction sent to a smart contract with given bytecode and storage.
func testGasUsage(t *testing.T, config *params.ChainConfig, engine consensus.Engine, bytecode []byte, initialStorage map[common.Hash]common.Hash, initialGas, expectedGasUsed uint64) {
var (
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
// Generate a canonical chain to act as the main dataset
db = rawdb.NewMemoryDatabase()
// A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
balanceBefore = big.NewInt(1000000000000000)
gspec = &Genesis{
Config: config,
Alloc: GenesisAlloc{
address: {Balance: balanceBefore},
aa: {
Code: bytecode,
Storage: initialStorage,
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
genesis = gspec.MustCommit(db)
)
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})
// One transaction to 0xAAAA
signer := types.LatestSigner(gspec.Config)
tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{
Nonce: 0,
To: &aa,
Gas: initialGas,
GasPrice: newGwei(5),
})
b.AddTx(tx)
})
// Import the canonical chain
diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, 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)
}
block := chain.GetBlockByNumber(1)
if block.GasUsed() != expectedGasUsed {
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGasUsed, block.GasUsed())
}
}