manual geth v1.11.1 merge

This commit is contained in:
philip-morlier
2023-02-17 07:53:01 -08:00
729 changed files with 29880 additions and 19327 deletions
+242 -122
View File
@@ -61,8 +61,19 @@ const (
// For non-archive nodes, this limit _will_ be overblown, as disk-backed tries
// will only be found every ~15K blocks or so.
defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024)
// maximumPendingTraceStates is the maximum number of states allowed waiting
// for tracing. The creation of trace state will be paused if the unused
// trace states exceed this limit.
maximumPendingTraceStates = 128
)
var errTxNotFound = errors.New("transaction not found")
// StateReleaseFunc is used to deallocate resources held by constructing a
// historical state for tracing purposes.
type StateReleaseFunc func()
// Backend interface provides the common API services (that are provided by
// both full and light clients) with access to necessary functions.
type Backend interface {
@@ -75,11 +86,8 @@ type Backend interface {
ChainConfig() *params.ChainConfig
Engine() consensus.Engine
ChainDb() ethdb.Database
// StateAtBlock returns the state corresponding to the stateroot of the block.
// N.B: For executing transactions on block N, the required stateRoot is block N-1,
// so this method should be called with the parent.
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error)
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error)
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
}
// API is the collection of tracing APIs exposed over the private debugging endpoint.
@@ -201,7 +209,7 @@ type txTraceResult struct {
type blockTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing
block *types.Block // Block to trace the transactions from
rootref common.Hash // Trie root reference held for this task
release StateReleaseFunc // The function to release the held resource for this task
results []*txTraceResult // Trace results produced by the task
}
@@ -234,13 +242,6 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf
if from.Number().Cmp(to.Number()) >= 0 {
return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start)
}
return api.traceChain(ctx, from, to, config)
}
// traceChain configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requested tracer.
func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) {
// Tracing a chain is a **long** operation, only do with subscriptions
notifier, supported := rpc.NotifierFromContext(ctx)
if !supported {
@@ -248,8 +249,21 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
}
sub := notifier.CreateSubscription()
// Prepare all the states for tracing. Note this procedure can take very
// long time. Timeout mechanism is necessary.
resCh := api.traceChain(from, to, config, notifier.Closed())
go func() {
for result := range resCh {
notifier.Notify(sub.ID, result)
}
}()
return sub, nil
}
// traceChain configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The tracing chain range includes
// the end block but excludes the start one. The return value will be one item per
// transaction, dependent on the requested tracer.
// The tracing procedure should be aborted in case the closed signal is received.
func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult {
reexec := defaultTraceReexec
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
@@ -260,20 +274,23 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
threads = blocks
}
var (
pend = new(sync.WaitGroup)
tasks = make(chan *blockTraceTask, threads)
results = make(chan *blockTraceTask, threads)
localctx = context.Background()
pend = new(sync.WaitGroup)
ctx = context.Background()
taskCh = make(chan *blockTraceTask, threads)
resCh = make(chan *blockTraceTask, threads)
tracker = newStateTracker(maximumPendingTraceStates, start.NumberU64())
)
for th := 0; th < threads; th++ {
pend.Add(1)
go func() {
defer pend.Done()
// Fetch and execute the next block trace tasks
for task := range tasks {
signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil)
// Fetch and execute the block trace taskCh
for task := range taskCh {
var (
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
)
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
@@ -282,7 +299,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
if err != nil {
task.results[i] = &txTraceResult{Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@@ -292,36 +309,40 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
task.results[i] = &txTraceResult{Result: res}
}
// Stream the result back to the user or abort on teardown
// Tracing state is used up, queue it for de-referencing. Note the
// state is the parent state of trace block, use block.number-1 as
// the state number.
tracker.releaseState(task.block.NumberU64()-1, task.release)
// Stream the result back to the result catcher or abort on teardown
select {
case results <- task:
case <-notifier.Closed():
case resCh <- task:
case <-closed:
return
}
}
}()
}
// Start a goroutine to feed all the blocks into the tracers
var (
begin = time.Now()
derefTodo []common.Hash // list of hashes to dereference from the db
derefsMu sync.Mutex // mutex for the derefs
)
go func() {
var (
logged time.Time
begin = time.Now()
number uint64
traced uint64
failed error
parent common.Hash
statedb *state.StateDB
release StateReleaseFunc
)
// Ensure everything is properly cleaned up on any exit path
defer func() {
close(tasks)
close(taskCh)
pend.Wait()
// Clean out any pending release functions of trace states.
tracker.callReleases()
// Log the chain result
switch {
case failed != nil:
log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed)
@@ -330,105 +351,104 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
default:
log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin))
}
close(results)
close(resCh)
}()
var preferDisk bool
// Feed all the blocks both into the tracer, as well as fast process concurrently
for number = start.NumberU64(); number < end.NumberU64(); number++ {
// Stop tracing if interruption was requested
select {
case <-notifier.Closed():
case <-closed:
return
default:
}
// clean out any derefs
derefsMu.Lock()
for _, h := range derefTodo {
statedb.Database().TrieDB().Dereference(h)
}
derefTodo = derefTodo[:0]
derefsMu.Unlock()
// Print progress logs if long enough time elapsed
if time.Since(logged) > 8*time.Second {
logged = time.Now()
log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin))
}
// Retrieve the parent state to trace on top
block, err := api.blockByNumber(localctx, rpc.BlockNumber(number))
// Retrieve the parent block and target block for tracing.
block, err := api.blockByNumber(ctx, rpc.BlockNumber(number))
if err != nil {
failed = err
break
}
next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1))
if err != nil {
failed = err
break
}
// Make sure the state creator doesn't go too far. Too many unprocessed
// trace state may cause the oldest state to become stale(e.g. in
// path-based scheme).
if err = tracker.wait(number); err != nil {
failed = err
break
}
// Prepare the statedb for tracing. Don't use the live database for
// tracing to avoid persisting state junks into the database.
statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false, preferDisk)
// tracing to avoid persisting state junks into the database. Switch
// over to `preferDisk` mode only if the memory usage exceeds the
// limit, the trie database will be reconstructed from scratch only
// if the relevant state is available in disk.
var preferDisk bool
if statedb != nil {
s1, s2 := statedb.Database().TrieDB().Size()
preferDisk = s1+s2 > defaultTracechainMemLimit
}
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk)
if err != nil {
failed = err
break
}
if trieDb := statedb.Database().TrieDB(); trieDb != nil {
// Hold the reference for tracer, will be released at the final stage
trieDb.Reference(block.Root(), common.Hash{})
// Clean out any pending release functions of trace state. Note this
// step must be done after constructing tracing state, because the
// tracing state of block next depends on the parent state and construction
// may fail if we release too early.
tracker.callReleases()
// Release the parent state because it's already held by the tracer
if parent != (common.Hash{}) {
trieDb.Dereference(parent)
}
// Prefer disk if the trie db memory grows too much
s1, s2 := trieDb.Size()
if !preferDisk && (s1+s2) > defaultTracechainMemLimit {
log.Info("Switching to prefer-disk mode for tracing", "size", s1+s2)
preferDisk = true
}
}
parent = block.Root()
next, err := api.blockByNumber(localctx, rpc.BlockNumber(number+1))
if err != nil {
failed = err
break
}
// Send the block over to the concurrent tracers (if not in the fast-forward phase)
txs := next.Transactions()
select {
case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: next, rootref: block.Root(), results: make([]*txTraceResult, len(txs))}:
case <-notifier.Closed():
case taskCh <- &blockTraceTask{statedb: statedb.Copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}:
case <-closed:
tracker.releaseState(number, release)
return
}
traced += uint64(len(txs))
}
}()
// Keep reading the trace results and stream the to the user
// Keep reading the trace results and stream them to result channel.
retCh := make(chan *blockTraceResult)
go func() {
defer close(retCh)
var (
done = make(map[uint64]*blockTraceResult)
next = start.NumberU64() + 1
done = make(map[uint64]*blockTraceResult)
)
for res := range results {
for res := range resCh {
// Queue up next received result
result := &blockTraceResult{
Block: hexutil.Uint64(res.block.NumberU64()),
Hash: res.block.Hash(),
Traces: res.results,
}
// Schedule any parent tries held in memory by this task for dereferencing
done[uint64(result.Block)] = result
derefsMu.Lock()
derefTodo = append(derefTodo, res.rootref)
derefsMu.Unlock()
// Stream completed traces to the user, aborting on the first error
// Stream completed traces to the result channel
for result, ok := done[next]; ok; result, ok = done[next] {
if len(result.Traces) > 0 || next == end.NumberU64() {
notifier.Notify(sub.ID, result)
// It will be blocked in case the channel consumer doesn't take the
// tracing result in time(e.g. the websocket connect is not stable)
// which will eventually block the entire chain tracer. It's the
// expected behavior to not waste node resources for a non-active user.
retCh <- result
}
delete(done, next)
next++
}
}
}()
return sub, nil
return retCh
}
// TraceBlockByNumber returns the structured logs created during the execution of
@@ -515,10 +535,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, err
}
defer release()
var (
roots []common.Hash
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
@@ -527,12 +549,15 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
)
for i, tx := range block.Transactions() {
if err := ctx.Err(); err != nil {
return nil, err
}
var (
msg, _ = tx.AsMessage(signer, block.BaseFee())
txContext = core.NewEVMTxContext(msg)
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
)
statedb.Prepare(tx.Hash(), i)
statedb.SetTxContext(tx.Hash(), i)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not
@@ -568,6 +593,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
if block.NumberU64() == 0 {
return nil, errors.New("genesis is not traceable")
}
// Prepare base state
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
if err != nil {
return nil, err
@@ -576,28 +602,70 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, err
}
defer release()
// JS tracers have high overhead. In this case run a parallel
// process that generates states in one thread and traces txes
// in separate worker threads.
if config != nil && config.Tracer != nil && *config.Tracer != "" {
if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS {
return api.traceBlockParallel(ctx, block, statedb, config)
}
}
// Native tracers have low overhead
var (
txs = block.Transactions()
blockHash = block.Hash()
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
results = make([]*txTraceResult, len(txs))
)
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, block.BaseFee())
txctx := &Context{
BlockHash: blockHash,
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config)
if err != nil {
return nil, err
}
results[i] = &txTraceResult{Result: res}
// Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(is158)
}
return results, nil
}
// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
// runs along and executes txes without tracing enabled to generate their prestate.
// Worker threads take the tasks and the prestate and trace them.
func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) {
// Execute all the transaction contained within the block concurrently
var (
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
txs = block.Transactions()
results = make([]*txTraceResult, len(txs))
pend = new(sync.WaitGroup)
jobs = make(chan *txTraceTask, len(txs))
txs = block.Transactions()
blockHash = block.Hash()
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
results = make([]*txTraceResult, len(txs))
pend sync.WaitGroup
)
threads := runtime.NumCPU()
if threads > len(txs) {
threads = len(txs)
}
blockHash := block.Hash()
jobs := make(chan *txTraceTask, threads)
for th := 0; th < threads; th++ {
pend.Add(1)
go func() {
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
defer pend.Done()
// Fetch and execute the next transaction trace tasks
for task := range jobs {
@@ -616,25 +684,33 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
}
}()
}
// Feed the transactions into the tracers and return
var failed error
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
txloop:
for i, tx := range txs {
// Send the trace task over for execution
jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
task := &txTraceTask{statedb: statedb.Copy(), index: i}
select {
case <-ctx.Done():
failed = ctx.Err()
break txloop
case jobs <- task:
}
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, block.BaseFee())
statedb.Prepare(tx.Hash(), i)
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err
break
break txloop
}
// Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
close(jobs)
pend.Wait()
@@ -666,10 +742,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, err
}
defer release()
// Retrieve the tracing configurations, or use default values
var (
logConfig logger.Config
@@ -694,17 +772,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// actual specified block, not any preceding blocks that we have to go through
// in order to obtain the state.
// Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork`
if config != nil && config.Overrides != nil {
// Copy the config, to not screw up the main config
// Note: the Clique-part is _not_ deep copied
chainConfigCopy := new(params.ChainConfig)
*chainConfigCopy = *chainConfig
chainConfig = chainConfigCopy
if berlin := config.Config.Overrides.BerlinBlock; berlin != nil {
chainConfig.BerlinBlock = berlin
canon = false
}
// Note: This copies the config, to not screw up the main config
chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
}
for i, tx := range block.Transactions() {
// Prepare the transaction for un-traced execution
@@ -739,7 +809,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
}
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.Prepare(tx.Hash(), i)
statedb.SetTxContext(tx.Hash(), i)
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
if writer != nil {
writer.Flush()
@@ -777,10 +847,14 @@ func containsTx(block *types.Block, hash common.Hash) bool {
// TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object.
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
if err != nil {
return nil, err
}
// Only mined txes are supported
if tx == nil {
return nil, errTxNotFound
}
// It shouldn't happen in practice.
if blockNumber == 0 {
return nil, errors.New("genesis is not traceable")
@@ -793,10 +867,12 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
if err != nil {
return nil, err
}
msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
if err != nil {
return nil, err
}
defer release()
txctx := &Context{
BlockHash: blockHash,
TxIndex: int(index),
@@ -837,10 +913,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
if err != nil {
return nil, err
}
defer release()
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
// Apply the customization rules if required.
if config != nil {
@@ -857,12 +935,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
var traceConfig *TraceConfig
if config != nil {
traceConfig = &TraceConfig{
Config: config.Config,
Tracer: config.Tracer,
Timeout: config.Timeout,
Reexec: config.Reexec,
}
traceConfig = &config.TraceConfig
}
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
}
@@ -895,6 +968,8 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
}
// end PluGeth injection
}
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
@@ -906,14 +981,14 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout"))
// Stop evm execution. Note cancellation is not necessarily immediate.
vmenv.Cancel()
}
}()
defer cancel()
// Run the transaction with tracing enabled.
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
// Call Prepare to clear out the statedb access list
statedb.Prepare(txctx.TxHash, txctx.TxIndex)
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
}
@@ -930,3 +1005,48 @@ func APIs(backend Backend) []rpc.API {
},
}
}
// overrideConfig returns a copy of original with forks enabled by override enabled,
// along with a boolean that indicates whether the copy is canonical (equivalent to the original).
// Note: the Clique-part is _not_ deep copied
func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) (*params.ChainConfig, bool) {
copy := new(params.ChainConfig)
*copy = *original
canon := true
// Apply forks (after Berlin) to the copy.
if block := override.BerlinBlock; block != nil {
copy.BerlinBlock = block
canon = false
}
if block := override.LondonBlock; block != nil {
copy.LondonBlock = block
canon = false
}
if block := override.ArrowGlacierBlock; block != nil {
copy.ArrowGlacierBlock = block
canon = false
}
if block := override.GrayGlacierBlock; block != nil {
copy.GrayGlacierBlock = block
canon = false
}
if block := override.MergeNetsplitBlock; block != nil {
copy.MergeNetsplitBlock = block
canon = false
}
if timestamp := override.ShanghaiTime; timestamp != nil {
copy.ShanghaiTime = timestamp
canon = false
}
if timestamp := override.CancunTime; timestamp != nil {
copy.CancunTime = timestamp
canon = false
}
if timestamp := override.PragueTime; timestamp != nil {
copy.PragueTime = timestamp
canon = false
}
return copy, canon
}
+334 -57
View File
@@ -26,6 +26,7 @@ import (
"math/big"
"reflect"
"sort"
"sync/atomic"
"testing"
"time"
@@ -47,9 +48,8 @@ import (
)
var (
errStateNotFound = errors.New("state not found")
errBlockNotFound = errors.New("block not found")
errTransactionNotFound = errors.New("transaction not found")
errStateNotFound = errors.New("state not found")
errBlockNotFound = errors.New("block not found")
)
type testBackend struct {
@@ -57,24 +57,23 @@ type testBackend struct {
engine consensus.Engine
chaindb ethdb.Database
chain *core.BlockChain
refHook func() // Hook is invoked when the requested state is referenced
relHook func() // Hook is invoked when the requested state is released
}
// testBackend creates a new test backend. OBS: After test is done, teardown must be
// invoked in order to release associated resources.
func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend {
backend := &testBackend{
chainConfig: params.TestChainConfig,
chainConfig: gspec.Config,
engine: ethash.NewFaker(),
chaindb: rawdb.NewMemoryDatabase(),
}
// Generate blocks for testing
gspec.Config = backend.chainConfig
var (
gendb = rawdb.NewMemoryDatabase()
genesis = gspec.MustCommit(gendb)
)
blocks, _ := core.GenerateChain(backend.chainConfig, genesis, backend.engine, gendb, n, generator)
_, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator)
// Import the canonical chain
gspec.MustCommit(backend.chaindb)
cacheConfig := &core.CacheConfig{
TrieCleanLimit: 256,
TrieDirtyLimit: 256,
@@ -82,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
SnapshotLimit: 0,
TrieDirtyDisabled: true, // Archive mode
}
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil)
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
@@ -117,9 +116,6 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber)
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
if tx == nil {
return nil, common.Hash{}, 0, 0, errTransactionNotFound
}
return tx, hash, blockNumber, index, nil
}
@@ -139,25 +135,38 @@ func (b *testBackend) ChainDb() ethdb.Database {
return b.chaindb
}
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) {
statedb, err := b.chain.StateAt(block.Root())
if err != nil {
return nil, errStateNotFound
}
return statedb, nil
// teardown releases the associated resources.
func (b *testBackend) teardown() {
b.chain.Stop()
}
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) {
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
statedb, err := b.chain.StateAt(block.Root())
if err != nil {
return nil, nil, errStateNotFound
}
if b.refHook != nil {
b.refHook()
}
release := func() {
if b.relHook != nil {
b.relHook()
}
}
return statedb, release, nil
}
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, vm.BlockContext{}, nil, errBlockNotFound
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
}
statedb, err := b.chain.StateAt(parent.Root())
statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, vm.BlockContext{}, nil, errStateNotFound
return nil, vm.BlockContext{}, nil, nil, errStateNotFound
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, nil
return nil, vm.BlockContext{}, statedb, release, nil
}
// Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number())
@@ -166,15 +175,15 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
if idx == txIndex {
return msg, context, statedb, nil
return msg, context, statedb, release, nil
}
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
}
func TestTraceCall(t *testing.T) {
@@ -182,20 +191,25 @@ func TestTraceCall(t *testing.T) {
// Initialize test accounts
accounts := newAccounts(3)
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
}}
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
},
}
genBlocks := 10
signer := types.HomesteadSigner{}
api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
}))
})
defer backend.teardown()
api := NewAPI(backend)
var testSuite = []struct {
blockNumber rpc.BlockNumber
call ethapi.TransactionArgs
@@ -312,20 +326,25 @@ func TestTraceTransaction(t *testing.T) {
// Initialize test accounts
accounts := newAccounts(2)
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
}}
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
},
}
target := common.Hash{}
signer := types.HomesteadSigner{}
api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
backend := newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
target = tx.Hash()
}))
})
defer backend.chain.Stop()
api := NewAPI(backend)
result, err := api.TraceTransaction(context.Background(), target, nil)
if err != nil {
t.Errorf("Failed to trace transaction %v", err)
@@ -342,6 +361,12 @@ func TestTraceTransaction(t *testing.T) {
}) {
t.Error("Transaction tracing result is different")
}
// Test non-existent transaction
_, err = api.TraceTransaction(context.Background(), common.Hash{42}, nil)
if !errors.Is(err, errTxNotFound) {
t.Fatalf("want %v, have %v", errTxNotFound, err)
}
}
func TestTraceBlock(t *testing.T) {
@@ -349,20 +374,25 @@ func TestTraceBlock(t *testing.T) {
// Initialize test accounts
accounts := newAccounts(3)
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
}}
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
},
}
genBlocks := 10
signer := types.HomesteadSigner{}
api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
}))
})
defer backend.chain.Stop()
api := NewAPI(backend)
var testSuite = []struct {
blockNumber rpc.BlockNumber
@@ -424,20 +454,34 @@ func TestTracingWithOverrides(t *testing.T) {
t.Parallel()
// Initialize test accounts
accounts := newAccounts(3)
genesis := &core.Genesis{Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
}}
storageAccount := common.Address{0x13, 37}
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
// An account with existing storage
storageAccount: {
Balance: new(big.Int),
Storage: map[common.Hash]common.Hash{
common.HexToHash("0x03"): common.HexToHash("0x33"),
common.HexToHash("0x04"): common.HexToHash("0x44"),
},
},
},
}
genBlocks := 10
signer := types.HomesteadSigner{}
api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
}))
})
defer backend.chain.Stop()
api := NewAPI(backend)
randomAccounts := newAccounts(3)
type res struct {
Gas int
@@ -544,6 +588,164 @@ func TestTracingWithOverrides(t *testing.T) {
},
want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
},
/*
pragma solidity =0.8.12;
contract Test {
uint private x;
function test2() external {
x = 1337;
revert();
}
function test() external returns (uint) {
x = 1;
try this.test2() {} catch (bytes memory) {}
return x;
}
}
*/
{ // First with only code override, not storage override
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &randomAccounts[2].addr,
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
},
config: &TraceCallConfig{
StateOverrides: &ethapi.StateOverride{
randomAccounts[2].addr: ethapi.OverrideAccount{
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
},
},
},
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
},
{ // Same again, this time with storage override
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &randomAccounts[2].addr,
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
},
config: &TraceCallConfig{
StateOverrides: &ethapi.StateOverride{
randomAccounts[2].addr: ethapi.OverrideAccount{
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
State: newStates([]common.Hash{{}}, []common.Hash{{}}),
},
},
},
//want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
},
{ // No state override
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &storageAccount,
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
},
config: &TraceCallConfig{
StateOverrides: &ethapi.StateOverride{
storageAccount: ethapi.OverrideAccount{
Code: newRPCBytes([]byte{
// SLOAD(3) + SLOAD(4) (which is 0x77)
byte(vm.PUSH1), 0x04,
byte(vm.SLOAD),
byte(vm.PUSH1), 0x03,
byte(vm.SLOAD),
byte(vm.ADD),
// 0x77 -> MSTORE(0)
byte(vm.PUSH1), 0x00,
byte(vm.MSTORE),
// RETURN (0, 32)
byte(vm.PUSH1), 32,
byte(vm.PUSH1), 00,
byte(vm.RETURN),
}),
},
},
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000077"}`,
},
{ // Full state override
// The original storage is
// 3: 0x33
// 4: 0x44
// With a full override, where we set 3:0x11, the slot 4 should be
// removed. So SLOT(3)+SLOT(4) should be 0x11.
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &storageAccount,
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
},
config: &TraceCallConfig{
StateOverrides: &ethapi.StateOverride{
storageAccount: ethapi.OverrideAccount{
Code: newRPCBytes([]byte{
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
byte(vm.PUSH1), 0x04,
byte(vm.SLOAD),
byte(vm.PUSH1), 0x03,
byte(vm.SLOAD),
byte(vm.ADD),
// 0x11 -> MSTORE(0)
byte(vm.PUSH1), 0x00,
byte(vm.MSTORE),
// RETURN (0, 32)
byte(vm.PUSH1), 32,
byte(vm.PUSH1), 00,
byte(vm.RETURN),
}),
State: newStates(
[]common.Hash{common.HexToHash("0x03")},
[]common.Hash{common.HexToHash("0x11")}),
},
},
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000011"}`,
},
{ // Partial state override
// The original storage is
// 3: 0x33
// 4: 0x44
// With a partial override, where we set 3:0x11, the slot 4 as before.
// So SLOT(3)+SLOT(4) should be 0x55.
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &storageAccount,
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
},
config: &TraceCallConfig{
StateOverrides: &ethapi.StateOverride{
storageAccount: ethapi.OverrideAccount{
Code: newRPCBytes([]byte{
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44)
byte(vm.PUSH1), 0x04,
byte(vm.SLOAD),
byte(vm.PUSH1), 0x03,
byte(vm.SLOAD),
byte(vm.ADD),
// 0x55 -> MSTORE(0)
byte(vm.PUSH1), 0x00,
byte(vm.MSTORE),
// RETURN (0, 32)
byte(vm.PUSH1), 32,
byte(vm.PUSH1), 00,
byte(vm.RETURN),
}),
StateDiff: &map[common.Hash]common.Hash{
common.HexToHash("0x03"): common.HexToHash("0x11"),
},
},
},
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
},
}
for i, tc := range testSuite {
result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)
@@ -570,7 +772,8 @@ func TestTracingWithOverrides(t *testing.T) {
json.Unmarshal(resBytes, &have)
json.Unmarshal([]byte(tc.want), &want)
if !reflect.DeepEqual(have, want) {
t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(resBytes), want)
t.Logf("result: %v\n", string(resBytes))
t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, have, want)
}
}
}
@@ -616,3 +819,77 @@ func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.H
}
return &m
}
func TestTraceChain(t *testing.T) {
// Initialize test accounts
accounts := newAccounts(3)
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
},
}
genBlocks := 50
signer := types.HomesteadSigner{}
var (
ref uint32 // total refs has made
rel uint32 // total rels has made
nonce uint64
)
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
for j := 0; j < i+1; j++ {
tx, _ := types.SignTx(types.NewTransaction(nonce, accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
nonce += 1
}
})
backend.refHook = func() { atomic.AddUint32(&ref, 1) }
backend.relHook = func() { atomic.AddUint32(&rel, 1) }
api := NewAPI(backend)
single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
var cases = []struct {
start uint64
end uint64
config *TraceConfig
}{
{0, 50, nil}, // the entire chain range, blocks [1, 50]
{10, 20, nil}, // the middle chain range, blocks [11, 20]
}
for _, c := range cases {
ref, rel = 0, 0 // clean up the counters
from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start))
to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end))
resCh := api.traceChain(from, to, c.config, nil)
next := c.start + 1
for result := range resCh {
if next != uint64(result.Block) {
t.Error("Unexpected tracing block")
}
if len(result.Traces) != int(next) {
t.Error("Unexpected tracing result")
}
for _, trace := range result.Traces {
blob, _ := json.Marshal(trace)
if string(blob) != single {
t.Error("Unexpected tracing result")
}
}
next += 1
}
if next != c.end+1 {
t.Error("Missing tracing block")
}
if ref != rel {
t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel)
}
}
}
+64 -121
View File
@@ -21,10 +21,8 @@ import (
"math/big"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"unicode"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -38,62 +36,8 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests"
// Force-load native and js packages, to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
)
// To generate a new callTracer test, copy paste the makeTest method below into
// a Geth console and call it with a transaction hash you which to export.
/*
// makeTest generates a callTracer test by running a prestate reassembled and a
// call trace run, assembling all the gathered information into a test case.
var makeTest = function(tx, rewind) {
// Generate the genesis block from the block, transaction and prestate data
var block = eth.getBlock(eth.getTransaction(tx).blockHash);
var genesis = eth.getBlock(block.parentHash);
delete genesis.gasUsed;
delete genesis.logsBloom;
delete genesis.parentHash;
delete genesis.receiptsRoot;
delete genesis.sha3Uncles;
delete genesis.size;
delete genesis.transactions;
delete genesis.transactionsRoot;
delete genesis.uncles;
genesis.gasLimit = genesis.gasLimit.toString();
genesis.number = genesis.number.toString();
genesis.timestamp = genesis.timestamp.toString();
genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind});
for (var key in genesis.alloc) {
genesis.alloc[key].nonce = genesis.alloc[key].nonce.toString();
}
genesis.config = admin.nodeInfo.protocols.eth.config;
// Generate the call trace and produce the test input
var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind});
delete result.time;
console.log(JSON.stringify({
genesis: genesis,
context: {
number: block.number.toString(),
difficulty: block.difficulty,
timestamp: block.timestamp.toString(),
gasLimit: block.gasLimit.toString(),
miner: block.miner,
},
input: eth.getRawTransaction(tx),
result: result,
}, null, 2));
}
*/
type callContext struct {
Number math.HexOrDecimal64 `json:"number"`
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
@@ -102,18 +46,28 @@ type callContext struct {
Miner common.Address `json:"miner"`
}
// callLog is the result of LOG opCode
type callLog struct {
Address common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
}
// callTrace is the result of a callTracer run.
type callTrace struct {
Type string `json:"type"`
From common.Address `json:"from"`
To common.Address `json:"to"`
Input hexutil.Bytes `json:"input"`
Output hexutil.Bytes `json:"output"`
Gas *hexutil.Uint64 `json:"gas,omitempty"`
GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"`
Value *hexutil.Big `json:"value,omitempty"`
Error string `json:"error,omitempty"`
Calls []callTrace `json:"calls,omitempty"`
From common.Address `json:"from"`
Gas *hexutil.Uint64 `json:"gas"`
GasUsed *hexutil.Uint64 `json:"gasUsed"`
To common.Address `json:"to,omitempty"`
Input hexutil.Bytes `json:"input"`
Output hexutil.Bytes `json:"output,omitempty"`
Error string `json:"error,omitempty"`
RevertReason string `json:"revertReason,omitempty"`
Calls []callTrace `json:"calls,omitempty"`
Logs []callLog `json:"logs,omitempty"`
Value *hexutil.Big `json:"value,omitempty"`
// Gencodec adds overridden fields at the end
Type string `json:"type"`
}
// callTracerTest defines a single test to check the call tracer against.
@@ -135,7 +89,12 @@ func TestCallTracerNative(t *testing.T) {
testCallTracer("callTracer", "call_tracer", t)
}
func TestCallTracerNativeWithLog(t *testing.T) {
testCallTracer("callTracer", "call_tracer_withLog", t)
}
func testCallTracer(tracerName string, dirPath string, t *testing.T) {
isLegacy := strings.HasSuffix(dirPath, "_legacy")
files, err := os.ReadDir(filepath.Join("testdata", dirPath))
if err != nil {
t.Fatalf("failed to retrieve tracer test suite: %v", err)
@@ -158,7 +117,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
} else if err := json.Unmarshal(blob, test); err != nil {
t.Fatalf("failed to parse testcase: %v", err)
}
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil {
t.Fatalf("failed to parse testcase input: %v", err)
}
// Configure a blockchain with the given prestate
@@ -174,13 +133,14 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
}
_, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
)
tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
@@ -189,57 +149,46 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil {
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
// Retrieve the trace result and compare against the etalon
// Retrieve the trace result and compare against the expected.
res, err := tracer.GetResult()
if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err)
}
ret := new(callTrace)
if err := json.Unmarshal(res, ret); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err)
// The legacy javascript calltracer marshals json in js, which
// is not deterministic (as opposed to the golang json encoder).
if isLegacy {
// This is a tweak to make it deterministic. Can be removed when
// we remove the legacy tracer.
var x callTrace
json.Unmarshal(res, &x)
res, _ = json.Marshal(x)
}
if !jsonEqual(ret, test.Result) {
// uncomment this for easier debugging
//have, _ := json.MarshalIndent(ret, "", " ")
//want, _ := json.MarshalIndent(test.Result, "", " ")
//t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want))
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result)
want, err := json.Marshal(test.Result)
if err != nil {
t.Fatalf("failed to marshal test: %v", err)
}
if string(want) != string(res) {
t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want))
}
// Sanity check: compare top call's gas used against vm result
type simpleResult struct {
GasUsed hexutil.Uint64
}
var topCall simpleResult
if err := json.Unmarshal(res, &topCall); err != nil {
t.Fatalf("failed to unmarshal top calls gasUsed: %v", err)
}
if uint64(topCall.GasUsed) != vmRet.UsedGas {
t.Fatalf("top call has invalid gasUsed. have: %d want: %d", topCall.GasUsed, vmRet.UsedGas)
}
})
}
}
// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to
// comparison
func jsonEqual(x, y interface{}) bool {
xTrace := new(callTrace)
yTrace := new(callTrace)
if xj, err := json.Marshal(x); err == nil {
json.Unmarshal(xj, xTrace)
} else {
return false
}
if yj, err := json.Marshal(y); err == nil {
json.Unmarshal(yj, yTrace)
} else {
return false
}
return reflect.DeepEqual(xTrace, yTrace)
}
// camel converts a snake cased input string into a camel cased output.
func camel(str string) string {
pieces := strings.Split(str, "_")
for i := 1; i < len(pieces); i++ {
pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:]
}
return strings.Join(pieces, "")
}
func BenchmarkTracers(b *testing.B) {
files, err := os.ReadDir(filepath.Join("testdata", "call_tracer"))
if err != nil {
@@ -285,7 +234,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
}
@@ -294,7 +243,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
tracer, err := tracers.New(tracerName, new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
@@ -339,7 +288,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
Transfer: core.Transfer,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000),
Time: new(big.Int).SetUint64(5),
Time: 5,
Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000),
}
@@ -360,7 +309,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
}
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false)
// Create the tracer, the EVM environment and run it
tracer, err := tracers.New("callTracer", nil, nil)
tracer, err := tracers.DefaultDirectory.New("callTracer", nil, nil)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
@@ -378,14 +327,8 @@ func TestZeroValueToNotExitCall(t *testing.T) {
if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err)
}
have := new(callTrace)
if err := json.Unmarshal(res, have); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err)
}
wantStr := `{"type":"CALL","from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}`
want := new(callTrace)
json.Unmarshal([]byte(wantStr), want)
if !jsonEqual(have, want) {
t.Error("have != want")
wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`
if string(res) != wantStr {
t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr)
}
}
@@ -0,0 +1,149 @@
// Copyright 2021 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 tracetest
import (
"encoding/json"
"math/big"
"os"
"path/filepath"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/tests"
)
// prestateTrace is the result of a prestateTrace run.
type prestateTrace = map[common.Address]*account
type account struct {
Balance string `json:"balance"`
Code string `json:"code"`
Nonce uint64 `json:"nonce"`
Storage map[common.Hash]common.Hash `json:"storage"`
}
// testcase defines a single test to check the stateDiff tracer against.
type testcase struct {
Genesis *core.Genesis `json:"genesis"`
Context *callContext `json:"context"`
Input string `json:"input"`
TracerConfig json.RawMessage `json:"tracerConfig"`
Result interface{} `json:"result"`
}
func TestPrestateTracerLegacy(t *testing.T) {
testPrestateDiffTracer("prestateTracerLegacy", "prestate_tracer_legacy", t)
}
func TestPrestateTracer(t *testing.T) {
testPrestateDiffTracer("prestateTracer", "prestate_tracer", t)
}
func TestPrestateWithDiffModeTracer(t *testing.T) {
testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t)
}
func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
files, err := os.ReadDir(filepath.Join("testdata", dirPath))
if err != nil {
t.Fatalf("failed to retrieve tracer test suite: %v", err)
}
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
file := file // capture range variable
t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) {
t.Parallel()
var (
test = new(testcase)
tx = new(types.Transaction)
)
// Call tracer test found, read if from disk
if blob, err := os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil {
t.Fatalf("failed to read testcase: %v", err)
} else if err := json.Unmarshal(blob, test); err != nil {
t.Fatalf("failed to parse testcase: %v", err)
}
if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil {
t.Fatalf("failed to parse testcase input: %v", err)
}
// Configure a blockchain with the given prestate
var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
origin, _ = signer.Sender(tx)
txContext = vm.TxContext{
Origin: origin,
GasPrice: tx.GasPrice(),
}
context = vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
}
_, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer, nil)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
// Retrieve the trace result and compare against the expected
res, err := tracer.GetResult()
if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err)
}
// The legacy javascript calltracer marshals json in js, which
// is not deterministic (as opposed to the golang json encoder).
if strings.HasSuffix(dirPath, "_legacy") {
// This is a tweak to make it deterministic. Can be removed when
// we remove the legacy tracer.
var x prestateTrace
json.Unmarshal(res, &x)
res, _ = json.Marshal(x)
}
want, err := json.Marshal(test.Result)
if err != nil {
t.Fatalf("failed to marshal test: %v", err)
}
if string(want) != string(res) {
t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want))
}
})
}
}
@@ -48,7 +48,7 @@
"result": {
"from": "0x13e4acefe6a6700604929946e70e6443e4e73447",
"gas": "0x5e106",
"gasUsed": "0x5e106",
"gasUsed": "0x897be",
"input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11",
"output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029",
"to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448",
@@ -263,7 +263,6 @@
"gas": "0x20ee1",
"gasUsed": "0x5374",
"input": "0x581d5d60000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
"to": "0xcf00ffd997ad14939736f026006498e3f099baaf",
"type": "CALL",
"value": "0x0"
@@ -305,7 +304,6 @@
"gas": "0x1a91d",
"gasUsed": "0x12fa",
"input": "0x0accce0600000000000000000000000000000000000000000000000000000000000000025842545553440000000000000000000000000000000000000000000000000000000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38",
"type": "CALL",
"value": "0x0"
@@ -377,7 +375,6 @@
"gas": "0x16e62",
"gasUsed": "0xebb",
"input": "0x645a3b72584254555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002816d180e30c390000",
"output": "0x",
"to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38",
"type": "CALL",
"value": "0x0"
@@ -387,7 +384,6 @@
"gas": "0x283b9",
"gasUsed": "0xc51c",
"input": "0x949ae479000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
"to": "0x3e9286eafa2db8101246c2131c09b49080d00690",
"type": "CALL",
"value": "0x0"
@@ -397,7 +393,6 @@
"gas": "0x30b4a",
"gasUsed": "0xedb7",
"input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
"to": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f",
"type": "CALL",
"value": "0x0"
@@ -405,9 +400,8 @@
],
"from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38",
"gasUsed": "0x12bb3",
"gasUsed": "0x1810b",
"input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
"type": "CALL",
"value": "0x0"
@@ -72,7 +72,8 @@
"input": "0x7d65837a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2",
"type": "DELEGATECALL"
"type": "DELEGATECALL",
"value": "0x0"
}
],
"from": "0x269296dddce321a6bcbaa2f0181127593d732cba",
@@ -87,9 +88,8 @@
],
"from": "0xa529806c67cc6486d4d62024471772f47f6fd672",
"gas": "0x2d6e28",
"gasUsed": "0x64bd",
"gasUsed": "0xbd55",
"input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e",
"output": "0x",
"to": "0x269296dddce321a6bcbaa2f0181127593d732cba",
"type": "CALL",
"value": "0x0"
File diff suppressed because one or more lines are too long
@@ -55,9 +55,7 @@
"to": "0x6c06b16512b332e6cd8293a2974872674716ce18",
"value": "0x0",
"gas": "0x1a466",
"gasUsed": "0x1dc6",
"input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000",
"output": "0x",
"calls": []
"gasUsed": "0x72de",
"input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000"
}
}
@@ -0,0 +1,86 @@
{
"genesis": {
"baseFeePerGas": "1000000000",
"difficulty": "1",
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000003623191d4ccfbbdf09e8ebf6382a1f8257417bc10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "11500000",
"hash": "0x2af138b8a06e65b8dd0999df70b9e87609e9fc91ea201f08b1cc4f25ef01fcf6",
"miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"number": "0",
"stateRoot": "0xa775801d572e9b79585eb131d18d79f8a0f71895455ab9a5b656911428e11708",
"timestamp": "0",
"totalDifficulty": "1",
"alloc": {
"0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1": {
"balance": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7"
},
"0xd15abca351f79181dedfb6d019e382db90f3628a": {
"balance": "0x0"
}
},
"config": {
"chainId": 1337,
"homesteadBlock": 0,
"eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"clique": {
"period": 0,
"epoch": 30000
}
}
},
"context": {
"number": "1",
"difficulty": "2",
"timestamp": "1665537018",
"gasLimit": "11511229",
"miner": "0x0000000000000000000000000000000000000000"
},
"input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc",
"result": {
"from": "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1",
"to": "0x0000000000000000000000000000000000000000",
"gas": "0x2cd774",
"gasUsed": "0x25590",
"input": "0x608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033",
"output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000",
"error": "execution reverted",
"revertReason": "This called failed",
"calls": [
{
"from": "0xdebfb4b387033eac57af7b3de5116dd60056803b",
"gas": "0x2ba851",
"gasUsed": "0xe557",
"to": "0xd15abca351f79181dedfb6d019e382db90f3628a",
"input": "0x608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033",
"output": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033",
"value": "0x0",
"type": "CREATE"
},
{
"from": "0xdebfb4b387033eac57af7b3de5116dd60056803b",
"gas": "0x2ac548",
"gasUsed": "0x1b2",
"to": "0xd15abca351f79181dedfb6d019e382db90f3628a",
"input": "0xc0406226",
"output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000",
"error": "execution reverted",
"revertReason": "This called failed",
"type": "STATICCALL"
}
],
"value": "0x0",
"type": "CREATE"
}
}
@@ -72,7 +72,7 @@
"error": "execution reverted",
"from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826",
"gas": "0x78d9e",
"gasUsed": "0x76fc0",
"gasUsed": "0x7c1c8",
"input": "0x",
"to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
"type": "CALL",
@@ -0,0 +1,19 @@
This test tests out the trace generated by the deployment of this contract:
```solidity
contract Revertor {
function run() public pure {
require(2 > 3, "This called failed");
}
}
contract Contract {
constructor() {
Revertor r = new Revertor();
r.run();
}
}
```
The trace should show a revert, with the revert reason for both the top-call as well
as the inner call.
@@ -51,7 +51,7 @@
"error": "out of gas",
"from": "0x94194bc2aaf494501d7880b61274a169f6502a54",
"gas": "0x7045",
"gasUsed": "0x7045",
"gasUsed": "0xca1d",
"input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000",
"to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62",
"type": "CALL",
@@ -49,7 +49,7 @@
"error": "execution reverted",
"from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9",
"gas": "0x2d55e8",
"gasUsed": "0xc3",
"gasUsed": "0x719b",
"input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae",
"type": "CALL",
@@ -54,11 +54,12 @@
"error": "execution reverted",
"from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
"gas": "0x2d7308",
"gasUsed": "0x588",
"gasUsed": "0x5940",
"input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
"to": "0xf58833cf0c791881b494eb79d461e08a1f043f52",
"type": "CALL",
"value": "0x0",
"output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000"
"output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000",
"revertReason": "Self-delegation is disallowed."
}
}
@@ -58,16 +58,15 @@
"gas": "0x0",
"gasUsed": "0x0",
"input": "0x",
"to": "0x000000000000000000000000000000000000dEaD",
"to": "0x000000000000000000000000000000000000dead",
"type": "SELFDESTRUCT",
"value": "0x4d87094125a369d9bd5"
}
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x10738",
"gasUsed": "0x7533",
"gasUsed": "0x6fcb",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
"type": "CALL",
"value": "0x0"
@@ -70,7 +70,7 @@
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x10738",
"gasUsed": "0x3ef9",
"gasUsed": "0x9751",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
@@ -62,7 +62,7 @@
"result": {
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x10738",
"gasUsed": "0x3ef9",
"gasUsed": "0x9751",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
@@ -53,7 +53,7 @@
"error": "invalid jump destination",
"from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38",
"gasUsed": "0x37b38",
"gasUsed": "0x3d090",
"input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
"type": "CALL",
@@ -48,7 +48,7 @@
"result": {
"from": "0x13e4acefe6a6700604929946e70e6443e4e73447",
"gas": "0x5e106",
"gasUsed": "0x5e106",
"gasUsed": "0x897be",
"input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11",
"output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029",
"to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448",
@@ -405,7 +405,7 @@
],
"from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38",
"gasUsed": "0x12bb3",
"gasUsed": "0x1810b",
"input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
@@ -87,7 +87,7 @@
],
"from": "0xa529806c67cc6486d4d62024471772f47f6fd672",
"gas": "0x2d6e28",
"gasUsed": "0x64bd",
"gasUsed": "0xbd55",
"input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e",
"output": "0x",
"to": "0x269296dddce321a6bcbaa2f0181127593d732cba",
@@ -68,7 +68,7 @@
"error": "invalid jump destination",
"from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8",
"gas": "0x435c8",
"gasUsed": "0x435c8",
"gasUsed": "0x493e0",
"input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8",
"to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a",
"type": "CALL",
@@ -55,7 +55,7 @@
"to": "0x6c06b16512b332e6cd8293a2974872674716ce18",
"value": "0x0",
"gas": "0x1a466",
"gasUsed": "0x1dc6",
"gasUsed": "0x72de",
"input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000",
"output": "0x",
"calls": [
@@ -72,7 +72,7 @@
"error": "execution reverted",
"from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826",
"gas": "0x78d9e",
"gasUsed": "0x76fc0",
"gasUsed": "0x7c1c8",
"input": "0x",
"to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
"type": "CALL",
@@ -51,7 +51,7 @@
"error": "out of gas",
"from": "0x94194bc2aaf494501d7880b61274a169f6502a54",
"gas": "0x7045",
"gasUsed": "0x7045",
"gasUsed": "0xca1d",
"input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000",
"to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62",
"type": "CALL",
@@ -49,7 +49,7 @@
"error": "execution reverted",
"from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9",
"gas": "0x2d55e8",
"gasUsed": "0xc3",
"gasUsed": "0x719b",
"input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae",
"type": "CALL",
@@ -54,7 +54,7 @@
"error": "execution reverted",
"from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
"gas": "0x2d7308",
"gasUsed": "0x588",
"gasUsed": "0x5940",
"input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
"to": "0xf58833cf0c791881b494eb79d461e08a1f043f52",
"type": "CALL",
@@ -63,7 +63,7 @@
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x10738",
"gasUsed": "0x7533",
"gasUsed": "0x6fcb",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
@@ -68,7 +68,7 @@
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"gas": "0x10738",
"gasUsed": "0x3ef9",
"gasUsed": "0x9751",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
@@ -53,7 +53,7 @@
"error": "invalid jump destination",
"from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38",
"gasUsed": "0x37b38",
"gasUsed": "0x3d090",
"input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
"type": "CALL",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,84 @@
{
"genesis": {
"difficulty": "8430028481555",
"extraData": "0xd783010302844765746887676f312e352e31856c696e7578",
"gasLimit": "3141592",
"hash": "0xde66937783697293f2e529d2034887c531535d78afa8c9051511ae12ba48fbea",
"miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226",
"mixHash": "0xba28a43bfbca4a2effbb76bb70d03482a8a0c92e2883ff36cbac3d7c6dbb7df5",
"nonce": "0xa3827ec0a82fe823",
"number": "765824",
"stateRoot": "0x8d96cb027a29f8ca0ccd6d31f9ea0656136ec8030ecda70bb9231849ed6f41a2",
"timestamp": "1451389443",
"totalDifficulty": "4838314986494741271",
"alloc": {
"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb": {
"balance": "0x14203bee2ea6fbe8c",
"nonce": "34"
},
"0xe2fe6b13287f28e193333fdfe7fedf2f6df6124a": {
"balance": "0x2717a9c870a286f4350"
},
"0xf4eced2f682ce333f96f2d8966c613ded8fc95dd": {
"balance": "0x0",
"code": "0x606060405260e060020a600035046306fdde038114610047578063313ce567146100a457806370a08231146100b057806395d89b41146100c8578063a9059cbb14610123575b005b61015260008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156101f55780601f106101ca576101008083540402835291602001916101f5565b6101c060025460ff1681565b6101c060043560036020526000908152604090205481565b610152600180546020601f6002600019610100858716150201909316929092049182018190040260809081016040526060828152929190828280156101f55780601f106101ca576101008083540402835291602001916101f5565b610045600435602435600160a060020a033316600090815260036020526040902054819010156101fd57610002565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156101b25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6060908152602090f35b820191906000526020600020905b8154815290600101906020018083116101d857829003601f168201915b505050505081565b600160a060020a03821660009081526040902054808201101561021f57610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505056",
"storage": {
"0x1dae8253445d3a5edbe8200da9fc39bc4f11db9362181dc1b640d08c3c2fb4d6": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x8ba52aac7f255d80a49abcf003d6af4752aba5a9531cae94fde7ac8d72191d67": "0x000000000000000000000000000000000000000000000000000000000178e460"
}
}
},
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficultyPassed": true,
"ethash": {}
}
},
"context": {
"number": "765825",
"difficulty": "8425912256743",
"timestamp": "1451389488",
"gasLimit": "3141592",
"miner": "0xe2fe6b13287f28e193333fdfe7fedf2f6df6124a"
},
"input": "0xf8aa22850ba43b740083024d4594f4eced2f682ce333f96f2d8966c613ded8fc95dd80b844a9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb00000000000000000000000000000000000000000000000000000000009896801ca067da548a2e0f381a957b9b51f086073375d6bfc7312cbc9540b3647ccab7db11a042c6e5b34bc7ba821e9c25b166fa13d82ad4b0d044d16174d5587d4f04ecfcd1",
"tracerConfig": {
"withLog": true
},
"result": {
"from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"gas": "0x1f36d",
"gasUsed": "0xc6a5",
"to": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd",
"input": "0xa9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb0000000000000000000000000000000000000000000000000000000000989680",
"logs": [
{
"address": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000d1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"0x000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000989680"
}
],
"value": "0x0",
"type": "CALL"
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,85 @@
{
"genesis": {
"difficulty": "6217248151198",
"extraData": "0xd783010103844765746887676f312e342e32856c696e7578",
"gasLimit": "3141592",
"hash": "0xe8bff55fe3e61936ef321cf3afaeb1ba2f7234e1e89535fa8ae39963caebe9c3",
"miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5",
"mixHash": "0x03da00d5a15a064e5ebddf53cd0aaeb9a8aff0f40c0fb031a74f463d11ec83b8",
"nonce": "0x6575fe08c4167044",
"number": "243825",
"stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf",
"timestamp": "1442424328",
"totalDifficulty": "1035061827427752845",
"alloc": {
"0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": {
"balance": "0xc820f93200f4000",
"nonce": "0x5E",
"code": "0x"
},
"0x332b656504f4eabb44c8617a42af37461a34e9dc": {
"balance": "0x11faea4f35e5af80000",
"code": "0x"
},
"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
"balance": "0xbf681825be002ac452",
"nonce": "0x70FA",
"code": "0x"
},
"0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": {
"balance": "0xb3d0ac5cb94df6f6b0",
"nonce": "0x1",
"code": "0x"
}
},
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficultyPassed": true,
"ethash": {}
}
},
"context": {
"number": "243826",
"difficulty": "6214212385501",
"timestamp": "1442424353",
"gasLimit": "3141592",
"miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5"
},
"input": "0xf8e85e850ba43b7400830f42408080b89660606040527382effbaaaf28614e55b2ba440fb198e0e5789b0f600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600a80608c6000396000f30060606040526008565b001ca0340b21661e5bb85a46319a15f33a362e5c0f02faa7cdbf9c5808b2134da968eaa0226e6788f8c20e211d436ab7f6298ef32fa4c23a509eeeaac0880d115c17bc3f",
"result": {
"0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": {
"balance": "0xc820f93200f4000",
"nonce": 94
},
"0x332b656504f4eabb44c8617a42af37461a34e9dc": {
"balance": "0x11faea4f35e5af80000",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
"balance": "0xbf681825be002ac452",
"nonce": 28922
},
"0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": {
"balance": "0xb3d0ac5cb94df6f6b0",
"nonce": 1
}
}
}
@@ -0,0 +1,83 @@
{
"context": {
"difficulty": "3502894804",
"gasLimit": "4722976",
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
"number": "2289806",
"timestamp": "1513601314"
},
"genesis": {
"alloc": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"code": "0x",
"nonce": "22",
"storage": {}
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"nonce": "1",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"code": "0x",
"nonce": "29072",
"storage": {}
}
},
"config": {
"byzantiumBlock": 1700000,
"chainId": 3,
"daoForkSupport": true,
"eip150Block": 0,
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
"eip155Block": 10,
"eip158Block": 10,
"ethash": {},
"homesteadBlock": 0
},
"difficulty": "3509749784",
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
"gasLimit": "4727564",
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
"nonce": "0x4eb12e19c16d43da",
"number": "2289805",
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
"timestamp": "1513601261",
"totalDifficulty": "7143276353481064"
},
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
"result": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"nonce": 22
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"nonce": 1,
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"nonce": 29072
},
"0x1585936b53834b021f68cc13eeefdec2efc8e724": {
"balance": "0x0"
}
}
}
@@ -0,0 +1,84 @@
{
"context": {
"difficulty": "3502894804",
"gasLimit": "4722976",
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
"number": "2289806",
"timestamp": "1513601314"
},
"genesis": {
"alloc": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"code": "0x",
"nonce": "22",
"storage": {}
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"nonce": "1",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"code": "0x",
"nonce": "29072",
"storage": {}
}
},
"config": {
"byzantiumBlock": 1700000,
"chainId": 3,
"daoForkSupport": true,
"eip150Block": 0,
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
"eip155Block": 10,
"eip158Block": 10,
"ethash": {},
"homesteadBlock": 0
},
"difficulty": "3509749784",
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
"gasLimit": "4727564",
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
"nonce": "0x4eb12e19c16d43da",
"number": "2289805",
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
"timestamp": "1513601261",
"totalDifficulty": "7143276353481064"
},
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
"result": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"code": "0x",
"nonce": 22,
"storage": {}
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"nonce": 1,
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"code": "0x",
"nonce": 29072,
"storage": {}
}
}
}
@@ -0,0 +1,102 @@
{
"genesis": {
"difficulty": "13756228101629",
"extraData": "0xd983010302844765746887676f312e342e328777696e646f7773",
"gasLimit": "3141592",
"hash": "0x58b7a87b6ba10b46b4e251d64ebc3d9822dd82218eaf24dff6796f6f1f687251",
"miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069",
"mixHash": "0x5984b9a316116bd890e6e5f4c52d655184b0d7aa74821e1382d7760f9803c1dd",
"nonce": "0xea4bb4997242c681",
"number": "1061221",
"stateRoot": "0x5402c04d481414248d824c3b61e924e0c9307adbc9fbaae774a74cce30a4163d",
"timestamp": "1456458069",
"totalDifficulty": "7930751135586064334",
"alloc": {
"0x2a65aca4d5fc5b5c859090a6c34d164135398226": {
"balance": "0x9fb6b81e112638b886",
"nonce": "217865",
"code": "0x"
},
"0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": {
"balance": "0x15b6828e22bb12188",
"nonce": "747",
"code": "0x"
}
},
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"ethash": {}
}
},
"context": {
"number": "1061222",
"difficulty": "13749511193633",
"timestamp": "1456458097",
"gasLimit": "3141592",
"miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226"
},
"input": "0xf905498202eb850ba43b7400830f42408080b904f460606040526040516102b43803806102b48339016040526060805160600190602001505b5b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b806001600050908051906020019082805482825590600052602060002090601f01602090048101928215609e579182015b82811115609d5782518260005055916020019190600101906081565b5b50905060c5919060a9565b8082111560c1576000818150600090555060010160a9565b5090565b50505b506101dc806100d86000396000f30060606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001ee7b225f6964223a225a473466784a7245323639384866623839222c22666f726d5f736f75726365223a22434c54523031222c22636f6d6d69746d656e745f64617465223a22222c22626f72726f7765725f6e616d65223a22222c22626f72726f7765725f616464726573735f6c696e6531223a22222c22626f72726f7765725f616464726573735f6c696e6532223a22222c22626f72726f7765725f636f6e74616374223a22222c22626f72726f7765725f7374617465223a22222c22626f72726f7765725f74797065223a22222c2270726f70657274795f61646472657373223a22222c226c6f616e5f616d6f756e745f7772697474656e223a22222c226c6f616e5f616d6f756e74223a22222c224c54565f7772697474656e223a22222c224c5456223a22222c2244534352223a22222c2270726f70657274795f74797065223a22222c2270726f70657274795f6465736372697074696f6e223a22222c226c656e646572223a22222c2267756172616e746f7273223a22222c226c696d69746564223a22222c226361705f616d6f756e74223a22222c226361705f70657263656e745f7772697474656e223a22222c226361705f70657263656e74616765223a22222c227465726d5f7772697474656e223a22222c227465726d223a22222c22657874656e64223a22227d0000000000000000000000000000000000001ba027d54712289af34f0ec0f06092745104d68e5801cd17097bc1104111f855258da070ec9f1c942d9bedf89f9660a684d3bb8cd9c2ac7f6dd883cb3e26a193180244",
"tracerConfig": {
"diffMode": true
},
"result": {
"pre": {
"0x2a65aca4d5fc5b5c859090a6c34d164135398226": {
"balance": "0x9fb6b81e112638b886",
"nonce": 217865
},
"0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": {
"balance": "0x15b6828e22bb12188",
"nonce": 747
}
},
"post": {
"0x2a65aca4d5fc5b5c859090a6c34d164135398226": {
"balance": "0x9fb71abdd2621d8886"
},
"0x40f2f445da6c9047554683fb382fba6769717116": {
"code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f0c5cef39b17c213cfe090a46b8c7760ffb7928a",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000000000000000001ee",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "0x7b225f6964223a225a473466784a7245323639384866623839222c22666f726d",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7": "0x5f736f75726365223a22434c54523031222c22636f6d6d69746d656e745f6461",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8": "0x7465223a22222c22626f72726f7765725f6e616d65223a22222c22626f72726f",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf9": "0x7765725f616464726573735f6c696e6531223a22222c22626f72726f7765725f",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfa": "0x616464726573735f6c696e6532223a22222c22626f72726f7765725f636f6e74",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfb": "0x616374223a22222c22626f72726f7765725f7374617465223a22222c22626f72",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfc": "0x726f7765725f74797065223a22222c2270726f70657274795f61646472657373",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfd": "0x223a22222c226c6f616e5f616d6f756e745f7772697474656e223a22222c226c",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfe": "0x6f616e5f616d6f756e74223a22222c224c54565f7772697474656e223a22222c",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cff": "0x224c5456223a22222c2244534352223a22222c2270726f70657274795f747970",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d00": "0x65223a22222c2270726f70657274795f6465736372697074696f6e223a22222c",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d01": "0x226c656e646572223a22222c2267756172616e746f7273223a22222c226c696d",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d02": "0x69746564223a22222c226361705f616d6f756e74223a22222c226361705f7065",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d03": "0x7263656e745f7772697474656e223a22222c226361705f70657263656e746167",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d04": "0x65223a22222c227465726d5f7772697474656e223a22222c227465726d223a22",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d05": "0x222c22657874656e64223a22227d000000000000000000000000000000000000"
}
},
"0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": {
"balance": "0x15b058920efcc5188",
"nonce": 748
}
}
}
}
@@ -0,0 +1,94 @@
{
"genesis": {
"baseFeePerGas": "51088069741",
"difficulty": "14315558652874667",
"extraData": "0xd883010a10846765746888676f312e31362e35856c696e7578",
"gasLimit": "30058590",
"hash": "0xdf6b95183f99054fb6541e3b482c0109c9f6be40553cff24efa3ac76736adbf5",
"miner": "0xb7e390864a90b7b923c9f9310c6f98aafe43f707",
"mixHash": "0x8d76b0d32e42ab277dbf00836eabef76674cd70ae2bb53718175069ad6b6147e",
"nonce": "0x8d3a1c010ad2c687",
"number": "14707767",
"stateRoot": "0x8a50c896a6f7eb1f3479337db981fa10ce316281cb4dd2f07487be9ca27dae6b",
"timestamp": "1651623275",
"alloc": {
"0x0000000000000000000000000000000000000000": {
"balance": "0x268fd0b894b8c4f6d1f"
},
"0x13b152c9f50878ffaf3de41e192653bda545d889": {
"balance": "0x0",
"nonce": "1",
"code": "0x363d3d373d3d3d363d73059ffafdc6ef594230de44f824e2bd0a51ca5ded5af43d82803e903d91602b57fd5bf3"
},
"0x808b4da0be6c9512e948521452227efc619bea52": {
"balance": "0x2cdb96c56db040b43",
"nonce": "1223932"
},
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {
"balance": "0x38079b28689d40240e",
"nonce": "44"
},
"0xffa397285ce46fb78c588a9e993286aac68c37cd": {
"balance": "0x0",
"nonce": "747319",
"code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063b97a23191461003b578063fb90b3201461006f575b600080fd5b6100436100bd565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100bb6004803603604081101561008557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506100e1565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b815260140182815260200192505050604051602081830303815290604052805190602001209050600061015960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff168361024d565b90508073ffffffffffffffffffffffffffffffffffffffff166319ab453c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156101c457600080fd5b505af11580156101d8573d6000803e3d6000fd5b505050507fa35ea2cc726861482a50a162c72aad60965cc64641d419cd4d675036238b52048185604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a150505050565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152836037826000f5925050509291505056fea2646970667358221220c87b2492828fdd7dad3175a32a98ff07fc0eedf106536f2eddd9a016971c56a764736f6c63430007050033",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000059ffafdc6ef594230de44f824e2bd0a51ca5ded"
}
}
},
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficultyPassed": true,
"ethash": {}
}
},
"context": {
"number": "14707768",
"difficulty": "14322823549655084",
"timestamp": "1651623279",
"gasLimit": "30029237",
"miner": "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7"
},
"input": "0x02f8b4018312acfc8459682f00851a46bcf47a8302b1a194ffa397285ce46fb78c588a9e993286aac68c37cd80b844fb90b3200000000000000000000000002a549b4af9ec39b03142da6dc32221fc390b553300000000000000000000000000000000000000000000000000000000000cb3d5c001a03002079d2873f7963c4278200c43aa71efad262b2150bc8524480acfc38b5faaa077d44aa09d56b9cf99443c7f55aaad1bbae9cfb5bbb9de31eaf7a8f9e623e980",
"tracerConfig": {
"diffMode": true
},
"result": {
"pre": {
"0x808b4da0be6c9512e948521452227efc619bea52": {
"balance": "0x2cdb96c56db040b43",
"nonce": 1223932
},
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {
"balance": "0x38079b28689d40240e",
"nonce": 44
}
},
"post": {
"0x808b4da0be6c9512e948521452227efc619bea52": {
"balance": "0x2cd72a36dd031f089",
"nonce": 1223933
},
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {
"balance": "0x38079c19423e44b30e"
}
}
}
}
@@ -0,0 +1,104 @@
{
"genesis": {
"difficulty": "6217248151198",
"extraData": "0xd783010103844765746887676f312e342e32856c696e7578",
"gasLimit": "3141592",
"hash": "0xe8bff55fe3e61936ef321cf3afaeb1ba2f7234e1e89535fa8ae39963caebe9c3",
"miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5",
"mixHash": "0x03da00d5a15a064e5ebddf53cd0aaeb9a8aff0f40c0fb031a74f463d11ec83b8",
"nonce": "0x6575fe08c4167044",
"number": "243825",
"stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf",
"timestamp": "1442424328",
"totalDifficulty": "1035061827427752845",
"alloc": {
"0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": {
"balance": "0xc820f93200f4000",
"nonce": "0x5E",
"code": "0x"
},
"0x332b656504f4eabb44c8617a42af37461a34e9dc": {
"balance": "0x11faea4f35e5af80000",
"code": "0x",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
"balance": "0xbf681825be002ac452",
"nonce": "0x70FA",
"code": "0x"
},
"0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": {
"balance": "0xb3d0ac5cb94df6f6b0",
"nonce": "0x1",
"code": "0x"
}
},
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"ethash": {}
}
},
"context": {
"number": "243826",
"difficulty": "6214212385501",
"timestamp": "1442424353",
"gasLimit": "3141592",
"miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5"
},
"input": "0xf8e85e850ba43b7400830f42408080b89660606040527382effbaaaf28614e55b2ba440fb198e0e5789b0f600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600a80608c6000396000f30060606040526008565b001ca0340b21661e5bb85a46319a15f33a362e5c0f02faa7cdbf9c5808b2134da968eaa0226e6788f8c20e211d436ab7f6298ef32fa4c23a509eeeaac0880d115c17bc3f",
"tracerConfig": {
"diffMode": true
},
"result": {
"pre": {
"0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": {
"balance": "0xc820f93200f4000",
"nonce": 94
},
"0x332b656504f4eabb44c8617a42af37461a34e9dc": {
"balance": "0x11faea4f35e5af80000",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
"balance": "0xbf681825be002ac452",
"nonce": 28922
},
"0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": {
"balance": "0xb3d0ac5cb94df6f6b0",
"nonce": 1
}
},
"post": {
"0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": {
"balance": "0xc7d4d88af8b4c00",
"nonce": 95
},
"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
"balance": "0xbf681ce7c870aeb852"
},
"0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": {
"balance": "0x1d37f515017a8eef6b0"
}
}
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,103 @@
{
"context": {
"difficulty": "3502894804",
"gasLimit": "4722976",
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
"number": "2289806",
"timestamp": "1513601314"
},
"genesis": {
"alloc": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"code": "0x",
"nonce": "22",
"storage": {}
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"nonce": "1",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"code": "0x",
"nonce": "29072",
"storage": {}
}
},
"config": {
"byzantiumBlock": 1700000,
"chainId": 3,
"daoForkSupport": true,
"eip150Block": 0,
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
"eip155Block": 10,
"eip158Block": 10,
"ethash": {},
"homesteadBlock": 0
},
"difficulty": "3509749784",
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
"gasLimit": "4727564",
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
"nonce": "0x4eb12e19c16d43da",
"number": "2289805",
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
"timestamp": "1513601261",
"totalDifficulty": "7143276353481064"
},
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
"tracerConfig": {
"diffMode": true
},
"result": {
"pre": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x0",
"nonce": 22
},
"0x1585936b53834b021f68cc13eeefdec2efc8e724": {
"balance": "0x0"
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d87094125a369d9bd5",
"nonce": 1,
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d77678137ac1b775",
"nonce": 29072
}
},
"post": {
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
"balance": "0x6f05b59d3b20000"
},
"0x1585936b53834b021f68cc13eeefdec2efc8e724": {
"balance": "0x420eed1bd6c00"
},
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
"balance": "0x4d869a3b70062eb9bd5",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b95e"
}
},
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
"balance": "0x1780d7725724a9044b75",
"nonce": 29073
}
}
}
}
File diff suppressed because one or more lines are too long
+72
View File
@@ -0,0 +1,72 @@
package tracetest
import (
"strings"
"unicode"
// Force-load native and js packages, to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
)
// To generate a new callTracer test, copy paste the makeTest method below into
// a Geth console and call it with a transaction hash you which to export.
/*
// makeTest generates a callTracer test by running a prestate reassembled and a
// call trace run, assembling all the gathered information into a test case.
var makeTest = function(tx, rewind) {
// Generate the genesis block from the block, transaction and prestate data
var block = eth.getBlock(eth.getTransaction(tx).blockHash);
var genesis = eth.getBlock(block.parentHash);
delete genesis.gasUsed;
delete genesis.logsBloom;
delete genesis.parentHash;
delete genesis.receiptsRoot;
delete genesis.sha3Uncles;
delete genesis.size;
delete genesis.transactions;
delete genesis.transactionsRoot;
delete genesis.uncles;
genesis.gasLimit = genesis.gasLimit.toString();
genesis.number = genesis.number.toString();
genesis.timestamp = genesis.timestamp.toString();
genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind});
for (var key in genesis.alloc) {
var nonce = genesis.alloc[key].nonce;
if (nonce) {
genesis.alloc[key].nonce = nonce.toString();
}
}
genesis.config = admin.nodeInfo.protocols.eth.config;
// Generate the call trace and produce the test input
var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind});
delete result.time;
console.log(JSON.stringify({
genesis: genesis,
context: {
number: block.number.toString(),
difficulty: block.difficulty,
timestamp: block.timestamp.toString(),
gasLimit: block.gasLimit.toString(),
miner: block.miner,
},
input: eth.getRawTransaction(tx),
result: result,
}, null, 2));
}
*/
// camel converts a snake cased input string into a camel cased output.
func camel(str string) string {
pieces := strings.Split(str, "_")
for i := 1; i < len(pieces); i++ {
pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:]
}
return strings.Join(pieces, "")
}
+54 -46
View File
@@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"math/big"
"time"
"github.com/dop251/goja"
@@ -33,6 +32,10 @@ import (
jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers"
)
const (
memoryPadLimit = 1024 * 1024
)
var assetTracers = make(map[string]string)
// init retrieves the JavaScript transaction tracers included in go-ethereum.
@@ -42,7 +45,16 @@ func init() {
if err != nil {
panic(err)
}
tracers.RegisterLookup(true, newJsTracer)
type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error)
lookup := func(code string) ctorFn {
return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
return newJsTracer(code, ctx, cfg)
}
}
for name, code := range assetTracers {
tracers.DefaultDirectory.Register(name, lookup(code), true)
}
tracers.DefaultDirectory.RegisterJSEval(newJsTracer)
}
// bigIntProgram is compiled once and the exported function mostly invoked to convert
@@ -119,16 +131,14 @@ type jsTracer struct {
frameResultValue goja.Value
}
// newJsTracer instantiates a new JS tracer instance. code is either
// the name of a built-in JS tracer or a Javascript snippet which
// evaluates to an expression returning an object with certain methods.
// newJsTracer instantiates a new JS tracer instance. code is a
// Javascript snippet which evaluates to an expression returning
// an object with certain methods:
//
// The methods `result` and `fault` are required to be present.
// The methods `step`, `enter`, and `exit` are optional, but note that
// `enter` and `exit` always go together.
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
if c, ok := assetTracers[code]; ok {
code = c
}
vm := goja.New()
// By default field names are exported to JS as is, i.e. capitalized.
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
@@ -210,9 +220,11 @@ func (t *jsTracer) CaptureTxStart(gasLimit uint64) {
t.gasLimit = gasLimit
}
// CaptureTxStart implements the Tracer interface and is invoked at the end of
// CaptureTxEnd implements the Tracer interface and is invoked at the end of
// transaction processing.
func (t *jsTracer) CaptureTxEnd(restGas uint64) {}
func (t *jsTracer) CaptureTxEnd(restGas uint64) {
t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas)
}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
@@ -237,9 +249,8 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
t.ctx["value"] = valueBig
t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64())
// Update list of precompiles based on current block
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil)
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
t.activePrecompiles = vm.ActivePrecompiles(rules)
t.ctx["intrinsicGas"] = t.vm.ToValue(t.gasLimit - gas)
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
@@ -256,10 +267,11 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope
log.memory.memory = scope.Memory
log.stack.stack = scope.Stack
log.contract.contract = scope.Contract
log.pc = uint(pc)
log.gas = uint(gas)
log.cost = uint(cost)
log.depth = uint(depth)
log.pc = pc
log.gas = gas
log.cost = cost
log.refund = t.env.StateDB.GetRefund()
log.depth = depth
log.err = err
if _, err := t.step(t.obj, t.logValue, t.dbValue); err != nil {
t.onError("step", err)
@@ -279,10 +291,8 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, duration time.Duration, err error) {
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
t.ctx["output"] = t.vm.ToValue(output)
t.ctx["time"] = t.vm.ToValue(duration.String())
t.ctx["gasUsed"] = t.vm.ToValue(gasUsed)
if err != nil {
t.ctx["error"] = t.vm.ToValue(err.Error())
}
@@ -561,10 +571,15 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) {
if end < begin || begin < 0 {
return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end)
}
if mo.memory.Len() < int(end) {
return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin)
mlen := mo.memory.Len()
if end-int64(mlen) > memoryPadLimit {
return nil, fmt.Errorf("tracer reached limit for padding memory slice: end %d, memorySize %d", end, mlen)
}
return mo.memory.GetCopy(begin, end-begin), nil
slice := make([]byte, end-begin)
end = min(end, int64(mo.memory.Len()))
ptr := mo.memory.GetPtr(begin, end-begin)
copy(slice[:], ptr[:])
return slice, nil
}
func (mo *memoryObj) GetUint(addr int64) goja.Value {
@@ -907,33 +922,19 @@ type steplog struct {
stack *stackObj
contract *contractObj
pc uint
gas uint
cost uint
depth uint
refund uint
pc uint64
gas uint64
cost uint64
depth int
refund uint64
err error
}
func (l *steplog) GetPC() uint {
return l.pc
}
func (l *steplog) GetGas() uint {
return l.gas
}
func (l *steplog) GetCost() uint {
return l.cost
}
func (l *steplog) GetDepth() uint {
return l.depth
}
func (l *steplog) GetRefund() uint {
return l.refund
}
func (l *steplog) GetPC() uint64 { return l.pc }
func (l *steplog) GetGas() uint64 { return l.gas }
func (l *steplog) GetCost() uint64 { return l.cost }
func (l *steplog) GetDepth() int { return l.depth }
func (l *steplog) GetRefund() uint64 { return l.refund }
func (l *steplog) GetError() goja.Value {
if l.err != nil {
@@ -958,3 +959,10 @@ func (l *steplog) setupObject() *goja.Object {
o.Set("contract", l.contract.setupObject())
return o
}
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}
@@ -204,7 +204,6 @@
gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16),
input: toHex(ctx.input),
output: toHex(ctx.output),
time: ctx.time,
};
if (this.callstack[0].calls !== undefined) {
result.calls = this.callstack[0].calls;
@@ -234,7 +233,6 @@
input: call.input,
output: call.output,
error: call.error,
time: call.time,
calls: call.calls,
}
for (var key in sorted) {
@@ -62,7 +62,7 @@
var toBal = bigInt(this.prestate[toHex(ctx.to)].balance.slice(2), 16);
this.prestate[toHex(ctx.to)].balance = '0x'+toBal.subtract(ctx.value).toString(16);
this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).add((ctx.gasUsed + ctx.intrinsicGas) * ctx.gasPrice).toString(16);
this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).add(ctx.gasUsed * ctx.gasPrice).toString(16);
// Decrement the caller's nonce, and remove empty create targets
this.prestate[toHex(ctx.from)].nonce--;
+32 -19
View File
@@ -60,7 +60,7 @@ func testCtx() *vmContext {
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
}
func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) {
func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
var (
env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer})
gasLimit uint64 = 31000
@@ -69,13 +69,16 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
contract = vm.NewContract(account{}, account{}, value, startGas)
)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
if contractCode != nil {
contract.Code = contractCode
}
tracer.CaptureTxStart(gasLimit)
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
ret, err := env.Interpreter().Run(contract, []byte{}, false)
tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err)
tracer.CaptureEnd(ret, startGas-contract.Gas, err)
// Rest gas assumes no refund
tracer.CaptureTxEnd(startGas - contract.Gas)
tracer.CaptureTxEnd(contract.Gas)
if err != nil {
return nil, err
}
@@ -83,35 +86,36 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
}
func TestTracer(t *testing.T) {
execTracer := func(code string) ([]byte, string) {
execTracer := func(code string, contract []byte) ([]byte, string) {
t.Helper()
tracer, err := newJsTracer(code, nil, nil)
if err != nil {
t.Fatal(err)
}
ret, err := runTrace(tracer, testCtx(), params.TestChainConfig)
ret, err := runTrace(tracer, testCtx(), params.TestChainConfig, contract)
if err != nil {
return nil, err.Error() // Stringify to allow comparison without nil checks
}
return ret, ""
}
for i, tt := range []struct {
code string
want string
fail string
code string
want string
fail string
contract []byte
}{
{ // tests that we don't panic on bad arguments to memory access
code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}",
want: ``,
fail: "tracer accessed out of bound memory: offset -1, end -2 at step (<eval>:1:53(15)) in server-side tracer function 'step'",
fail: "tracer accessed out of bound memory: offset -1, end -2 at step (<eval>:1:53(13)) in server-side tracer function 'step'",
}, { // tests that we don't panic on bad arguments to stack peeks
code: "{depths: [], step: function(log) { this.depths.push(log.stack.peek(-1)); }, fault: function() {}, result: function() { return this.depths; }}",
want: ``,
fail: "tracer accessed out of bound stack: size 0, index -1 at step (<eval>:1:53(13)) in server-side tracer function 'step'",
fail: "tracer accessed out of bound stack: size 0, index -1 at step (<eval>:1:53(11)) in server-side tracer function 'step'",
}, { // tests that we don't panic on bad arguments to memory getUint
code: "{ depths: [], step: function(log, db) { this.depths.push(log.memory.getUint(-64));}, fault: function() {}, result: function() { return this.depths; }}",
want: ``,
fail: "tracer accessed out of bound memory: available 0, offset -64, size 32 at step (<eval>:1:58(13)) in server-side tracer function 'step'",
fail: "tracer accessed out of bound memory: available 0, offset -64, size 32 at step (<eval>:1:58(11)) in server-side tracer function 'step'",
}, { // tests some general counting
code: "{count: 0, step: function() { this.count += 1; }, fault: function() {}, result: function() { return this.count; }}",
want: `3`,
@@ -124,9 +128,9 @@ func TestTracer(t *testing.T) {
}, { // tests to-string of opcodes
code: "{opcodes: [], step: function(log) { this.opcodes.push(log.op.toString()); }, fault: function() {}, result: function() { return this.opcodes; }}",
want: `["PUSH1","PUSH1","STOP"]`,
}, { // tests intrinsic gas
code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed+'.'+ctx.intrinsicGas; }}",
want: `"100000.6.21000"`,
}, { // tests gasUsed
code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed; }}",
want: `"100000.21006"`,
}, {
code: "{res: null, step: function(log) {}, fault: function() {}, result: function() { return toWord('0xffaa') }}",
want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":255,"31":170}`,
@@ -139,9 +143,18 @@ func TestTracer(t *testing.T) {
}, {
code: "{res: null, step: function(log) { var address = Array.prototype.slice.call(log.contract.getAddress()); this.res = toAddress(address); }, fault: function() {}, result: function() { return this.res }}",
want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`,
}, {
code: "{res: [], step: function(log) { var op = log.op.toString(); if (op === 'MSTORE8' || op === 'STOP') { this.res.push(log.memory.slice(0, 2)) } }, fault: function() {}, result: function() { return this.res }}",
want: `[{"0":0,"1":0},{"0":255,"1":0}]`,
contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)},
}, {
code: "{res: [], step: function(log) { if (log.op.toString() === 'STOP') { this.res.push(log.memory.slice(5, 1025 * 1024)) } }, fault: function() {}, result: function() { return this.res }}",
want: "",
fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (<eval>:1:83(20)) in server-side tracer function 'step'",
contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)},
},
} {
if have, err := execTracer(tt.code); tt.want != string(have) || tt.fail != err {
if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err {
t.Errorf("testcase %d: expected return value to be '%s' got '%s', error to be '%s' got '%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code)
}
}
@@ -157,7 +170,7 @@ func TestHalt(t *testing.T) {
time.Sleep(1 * time.Second)
tracer.Stop(timeout)
}()
if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); !strings.Contains(err.Error(), "stahp") {
if _, err = runTrace(tracer, testCtx(), params.TestChainConfig, nil); !strings.Contains(err.Error(), "stahp") {
t.Errorf("Expected timeout error, got %v", err)
}
}
@@ -193,7 +206,7 @@ func TestNoStepExec(t *testing.T) {
}
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0))
tracer.CaptureEnd(nil, 0, 1, nil)
tracer.CaptureEnd(nil, 0, nil)
ret, err := tracer.GetResult()
if err != nil {
t.Fatal(err)
@@ -227,7 +240,7 @@ func TestIsPrecompile(t *testing.T) {
}
blockCtx := vm.BlockContext{BlockNumber: big.NewInt(150)}
res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg)
res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil)
if err != nil {
t.Error(err)
}
@@ -237,7 +250,7 @@ func TestIsPrecompile(t *testing.T) {
tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)}
res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg)
res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil)
if err != nil {
t.Error(err)
}
+1 -2
View File
@@ -18,7 +18,6 @@ package logger
import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
@@ -162,7 +161,7 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6
func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
}
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
}
+2 -4
View File
@@ -24,7 +24,6 @@ import (
"math/big"
"strings"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -151,7 +150,6 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.
func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
// If tracing was interrupted, set the error and stop
if atomic.LoadUint32(&l.interrupt) > 0 {
l.env.Cancel()
return
}
// check if already accumulated the specified number of logs
@@ -220,7 +218,7 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
l.output = output
l.err = err
if l.cfg.Debug {
@@ -386,7 +384,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
}
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) {
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
output, gasUsed, err)
}
+2 -4
View File
@@ -20,7 +20,6 @@ import (
"encoding/json"
"io"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
@@ -80,18 +79,17 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
}
// CaptureEnd is triggered at end of execution.
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
type endLog struct {
Output string `json:"output"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
Time time.Duration `json:"time"`
Err string `json:"error,omitempty"`
}
var errMsg string
if err != nil {
errMsg = err.Error()
}
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, errMsg})
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg})
}
func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+16 -36
View File
@@ -21,7 +21,6 @@ import (
"math/big"
"strconv"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
@@ -29,7 +28,7 @@ import (
)
func init() {
register("4byteTracer", newFourByteTracer)
tracers.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false)
}
// fourByteTracer searches for 4byte-identifiers, and collects them for post-processing.
@@ -37,16 +36,17 @@ func init() {
// a reversed signature can be matched against the size of the data.
//
// Example:
// > debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"})
// {
// 0x27dc297e-128: 1,
// 0x38cc4831-0: 2,
// 0x524f3889-96: 1,
// 0xadf59f99-288: 1,
// 0xc281d19e-0: 1
// }
//
// > debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"})
// {
// 0x27dc297e-128: 1,
// 0x38cc4831-0: 2,
// 0x524f3889-96: 1,
// 0xadf59f99-288: 1,
// 0xc281d19e-0: 1
// }
type fourByteTracer struct {
env *vm.EVM
noopTracer
ids map[string]int // ids aggregates the 4byte ids found
interrupt uint32 // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
@@ -80,10 +80,8 @@ func (t *fourByteTracer) store(id []byte, size int) {
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
t.env = env
// Update list of precompiles based on current block
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil)
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
t.activePrecompiles = vm.ActivePrecompiles(rules)
// Save the outer calldata also
@@ -92,15 +90,10 @@ func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to commo
}
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
}
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
// Skip if tracing was interrupted
if atomic.LoadUint32(&t.interrupt) > 0 {
t.env.Cancel()
return
}
if len(input) < 4 {
@@ -118,23 +111,6 @@ func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to comm
t.store(input[0:4], len(input)-4)
}
// CaptureExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *fourByteTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
}
// CaptureFault implements the EVMLogger interface to trace an execution fault.
func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) {
}
func (*fourByteTracer) CaptureTxStart(gasLimit uint64) {}
func (*fourByteTracer) CaptureTxEnd(restGas uint64) {}
// GetResult returns the json-encoded nested list of call traces, and any
// error arising from the encoding or forceful termination (via `Stop`).
func (t *fourByteTracer) GetResult() (json.RawMessage, error) {
@@ -150,3 +126,7 @@ func (t *fourByteTracer) Stop(err error) {
t.reason = err
atomic.StoreUint32(&t.interrupt, 1)
}
func bytesToHex(s []byte) string {
return "0x" + common.Bytes2Hex(s)
}
+135 -70
View File
@@ -20,43 +20,95 @@ import (
"encoding/json"
"errors"
"math/big"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
)
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
func init() {
register("callTracer", newCallTracer)
tracers.DefaultDirectory.Register("callTracer", newCallTracer, false)
}
type callLog struct {
Address common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
}
type callFrame struct {
Type string `json:"type"`
From string `json:"from"`
To string `json:"to,omitempty"`
Value string `json:"value,omitempty"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
Input string `json:"input"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
Calls []callFrame `json:"calls,omitempty"`
Type vm.OpCode `json:"-"`
From common.Address `json:"from"`
Gas uint64 `json:"gas"`
GasUsed uint64 `json:"gasUsed"`
To common.Address `json:"to,omitempty" rlp:"optional"`
Input []byte `json:"input" rlp:"optional"`
Output []byte `json:"output,omitempty" rlp:"optional"`
Error string `json:"error,omitempty" rlp:"optional"`
RevertReason string `json:"revertReason,omitempty"`
Calls []callFrame `json:"calls,omitempty" rlp:"optional"`
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
// Placed at end on purpose. The RLP will be decoded to 0 instead of
// nil if there are non-empty elements after in the struct.
Value *big.Int `json:"value,omitempty" rlp:"optional"`
}
func (f callFrame) TypeString() string {
return f.Type.String()
}
func (f callFrame) failed() bool {
return len(f.Error) > 0
}
func (f *callFrame) processOutput(output []byte, err error) {
output = common.CopyBytes(output)
if err == nil {
f.Output = output
return
}
f.Error = err.Error()
if f.Type == vm.CREATE || f.Type == vm.CREATE2 {
f.To = common.Address{}
}
if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 {
return
}
f.Output = output
if len(output) < 4 {
return
}
if unpacked, err := abi.UnpackRevert(output); err == nil {
f.RevertReason = unpacked
}
}
type callFrameMarshaling struct {
TypeString string `json:"type"`
Gas hexutil.Uint64
GasUsed hexutil.Uint64
Value *hexutil.Big
Input hexutil.Bytes
Output hexutil.Bytes
}
type callTracer struct {
env *vm.EVM
noopTracer
callstack []callFrame
config callTracerConfig
gasLimit uint64
interrupt uint32 // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
}
type callTracerConfig struct {
OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls
WithLog bool `json:"withLog"` // If true, call tracer will collect event logs
}
// newCallTracer returns a native go tracer which tracks
@@ -75,39 +127,58 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
t.env = env
t.callstack[0] = callFrame{
Type: "CALL",
From: addrToHex(from),
To: addrToHex(to),
Input: bytesToHex(input),
Gas: uintToHex(gas),
Value: bigToHex(value),
Type: vm.CALL,
From: from,
To: to,
Input: common.CopyBytes(input),
Gas: gas,
Value: value,
}
if create {
t.callstack[0].Type = "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, _ time.Duration, err error) {
t.callstack[0].GasUsed = uintToHex(gasUsed)
if err != nil {
t.callstack[0].Error = err.Error()
if err.Error() == "execution reverted" && len(output) > 0 {
t.callstack[0].Output = bytesToHex(output)
}
} else {
t.callstack[0].Output = bytesToHex(output)
}
func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
t.callstack[0].processOutput(output, err)
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
}
// Only logs need to be captured via opcode processing
if !t.config.WithLog {
return
}
// Avoid processing nested calls when only caring about top call
if t.config.OnlyTopCall && depth > 0 {
return
}
// Skip if tracing was interrupted
if atomic.LoadUint32(&t.interrupt) > 0 {
return
}
switch op {
case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4:
size := int(op - vm.LOG0)
// CaptureFault implements the EVMLogger interface to trace an execution fault.
func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
stack := scope.Stack
stackData := stack.Data()
// Don't modify the stack
mStart := stackData[len(stackData)-1]
mSize := stackData[len(stackData)-2]
topics := make([]common.Hash, size)
for i := 0; i < size; i++ {
topic := stackData[len(stackData)-2-(i+1)]
topics[i] = common.Hash(topic.Bytes32())
}
data := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)}
t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log)
}
}
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
@@ -117,17 +188,16 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
}
// Skip if tracing was interrupted
if atomic.LoadUint32(&t.interrupt) > 0 {
t.env.Cancel()
return
}
call := callFrame{
Type: typ.String(),
From: addrToHex(from),
To: addrToHex(to),
Input: bytesToHex(input),
Gas: uintToHex(gas),
Value: bigToHex(value),
Type: typ,
From: from,
To: to,
Input: common.CopyBytes(input),
Gas: gas,
Value: value,
}
t.callstack = append(t.callstack, call)
}
@@ -147,21 +217,22 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
t.callstack = t.callstack[:size-1]
size -= 1
call.GasUsed = uintToHex(gasUsed)
if err == nil {
call.Output = bytesToHex(output)
} else {
call.Error = err.Error()
if call.Type == "CREATE" || call.Type == "CREATE2" {
call.To = ""
}
}
call.GasUsed = gasUsed
call.processOutput(output, err)
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
}
func (*callTracer) CaptureTxStart(gasLimit uint64) {}
func (t *callTracer) CaptureTxStart(gasLimit uint64) {
t.gasLimit = gasLimit
}
func (*callTracer) CaptureTxEnd(restGas uint64) {}
func (t *callTracer) CaptureTxEnd(restGas uint64) {
t.callstack[0].GasUsed = t.gasLimit - restGas
if t.config.WithLog {
// Logs are not emitted when the call fails
clearFailedLogs(&t.callstack[0], false)
}
}
// GetResult returns the json-encoded nested list of call traces, and any
// error arising from the encoding or forceful termination (via `Stop`).
@@ -182,21 +253,15 @@ func (t *callTracer) Stop(err error) {
atomic.StoreUint32(&t.interrupt, 1)
}
func bytesToHex(s []byte) string {
return "0x" + common.Bytes2Hex(s)
}
func bigToHex(n *big.Int) string {
if n == nil {
return ""
// clearFailedLogs clears the logs of a callframe and all its children
// in case of execution failure.
func clearFailedLogs(cf *callFrame, parentFailed bool) {
failed := cf.failed() || parentFailed
// Clear own logs
if failed {
cf.Logs = nil
}
for i := range cf.Calls {
clearFailedLogs(&cf.Calls[i], failed)
}
return "0x" + n.Text(16)
}
func uintToHex(n uint64) string {
return "0x" + strconv.FormatUint(n, 16)
}
func addrToHex(a common.Address) string {
return strings.ToLower(a.Hex())
}
+56
View File
@@ -0,0 +1,56 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package native
import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*accountMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (a account) MarshalJSON() ([]byte, error) {
type account struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code hexutil.Bytes `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
var enc account
enc.Balance = (*hexutil.Big)(a.Balance)
enc.Code = a.Code
enc.Nonce = a.Nonce
enc.Storage = a.Storage
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (a *account) UnmarshalJSON(input []byte) error {
type account struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code *hexutil.Bytes `json:"code,omitempty"`
Nonce *uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
var dec account
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Balance != nil {
a.Balance = (*big.Int)(dec.Balance)
}
if dec.Code != nil {
a.Code = *dec.Code
}
if dec.Nonce != nil {
a.Nonce = *dec.Nonce
}
if dec.Storage != nil {
a.Storage = dec.Storage
}
return nil
}
+107
View File
@@ -0,0 +1,107 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package native
import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
)
var _ = (*callFrameMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (c callFrame) MarshalJSON() ([]byte, error) {
type callFrame0 struct {
Type vm.OpCode `json:"-"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasUsed hexutil.Uint64 `json:"gasUsed"`
To common.Address `json:"to,omitempty" rlp:"optional"`
Input hexutil.Bytes `json:"input" rlp:"optional"`
Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"`
Error string `json:"error,omitempty" rlp:"optional"`
RevertReason string `json:"revertReason,omitempty"`
Calls []callFrame `json:"calls,omitempty" rlp:"optional"`
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
Value *hexutil.Big `json:"value,omitempty" rlp:"optional"`
TypeString string `json:"type"`
}
var enc callFrame0
enc.Type = c.Type
enc.From = c.From
enc.Gas = hexutil.Uint64(c.Gas)
enc.GasUsed = hexutil.Uint64(c.GasUsed)
enc.To = c.To
enc.Input = c.Input
enc.Output = c.Output
enc.Error = c.Error
enc.RevertReason = c.RevertReason
enc.Calls = c.Calls
enc.Logs = c.Logs
enc.Value = (*hexutil.Big)(c.Value)
enc.TypeString = c.TypeString()
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (c *callFrame) UnmarshalJSON(input []byte) error {
type callFrame0 struct {
Type *vm.OpCode `json:"-"`
From *common.Address `json:"from"`
Gas *hexutil.Uint64 `json:"gas"`
GasUsed *hexutil.Uint64 `json:"gasUsed"`
To *common.Address `json:"to,omitempty" rlp:"optional"`
Input *hexutil.Bytes `json:"input" rlp:"optional"`
Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"`
Error *string `json:"error,omitempty" rlp:"optional"`
RevertReason *string `json:"revertReason,omitempty"`
Calls []callFrame `json:"calls,omitempty" rlp:"optional"`
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
Value *hexutil.Big `json:"value,omitempty" rlp:"optional"`
}
var dec callFrame0
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Type != nil {
c.Type = *dec.Type
}
if dec.From != nil {
c.From = *dec.From
}
if dec.Gas != nil {
c.Gas = uint64(*dec.Gas)
}
if dec.GasUsed != nil {
c.GasUsed = uint64(*dec.GasUsed)
}
if dec.To != nil {
c.To = *dec.To
}
if dec.Input != nil {
c.Input = *dec.Input
}
if dec.Output != nil {
c.Output = *dec.Output
}
if dec.Error != nil {
c.Error = *dec.Error
}
if dec.RevertReason != nil {
c.RevertReason = *dec.RevertReason
}
if dec.Calls != nil {
c.Calls = dec.Calls
}
if dec.Logs != nil {
c.Logs = dec.Logs
}
if dec.Value != nil {
c.Value = (*big.Int)(dec.Value)
}
return nil
}
+138
View File
@@ -0,0 +1,138 @@
// Copyright 2022 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 native
import (
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
)
func init() {
tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
}
// muxTracer is a go implementation of the Tracer interface which
// runs multiple tracers in one go.
type muxTracer struct {
names []string
tracers []tracers.Tracer
}
// newMuxTracer returns a new mux tracer.
func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
var config map[string]json.RawMessage
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
return nil, err
}
}
objects := make([]tracers.Tracer, 0, len(config))
names := make([]string, 0, len(config))
for k, v := range config {
t, err := tracers.DefaultDirectory.New(k, ctx, v)
if err != nil {
return nil, err
}
objects = append(objects, t)
names = append(names, k)
}
return &muxTracer{names: names, tracers: objects}, nil
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
for _, t := range t.tracers {
t.CaptureStart(env, from, to, create, input, gas, value)
}
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
for _, t := range t.tracers {
t.CaptureEnd(output, gasUsed, err)
}
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
for _, t := range t.tracers {
t.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
}
}
// CaptureFault implements the EVMLogger interface to trace an execution fault.
func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
for _, t := range t.tracers {
t.CaptureFault(pc, op, gas, cost, scope, depth, err)
}
}
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
for _, t := range t.tracers {
t.CaptureEnter(typ, from, to, input, gas, value)
}
}
// CaptureExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
for _, t := range t.tracers {
t.CaptureExit(output, gasUsed, err)
}
}
func (t *muxTracer) CaptureTxStart(gasLimit uint64) {
for _, t := range t.tracers {
t.CaptureTxStart(gasLimit)
}
}
func (t *muxTracer) CaptureTxEnd(restGas uint64) {
for _, t := range t.tracers {
t.CaptureTxEnd(restGas)
}
}
// GetResult returns an empty json object.
func (t *muxTracer) GetResult() (json.RawMessage, error) {
resObject := make(map[string]json.RawMessage)
for i, tt := range t.tracers {
r, err := tt.GetResult()
if err != nil {
return nil, err
}
resObject[t.names[i]] = r
}
res, err := json.Marshal(resObject)
if err != nil {
return nil, err
}
return res, nil
}
// Stop terminates execution of the tracer at the first opportune moment.
func (t *muxTracer) Stop(err error) {
for _, t := range t.tracers {
t.Stop(err)
}
}
+2 -3
View File
@@ -19,7 +19,6 @@ package native
import (
"encoding/json"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
@@ -27,7 +26,7 @@ import (
)
func init() {
register("noopTracer", newNoopTracer)
tracers.DefaultDirectory.Register("noopTracer", newNoopTracer, false)
}
// noopTracer is a go implementation of the Tracer interface which
@@ -44,7 +43,7 @@ func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) {
func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
+154 -47
View File
@@ -17,10 +17,10 @@
package native
import (
"bytes"
"encoding/json"
"math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -29,32 +29,63 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers"
)
//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
func init() {
register("prestateTracer", newPrestateTracer)
tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false)
}
type prestate = map[common.Address]*account
type state = map[common.Address]*account
type account struct {
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Code string `json:"code"`
Storage map[common.Hash]common.Hash `json:"storage"`
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
func (a *account) exists() bool {
return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
}
type accountMarshaling struct {
Balance *hexutil.Big
Code hexutil.Bytes
}
type prestateTracer struct {
noopTracer
env *vm.EVM
prestate prestate
pre state
post state
create bool
to common.Address
gasLimit uint64 // Amount of gas bought for the whole tx
config prestateTracerConfig
interrupt uint32 // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
created map[common.Address]bool
deleted map[common.Address]bool
}
func newPrestateTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
// First callframe contains tx context info
// and is populated on start and end.
return &prestateTracer{prestate: prestate{}}, nil
type prestateTracerConfig struct {
DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications
}
func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
var config prestateTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
return nil, err
}
}
return &prestateTracer{
pre: state{},
post: state{},
config: config,
created: make(map[common.Address]bool),
deleted: make(map[common.Address]bool),
}, nil
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
@@ -65,27 +96,38 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo
t.lookupAccount(from)
t.lookupAccount(to)
t.lookupAccount(env.Context.Coinbase)
// The recipient balance includes the value transferred.
toBal := hexutil.MustDecodeBig(t.prestate[to].Balance)
toBal = new(big.Int).Sub(toBal, value)
t.prestate[to].Balance = hexutil.EncodeBig(toBal)
toBal := new(big.Int).Sub(t.pre[to].Balance, value)
t.pre[to].Balance = toBal
// The sender balance is after reducing: value and gasLimit.
// We need to re-add them to get the pre-tx balance.
fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance)
fromBal := new(big.Int).Set(t.pre[from].Balance)
gasPrice := env.TxContext.GasPrice
consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit))
fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas))
t.prestate[from].Balance = hexutil.EncodeBig(fromBal)
t.prestate[from].Nonce--
t.pre[from].Balance = fromBal
t.pre[from].Nonce--
if create && t.config.DiffMode {
t.created[to] = true
}
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) {
func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
if t.config.DiffMode {
return
}
if t.create {
// Exclude created contract.
delete(t.prestate, t.to)
// Keep existing account prior to contract creation at that address
if s := t.pre[t.to]; s != nil && !s.exists() {
// Exclude newly created contract.
delete(t.pre, t.to)
}
}
}
@@ -94,53 +136,117 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
stack := scope.Stack
stackData := stack.Data()
stackLen := len(stackData)
caller := scope.Contract.Address()
switch {
case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE):
slot := common.Hash(stackData[stackLen-1].Bytes32())
t.lookupStorage(scope.Contract.Address(), slot)
t.lookupStorage(caller, slot)
case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT):
addr := common.Address(stackData[stackLen-1].Bytes20())
t.lookupAccount(addr)
if op == vm.SELFDESTRUCT {
t.deleted[caller] = true
}
case stackLen >= 5 && (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE):
addr := common.Address(stackData[stackLen-2].Bytes20())
t.lookupAccount(addr)
case op == vm.CREATE:
addr := scope.Contract.Address()
nonce := t.env.StateDB.GetNonce(addr)
t.lookupAccount(crypto.CreateAddress(addr, nonce))
nonce := t.env.StateDB.GetNonce(caller)
addr := crypto.CreateAddress(caller, nonce)
t.lookupAccount(addr)
t.created[addr] = true
case stackLen >= 4 && op == vm.CREATE2:
offset := stackData[stackLen-2]
size := stackData[stackLen-3]
init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
inithash := crypto.Keccak256(init)
salt := stackData[stackLen-4]
t.lookupAccount(crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), inithash))
addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash)
t.lookupAccount(addr)
t.created[addr] = true
}
}
// CaptureFault implements the EVMLogger interface to trace an execution fault.
func (t *prestateTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
}
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
}
// CaptureExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
}
func (t *prestateTracer) CaptureTxStart(gasLimit uint64) {
t.gasLimit = gasLimit
}
func (t *prestateTracer) CaptureTxEnd(restGas uint64) {}
func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
if !t.config.DiffMode {
return
}
for addr, state := range t.pre {
// The deleted account's state is pruned from `post` but kept in `pre`
if _, ok := t.deleted[addr]; ok {
continue
}
modified := false
postAccount := &account{Storage: make(map[common.Hash]common.Hash)}
newBalance := t.env.StateDB.GetBalance(addr)
newNonce := t.env.StateDB.GetNonce(addr)
newCode := t.env.StateDB.GetCode(addr)
if newBalance.Cmp(t.pre[addr].Balance) != 0 {
modified = true
postAccount.Balance = newBalance
}
if newNonce != t.pre[addr].Nonce {
modified = true
postAccount.Nonce = newNonce
}
if !bytes.Equal(newCode, t.pre[addr].Code) {
modified = true
postAccount.Code = newCode
}
for key, val := range state.Storage {
// don't include the empty slot
if val == (common.Hash{}) {
delete(t.pre[addr].Storage, key)
}
newVal := t.env.StateDB.GetState(addr, key)
if val == newVal {
// Omit unchanged slots
delete(t.pre[addr].Storage, key)
} else {
modified = true
if newVal != (common.Hash{}) {
postAccount.Storage[key] = newVal
}
}
}
if modified {
t.post[addr] = postAccount
} else {
// if state is not modified, then no need to include into the pre state
delete(t.pre, addr)
}
}
// the new created contracts' prestate were empty, so delete them
for a := range t.created {
// the created contract maybe exists in statedb before the creating tx
if s := t.pre[a]; s != nil && !s.exists() {
delete(t.pre, a)
}
}
}
// GetResult returns the json-encoded nested list of call traces, and any
// error arising from the encoding or forceful termination (via `Stop`).
func (t *prestateTracer) GetResult() (json.RawMessage, error) {
res, err := json.Marshal(t.prestate)
var res []byte
var err error
if t.config.DiffMode {
res, err = json.Marshal(struct {
Post state `json:"post"`
Pre state `json:"pre"`
}{t.post, t.pre})
} else {
res, err = json.Marshal(t.pre)
}
if err != nil {
return nil, err
}
@@ -156,13 +262,14 @@ func (t *prestateTracer) Stop(err error) {
// lookupAccount fetches details of an account and adds it to the prestate
// if it doesn't exist there.
func (t *prestateTracer) lookupAccount(addr common.Address) {
if _, ok := t.prestate[addr]; ok {
if _, ok := t.pre[addr]; ok {
return
}
t.prestate[addr] = &account{
Balance: bigToHex(t.env.StateDB.GetBalance(addr)),
t.pre[addr] = &account{
Balance: t.env.StateDB.GetBalance(addr),
Nonce: t.env.StateDB.GetNonce(addr),
Code: bytesToHex(t.env.StateDB.GetCode(addr)),
Code: t.env.StateDB.GetCode(addr),
Storage: make(map[common.Hash]common.Hash),
}
}
@@ -171,8 +278,8 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
// it to the prestate of the given contract. It assumes `lookupAccount`
// has been performed on the contract before.
func (t *prestateTracer) lookupStorage(addr common.Address, key common.Hash) {
if _, ok := t.prestate[addr].Storage[key]; ok {
if _, ok := t.pre[addr].Storage[key]; ok {
return
}
t.prestate[addr].Storage[key] = t.env.StateDB.GetState(addr, key)
t.pre[addr].Storage[key] = t.env.StateDB.GetState(addr, key)
}
-108
View File
@@ -1,108 +0,0 @@
// Copyright 2022 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 native
import (
"bytes"
"encoding/json"
"math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers"
)
func init() {
register("revertReasonTracer", newRevertReasonTracer)
}
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
// revertReasonTracer is a go implementation of the Tracer interface which
// track the error message or revert reason return by the contract.
type revertReasonTracer struct {
env *vm.EVM
revertReason string // The revert reason return from the tx, if tx success, empty string return
interrupt uint32 // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
}
// newRevertReasonTracer returns a new revert reason tracer.
func newRevertReasonTracer(_ *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
return &revertReasonTracer{}, nil
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *revertReasonTracer) CaptureStart(env *vm.EVM, _ common.Address, _ common.Address, _ bool, _ []byte, _ uint64, _ *big.Int) {
t.env = env
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (t *revertReasonTracer) CaptureEnd(output []byte, _ uint64, _ time.Duration, err error) {
if err != nil {
if err == vm.ErrExecutionReverted && len(output) > 4 && bytes.Equal(output[:4], revertSelector) {
errMsg, _ := abi.UnpackRevert(output)
t.revertReason = err.Error() + ": " + errMsg
} else {
t.revertReason = err.Error()
}
}
}
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *revertReasonTracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, _ int, _ error) {
}
// CaptureFault implements the EVMLogger interface to trace an execution fault.
func (t *revertReasonTracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) {
}
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
func (t *revertReasonTracer) CaptureEnter(_ vm.OpCode, _ common.Address, _ common.Address, _ []byte, _ uint64, _ *big.Int) {
// Skip if tracing was interrupted
if atomic.LoadUint32(&t.interrupt) > 0 {
t.env.Cancel()
return
}
}
// CaptureExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
func (t *revertReasonTracer) CaptureExit(_ []byte, _ uint64, _ error) {}
func (t *revertReasonTracer) CaptureTxStart(_ uint64) {}
func (t *revertReasonTracer) CaptureTxEnd(_ uint64) {}
// GetResult returns an error message json object.
func (t *revertReasonTracer) GetResult() (json.RawMessage, error) {
res, err := json.Marshal(t.revertReason)
if err != nil {
return nil, err
}
return res, t.reason
}
// Stop terminates execution of the tracer at the first opportune moment.
func (t *revertReasonTracer) Stop(err error) {
t.reason = err
atomic.StoreUint32(&t.interrupt, 1)
}
-83
View File
@@ -1,83 +0,0 @@
// Copyright 2021 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 native is a collection of tracers written in go.
In order to add a native tracer and have it compiled into the binary, a new
file needs to be added to this folder, containing an implementation of the
`eth.tracers.Tracer` interface.
Aside from implementing the tracer, it also needs to register itself, using the
`register` method -- and this needs to be done in the package initialization.
Example:
```golang
func init() {
register("noopTracerNative", newNoopTracer)
}
```
*/
package native
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/eth/tracers"
)
// init registers itself this packages as a lookup for tracers.
func init() {
tracers.RegisterLookup(false, lookup)
}
// ctorFn is the constructor signature of a native tracer.
type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error)
/*
ctors is a map of package-local tracer constructors.
We cannot be certain about the order of init-functions within a package,
The go spec (https://golang.org/ref/spec#Package_initialization) says
> To ensure reproducible initialization behavior, build systems
> are encouraged to present multiple files belonging to the same
> package in lexical file name order to a compiler.
Hence, we cannot make the map in init, but must make it upon first use.
*/
var ctors map[string]ctorFn
// register is used by native tracers to register their presence.
func register(name string, ctor ctorFn) {
if ctors == nil {
ctors = make(map[string]ctorFn)
}
ctors[name] = ctor
}
// lookup returns a tracer, if one can be matched to the given name.
func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
if ctors == nil {
ctors = make(map[string]ctorFn)
}
if ctor, ok := ctors[name]; ok {
return ctor(ctx, cfg)
}
return nil, errors.New("no tracer found")
}
+45 -22
View File
@@ -19,7 +19,6 @@ package tracers
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
@@ -42,31 +41,55 @@ type Tracer interface {
Stop(err error)
}
type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error)
type ctorFn func(*Context, json.RawMessage) (Tracer, error)
type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error)
var (
lookups []lookupFunc
)
type elem struct {
ctor ctorFn
isJS bool
}
// RegisterLookup registers a method as a lookup for tracers, meaning that
// users can invoke a named tracer through that lookup. If 'wildcard' is true,
// then the lookup will be placed last. This is typically meant for interpreted
// engines (js) which can evaluate dynamic user-supplied code.
func RegisterLookup(wildcard bool, lookup lookupFunc) {
if wildcard {
lookups = append(lookups, lookup)
} else {
lookups = append([]lookupFunc{lookup}, lookups...)
}
// DefaultDirectory is the collection of tracers bundled by default.
var DefaultDirectory = directory{elems: make(map[string]elem)}
// directory provides functionality to lookup a tracer by name
// and a function to instantiate it. It falls back to a JS code evaluator
// if no tracer of the given name exists.
type directory struct {
elems map[string]elem
jsEval jsCtorFn
}
// Register registers a method as a lookup for tracers, meaning that
// users can invoke a named tracer through that lookup.
func (d *directory) Register(name string, f ctorFn, isJS bool) {
d.elems[name] = elem{ctor: f, isJS: isJS}
}
// RegisterJSEval registers a tracer that is able to parse
// dynamic user-provided JS code.
func (d *directory) RegisterJSEval(f jsCtorFn) {
d.jsEval = f
}
// New returns a new instance of a tracer, by iterating through the
// registered lookups.
func New(code string, ctx *Context, cfg json.RawMessage) (Tracer, error) {
for _, lookup := range lookups {
if tracer, err := lookup(code, ctx, cfg); err == nil {
return tracer, nil
}
// registered lookups. Name is either name of an existing tracer
// or an arbitrary JS code.
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) {
if elem, ok := d.elems[name]; ok {
return elem.ctor(ctx, cfg)
}
return nil, errors.New("tracer not found")
// Assume JS code
return d.jsEval(name, ctx, cfg)
}
// IsJS will return true if the given tracer will evaluate
// JS code. Because code evaluation has high overhead, this
// info will be used in determining fast and slow code paths.
func (d *directory) IsJS(name string) bool {
if elem, ok := d.elems[name]; ok {
return elem.isJS
}
// JS eval will execute JS code
return true
}
+1 -1
View File
@@ -56,7 +56,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
Transfer: core.Transfer,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(uint64(5)),
Time: new(big.Int).SetUint64(uint64(5)),
Time: 5,
Difficulty: big.NewInt(0xffffffff),
GasLimit: gas,
BaseFee: big.NewInt(8),
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2022 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 tracers
import (
"fmt"
"sync"
)
// stateTracker is an auxiliary tool used to cache the release functions of all
// used trace states, and to determine whether the creation of trace state needs
// to be paused in case there are too many states waiting for tracing.
type stateTracker struct {
limit int // Maximum number of states allowed waiting for tracing
oldest uint64 // The number of the oldest state which is still using for trace
used []bool // List of flags indicating whether the trace state has been used up
releases []StateReleaseFunc // List of trace state release functions waiting to be called
cond *sync.Cond
lock *sync.RWMutex
}
// newStateTracker initializes the tracker with provided state limits and
// the number of the first state that will be used.
func newStateTracker(limit int, oldest uint64) *stateTracker {
lock := new(sync.RWMutex)
return &stateTracker{
limit: limit,
oldest: oldest,
used: make([]bool, limit),
cond: sync.NewCond(lock),
lock: lock,
}
}
// releaseState marks the state specified by the number as released and caches
// the corresponding release functions internally.
func (t *stateTracker) releaseState(number uint64, release StateReleaseFunc) {
t.lock.Lock()
defer t.lock.Unlock()
// Set the state as used, the corresponding flag is indexed by
// the distance between the specified state and the oldest state
// which is still using for trace.
t.used[int(number-t.oldest)] = true
// If the oldest state is used up, update the oldest marker by moving
// it to the next state which is not used up.
if number == t.oldest {
var count int
for _, used := range t.used {
if !used {
break
}
count += 1
}
t.oldest += uint64(count)
copy(t.used, t.used[count:])
// Clean up the array tail since they are useless now.
for i := t.limit - count; i < t.limit; i++ {
t.used[i] = false
}
// Fire the signal to all waiters that oldest marker is updated.
t.cond.Broadcast()
}
t.releases = append(t.releases, release)
}
// callReleases invokes all cached release functions.
func (t *stateTracker) callReleases() {
t.lock.Lock()
defer t.lock.Unlock()
for _, release := range t.releases {
release()
}
t.releases = t.releases[:0]
}
// wait blocks until the accumulated trace states are less than the limit.
func (t *stateTracker) wait(number uint64) error {
t.lock.Lock()
defer t.lock.Unlock()
for {
if number < t.oldest {
return fmt.Errorf("invalid state number %d head %d", number, t.oldest)
}
if number < t.oldest+uint64(t.limit) {
// number is now within limit, wait over
return nil
}
t.cond.Wait()
}
}
+171
View File
@@ -0,0 +1,171 @@
// Copyright 2022 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 tracers
import (
"reflect"
"testing"
"time"
)
func TestTracker(t *testing.T) {
var cases = []struct {
limit int
calls []uint64
expHead uint64
}{
// Release in order
{
limit: 3,
calls: []uint64{0, 1, 2},
expHead: 3,
},
{
limit: 3,
calls: []uint64{0, 1, 2, 3, 4, 5},
expHead: 6,
},
// Release out of order
{
limit: 3,
calls: []uint64{1, 2, 0},
expHead: 3,
},
{
limit: 3,
calls: []uint64{1, 2, 0, 5, 4, 3},
expHead: 6,
},
}
for _, c := range cases {
tracker := newStateTracker(c.limit, 0)
for _, call := range c.calls {
tracker.releaseState(call, func() {})
}
tracker.lock.RLock()
head := tracker.oldest
tracker.lock.RUnlock()
if head != c.expHead {
t.Fatalf("Unexpected head want %d got %d", c.expHead, head)
}
}
var calls = []struct {
number uint64
expUsed []bool
expHead uint64
}{
// Release the first one, update the oldest flag
{
number: 0,
expUsed: []bool{false, false, false, false, false},
expHead: 1,
},
// Release the second one, oldest shouldn't be updated
{
number: 2,
expUsed: []bool{false, true, false, false, false},
expHead: 1,
},
// Release the forth one, oldest shouldn't be updated
{
number: 4,
expUsed: []bool{false, true, false, true, false},
expHead: 1,
},
// Release the first one, the first two should all be cleaned,
// and the remaining flags should all be left-shifted.
{
number: 1,
expUsed: []bool{false, true, false, false, false},
expHead: 3,
},
// Release the first one, the first two should all be cleaned
{
number: 3,
expUsed: []bool{false, false, false, false, false},
expHead: 5,
},
}
tracker := newStateTracker(5, 0) // limit = 5, oldest = 0
for _, call := range calls {
tracker.releaseState(call.number, nil)
tracker.lock.RLock()
if !reflect.DeepEqual(tracker.used, call.expUsed) {
t.Fatalf("Unexpected used array")
}
if tracker.oldest != call.expHead {
t.Fatalf("Unexpected head")
}
tracker.lock.RUnlock()
}
}
func TestTrackerWait(t *testing.T) {
var (
tracker = newStateTracker(5, 0) // limit = 5, oldest = 0
result = make(chan error, 1)
doCall = func(number uint64) {
go func() {
result <- tracker.wait(number)
}()
}
checkNoWait = func() {
select {
case <-result:
return
case <-time.NewTimer(time.Second).C:
t.Fatal("No signal fired")
}
}
checkWait = func() {
select {
case <-result:
t.Fatal("Unexpected signal")
case <-time.NewTimer(time.Millisecond * 100).C:
}
}
)
// States [0, 5) should all be available
doCall(0)
checkNoWait()
doCall(4)
checkNoWait()
// State 5 is not available
doCall(5)
checkWait()
// States [1, 6) are available
tracker.releaseState(0, nil)
checkNoWait()
// States [1, 6) are available
doCall(7)
checkWait()
// States [2, 7) are available
tracker.releaseState(1, nil)
checkWait()
// States [3, 8) are available
tracker.releaseState(2, nil)
checkNoWait()
}