github.com/theQRL/go-zond@v0.1.1/zond/tracers/tracers.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package tracers is a manager for transaction tracing engines. 18 package tracers 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math/big" 25 26 "github.com/theQRL/go-zond/common" 27 "github.com/theQRL/go-zond/core/vm" 28 ) 29 30 // Context contains some contextual infos for a transaction execution that is not 31 // available from within the EVM object. 32 type Context struct { 33 BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call) 34 BlockNumber *big.Int // Number of the block the tx is contained within (zero if dangling tx or call) 35 TxIndex int // Index of the transaction within a block (zero if dangling tx or call) 36 TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) 37 } 38 39 // Tracer interface extends vm.EVMLogger and additionally 40 // allows collecting the tracing result. 41 type Tracer interface { 42 vm.EVMLogger 43 GetResult() (json.RawMessage, error) 44 // Stop terminates execution of the tracer at the first opportune moment. 45 Stop(err error) 46 } 47 48 type ctorFn func(*Context, json.RawMessage) (Tracer, error) 49 type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error) 50 51 type elem struct { 52 ctor ctorFn 53 isJS bool 54 } 55 56 // DefaultDirectory is the collection of tracers bundled by default. 57 var DefaultDirectory = directory{elems: make(map[string]elem)} 58 59 // directory provides functionality to lookup a tracer by name 60 // and a function to instantiate it. It falls back to a JS code evaluator 61 // if no tracer of the given name exists. 62 type directory struct { 63 elems map[string]elem 64 jsEval jsCtorFn 65 } 66 67 // Register registers a method as a lookup for tracers, meaning that 68 // users can invoke a named tracer through that lookup. 69 func (d *directory) Register(name string, f ctorFn, isJS bool) { 70 d.elems[name] = elem{ctor: f, isJS: isJS} 71 } 72 73 // RegisterJSEval registers a tracer that is able to parse 74 // dynamic user-provided JS code. 75 func (d *directory) RegisterJSEval(f jsCtorFn) { 76 d.jsEval = f 77 } 78 79 // New returns a new instance of a tracer, by iterating through the 80 // registered lookups. Name is either name of an existing tracer 81 // or an arbitrary JS code. 82 func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) { 83 if elem, ok := d.elems[name]; ok { 84 return elem.ctor(ctx, cfg) 85 } 86 // Assume JS code 87 return d.jsEval(name, ctx, cfg) 88 } 89 90 // IsJS will return true if the given tracer will evaluate 91 // JS code. Because code evaluation has high overhead, this 92 // info will be used in determining fast and slow code paths. 93 func (d *directory) IsJS(name string) bool { 94 if elem, ok := d.elems[name]; ok { 95 return elem.isJS 96 } 97 // JS eval will execute JS code 98 return true 99 } 100 101 const ( 102 memoryPadLimit = 1024 * 1024 103 ) 104 105 // GetMemoryCopyPadded returns offset + size as a new slice. 106 // It zero-pads the slice if it extends beyond memory bounds. 107 func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { 108 if offset < 0 || size < 0 { 109 return nil, errors.New("offset or size must not be negative") 110 } 111 if int(offset+size) < m.Len() { // slice fully inside memory 112 return m.GetCopy(offset, size), nil 113 } 114 paddingNeeded := int(offset+size) - m.Len() 115 if paddingNeeded > memoryPadLimit { 116 return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) 117 } 118 cpy := make([]byte, size) 119 if overlap := int64(m.Len()) - offset; overlap > 0 { 120 copy(cpy, m.GetPtr(offset, overlap)) 121 } 122 return cpy, nil 123 }