Series of changes to get backport to 1.13.5 working

This commit is contained in:
Matthieu Vachon 2024-03-14 16:53:22 -04:00
parent 28a80d617f
commit 3834f135a9
17 changed files with 161 additions and 142 deletions

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/filters"
@ -681,7 +682,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
// Set infinite balance to the fake caller account. // Set infinite balance to the fake caller account.
from := stateDB.GetOrNewStateObject(call.From) from := stateDB.GetOrNewStateObject(call.From)
from.SetBalance(math.MaxBig256, state.BalanceChangeUnspecified) from.SetBalance(math.MaxBig256, tracing.BalanceChangeUnspecified)
// Execute the call. // Execute the call.
msg := &core.Message{ msg := &core.Message{

View file

@ -186,9 +186,7 @@ func Transition(ctx *cli.Context) error {
} }
prestate.Env = *inputData.Env prestate.Env = *inputData.Env
vmConfig := vm.Config{ vmConfig := vm.Config{}
Tracer: tracer,
}
// Construct the chainconfig // Construct the chainconfig
var chainConfig *params.ChainConfig var chainConfig *params.ChainConfig
if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil {

View file

@ -568,11 +568,10 @@ func dumpState(ctx *cli.Context) error {
return err return err
} }
da := &state.DumpAccount{ da := &state.DumpAccount{
Balance: account.Balance.String(), Balance: account.Balance.String(),
Nonce: account.Nonce, Nonce: account.Nonce,
Root: account.Root.Bytes(), Root: account.Root.Bytes(),
CodeHash: account.CodeHash, CodeHash: account.CodeHash,
SecureKey: accIt.Hash().Bytes(),
} }
if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash)) da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))

View file

