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

Feature/transient storage opcodes #486

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions evmcore/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/params"

"github.com/Fantom-foundation/go-opera/inter"
"github.com/Fantom-foundation/go-opera/opera"
)

// BlockGen creates blocks for testing.
Expand Down Expand Up @@ -78,36 +77,45 @@ func (b *BlockGen) SetCoinbase(addr common.Address) {
// added. Notably, contract code relying on the BLOCKHASH instruction
// will panic during execution.
func (b *BlockGen) AddTx(tx *types.Transaction) {
b.AddTxWithChain(nil, tx)
b.addTx(nil, vm.Config{}, tx)
}

// AddTxWithChain adds a transaction to the generated block. If no coinbase has
// addTx adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address.
//
// AddTxWithChain panics if the transaction cannot be executed. In addition to
// the protocol-imposed limitations (gas limit, etc.), there are some
// further limitations on the content of transactions that can be
// added. If contract code relies on the BLOCKHASH instruction,
// the block in chain will be returned.
func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) {
// There are a few options can be passed as well in order to run some
// customized rules.
// - bc: enables the ability to query historical block hashes for BLOCKHASH
// - vmConfig: extends the flexibility for customizing evm rules, e.g. enable extra EIPs
func (b *BlockGen) addTx(bc DummyChain, vmConfig vm.Config, tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
msg, err := TxAsMessage(tx, types.MakeSigner(b.config, b.header.Number), b.header.BaseFee)
if err != nil {
panic(err)
}
b.statedb.Prepare(tx.Hash(), len(b.txs))
blockContext := NewEVMBlockContext(b.header, bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.config, opera.DefaultVMConfig)
receipt, _, _, err := applyTransaction(msg, b.config, b.gasPool, b.statedb, b.header.Number, b.header.Hash, tx, &b.header.GasUsed, vmenv, func(log *types.Log, db *state.StateDB) {})
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
if err != nil {
panic(err)
}
b.txs = append(b.txs, tx)
b.receipts = append(b.receipts, receipt)
}

// AddTxWithChain adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address.
//
// AddTxWithChain panics if the transaction cannot be executed. In addition to
// the protocol-imposed limitations (gas limit, etc.), there are some
// further limitations on the content of transactions that can be
// added. If contract code relies on the BLOCKHASH instruction,
// the block in chain will be returned.
func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) {
b.addTx(bc, vm.Config{}, tx)
}

func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) {
b.addTx(nil, config, tx)
}

// GetBalance returns the balance of the given address at the generated block.
func (b *BlockGen) GetBalance(addr common.Address) *big.Int {
return b.statedb.GetBalance(addr)
Expand Down
2 changes: 1 addition & 1 deletion evmcore/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (p *statePrefetcher) Prefetch(block *EvmBlock, statedb *state.StateDB, cfg
if err != nil {
return // Also invalid block, bail out
}
statedb.Prepare(tx.Hash(), i)
statedb.SetTxContext(tx.Hash(), i)
if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil {
return // Ugh, something went horribly wrong, bail out
}
Expand Down
18 changes: 17 additions & 1 deletion evmcore/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (p *StateProcessor) Process(
return nil, nil, nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}

statedb.Prepare(tx.Hash(), i)
statedb.SetTxContext(tx.Hash(), i)
receipt, _, skip, err = applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, onNewLog)
if skip {
skipped = append(skipped, uint32(i))
Expand Down Expand Up @@ -161,6 +161,22 @@ func applyTransaction(
return receipt, result.UsedGas, false, err
}

// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc DummyChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *EvmHeader, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
if err != nil {
return nil, err
}
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
receipt, _, _, err := applyTransaction(msg, config, gp, statedb, header.Number, header.Hash, tx, usedGas, vmenv, func(log *types.Log, db *state.StateDB) {})
return receipt, err
}

func TxAsMessage(tx *types.Transaction, signer types.Signer, baseFee *big.Int) (types.Message, error) {
if !internaltx.IsInternal(tx) {
return tx.AsMessage(signer, baseFee)
Expand Down
30 changes: 17 additions & 13 deletions evmcore/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ The state transitioning model does all the necessary work to work out a valid ne
3) Create a new state object if the recipient is \0*32
4) Value transfer
== If contract creation ==
4a) Attempt to run transaction data
4b) If valid, use result as code for the new state object

4a) Attempt to run transaction data
4b) If valid, use result as code for the new state object

== end ==
5) Run Script section
6) Derive new state root
Expand Down Expand Up @@ -232,13 +234,13 @@ func (st *StateTransition) internal() bool {
// TransitionDb will transition the state by applying the current message and
// returning the evm execution result with following fields.
//
// - used gas:
// total gas used (including gas being refunded)
// - returndata:
// the returned data from evm
// - concrete execution error:
// various **EVM** error which aborts the execution,
// e.g. ErrOutOfGas, ErrExecutionReverted
// - used gas:
// total gas used (including gas being refunded)
// - returndata:
// the returned data from evm
// - concrete execution error:
// various **EVM** error which aborts the execution,
// e.g. ErrOutOfGas, ErrExecutionReverted
//
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
Expand All @@ -261,6 +263,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}
msg := st.msg
sender := vm.AccountRef(msg.From())
//rules := st.evm.ChainConfig().Rules(st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber))
rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)
contractCreation := msg.To() == nil

london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber)
Expand All @@ -275,10 +279,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}
st.gas -= gas

// 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())
}
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())

var (
ret []byte
Expand Down