Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge scroll v3.2.0 #1

Merged
merged 8 commits into from
May 19, 2023
12 changes: 12 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## 1. Purpose or design rationale of this PR

...


## 2. Deployment tag versioning

Has the version in `params/version.go` been updated?

- [ ] This PR doesn't involve a new deployment, git tag, docker image tag, and it doesn't affect traces
- [ ] Yes

6 changes: 5 additions & 1 deletion cmd/evm/internal/t8ntool/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func Transaction(ctx *cli.Context) error {
}
// Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil {
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil {
r.Error = err
results = append(results, r)
continue
Expand Down Expand Up @@ -172,6 +172,10 @@ func Transaction(ctx *cli.Context) error {
case new(big.Int).Mul(tx.GasFeeCap(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256:
r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits")
}
// Check whether the init code size has been exceeded.
if chainConfig.IsShanghai(new(big.Int)) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
r.Error = errors.New("max initcode size exceeded")
}
results = append(results, r)
}
out, err := json.MarshalIndent(results, "", " ")
Expand Down
2 changes: 1 addition & 1 deletion core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, nil, false, false, false)
gas, _ := IntrinsicGas(data, nil, false, false, false, false)
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)))
gasPrice := big.NewInt(0)
if gen.header.BaseFee != nil {
Expand Down
115 changes: 115 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3238,3 +3238,118 @@ func TestTransactionCountLimit(t *testing.T) {
t.Fatalf("error mismatch: have: %v, want: %v", err, consensus.ErrInvalidTxCount)
}
}

func TestEIP3651(t *testing.T) {
var (
addraa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
addrbb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
engine = ethash.NewFaker()
db = rawdb.NewMemoryDatabase()

// A sender who makes transactions, has some funds
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
gspec = &Genesis{
Config: params.AllEthashProtocolChanges,
Alloc: GenesisAlloc{
addr1: {Balance: funds},
addr2: {Balance: funds},
// The address 0xAAAA sloads 0x00 and 0x01
addraa: {
Code: []byte{
byte(vm.PC),
byte(vm.PC),
byte(vm.SLOAD),
byte(vm.SLOAD),
},
Nonce: 0,
Balance: big.NewInt(0),
},
// The address 0xBBBB calls 0xAAAA
addrbb: {
Code: []byte{
byte(vm.PUSH1), 0, // out size
byte(vm.DUP1), // out offset
byte(vm.DUP1), // out insize
byte(vm.DUP1), // in offset
byte(vm.PUSH2), // address
byte(0xaa),
byte(0xaa),
byte(vm.GAS), // gas
byte(vm.DELEGATECALL),
},
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
genesis = gspec.MustCommit(db)
)

gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0
gspec.Config.ShanghaiBlock = common.Big0
signer := types.LatestSigner(gspec.Config)

blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
b.SetCoinbase(addraa)
// One transaction to Coinbase
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 0,
To: &addrbb,
Gas: 500000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: nil,
Data: []byte{},
}
tx := types.NewTx(txdata)
tx, err := types.SignTx(tx, signer, key1)
if err != nil {
t.Fatalf("failed to sign tx: %v", err)
}
b.AddTx(tx)
})
chain, err := NewBlockChain(db, 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)

// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2
expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list
if block.GasUsed() != expectedGas {
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
}

state, err := chain.State()
if err != nil {
t.Fatalf("failed to get new state: %v", err)
}

// 3: Ensure that miner received only the tx's tip.
actual := state.GetBalance(block.Coinbase())
expected := new(big.Int).Add(
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
ethash.ConstantinopleBlockReward,
)
if actual.Cmp(expected) != 0 {
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
}

// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
if actual.Cmp(expected) != 0 {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
}
4 changes: 4 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ var (
// have enough funds for transfer(topmost call only).
ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer")

// ErrMaxInitCodeSizeExceeded is returned if creation transaction provides the init code bigger
// than init code size limit.
ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded")

// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
Expand Down
9 changes: 7 additions & 2 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/rlp"
"github.com/scroll-tech/go-ethereum/trie"
)
Expand Down Expand Up @@ -1018,15 +1019,16 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
}

// PrepareAccessList handles the preparatory steps for executing a state transition with
// regards to both EIP-2929 and EIP-2930:
// regards to EIP-2929, EIP-2930 and EIP-3651:
//
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
// - Add coinbase to access list (3651)
//
// This method should only be called if Berlin/2929+2930 is applicable at the current number.
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
func (s *StateDB) PrepareAccessList(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
s.AddAddressToAccessList(sender)
if dst != nil {
s.AddAddressToAccessList(*dst)
Expand All @@ -1041,6 +1043,9 @@ func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address,
s.AddSlotToAccessList(el.Address, key)
}
}
if rules.IsShanghai { // EIP-3651: warm coinbase
s.AddAddressToAccessList(coinbase)
}
}