@ -18,7 +18,6 @@ package core
import ( import (
"bytes" "bytes"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -41,7 +40,6 @@ import (
) )
//go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go //go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
//go:generate go run github.com/fjl/gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
var errGenesisNoConfig = errors.New("genesis has no chain configuration") var errGenesisNoConfig = errors.New("genesis has no chain configuration")
@ -106,23 +104,14 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) {
return &genesis, nil return &genesis, nil
} }
// GenesisAlloc specifies the initial state that is part of the genesis block. // Deprecated: use types.GenesisAccount instead.
type GenesisAlloc map[common.Address]GenesisAccount type GenesisAccount = types.Account
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { // Deprecated: use types.GenesisAlloc instead.
m := make(map[common.UnprefixedAddress]GenesisAccount) type GenesisAlloc = types.GenesisAlloc
if err := json.Unmarshal(data, &m); err != nil {
return err
}
*ga = make(GenesisAlloc)
for addr, a := range m {
(*ga)[common.Address(addr)] = a
}
return nil
}
// hash computes the state root according to the genesis specification. // hashAlloc computes the state root according to the genesis specification.
func (ga *GenesisAlloc) hash() (common.Hash, error) { func hashAlloc(ga *types.GenesisAlloc) (common.Hash, error) {
// Create an ephemeral in-memory database for computing hash, // Create an ephemeral in-memory database for computing hash,
// all the derived states will be discarded to not pollute disk. // all the derived states will be discarded to not pollute disk.
db := state.NewDatabase(rawdb.NewMemoryDatabase()) db := state.NewDatabase(rawdb.NewMemoryDatabase())
@ -143,10 +132,10 @@ func (ga *GenesisAlloc) hash() (common.Hash, error) {
return statedb.Commit(0, false) return statedb.Commit(0, false)
} }
// flush is very similar with hash, but the main difference is all the generated // flushAlloc is very similar with hash, but the main difference is all the generated
// states will be persisted into the given database. Also, the genesis state // states will be persisted into the given database. Also, the genesis state
// specification will be flushed as well. // specification will be flushed as well.
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
if err != nil { if err != nil {
return err return err
@ -215,15 +204,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc GenesisAll
return nil, nil return nil, nil
} }
// GenesisAccount is an account in the state of the genesis block.
type GenesisAccount struct {
Code []byte `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
Balance *big.Int `json:"balance" gencodec:"required"`
Nonce uint64 `json:"nonce,omitempty"`
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
}
// field type overrides for gencodec // field type overrides for gencodec
type genesisSpecMarshaling struct { type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64 Nonce math.HexOrDecimal64
@ -239,34 +219,6 @@ type genesisSpecMarshaling struct {
BlobGasUsed *math.HexOrDecimal64 BlobGasUsed *math.HexOrDecimal64
} }
type genesisAccountMarshaling struct {
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
Storage map[storageJSON]storageJSON
PrivateKey hexutil.Bytes
}
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
// unmarshaling from hex.
type storageJSON common.Hash
func (h *storageJSON) UnmarshalText(text []byte) error {
text = bytes.TrimPrefix(text, []byte("0x"))
if len(text) > 64 {
return fmt.Errorf("too many hex characters in storage key/value %q", text)
}
offset := len(h) - len(text)/2 // pad on the left
if _, err := hex.Decode(h[offset:], text); err != nil {
return fmt.Errorf("invalid hex storage key/value %q", text)
}
return nil
}
func (h storageJSON) MarshalText() ([]byte, error) {
return hexutil.Bytes(h[:]).MarshalText()
}
// GenesisMismatchError is raised when trying to overwrite an existing // GenesisMismatchError is raised when trying to overwrite an existing
// genesis block with an incompatible one. // genesis block with an incompatible one.
type GenesisMismatchError struct { type GenesisMismatchError struct {
@ -449,7 +401,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
// ToBlock returns the genesis block according to genesis specification. // ToBlock returns the genesis block according to genesis specification.
func (g *Genesis) ToBlock() *types.Block { func (g *Genesis) ToBlock() *types.Block {
root, err := g.Alloc.hash() root, err := hashAlloc(&g.Alloc)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -526,7 +478,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
// All the checks has passed, flush the states derived from the genesis // All the checks has passed, flush the states derived from the genesis
// specification as well as the specification itself into the provided // specification as well as the specification itself into the provided
// database. // database.
if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil { if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
return nil, err return nil, err
} }
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())

View file

@ -231,7 +231,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}}, {2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
} }
hash, _ = alloc.hash() hash, _ = hashAlloc(alloc)
) )
blob, _ := json.Marshal(alloc) blob, _ := json.Marshal(alloc)
rawdb.WriteGenesisStateSpec(db, hash, blob) rawdb.WriteGenesisStateSpec(db, hash, blob)

View file

@ -104,14 +104,13 @@ type iterativeDump struct {
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) {
dumpAccount := &DumpAccount{ dumpAccount := &DumpAccount{
Balance: account.Balance, Balance: account.Balance,
Nonce: account.Nonce, Nonce: account.Nonce,
Root: account.Root, Root: account.Root,
CodeHash: account.CodeHash, CodeHash: account.CodeHash,
Code: account.Code, Code: account.Code,
Storage: account.Storage, Storage: account.Storage,
SecureKey: account.SecureKey, Address: addr,
Address: addr,
} }
d.Encode(dumpAccount) d.Encode(dumpAccount)
} }
@ -150,11 +149,10 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
panic(err) panic(err)
} }
account := DumpAccount{ account := DumpAccount{
Balance: data.Balance.String(), Balance: data.Balance.String(),
Nonce: data.Nonce, Nonce: data.Nonce,
Root: data.Root[:], Root: data.Root[:],
CodeHash: data.CodeHash, CodeHash: data.CodeHash,
SecureKey: it.Key,
} }
var ( var (
addrBytes = s.trie.GetKey(it.Key) addrBytes = s.trie.GetKey(it.Key)

View file

@ -420,7 +420,7 @@ func (s *stateObject) AddBalance(amount *big.Int, reason tracing.BalanceChangeRe
// SubBalance removes amount from s's balance. // SubBalance removes amount from s's balance.
// It is used to remove funds from the origin account of a transfer. // It is used to remove funds from the origin account of a transfer.
func (s *stateObject) SubBalance(amount *big.Int, reason tracing.BalanceChangeReason) { func (s *stateObject) SubBalance(amount *big.Int, reason tracing.BalanceChangeReason) {
if amount.IsZero() { if amount.Sign() == 0 {
return return
} }
s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason) s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason)

View file

@ -384,7 +384,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
// AddBalance adds amount to the account associated with addr. // AddBalance adds amount to the account associated with addr.
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.getOrNewStateObject(addr) stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.AddBalance(amount, reason) stateObject.AddBalance(amount, reason)
} }
@ -392,14 +392,14 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracin
// SubBalance subtracts amount from the account associated with addr. // SubBalance subtracts amount from the account associated with addr.
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.getOrNewStateObject(addr) stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SubBalance(amount, reason) stateObject.SubBalance(amount, reason)
} }
} }
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.getOrNewStateObject(addr) stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetBalance(amount, reason) stateObject.SetBalance(amount, reason)
} }

View file

@ -22,13 +22,14 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
) )
// OpContext provides the context at which the opcode is being // OpContext provides the context at which the opcode is being
// executed in, including the memory, stack and various contract-level information. // executed in, including the memory, stack and various contract-level information.
type OpContext interface { type OpContext interface {
MemoryData() []byte MemoryData() []byte
StackData() []big.Int StackData() []uint256.Int
Caller() common.Address Caller() common.Address
Address() common.Address Address() common.Address
CallValue() *big.Int CallValue() *big.Int

87
core/types/account.go Normal file
View file

@ -0,0 +1,87 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
)
//go:generate go run github.com/fjl/gencodec -type Account -field-override accountMarshaling -out gen_account.go
// Account represents an Ethereum account and its attached data.
// This type is used to specify accounts in the genesis block state, and
// is also useful for JSON encoding/decoding of accounts.
type Account struct {
Code []byte `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
Balance *big.Int `json:"balance" gencodec:"required"`
Nonce uint64 `json:"nonce,omitempty"`
// used in tests
PrivateKey []byte `json:"secretKey,omitempty"`
}
type accountMarshaling struct {
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
Storage map[storageJSON]storageJSON
PrivateKey hexutil.Bytes
}
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
// unmarshaling from hex.
type storageJSON common.Hash
func (h *storageJSON) UnmarshalText(text []byte) error {
text = bytes.TrimPrefix(text, []byte("0x"))
if len(text) > 64 {
return fmt.Errorf("too many hex characters in storage key/value %q", text)
}
offset := len(h) - len(text)/2 // pad on the left
if _, err := hex.Decode(h[offset:], text); err != nil {
return fmt.Errorf("invalid hex storage key/value %q", text)
}
return nil
}
func (h storageJSON) MarshalText() ([]byte, error) {
return hexutil.Bytes(h[:]).MarshalText()
}
// GenesisAlloc specifies the initial state of a genesis block.
type GenesisAlloc map[common.Address]Account
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
m := make(map[common.UnprefixedAddress]Account)
if err := json.Unmarshal(data, &m); err != nil {
return err
}
*ga = make(GenesisAlloc)
for addr, a := range m {
(*ga)[common.Address(addr)] = a
}
return nil
}

