Merge tag 'v1.10.5' into plugeth

This commit is contained in:
Austin Roberts
2021-07-14 08:46:10 -05:00
97 changed files with 2055 additions and 791 deletions
+1 -1
View File
@@ -102,7 +102,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
b.statedb.Prepare(tx.Hash(), len(b.txs))
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
if err != nil {
panic(err)
+6 -4
View File
@@ -61,8 +61,10 @@ func TestCreation(t *testing.T) {
{9199999, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block
{9200000, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block
{12243999, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block
{12244000, ID{Hash: checksumToBytes(0x0eb440f6), Next: 0}}, // First Berlin block
{20000000, ID{Hash: checksumToBytes(0x0eb440f6), Next: 0}}, // Future Berlin block
{12244000, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block
{12964999, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block
{12965000, ID{Hash: checksumToBytes(0xb715077d), Next: 0}}, // First London block
{20000000, ID{Hash: checksumToBytes(0xb715077d), Next: 0}}, // Future London block
},
},
// Ropsten test cases
@@ -203,11 +205,11 @@ func TestValidation(t *testing.T) {
// Local is mainnet Petersburg, remote is Rinkeby Petersburg.
{7987396, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale},
// Local is mainnet Berlin, far in the future. Remote announces Gopherium (non existing fork)
// Local is mainnet London, far in the future. Remote announces Gopherium (non existing fork)
// at some future block 88888888, for itself, but past block for local. Local is incompatible.
//
// This case detects non-upgraded nodes with majority hash power (typical Ropsten mess).
{88888888, ID{Hash: checksumToBytes(0x0eb440f6), Next: 88888888}, ErrLocalIncompatibleOrStale},
{88888888, ID{Hash: checksumToBytes(0xb715077d), Next: 88888888}, ErrLocalIncompatibleOrStale},
// Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non existing
// fork) at block 7279999, before Petersburg. Local is incompatible.
+4 -1
View File
@@ -415,7 +415,10 @@ func DefaultCalaverasGenesisBlock() *Genesis {
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
// Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges
config.Clique.Period = period
config.Clique = &params.CliqueConfig{
Period: period,
Epoch: config.Clique.Epoch,
}
// Assemble and return the genesis with the precompiles and faucet pre-funded
return &Genesis{
+6 -2
View File
@@ -165,6 +165,7 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header) (result *headerWrit
)
batch := hc.chainDb.NewBatch()
parentKnown := true // Set to true to force hc.HasHeader check the first iteration
for i, header := range headers {
var hash common.Hash
// The headers have already been validated at this point, so we already
@@ -178,8 +179,10 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header) (result *headerWrit
number := header.Number.Uint64()
newTD.Add(newTD, header.Difficulty)
// If the parent was not present, store it
// If the header is already known, skip it, otherwise store
if !hc.HasHeader(hash, number) {
alreadyKnown := parentKnown && hc.HasHeader(hash, number)
if !alreadyKnown {
// Irrelevant of the canonical status, write the TD and header to the database.
rawdb.WriteTd(batch, hash, number, newTD)
hc.tdCache.Add(hash, new(big.Int).Set(newTD))
@@ -192,6 +195,7 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header) (result *headerWrit
firstInserted = i
}
}
parentKnown = alreadyKnown
lastHeader, lastHash, lastNumber = header, hash, number
}
@@ -570,7 +574,7 @@ func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, d
if parent == nil {
parent = hc.genesisHeader
}
parentHash = hdr.ParentHash
parentHash = parent.Hash()
// Notably, since geth has the possibility for setting the head to a low
// height which is even lower than ancient head.
-3
View File
@@ -450,9 +450,6 @@ func (s *stateObject) setBalance(amount *big.Int) {
s.data.Balance = amount
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (s *stateObject) ReturnGas(gas *big.Int) {}
func (s *stateObject) deepCopy(db *StateDB) *stateObject {
stateObject := newObject(db, s.address, s.data)
if s.trie != nil {
+11 -26
View File
@@ -89,10 +89,10 @@ type StateDB struct {
// The refund counter, also used by state transitioning.
refund uint64
thash, bhash common.Hash
txIndex int
logs map[common.Hash][]*types.Log
logSize uint
thash common.Hash
txIndex int
logs map[common.Hash][]*types.Log
logSize uint
preimages map[common.Hash][]byte
@@ -186,15 +186,18 @@ func (s *StateDB) AddLog(log *types.Log) {
s.journal.append(addLogChange{txhash: s.thash})
log.TxHash = s.thash
log.BlockHash = s.bhash
log.TxIndex = uint(s.txIndex)
log.Index = s.logSize
s.logs[s.thash] = append(s.logs[s.thash], log)
s.logSize++
}
func (s *StateDB) GetLogs(hash common.Hash) []*types.Log {
return s.logs[hash]
func (s *StateDB) GetLogs(hash common.Hash, blockHash common.Hash) []*types.Log {
logs := s.logs[hash]
for _, l := range logs {
l.BlockHash = blockHash
}
return logs
}
func (s *StateDB) Logs() []*types.Log {
@@ -272,11 +275,6 @@ func (s *StateDB) TxIndex() int {
return s.txIndex
}
// BlockHash returns the current block hash set by Prepare.
func (s *StateDB) BlockHash() common.Hash {
return s.bhash
}
func (s *StateDB) GetCode(addr common.Address) []byte {
stateObject := s.getStateObject(addr)
if stateObject != nil {
@@ -333,17 +331,6 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte,
return proof, err
}
// GetStorageProofByHash returns the Merkle proof for given storage slot.
func (s *StateDB) GetStorageProofByHash(a common.Address, key common.Hash) ([][]byte, error) {
var proof proofList
trie := s.StorageTrie(a)
if trie == nil {
return proof, errors.New("storage trie for requested address does not exist")
}
err := trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
return proof, err
}
// GetCommittedState retrieves a value from the given account's committed storage trie.
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
stateObject := s.getStateObject(addr)
@@ -597,7 +584,6 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
}
}
newobj = newObject(s, addr, Account{})
newobj.setNonce(0) // sets the object to dirty
if prev == nil {
s.journal.append(createObjectChange{account: &addr})
} else {
@@ -894,9 +880,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Prepare sets the current transaction hash and index and block hash which is
// used when the EVM emits new state logs.
func (s *StateDB) Prepare(thash, bhash common.Hash, ti int) {
func (s *StateDB) Prepare(thash common.Hash, ti int) {
s.thash = thash
s.bhash = bhash
s.txIndex = ti
s.accessList = newAccessList()
}
+2 -2
View File
@@ -463,9 +463,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
state.GetRefund(), checkstate.GetRefund())
}
if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
if !reflect.DeepEqual(state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{})) {
return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{}))
}
return nil
}
+2 -3
View File
@@ -312,12 +312,11 @@ func (sf *subfetcher) loop() {
default:
// No termination request yet, prefetch the next entry
taskid := string(task)
if _, ok := sf.seen[taskid]; ok {
if _, ok := sf.seen[string(task)]; ok {
sf.dups++
} else {
sf.trie.TryGet(task)
sf.seen[taskid] = struct{}{}
sf.seen[string(task)] = struct{}{}
}
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
if err != nil {
return // Also invalid block, bail out
}
statedb.Prepare(tx.Hash(), block.Hash(), i)
statedb.Prepare(tx.Hash(), i)
if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil {
return // Ugh, something went horribly wrong, bail out
}
+17 -14
View File
@@ -18,6 +18,7 @@ package core
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
@@ -57,11 +58,13 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen
// transactions failed to execute due to insufficient gas it will return an error.
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
var (
receipts types.Receipts
usedGas = new(uint64)
header = block.Header()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
receipts types.Receipts
usedGas = new(uint64)
header = block.Header()
blockHash = block.Hash()
blockNumber = block.Number()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
)
// Mutate the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
@@ -77,9 +80,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
pluginBlockProcessingError(tx, block, err)
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
statedb.Prepare(tx.Hash(), block.Hash(), i)
statedb.Prepare(tx.Hash(), i)
pluginPreProcessTransaction(tx, block, i)
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv)
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
if err != nil {
pluginBlockProcessingError(tx, block, err)
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
@@ -94,7 +97,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return receipts, allLogs, *usedGas, nil
}
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
// Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb)
@@ -107,10 +110,10 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
// Update the state with pending changes.
var root []byte
if config.IsByzantium(header.Number) {
if config.IsByzantium(blockNumber) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
}
*usedGas += result.UsedGas
@@ -131,10 +134,10 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
}
// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash)
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
receipt.BlockHash = statedb.BlockHash()
receipt.BlockNumber = header.Number
receipt.BlockHash = blockHash
receipt.BlockNumber = blockNumber
receipt.TransactionIndex = uint(statedb.TxIndex())
return receipt, err
}
@@ -151,5 +154,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// 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)
return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv)
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
}
+2 -2
View File
@@ -138,7 +138,7 @@ func (journal *txJournal) rotate(all map[common.Address]types.Transactions) erro
journal.writer = nil
}
// Generate a new journal with the contents of the current pool
replacement, err := os.OpenFile(journal.path+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
replacement, err := os.OpenFile(journal.path+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
@@ -158,7 +158,7 @@ func (journal *txJournal) rotate(all map[common.Address]types.Transactions) erro
if err = os.Rename(journal.path+".new", journal.path); err != nil {
return err
}
sink, err := os.OpenFile(journal.path, os.O_WRONLY|os.O_APPEND, 0755)
sink, err := os.OpenFile(journal.path, os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
+17
View File
@@ -494,6 +494,23 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common
return pending, queued
}
// ContentFrom retrieves the data content of the transaction pool, returning the
// pending as well as queued transactions of this address, grouped by nonce.
func (pool *TxPool) ContentFrom(addr common.Address) (types.Transactions, types.Transactions) {
pool.mu.RLock()
defer pool.mu.RUnlock()
var pending types.Transactions
if list, ok := pool.pending[addr]; ok {
pending = list.Flatten()
}
var queued types.Transactions
if list, ok := pool.queue[addr]; ok {
queued = list.Flatten()
}
return pending, queued
}
// Pending retrieves all currently processable transactions, grouped by origin
// account and sorted by nonce. The returned transaction set is a copy and can be
// freely modified by calling code.
+5
View File
@@ -129,6 +129,11 @@ func (h *Header) SanityCheck() error {
if eLen := len(h.Extra); eLen > 100*1024 {
return fmt.Errorf("too large block extradata: size %d", eLen)
}
if h.BaseFee != nil {
if bfLen := h.BaseFee.BitLen(); bfLen > 256 {
return fmt.Errorf("too large base fee: bitlen %d", bfLen)
}
}
return nil
}
+12 -12
View File
@@ -18,12 +18,12 @@ func (l Log) MarshalJSON() ([]byte, error) {
Address common.Address `json:"address" gencodec:"required"`
Topics []common.Hash `json:"topics" gencodec:"required"`
Data hexutil.Bytes `json:"data" gencodec:"required"`
BlockNumber hexutil.Uint64 `json:"blockNumber"`
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
TxIndex hexutil.Uint `json:"transactionIndex"`
BlockHash common.Hash `json:"blockHash"`
Index hexutil.Uint `json:"logIndex"`
Removed bool `json:"removed"`
BlockNumber hexutil.Uint64 `json:"blockNumber" rlp:"-"`
TxHash common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
TxIndex hexutil.Uint `json:"transactionIndex" rlp:"-"`
BlockHash common.Hash `json:"blockHash" rlp:"-"`
Index hexutil.Uint `json:"logIndex" rlp:"-"`
Removed bool `json:"removed" rlp:"-"`
}
var enc Log
enc.Address = l.Address
@@ -44,12 +44,12 @@ func (l *Log) UnmarshalJSON(input []byte) error {
Address *common.Address `json:"address" gencodec:"required"`
Topics []common.Hash `json:"topics" gencodec:"required"`
Data *hexutil.Bytes `json:"data" gencodec:"required"`
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
TxIndex *hexutil.Uint `json:"transactionIndex"`
BlockHash *common.Hash `json:"blockHash"`
Index *hexutil.Uint `json:"logIndex"`
Removed *bool `json:"removed"`
BlockNumber *hexutil.Uint64 `json:"blockNumber" rlp:"-"`
TxHash *common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
TxIndex *hexutil.Uint `json:"transactionIndex" rlp:"-"`
BlockHash *common.Hash `json:"blockHash" rlp:"-"`
Index *hexutil.Uint `json:"logIndex" rlp:"-"`
Removed *bool `json:"removed" rlp:"-"`
}
var dec Log
if err := json.Unmarshal(input, &dec); err != nil {
+6 -58
View File
@@ -17,11 +17,8 @@
package types
import (
"io"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)
//go:generate gencodec -type Log -field-override logMarshaling -out gen_log_json.go
@@ -40,19 +37,19 @@ type Log struct {
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
// block in which the transaction was included
BlockNumber uint64 `json:"blockNumber"`
BlockNumber uint64 `json:"blockNumber" rlp:"-"`
// hash of the transaction
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
TxHash common.Hash `json:"transactionHash" gencodec:"required" rlp:"-"`
// index of the transaction in the block
TxIndex uint `json:"transactionIndex"`
TxIndex uint `json:"transactionIndex" rlp:"-"`
// hash of the block in which the transaction was included
BlockHash common.Hash `json:"blockHash"`
BlockHash common.Hash `json:"blockHash" rlp:"-"`
// index of the log in the block
Index uint `json:"logIndex"`
Index uint `json:"logIndex" rlp:"-"`
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
Removed bool `json:"removed"`
Removed bool `json:"removed" rlp:"-"`
}
type logMarshaling struct {
@@ -61,52 +58,3 @@ type logMarshaling struct {
TxIndex hexutil.Uint
Index hexutil.Uint
}
type rlpLog struct {
Address common.Address
Topics []common.Hash
Data []byte
}
// rlpStorageLog is the storage encoding of a log.
type rlpStorageLog rlpLog
// EncodeRLP implements rlp.Encoder.
func (l *Log) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
}
// DecodeRLP implements rlp.Decoder.
func (l *Log) DecodeRLP(s *rlp.Stream) error {
var dec rlpLog
err := s.Decode(&dec)
if err == nil {
l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
}
return err
}
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type LogForStorage Log
// EncodeRLP implements rlp.Encoder.
func (l *LogForStorage) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpStorageLog{
Address: l.Address,
Topics: l.Topics,
Data: l.Data,
})
}
// DecodeRLP implements rlp.Decoder.
//
// Note some redundant fields(e.g. block number, tx hash etc) will be assembled later.
func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
var dec rlpStorageLog
if err := s.Decode(&dec); err != nil {
return err
}
*l = LogForStorage{Address: dec.Address, Topics: dec.Topics, Data: dec.Data}
return nil
}
+3 -9
View File
@@ -94,7 +94,7 @@ type receiptRLP struct {
type storedReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Logs []*LogForStorage
Logs []*Log
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -217,10 +217,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
enc := &storedReceiptRLP{
PostStateOrStatus: (*Receipt)(r).statusEncoding(),
CumulativeGasUsed: r.CumulativeGasUsed,
Logs: make([]*LogForStorage, len(r.Logs)),
}
for i, log := range r.Logs {
enc.Logs[i] = (*LogForStorage)(log)
Logs: r.Logs,
}
return rlp.Encode(w, enc)
}
@@ -235,10 +232,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
return err
}
r.CumulativeGasUsed = stored.CumulativeGasUsed
r.Logs = make([]*Log, len(stored.Logs))
for i, log := range stored.Logs {
r.Logs[i] = (*Log)(log)
}
r.Logs = stored.Logs
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
return nil
}
+1 -1
View File
@@ -67,7 +67,7 @@ func NewTx(inner TxData) *Transaction {
// TxData is the underlying data of a transaction.
//
// This is implemented by LegacyTx and AccessListTx.
// This is implemented by DynamicFeeTx, LegacyTx and AccessListTx.
type TxData interface {
txType() byte // returns the type ID
copy() TxData // creates a deep copy and initializes all fields
+14 -56
View File
@@ -17,7 +17,6 @@
package vm
import (
"errors"
"math/big"
"sync/atomic"
"time"
@@ -58,24 +57,6 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
return p, ok
}
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
for _, interpreter := range evm.interpreters {
if interpreter.CanRun(contract.Code) {
if evm.interpreter != interpreter {
// Ensure that the interpreter pointer is set back
// to its current value upon return.
defer func(i Interpreter) {
evm.interpreter = i
}(evm.interpreter)
evm.interpreter = interpreter
}
return interpreter.Run(contract, input, readOnly)
}
}
return nil, errors.New("no compatible interpreter")
}
// BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified.
type BlockContext struct {
@@ -131,8 +112,7 @@ type EVM struct {
Config Config
// global (to this context) ethereum virtual machine
// used throughout the execution of the tx.
interpreters []Interpreter
interpreter Interpreter
interpreter *EVMInterpreter
// abort is used to abort the EVM calling operations
// NOTE: must be set atomically
abort int32
@@ -146,36 +126,14 @@ type EVM struct {
// only ever be used *once*.
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
evm := &EVM{
Context: blockCtx,
TxContext: txCtx,
StateDB: statedb,
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
interpreters: make([]Interpreter, 0, 1),
Context: blockCtx,
TxContext: txCtx,
StateDB: statedb,
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
}
if chainConfig.IsEWASM(blockCtx.BlockNumber) {
// to be implemented by EVM-C and Wagon PRs.
// if vmConfig.EWASMInterpreter != "" {
// extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
// path := extIntOpts[0]
// options := []string{}
// if len(extIntOpts) > 1 {
// options = extIntOpts[1..]
// }
// evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options))
// } else {
// evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig))
// }
panic("No supported ewasm interpreter yet.")
}
// vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
// as we always want to have the built-in EVM as the failover option.
evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, config))
evm.interpreter = evm.interpreters[0]
evm.interpreter = NewEVMInterpreter(evm, config)
return evm
}
@@ -198,7 +156,7 @@ func (evm *EVM) Cancelled() bool {
}
// Interpreter returns the current interpreter
func (evm *EVM) Interpreter() Interpreter {
func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}
@@ -256,7 +214,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// The depth-check is already done, and precompiles handled above
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
}
@@ -308,7 +266,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
@@ -343,7 +301,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// Initialise a new contract and make initialise the delegate values
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
@@ -394,7 +352,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
ret, err = run(evm, contract, input, true)
ret, err = evm.interpreter.Run(contract, input, true)
gas = contract.Gas
}
if err != nil {
@@ -462,7 +420,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}
start := time.Now()
ret, err := run(evm, contract, nil, false)
ret, err := evm.interpreter.Run(contract, nil, false)
// Check whether the max code size has been exceeded, assign err if the case.
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
+5 -14
View File
@@ -4,11 +4,11 @@ package vm
import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/holiman/uint256"
)
var _ = (*structLogMarshaling)(nil)
@@ -22,8 +22,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
GasCost math.HexOrDecimal64 `json:"gasCost"`
Memory hexutil.Bytes `json:"memory"`
MemorySize int `json:"memSize"`
Stack []*math.HexOrDecimal256 `json:"stack"`
ReturnStack []math.HexOrDecimal64 `json:"returnStack"`
Stack []uint256.Int `json:"stack"`
ReturnData hexutil.Bytes `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
@@ -39,12 +38,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.GasCost = math.HexOrDecimal64(s.GasCost)
enc.Memory = s.Memory
enc.MemorySize = s.MemorySize
if s.Stack != nil {
enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack))
for k, v := range s.Stack {
enc.Stack[k] = (*math.HexOrDecimal256)(v)
}
}
enc.Stack = s.Stack
enc.ReturnData = s.ReturnData
enc.Storage = s.Storage
enc.Depth = s.Depth
@@ -64,7 +58,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
GasCost *math.HexOrDecimal64 `json:"gasCost"`
Memory *hexutil.Bytes `json:"memory"`
MemorySize *int `json:"memSize"`
Stack []*math.HexOrDecimal256 `json:"stack"`
Stack []uint256.Int `json:"stack"`
ReturnData *hexutil.Bytes `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth *int `json:"depth"`
@@ -94,10 +88,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s.MemorySize = *dec.MemorySize
}
if dec.Stack != nil {
s.Stack = make([]*big.Int, len(dec.Stack))
for k, v := range dec.Stack {
s.Stack[k] = (*big.Int)(v)
}
s.Stack = dec.Stack
}
if dec.ReturnData != nil {
s.ReturnData = *dec.ReturnData
+2 -2
View File
@@ -96,7 +96,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = env.interpreter.(*EVMInterpreter)
evmInterpreter = env.interpreter
)
for i, test := range tests {
@@ -234,7 +234,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
interpreter = env.interpreter.(*EVMInterpreter)
interpreter = env.interpreter
)
result := make([]TwoOperandTestcase, len(args))
for i, param := range args {
-31
View File
@@ -35,34 +35,9 @@ type Config struct {
JumpTable [256]*operation // EVM instruction table, automatically populated if unset
EWASMInterpreter string // External EWASM interpreter options
EVMInterpreter string // External EVM interpreter options
ExtraEips []int // Additional EIPS that are to be enabled
}
// Interpreter is used to run Ethereum based contracts and will utilise the
// passed environment to query external sources for state information.
// The Interpreter will run the byte code VM based on the passed
// configuration.
type Interpreter interface {
// Run loops and evaluates the contract's code with the given input data and returns
// the return byte-slice and an error if one occurred.
Run(contract *Contract, input []byte, static bool) ([]byte, error)
// CanRun tells if the contract, passed as an argument, can be
// run by the current interpreter. This is meant so that the
// caller can do something like:
//
// ```golang
// for _, interpreter := range interpreters {
// if interpreter.CanRun(contract.code) {
// interpreter.Run(contract.code, input)
// }
// }
// ```
CanRun([]byte) bool
}
// ScopeContext contains the things that are per-call, such as stack and memory,
// but not transients like pc and gas
type ScopeContext struct {
@@ -303,9 +278,3 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
return nil, nil
}
// CanRun tells if the contract, passed as an argument, can be
// run by the current interpreter.
func (in *EVMInterpreter) CanRun(code []byte) bool {
return true
}
+20 -12
View File
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// Storage represents a contract's storage.
@@ -66,7 +67,7 @@ type StructLog struct {
GasCost uint64 `json:"gasCost"`
Memory []byte `json:"memory"`
MemorySize int `json:"memSize"`
Stack []*big.Int `json:"stack"`
Stack []uint256.Int `json:"stack"`
ReturnData []byte `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
@@ -76,7 +77,6 @@ type StructLog struct {
// overrides for gencodec
type structLogMarshaling struct {
Stack []*math.HexOrDecimal256
Gas math.HexOrDecimal64
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
@@ -135,6 +135,14 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
return logger
}
// Reset clears the data held by the logger.
func (l *StructLogger) Reset() {
l.storage = make(map[common.Address]Storage)
l.output = make([]byte, 0)
l.logs = l.logs[:0]
l.err = nil
}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
@@ -157,16 +165,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
copy(mem, memory.Data())
}
// Copy a snapshot of the current stack state to a new buffer
var stck []*big.Int
var stck []uint256.Int
if !l.cfg.DisableStack {
stck = make([]*big.Int, len(stack.Data()))
stck = make([]uint256.Int, len(stack.Data()))
for i, item := range stack.Data() {
stck[i] = new(big.Int).Set(item.ToBig())
stck[i] = item
}
}
// Copy a snapshot of the current storage to a new container
var storage Storage
if !l.cfg.DisableStorage {
if !l.cfg.DisableStorage && (op == SLOAD || op == SSTORE) {
// initialise new changed values storage container for this contract
// if not present.
if l.storage[contract.Address()] == nil {
@@ -179,16 +187,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
value = env.StateDB.GetState(contract.Address(), address)
)
l.storage[contract.Address()][address] = value
}
// capture SSTORE opcodes and record the written entry in the local storage.
if op == SSTORE && stack.len() >= 2 {
storage = l.storage[contract.Address()].Copy()
} else if op == SSTORE && stack.len() >= 2 {
// capture SSTORE opcodes and record the written entry in the local storage.
var (
value = common.Hash(stack.data[stack.len()-2].Bytes32())
address = common.Hash(stack.data[stack.len()-1].Bytes32())
)
l.storage[contract.Address()][address] = value
storage = l.storage[contract.Address()].Copy()
}
storage = l.storage[contract.Address()].Copy()
}
var rdata []byte
if !l.cfg.DisableReturnData {
@@ -238,7 +246,7 @@ func WriteTrace(writer io.Writer, logs []StructLog) {
if len(log.Stack) > 0 {
fmt.Fprintln(writer, "Stack:")
for i := len(log.Stack) - 1; i >= 0; i-- {
fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32))
fmt.Fprintf(writer, "%08d %s\n", len(log.Stack)-i-1, log.Stack[i].Hex())
}
}
if len(log.Memory) > 0 {
@@ -314,7 +322,7 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
// format stack
var a []string
for _, elem := range stack.data {
a = append(a, fmt.Sprintf("%v", elem.String()))
a = append(a, elem.Hex())
}
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
fmt.Fprintf(t.out, "%10v |", b)
+1 -7
View File
@@ -57,7 +57,6 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
Gas: gas,
GasCost: cost,
MemorySize: memory.Len(),
Storage: nil,
Depth: depth,
RefundCounter: env.StateDB.GetRefund(),
Err: err,
@@ -66,12 +65,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
log.Memory = memory.Data()
}
if !l.cfg.DisableStack {
//TODO(@holiman) improve this
logstack := make([]*big.Int, len(stack.Data()))
for i, item := range stack.Data() {
logstack[i] = item.ToBig()
}
log.Stack = logstack
log.Stack = stack.data
}
if !l.cfg.DisableReturnData {
log.ReturnData = rData
-1
View File
@@ -30,7 +30,6 @@ type dummyContractRef struct {
calledForEach bool
}
func (dummyContractRef) ReturnGas(*big.Int) {}
func (dummyContractRef) Address() common.Address { return common.Address{} }
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
func (dummyContractRef) SetCode(common.Hash, []byte) {}