// AddAddressToAccessList adds the given address to the access list
Expand Down
75 changes: 75 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func TestStateProcessorErrors(t *testing.T) {
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ShanghaiBlock: big.NewInt(0),
Ethash: new(params.EthashConfig),
}
signer = types.LatestSigner(config)
Expand All @@ -76,6 +77,17 @@ func TestStateProcessorErrors(t *testing.T) {
}), signer, key1)
return tx
}
var mkDynamicCreationTx = func(nonce uint64, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, data []byte) *types.Transaction {
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
Nonce: nonce,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Gas: gasLimit,
Value: big.NewInt(0),
Data: data,
}), signer, key1)
return tx
}
{ // Tests against a 'recent' chain definition
var (
db = rawdb.NewMemoryDatabase()
Expand Down Expand Up @@ -298,6 +310,69 @@ func TestStateProcessorErrors(t *testing.T) {
}
}
}

// ErrMaxInitCodeSizeExceeded, for this we need extra Shanghai (EIP-3860) enabled.
{
var (
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{
Config: &params.ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
ArchimedesBlock: big.NewInt(0),
ShanghaiBlock: big.NewInt(0),
},
Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
},
},
}
genesis = gspec.MustCommit(db)
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
smallInitCode = [320]byte{}
)
defer blockchain.Stop()
for i, tt := range []struct {
txs []*types.Transaction
want string
}{
{ // ErrMaxInitCodeSizeExceeded
txs: []*types.Transaction{
mkDynamicCreationTx(0, 500000, common.Big0, misc.CalcBaseFee(config, genesis.Header()), tooBigInitCode[:]),
},
want: "could not apply tx 0 [0x7b33776d375660694a23ef992c090265682f3687607e0099b14503fdb65d73e3]: max initcode size exceeded: code size 49153 limit 49152",
},
{ // ErrIntrinsicGas: Not enough gas to cover init code
txs: []*types.Transaction{
mkDynamicCreationTx(0, 54299, common.Big0, misc.CalcBaseFee(config, genesis.Header()), smallInitCode[:]),
},
want: "could not apply tx 0 [0x98e54c5ecfa7986a66480d65ba32f2c6a2a6aedc3a67abb91b1e118b0717ed2d]: intrinsic gas too low: have 54299, want 54300",
},
} {
block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config)
_, err := blockchain.InsertChain(types.Blocks{block})
if err == nil {
t.Fatal("block imported without errors")
}
if have, want := err.Error(), tt.want; have != want {
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
}
}
}
}

// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
Expand Down
39 changes: 33 additions & 6 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,17 @@ func (result *ExecutionResult) Revert() []byte {
}

// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
if isContractCreation && isHomestead {
gas = params.TxGasContractCreation
} else {
gas = params.TxGas
}
dataLen := uint64(len(data))
// Bump the required gas by the amount of transactional data
if len(data) > 0 {
if dataLen > 0 {
// Zero and non-zero bytes are priced differently
var nz uint64
for _, byt := range data {
Expand All @@ -149,11 +150,19 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
}
gas += nz * nonZeroGas

z := uint64(len(data)) - nz
z := dataLen - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
return 0, ErrGasUintOverflow
}
gas += z * params.TxDataZeroGas

if isContractCreation && isEIP3860 {
lenWords := toWordSize(dataLen)
if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords {
return 0, ErrGasUintOverflow
}
gas += lenWords * params.InitCodeWordGas
}
}
if accessList != nil {
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
Expand All @@ -162,6 +171,15 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
return gas, nil
}

// toWordSize returns the ceiled word size required for init code payment calculation.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
return math.MaxUint64/32 + 1
}

return (size + 31) / 32
}

// NewStateTransition initialises and returns a new state transition object.
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
l1Fee := new(big.Int)
Expand Down Expand Up @@ -327,11 +345,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber)
shanghai := st.evm.ChainConfig().IsShanghai(st.evm.Context.BlockNumber)
london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber)
contractCreation := msg.To() == nil

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul, shanghai)
if err != nil {
return nil, err
}
Expand All @@ -345,10 +364,18 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
}

rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)

// Check whether the init code size has been exceeded.
if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize {
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
}

// Set up the initial access list.
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
if rules.IsBerlin {
st.state.PrepareAccessList(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
}

var (
ret []byte
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
Expand Down
Loading