View file

@ -1,6 +1,6 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT. // Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package core package types
import ( import (
"encoding/json" "encoding/json"
@ -12,62 +12,62 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
) )
var _ = (*genesisAccountMarshaling)(nil) var _ = (*accountMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (g GenesisAccount) MarshalJSON() ([]byte, error) { func (a Account) MarshalJSON() ([]byte, error) {
type GenesisAccount struct { type Account struct {
Code hexutil.Bytes `json:"code,omitempty"` Code hexutil.Bytes `json:"code,omitempty"`
Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
Nonce math.HexOrDecimal64 `json:"nonce,omitempty"` Nonce math.HexOrDecimal64 `json:"nonce,omitempty"`
PrivateKey hexutil.Bytes `json:"secretKey,omitempty"` PrivateKey hexutil.Bytes `json:"secretKey,omitempty"`
} }
var enc GenesisAccount var enc Account
enc.Code = g.Code enc.Code = a.Code
if g.Storage != nil { if a.Storage != nil {
enc.Storage = make(map[storageJSON]storageJSON, len(g.Storage)) enc.Storage = make(map[storageJSON]storageJSON, len(a.Storage))
for k, v := range g.Storage { for k, v := range a.Storage {
enc.Storage[storageJSON(k)] = storageJSON(v) enc.Storage[storageJSON(k)] = storageJSON(v)
} }
} }
enc.Balance = (*math.HexOrDecimal256)(g.Balance) enc.Balance = (*math.HexOrDecimal256)(a.Balance)
enc.Nonce = math.HexOrDecimal64(g.Nonce) enc.Nonce = math.HexOrDecimal64(a.Nonce)
enc.PrivateKey = g.PrivateKey enc.PrivateKey = a.PrivateKey
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (g *GenesisAccount) UnmarshalJSON(input []byte) error { func (a *Account) UnmarshalJSON(input []byte) error {
type GenesisAccount struct { type Account struct {
Code *hexutil.Bytes `json:"code,omitempty"` Code *hexutil.Bytes `json:"code,omitempty"`
Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"` Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"`
PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"` PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"`
} }
var dec GenesisAccount var dec Account
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
if dec.Code != nil { if dec.Code != nil {
g.Code = *dec.Code a.Code = *dec.Code
} }
if dec.Storage != nil { if dec.Storage != nil {
g.Storage = make(map[common.Hash]common.Hash, len(dec.Storage)) a.Storage = make(map[common.Hash]common.Hash, len(dec.Storage))
for k, v := range dec.Storage { for k, v := range dec.Storage {
g.Storage[common.Hash(k)] = common.Hash(v) a.Storage[common.Hash(k)] = common.Hash(v)
} }
} }
if dec.Balance == nil { if dec.Balance == nil {
return errors.New("missing required field 'balance' for GenesisAccount") return errors.New("missing required field 'balance' for Account")
} }
g.Balance = (*big.Int)(dec.Balance) a.Balance = (*big.Int)(dec.Balance)
if dec.Nonce != nil { if dec.Nonce != nil {
g.Nonce = uint64(*dec.Nonce) a.Nonce = uint64(*dec.Nonce)
} }
if dec.PrivateKey != nil { if dec.PrivateKey != nil {
g.PrivateKey = *dec.PrivateKey a.PrivateKey = *dec.PrivateKey
} }
return nil return nil
} }

View file

@ -835,7 +835,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
} }
if tracer.OnExit != nil { if tracer.OnExit != nil {
tracer.OnExit([]byte{}, 0, nil, false) tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
} }
} }
return nil, errStopToken return nil, errStopToken
@ -855,7 +855,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
} }
if tracer.OnExit != nil { if tracer.OnExit != nil {
tracer.OnExit([]byte{}, 0, nil, false) tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
} }
} }
return nil, errStopToken return nil, errStopToken

