Skip to content

Commit

Permalink
consortium-v2: prepare access list and transient storage in system tr…
Browse files Browse the repository at this point in the history
…ansaction (#509)

* consortium-v2: prepare access list and transient storage in system transaction

In 5768525 ("core/state: remove newAccessList in SetTxContext"), we remove the
access list reset in SetTxContext because later in statedb.Prepare we already
reset the list. However, system transaction does not call to statedb.Prepare
before processing transaction. This results in a consensus breaking change. This
commit create a new access list reset function and adds to system transaction
path to fix the issue. Moreover, we add the statedb.Prepare call to system
transaction path after Shanghai to make EIP-3651: warm coinbase and EIP-1153 -
Transient storage opcodes work correctly in system transaction.

* consortium-v2: add access list and transient storage test for system transaction
  • Loading branch information
minh-bq authored Aug 16, 2024
1 parent 71f207d commit c004b7d
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
8 changes: 8 additions & 0 deletions consensus/consortium/common/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,14 @@ func applyMessage(
// Create a new context to be used in the EVM environment
opts.EVMContext.CurrentTransaction = tx
from, _ := types.Sender(types.MakeSigner(opts.ChainConfig, opts.Header.Number), tx)

chainRules := opts.ChainConfig.Rules(opts.Header.Number)
if chainRules.IsShanghai {
opts.State.Prepare(chainRules, from, from, tx.To(), vm.ActivePrecompiles(chainRules), nil)
} else if chainRules.IsBerlin {
opts.State.ResetAccessList()
}

// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(*opts.EVMContext, vm.TxContext{Origin: from, GasPrice: big.NewInt(0)}, opts.State, opts.ChainConfig, vm.Config{})
Expand Down
95 changes: 95 additions & 0 deletions consensus/consortium/common/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"reflect"
"testing"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
legacyProfile "github.com/ethereum/go-ethereum/consensus/consortium/generated_contracts/legacy_profile"
"github.com/ethereum/go-ethereum/consensus/consortium/generated_contracts/profile"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"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"
)
Expand Down Expand Up @@ -292,3 +294,96 @@ func TestContractCall(t *testing.T) {
}
}
}

func TestApplyTransaction(t *testing.T) {
minerKey, _ := crypto.GenerateKey()
minerAddr := crypto.PubkeyToAddress(minerKey.PublicKey)

chainId := big.NewInt(2020)
signer := types.NewMikoSigner(chainId)
chainConfig := params.ChainConfig{
ChainID: chainId,
ByzantiumBlock: common.Big0,
BerlinBlock: common.Big0,
}
tx, err := types.SignNewTx(minerKey, signer, &types.LegacyTx{
To: &common.Address{0x22},
})
if err != nil {
t.Fatal(err)
}
msg := types.NewMessage(minerAddr, tx.To(), tx.Nonce(), tx.Value(), tx.Gas(),
tx.GasPrice(), tx.GasFeeCap(), tx.GasTipCap(), tx.Data(), nil, false)

state, err := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
if err != nil {
t.Fatal(err)
}
dummyAccount := common.Address{0x11}
state.AddAddressToAccessList(dummyAccount)

var (
txs []*types.Transaction
receipts []*types.Receipt
)
opts := ApplyTransactOpts{
ApplyMessageOpts: &ApplyMessageOpts{
Header: &types.Header{
Coinbase: minerAddr,
Number: common.Big0,
},
EVMContext: &vm.BlockContext{
Transfer: func(_ vm.StateDB, _, _ common.Address, _ *big.Int) {},
},
State: state,
ChainConfig: &chainConfig,
},
Signer: signer,
SignTxFn: func(_ accounts.Account, tx *types.Transaction, chainId *big.Int) (*types.Transaction, error) {
return types.SignTx(tx, signer, minerKey)
},
Mining: true,
UsedGas: new(uint64),
Txs: &txs,
Receipts: &receipts,
}
err = ApplyTransaction(msg, &opts)
if err != nil {
t.Fatalf("Failed to apply transaction, err %v", err)
}

if state.AddressInAccessList(dummyAccount) {
t.Fatalf("Expect the access list to be reset after Berlin")
}

state.AddAddressToAccessList(dummyAccount)
dummyKey := common.Hash{0x33}
state.SetTransientState(dummyAccount, dummyKey, common.Hash{0x44})
chainConfig.ShanghaiBlock = common.Big0
err = ApplyTransaction(msg, &opts)
if err != nil {
t.Fatalf("Failed to apply transaction, err %v", err)
}

if state.AddressInAccessList(dummyAccount) {
t.Fatalf("Expect the access list to be reset after Berlin")
}

if state.GetTransientState(dummyAccount, dummyKey) != (common.Hash{}) {
t.Fatalf("Expect the transient state to be reset")
}

if !state.AddressInAccessList(minerAddr) {
t.Fatalf("Expect sender to be in the access list after Shanghai")
}

if !state.AddressInAccessList(*tx.To()) {
t.Fatalf("Expect recipient to be in the access list after Shanghai")
}

for _, addr := range vm.ActivePrecompiles(chainConfig.Rules(common.Big0)) {
if !state.AddressInAccessList(addr) {
t.Fatalf("Expect precompile %v to be in the access list after Shanghai", addr)
}
}
}
5 changes: 5 additions & 0 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
return root, err
}

// ResetAccessList sets access list to empty
func (s *StateDB) ResetAccessList() {
s.accessList = newAccessList()
}

// Prepare handles the preparatory steps for executing a state transition with.
// This method must be invoked before state transition.
//
Expand Down

0 comments on commit c004b7d

Please sign in to comment.