View file

@ -17,6 +17,8 @@
package vm package vm
import ( import (
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
@ -63,7 +65,7 @@ func (ctx *ScopeContext) Address() common.Address {
return ctx.Contract.Address() return ctx.Contract.Address()
} }
func (ctx *ScopeContext) CallValue() *uint256.Int { func (ctx *ScopeContext) CallValue() *big.Int {
return ctx.Contract.Value() return ctx.Contract.Value()
} }

View file

@ -77,7 +77,7 @@ func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.Chain
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value)
ret, err := env.Interpreter().Run(contract, []byte{}, false) ret, err := env.Interpreter().Run(contract, []byte{}, false)
tracer.OnEnd(ret, startGas-contract.Gas, err, true) tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
// Rest gas assumes no refund // Rest gas assumes no refund
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
if err != nil { if err != nil {

View file

@ -147,32 +147,7 @@ func newCallTracerObject(ctx *directory.Context, cfg json.RawMessage) (*callTrac
} }
// First callframe contains tx context info // First callframe contains tx context info
// and is populated on start and end. // and is populated on start and end.
return &callTracer{callstack: make([]callFrame, 1), config: config}, nil return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *callTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
toCopy := to
t.callstack[0] = callFrame{
Type: vm.CALL,
From: from,
To: &toCopy,
Input: common.CopyBytes(input),
Gas: t.gasLimit,
Value: value,
}
if create {
t.callstack[0].Type = vm.CREATE
}
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
t.callstack[0].processOutput(output, err, reverted)
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
} }
// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
@ -195,6 +170,9 @@ func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common
Gas: gas, Gas: gas,
Value: value, Value: value,
} }
if depth == 0 {
call.Gas = t.gasLimit
}
t.callstack = append(t.callstack, call) t.callstack = append(t.callstack, call)
} }
@ -210,17 +188,19 @@ func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error,
if t.config.OnlyTopCall { if t.config.OnlyTopCall {
return return
} }
size := len(t.callstack) size := len(t.callstack)
if size <= 1 { if size <= 1 {
return return
} }
// pop call // Pop call.
call := t.callstack[size-1] call := t.callstack[size-1]
t.callstack = t.callstack[:size-1] t.callstack = t.callstack[:size-1]
size -= 1 size -= 1
call.GasUsed = gasUsed call.GasUsed = gasUsed
call.processOutput(output, err, reverted) call.processOutput(output, err, reverted)
// Nest call into parent.
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
} }

View file

@ -104,7 +104,7 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason)
func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
for _, t := range t.tracers { for _, t := range t.tracers {
if t.OnEnter != nil { if t.OnEnter != nil {
t.OnEnter(typ, from, to, input, gas, value) t.OnEnter(depth, typ, from, to, input, gas, value)
} }
} }
} }
@ -112,7 +112,7 @@ func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.
func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
for _, t := range t.tracers { for _, t := range t.tracers {
if t.OnExit != nil { if t.OnExit != nil {
t.OnExit(output, gasUsed, err, reverted) t.OnExit(depth, output, gasUsed, err, reverted)
} }
} }
} }

View file

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -201,7 +202,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
} }
// Perform read-only call. // Perform read-only call.
st.SetBalance(testBankAddress, math.MaxBig256, state.BalanceChangeUnspecified) st.SetBalance(testBankAddress, math.MaxBig256, tracing.BalanceChangeUnspecified)
msg := &core.Message{ msg := &core.Message{
From: testBankAddress, From: testBankAddress,
To: &testContractAddr, To: &testContractAddr,