├── main ├── build_win32 ├── util.go ├── cmd.go └── main.go ├── hooks ├── symbolic │ ├── pattern.go │ ├── print.go │ ├── optimize_test.go │ ├── optimize.go │ ├── node_util.go │ ├── node.go │ └── high_level_tracer.go ├── breakpoint.go ├── param_tracer.go └── low_level_tracer.go ├── stack.go ├── go.mod ├── util ├── util.go └── hex_dump.go ├── hook.go ├── asm.go ├── memory.go ├── gas.go ├── README.md ├── context.go ├── eth_client.go ├── opcode.go └── go.sum /main/build_win32: -------------------------------------------------------------------------------- 1 | #!/bin/fish 2 | rm /main.exe 3 | GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -ldflags "-s -w -extldflags=-static" 4 | 5 | -------------------------------------------------------------------------------- /hooks/symbolic/pattern.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | // match to any node 4 | // type AnyNode struct{} 5 | // 6 | // func (n *AnyNode) String() string { 7 | // return "AnyNode" 8 | // } 9 | // 10 | // // match to any Const node 11 | // type AnyConst struct{} 12 | // 13 | // func (n *AnyConst) String() string { 14 | // return "AnyConst" 15 | // } 16 | // 17 | // func Match(ptn, n Node) bool { 18 | // // switch n1.(type) { 19 | // // 20 | // // } 21 | // return false 22 | // } 23 | -------------------------------------------------------------------------------- /main/util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func to_pretty_json[T any](obj T) string { 10 | bs, _ := json.MarshalIndent(obj, "", " ") 11 | return string(bs) 12 | } 13 | 14 | // dec: 123 15 | // hex: 1a, 0x1a, 1A 16 | func parse_any_int(s string) (uint64, error) { 17 | var is_hex bool 18 | 19 | if strings.ContainsAny(s, "abcdefABCDEF") { 20 | is_hex = true 21 | } 22 | if strings.Contains(s, "0x") { 23 | is_hex = true 24 | s = strings.ReplaceAll(s, "0x", "") 25 | } 26 | 27 | if is_hex { 28 | return strconv.ParseUint(s, 16, 64) 29 | } else { 30 | return strconv.ParseUint(s, 10, 64) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /stack.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | // IMPORTANT: 4 | // Use Pointer as value type 5 | // because slice allocates and copies when it excceeds the max capacity 6 | type Stack[T any] struct { 7 | Data []T 8 | } 9 | 10 | func (st *Stack[T]) Push(d T) { 11 | st.Data = append(st.Data, d) 12 | } 13 | func (st *Stack[T]) PushN(ds ...T) { 14 | st.Data = append(st.Data, ds...) 15 | } 16 | 17 | func (st *Stack[T]) Pop() (ret T) { 18 | ret = st.Data[len(st.Data)-1] 19 | st.Data = st.Data[:len(st.Data)-1] 20 | return 21 | } 22 | 23 | func (st *Stack[T]) Len() int { 24 | return len(st.Data) 25 | } 26 | 27 | func (st *Stack[T]) Swap(n int) { 28 | st.Data[st.Len()-n], st.Data[st.Len()-1] = st.Data[st.Len()-1], st.Data[st.Len()-n] 29 | } 30 | 31 | func (st *Stack[T]) Dup(n int) { 32 | st.Push(st.Data[st.Len()-n]) 33 | } 34 | 35 | func (st *Stack[T]) PeekI(n int) *T { 36 | return &st.Data[st.Len()-1-n] 37 | } 38 | func (st *Stack[T]) Peek() *T { 39 | return st.PeekI(0) 40 | } 41 | 42 | func (st *Stack[T]) Clear() { 43 | st.Data = nil 44 | } 45 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aj3423/edb 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/c-bata/go-prompt v0.2.6 7 | github.com/ethereum/go-ethereum v1.10.12 8 | github.com/fatih/color v1.13.0 9 | github.com/holiman/uint256 v1.2.0 10 | github.com/pkg/errors v0.9.1 11 | github.com/stretchr/testify v1.7.2 12 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e 13 | ) 14 | 15 | require ( 16 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect 17 | github.com/btcsuite/btcd v0.20.1-beta // indirect 18 | github.com/davecgh/go-spew v1.1.1 // indirect 19 | github.com/deckarep/golang-set v1.8.0 // indirect 20 | github.com/go-ole/go-ole v1.2.1 // indirect 21 | github.com/go-stack/stack v1.8.0 // indirect 22 | github.com/gorilla/websocket v1.4.2 // indirect 23 | github.com/mattn/go-colorable v0.1.9 // indirect 24 | github.com/mattn/go-isatty v0.0.14 // indirect 25 | github.com/mattn/go-runewidth v0.0.9 // indirect 26 | github.com/mattn/go-tty v0.0.3 // indirect 27 | github.com/pkg/term v1.2.0-beta.2 // indirect 28 | github.com/pmezard/go-difflib v1.0.0 // indirect 29 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect 30 | github.com/tklauser/go-sysconf v0.3.5 // indirect 31 | github.com/tklauser/numcpus v0.2.2 // indirect 32 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect 33 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect 34 | gopkg.in/yaml.v3 v3.0.1 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /hooks/breakpoint.go: -------------------------------------------------------------------------------- 1 | package hooks 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aj3423/edb" 7 | "github.com/ethereum/go-ethereum/common" 8 | "github.com/ethereum/go-ethereum/core/vm" 9 | "github.com/pkg/errors" 10 | ) 11 | 12 | var ErrBreakpoint = errors.New("breakpoint") 13 | 14 | func init() { 15 | edb.Register((*BpPc)(nil)) 16 | edb.Register((*BpOpCode)(nil)) 17 | } 18 | 19 | // break at Pc of target cotract 20 | type BpPc struct { 21 | edb.EmptyHook 22 | Contract *common.Address 23 | Pc uint64 24 | } 25 | 26 | func (bp *BpPc) String() string { 27 | if bp.Contract == nil { 28 | return fmt.Sprintf("@ Pc: %x", bp.Pc) 29 | } else { 30 | return fmt.Sprintf("@ Pc: %x of %s", 31 | bp.Pc, bp.Contract.Hex()) 32 | } 33 | } 34 | 35 | func (bp *BpPc) PreRun(call *edb.Call, line *edb.Line) error { 36 | if bp.Contract != nil && *bp.Contract != call.CodeAddress() { 37 | return nil 38 | } 39 | if line.Pc != bp.Pc { 40 | return nil 41 | } 42 | return errors.Wrap(ErrBreakpoint, bp.String()) 43 | } 44 | 45 | // break at Op code of target contract 46 | // eg: break at `SHA3` 47 | type BpOpCode struct { 48 | edb.EmptyHook 49 | Contract *common.Address 50 | OpCode vm.OpCode 51 | } 52 | 53 | func (bp *BpOpCode) String() string { 54 | if bp.Contract == nil { 55 | return fmt.Sprintf( 56 | "@ OpCode: %s", bp.OpCode.String()) 57 | } else { 58 | return fmt.Sprintf( 59 | "@ OpCode: %s of %s", 60 | bp.OpCode.String(), bp.Contract.Hex()) 61 | } 62 | } 63 | 64 | func (bp *BpOpCode) PreRun(call *edb.Call, line *edb.Line) error { 65 | if bp.Contract != nil && *bp.Contract != call.CodeAddress() { 66 | return nil 67 | } 68 | if line.Op.OpCode != bp.OpCode { 69 | return nil 70 | } 71 | return errors.Wrap(ErrBreakpoint, bp.String()) 72 | } 73 | -------------------------------------------------------------------------------- /hooks/symbolic/print.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/ethereum/go-ethereum/core/vm" 8 | ) 9 | 10 | // Low performance, maybe replace 11 | // `Node.String` -> `Node.Print` 12 | type printer struct { 13 | indentLevel int 14 | sb strings.Builder 15 | indentString string 16 | } 17 | 18 | // Add "\t" before string 19 | func (p *printer) line(s string) { 20 | p.sb.WriteString( 21 | strings.Repeat(p.indentString, p.indentLevel) + 22 | s + "\n") 23 | } 24 | 25 | // For printing node with indention 26 | func (p *printer) print(n Node) { 27 | switch n := n.(type) { 28 | 29 | case *Call: // increase indent level by 1 30 | p.line("") 31 | p.line(fmt.Sprintf("%s -> %s, func: %s {", 32 | n.OpCode.String(), n.Target.String(), n.FuncSig(), 33 | )) 34 | p.indentLevel++ 35 | 36 | for _, ch := range n.List { 37 | p.print(ch) 38 | } 39 | 40 | p.indentLevel-- 41 | p.line("}") // last line "}" 42 | case *Sha3Calc, *Log, *Return, *Precompiled: 43 | // add indent to all output lines of `Sha3Calc.String()` 44 | ss := strings.Split(n.String(), "\n") 45 | for _, s := range ss { 46 | p.line(s) 47 | } 48 | 49 | default: // for all other Node, just print their `String()` 50 | p.line(n.String()) 51 | } 52 | 53 | } 54 | func PrintNode(n Node) string { 55 | p := &printer{indentString: " "} 56 | p.print(n) 57 | return p.sb.String() 58 | } 59 | 60 | func PrettifyOp(op vm.OpCode) string { 61 | switch op { 62 | case vm.ISZERO: 63 | return "!" 64 | case vm.LT, vm.SLT: 65 | return "<" 66 | case vm.GT, vm.SGT: 67 | return ">" 68 | case vm.EQ: 69 | return "==" 70 | case vm.ADD: 71 | return "+" 72 | case vm.SUB: 73 | return "-" 74 | case vm.MUL: 75 | return "*" 76 | case vm.DIV: 77 | return "/" 78 | case vm.MOD: 79 | return "%" 80 | case vm.AND: 81 | return "&" 82 | case vm.OR: 83 | return "|" 84 | case vm.SHR: 85 | return ">>" 86 | case vm.SHL: 87 | return "<<" 88 | 89 | default: 90 | return op.String() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /hooks/param_tracer.go: -------------------------------------------------------------------------------- 1 | package hooks 2 | 3 | import ( 4 | "github.com/aj3423/edb" 5 | "github.com/aj3423/edb/util" 6 | "github.com/ethereum/go-ethereum/core/vm" 7 | "github.com/holiman/uint256" 8 | ) 9 | 10 | func init() { 11 | 12 | edb.Register((*ParamTracer)(nil)) 13 | } 14 | 15 | // Get stack input/outpus when executing op code 16 | type ParamTracer struct { 17 | StackPre edb.Stack[uint256.Int] // stack args before exec 18 | StackPost edb.Stack[uint256.Int] // result pushed to stack after exec 19 | 20 | PcPre uint64 // pc before exec 21 | PcPost uint64 // pc after exec 22 | 23 | MemPre []byte // full memory copy(before exec) 24 | MemPost []byte // full memory copy(after exec) 25 | } 26 | 27 | func (t *ParamTracer) PreRun(call *edb.Call, line *edb.Line) error { 28 | stack := &call.Stack 29 | size := stack.Len() 30 | 31 | t.PcPre = call.Pc 32 | // Stack: 33 | // last n items in stack, n == param count for this OpCode 34 | t.StackPre.Data = util.CloneSlice(stack.Data[size-int(line.Op.NStackIn) : size]) // clone stack params 35 | 36 | // Memory: 37 | // memory is only used for some op code 38 | switch line.Op.OpCode { 39 | case vm.SHA3, vm.MLOAD, vm.MSTORE, vm.MSTORE8, vm.CALL, vm.DELEGATECALL, vm.STATICCALL: 40 | m := call.Memory.Data() 41 | t.MemPre = append(m[:0:0], m...) // clone byte slice 42 | } 43 | 44 | return nil 45 | } 46 | func (t *ParamTracer) PostRun(call *edb.Call, line *edb.Line) error { 47 | stack := &call.Stack 48 | size := stack.Len() 49 | 50 | t.PcPost = call.Pc 51 | 52 | // Stack: 53 | // return values on stack after executing this op code 54 | t.StackPost.Data = util.CloneSlice(stack.Data[size-int(line.Op.NStackOut) : size]) // clone stack params 55 | 56 | // Memory: 57 | // Memory is only used for opcodes below. 58 | // Not copy memory for other opcodes to improve performance. 59 | switch line.Op.OpCode { 60 | case vm.SHA3, vm.MLOAD, vm.MSTORE, vm.MSTORE8, vm.CALL, 61 | vm.DELEGATECALL, vm.STATICCALL, vm.CODECOPY, vm.CALLDATACOPY, 62 | vm.RETURNDATACOPY, vm.EXTCODECOPY, vm.RETURN, vm.REVERT: 63 | 64 | m := call.Memory.Data() 65 | t.MemPost = append(m[:0:0], m...) // clone byte slice 66 | } 67 | 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /hooks/symbolic/optimize_test.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ethereum/go-ethereum/core/vm" 7 | "github.com/holiman/uint256" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestFuncSig(t *testing.T) { 12 | n := &BinaryOp{ 13 | OpNode: OpNode{vm.EQ}, 14 | X: NewConst(uint256.NewInt(0x11223344)), 15 | Y: &BinaryOp{ 16 | OpNode: OpNode{vm.SHR}, 17 | X: &UnaryOp{ 18 | OpNode: OpNode{vm.CALLDATALOAD}, 19 | X: NewConst(uint256.NewInt(0)), 20 | }, 21 | Y: NewConst(uint256.NewInt(0xe0)), 22 | }, 23 | } 24 | 25 | n2, _ := Optimize(n, Optimizers{&FunSig{}}) 26 | 27 | assert.Equal(t, "(0x11223344 == func_sig)", n2.String()) 28 | } 29 | 30 | // `ADD(0x4, SUB(x, 0x4))` 31 | func TestConterBinaryOp(t *testing.T) { 32 | n := &BinaryOp{ 33 | OpNode: OpNode{vm.ADD}, 34 | X: NewConst(uint256.NewInt(4)), 35 | Y: &BinaryOp{ 36 | OpNode: OpNode{vm.SUB}, 37 | X: &Label{Str: "x"}, 38 | Y: NewConst(uint256.NewInt(4)), 39 | }, 40 | } 41 | 42 | n2, _ := Optimize(n, Optimizers{&CounterBinaryOp{}}) 43 | 44 | assert.Equal(t, "x", n2.String()) 45 | } 46 | 47 | // `!(!(x))` 48 | func TestConterUnaryOp(t *testing.T) { 49 | n := &UnaryOp{ 50 | OpNode: OpNode{vm.ISZERO}, 51 | X: &UnaryOp{ 52 | OpNode: OpNode{vm.ISZERO}, 53 | X: &Label{Str: "x"}, 54 | }, 55 | } 56 | 57 | n2, _ := Optimize(n, Optimizers{&CounterUnaryOp{}}) 58 | 59 | assert.Equal(t, "x", n2.String()) 60 | } 61 | 62 | // `((CALLER << 0x60) & NOT(((0x1 << 0x60) - 0x1)))` 63 | // -> 64 | // (CALLER << 0x60) 65 | func TestSignCast(t *testing.T) { 66 | n := &BinaryOp{ 67 | OpNode: OpNode{vm.AND}, 68 | X: &BinaryOp{ 69 | OpNode: OpNode{vm.SHL}, 70 | X: &NullaryOp{OpNode: OpNode{vm.CALLER}}, 71 | Y: NewConst(uint256.NewInt(0x60)), 72 | }, 73 | Y: &UnaryOp{ 74 | OpNode: OpNode{vm.NOT}, 75 | X: &BinaryOp{ 76 | OpNode: OpNode{vm.SUB}, 77 | Y: NewConst(uint256.NewInt(1)), 78 | X: &BinaryOp{ 79 | OpNode: OpNode{vm.SHL}, 80 | X: NewConst(uint256.NewInt(1)), 81 | Y: NewConst(uint256.NewInt(0x60)), 82 | }, 83 | }, 84 | }, 85 | } 86 | 87 | n2, _ := Optimize(n, Optimizers{&SignCast{}}) 88 | 89 | assert.Equal(t, "(CALLER << 0x60)", n2.String()) 90 | } 91 | -------------------------------------------------------------------------------- /util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "os" 10 | "sort" 11 | 12 | "github.com/ethereum/go-ethereum/common" 13 | "golang.org/x/crypto/sha3" 14 | ) 15 | 16 | var ZeroAddress common.Address // all zeroes 17 | 18 | // hex encoded in json, instead of base64 19 | type ByteSlice []byte 20 | 21 | func (s ByteSlice) MarshalJSON() ([]byte, error) { 22 | return json.Marshal(hex.EncodeToString(s)) 23 | } 24 | func (s *ByteSlice) UnmarshalJSON(data []byte) error { 25 | var str string 26 | e := json.Unmarshal(data, &str) 27 | if e != nil { 28 | return e 29 | } 30 | 31 | bs, e := hex.DecodeString(str) 32 | if e != nil { 33 | return e 34 | } 35 | *s = bs 36 | return nil 37 | } 38 | 39 | func MapToStruct(in, out interface{}) error { 40 | buf := new(bytes.Buffer) 41 | if e := json.NewEncoder(buf).Encode(in); e != nil { 42 | return e 43 | } 44 | return json.NewDecoder(buf).Decode(out) 45 | } 46 | 47 | type comparable interface { 48 | int | int8 | int16 | int32 | int64 | 49 | uint | uint8 | uint16 | uint32 | uint64 | 50 | float32 | float64 51 | } 52 | 53 | func Max[T comparable](x, y T) T { 54 | if x > y { 55 | return x 56 | } 57 | return y 58 | } 59 | 60 | func Min[T comparable](x, y T) T { 61 | if x < y { 62 | return x 63 | } 64 | return y 65 | } 66 | 67 | func ReverseSlice[T any](s []T) { 68 | sort.SliceStable(s, func(i, j int) bool { 69 | return i > j 70 | }) 71 | } 72 | func CloneSlice[T any](s []T) []T { 73 | return append(s[:0:0], s...) 74 | } 75 | 76 | func HexEnc(data []byte) string { 77 | return fmt.Sprintf("%x", data) 78 | } 79 | func HexDec(data string) []byte { 80 | decoded, _ := hex.DecodeString(data) 81 | return decoded 82 | } 83 | 84 | func FileWrite(fn string, data []byte) error { 85 | return ioutil.WriteFile(fn, data, 0666) 86 | } 87 | func FileWriteStr(fn string, data string) error { 88 | return FileWrite(fn, []byte(data)) 89 | } 90 | func FileExist(fn string) bool { 91 | _, err := os.Stat(fn) 92 | if err == nil || os.IsExist(err) { 93 | return true 94 | 95 | } else { 96 | return false 97 | } 98 | } 99 | 100 | func Sha3(bs []byte) []byte { 101 | hash := sha3.NewLegacyKeccak256() 102 | hash.Write(bs) 103 | return hash.Sum(nil) 104 | } 105 | -------------------------------------------------------------------------------- /hook.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | 8 | "github.com/aj3423/edb/util" 9 | ) 10 | 11 | type hook interface { 12 | // called before executing current instruction, return error to stop running 13 | PreRun(call *Call, line *Line) error 14 | // called after executing current instruction, return error to stop running 15 | PostRun(call *Call, line *Line) error 16 | } 17 | 18 | type EmptyHook struct{} 19 | 20 | func (h *EmptyHook) PreRun(call *Call, line *Line) error { return nil } 21 | func (h *EmptyHook) PostRun(call *Call, line *Line) error { return nil } 22 | 23 | var map_hook_types = make(map[string]reflect.Type) // eg: map["BpPc"]*main.BpPc 24 | 25 | // To support save/load of Hooks, they should be Registered first 26 | func Register(c hook) { 27 | name := reflect.TypeOf(c).Elem().Name() 28 | t := reflect.TypeOf(c).Elem() 29 | map_hook_types[name] = t 30 | } 31 | func makeInstance(name string) interface{} { 32 | return reflect.New(map_hook_types[name]).Interface() 33 | } 34 | 35 | type Hooks struct { 36 | arr []hook 37 | } 38 | 39 | /* 40 | result: 41 | [ 42 | { "Type": "BpPc", "Value": {Pc:3} }, 43 | { "Type": "BpOp", "Value": {Op:4} }, 44 | ... 45 | ] 46 | */ 47 | func (hks *Hooks) MarshalJSON() ([]byte, error) { 48 | arr := []any{} 49 | for _, hk := range hks.arr { 50 | arr = append(arr, map[string]any{ 51 | "Type": reflect.TypeOf(hk).Elem().Name(), 52 | "Value": hk, 53 | }) 54 | } 55 | return json.MarshalIndent(arr, "", " ") 56 | } 57 | func (hks *Hooks) UnmarshalJSON(bs []byte) error { 58 | arr := []any{} 59 | e := json.Unmarshal(bs, &arr) 60 | if e != nil { 61 | return e 62 | } 63 | for i := 0; i < len(arr); i++ { 64 | x, ok := arr[i].(map[string]any) 65 | if !ok { 66 | return fmt.Errorf("invalid hook format: %v", arr[i]) 67 | } 68 | type_, ok := x["Type"].(string) 69 | if !ok { 70 | return fmt.Errorf("invalid 'Name' field: %v", x) 71 | } 72 | 73 | hk := makeInstance(type_) 74 | 75 | if e := util.MapToStruct(x["Value"], hk); e != nil { 76 | return e 77 | } 78 | hks.Attach(hk.(hook)) 79 | } 80 | 81 | return nil 82 | } 83 | 84 | func (hks *Hooks) PreRunAll( 85 | call *Call, line *Line, 86 | ) error { 87 | var err error 88 | for _, h := range hks.arr { 89 | if e := h.PreRun(call, line); e != nil { 90 | err = e 91 | } 92 | } 93 | return err 94 | } 95 | func (hks *Hooks) PostRunAll( 96 | call *Call, line *Line, 97 | ) error { 98 | var err error 99 | for _, h := range hks.arr { 100 | if e := h.PostRun(call, line); e != nil { 101 | err = e 102 | } 103 | } 104 | return err 105 | } 106 | 107 | func (hks *Hooks) Attach(h hook) { 108 | hks.arr = append(hks.arr, h) 109 | } 110 | func (hks *Hooks) Detach(i int) { 111 | if i >= 0 && i < len(hks.arr) { 112 | hks.arr = append((hks.arr)[0:i], (hks.arr)[i+1:]...) 113 | } 114 | } 115 | func (hks *Hooks) List() []hook { 116 | return hks.arr 117 | } 118 | -------------------------------------------------------------------------------- /asm.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | 7 | "github.com/aj3423/edb/util" 8 | "github.com/ethereum/go-ethereum/core/vm" 9 | "github.com/fatih/color" 10 | ) 11 | 12 | var ShowHexPC = false 13 | 14 | // structs for display only 15 | type Line struct { 16 | Pc uint64 17 | LineNum uint64 18 | Op *Operation 19 | Data []byte // additional bytes for OpCode, eg: 4 bytes for PUSH4 20 | } 21 | 22 | func (l *Line) String() string { 23 | if ShowHexPC { 24 | return fmt.Sprintf("%8x %12s %s", l.Pc, l.Op.OpCode.String(), util.HexEnc(l.Data)) 25 | } else { 26 | return fmt.Sprintf("% 8d %12s %s", l.Pc, l.Op.OpCode.String(), util.HexEnc(l.Data)) 27 | } 28 | } 29 | 30 | // TODO replace with IndexedArray 31 | type Asm struct { 32 | // for finding *Line by lineNum 33 | sequence []*Line 34 | 35 | // for finding *Line by pc 36 | mapPc map[uint64]*Line // map[pc]*Line 37 | } 38 | 39 | func NewAsm() *Asm { 40 | a := &Asm{} 41 | return a.Reset() 42 | } 43 | 44 | func (a *Asm) Reset() *Asm { 45 | a.sequence = nil 46 | a.mapPc = map[uint64]*Line{} 47 | return a 48 | } 49 | func (a *Asm) LineCount() int { 50 | return len(a.sequence) 51 | } 52 | func (a *Asm) LineAtPc(pc uint64) (*Line, error) { 53 | line, ok := a.mapPc[pc] 54 | if !ok { 55 | fmt.Println("mapPc len", len(a.mapPc)) 56 | return nil, fmt.Errorf("invalid pc: %d", pc) 57 | } 58 | return line, nil 59 | } 60 | func (a *Asm) AtRow(row int) *Line { 61 | return a.sequence[row] 62 | } 63 | 64 | func (a *Asm) Disasm( 65 | code []byte, 66 | ) error { 67 | a.Reset() 68 | 69 | if len(code) > 2 { // remove trailing CBOR encoded metadata: 70 | last_2 := code[len(code)-2:] 71 | meta_len := binary.BigEndian.Uint16(last_2) 72 | code = code[0 : len(code)-int(meta_len)-2] 73 | } 74 | 75 | var codeLen = uint64(len(code)) 76 | 77 | var pc uint64 = 0 78 | 79 | var line *Line 80 | 81 | for pc < codeLen { 82 | opCode := code[pc] 83 | op, ok := OpTable[vm.OpCode(opCode)] 84 | if !ok { 85 | // invalid op occurs at the end of code, 86 | // don't know how to parse the code+metadata perfectly, 87 | // stop disassembling with a warning 88 | 89 | color.Yellow("Warning: Disasm: invalid opcode: %s @pc: %d/%d", vm.OpCode(opCode).String(), pc, codeLen) 90 | return nil 91 | } 92 | 93 | if pc+1+op.OpSize > codeLen { 94 | /* 95 | In most cases this error is caused by trailing CBOR metadata, see: 96 | https://docs.soliditylang.org/en/v0.8.13/metadata.html#contract-metadata 97 | */ 98 | // TODO skip metadata 99 | color.Yellow("Warning: Disasm: not enough data for opcode: %s at pc: %d/%d, require %d bytes", 100 | op.OpCode.String(), pc, codeLen, op.OpSize) 101 | return nil 102 | } 103 | line = &Line{ 104 | Pc: pc, 105 | LineNum: uint64(len(a.sequence)), 106 | Op: op, 107 | Data: code[pc+1 : pc+1+op.OpSize], 108 | } 109 | a.sequence = append(a.sequence, line) 110 | a.mapPc[uint64(pc)] = line 111 | 112 | pc += 1 + op.OpSize 113 | } 114 | return nil 115 | } 116 | -------------------------------------------------------------------------------- /memory.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "encoding/hex" 5 | "encoding/json" 6 | "strings" 7 | 8 | "github.com/aj3423/edb/util" 9 | "github.com/holiman/uint256" 10 | ) 11 | 12 | type Memory struct { 13 | store []byte 14 | } 15 | 16 | func (m *Memory) MarshalJSON() ([]byte, error) { 17 | ss := []string{} 18 | p := 0 19 | for p < len(m.store) { 20 | chunkLen := util.Min(32, len(m.store)-p) 21 | 22 | chunk := m.store[p : p+chunkLen] 23 | ss = append(ss, util.HexEnc(chunk)) 24 | p += chunkLen 25 | } 26 | 27 | return json.MarshalIndent(ss, "", " ") 28 | } 29 | func (m *Memory) UnmarshalJSON(bs []byte) error { 30 | ss := []string{} 31 | e := json.Unmarshal(bs, &ss) 32 | if e != nil { 33 | return e 34 | } 35 | all := strings.Join(ss, "") 36 | m.store, e = hex.DecodeString(all) 37 | return e 38 | } 39 | 40 | // Set sets offset + size to value 41 | func (m *Memory) Set(offset, size uint64, value []byte) { 42 | // It's possible the offset is greater than 0 and size equals 0. This is because 43 | // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP) 44 | if size > 0 { 45 | // length of store may never be less than offset + size. 46 | // The store should be resized PRIOR to setting the memory 47 | if offset+size > uint64(len(m.store)) { 48 | m.Resize(offset + size) 49 | } 50 | copy(m.store[offset:offset+size], value) 51 | } 52 | } 53 | 54 | // Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to 55 | // 32 bytes. 56 | func (m *Memory) Set32(offset uint64, val *uint256.Int) { 57 | // length of store may never be less than offset + size. 58 | // The store should be resized PRIOR to setting the memory 59 | if offset+32 > uint64(len(m.store)) { 60 | m.Resize(offset + 32) 61 | } 62 | // Zero the memory area 63 | copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) 64 | // Fill in relevant bits 65 | val.WriteToSlice(m.store[offset:]) 66 | } 67 | 68 | // Resize resizes the memory to size 69 | func (m *Memory) Resize(size uint64) { 70 | if m.Len() < size { 71 | m.store = append(m.store, make([]byte, size-m.Len())...) 72 | } 73 | } 74 | 75 | // Get returns offset + size as a new slice 76 | func (m *Memory) GetCopy(offset, size int64) (cpy []byte) { 77 | if size == 0 { 78 | return nil 79 | } 80 | 81 | if len(m.store) > int(offset) { 82 | cpy = make([]byte, size) 83 | copy(cpy, m.store[offset:offset+size]) 84 | 85 | return 86 | } 87 | 88 | return 89 | } 90 | 91 | // GetPtr returns the offset + size 92 | func (m *Memory) GetPtr(offset, size int64) []byte { 93 | if size == 0 { 94 | return nil 95 | } 96 | 97 | if len(m.store) > int(offset) { 98 | return m.store[offset : offset+size] 99 | } 100 | 101 | return nil 102 | } 103 | 104 | // Len returns the length of the backing slice 105 | func (m *Memory) Len() uint64 { 106 | return uint64(len(m.store)) 107 | } 108 | 109 | // Data returns the backing slice 110 | func (m *Memory) Data() []byte { 111 | return m.store 112 | } 113 | -------------------------------------------------------------------------------- /main/cmd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "path/filepath" 6 | "strings" 7 | 8 | "github.com/c-bata/go-prompt" 9 | ) 10 | 11 | type cmd interface { 12 | Match(args []string) Matches 13 | } 14 | 15 | // executable commands 16 | type executableCmd interface { 17 | cmd 18 | Exec() 19 | } 20 | 21 | // match result 22 | type Match struct { 23 | cmd 24 | isPartial bool 25 | *prompt.Suggest 26 | } 27 | type Matches []Match 28 | 29 | type Sub []cmd 30 | 31 | func (n *Sub) Match(args []string) (matches Matches) { 32 | for _, sub := range *n { 33 | matches = append(matches, sub.Match(args)...) 34 | } 35 | return matches 36 | } 37 | 38 | type Cmd struct { 39 | name string 40 | help string 41 | exec func() 42 | *Sub // sub command list 43 | } 44 | 45 | func (c *Cmd) Name() string { 46 | return c.name 47 | } 48 | func (c *Cmd) Help() string { 49 | return c.help 50 | } 51 | 52 | func (c *Cmd) Match(args []string) (matches Matches) { 53 | size := len(args) 54 | if size == 0 { // no arg left, no match 55 | return 56 | } 57 | if args[0] == c.name { // fully match for current arg 58 | if size == 1 { 59 | return Matches{{c, false, &prompt.Suggest{c.name, c.help}}} 60 | } else { // more sub commands 61 | return c.Sub.Match(args[1:]) 62 | } 63 | } 64 | if size == 1 && strings.HasPrefix(c.name, args[0]) { // partially match 65 | return Matches{{c, true, &prompt.Suggest{c.name, c.help}}} 66 | } 67 | return 68 | } 69 | func (n *Cmd) Exec() { 70 | n.exec() 71 | } 72 | 73 | type Value[T any] struct { 74 | val T 75 | exec func(T) 76 | } 77 | 78 | type IntValue Value[uint64] 79 | 80 | func (n *IntValue) Match(args []string) (matches Matches) { 81 | if len(args) != 1 || args[0] == "" { 82 | return 83 | } 84 | var e error 85 | n.val, e = parse_any_int(args[0]) 86 | if e != nil { 87 | return 88 | } 89 | return Matches{{n, false, nil}} 90 | } 91 | func (n *IntValue) Exec() { n.exec(n.val) } 92 | 93 | type StrValue Value[string] 94 | 95 | func (n *StrValue) Match(args []string) (matches Matches) { 96 | if len(args) != 1 || args[0] == "" { 97 | return 98 | } 99 | n.val = args[0] 100 | return Matches{{n, false, nil}} 101 | } 102 | func (n *StrValue) Exec() { n.exec(n.val) } 103 | 104 | type File struct { 105 | fn string // executing target 106 | ext string // target extension ".json" 107 | exec func(fn string) 108 | } 109 | 110 | func (n *File) Match(args []string) (matches Matches) { 111 | if len(args) != 1 || args[0] == "" { 112 | return 113 | } 114 | dir, inputFn := filepath.Split(args[0]) 115 | if dir == "" { 116 | dir = "." 117 | } 118 | files, e := ioutil.ReadDir(dir) 119 | if e != nil { 120 | return 121 | } 122 | for _, f := range files { 123 | if f.IsDir() { // only match file 124 | continue 125 | } 126 | fn := f.Name() 127 | ext := filepath.Ext(fn) 128 | if ext != n.ext { // match extension 129 | continue 130 | } 131 | 132 | // fmt.Println(fn, ", ", args[0]) 133 | 134 | if fn == inputFn { // fully match 135 | n.fn = fn 136 | matches = append(matches, Match{n, false, nil}) 137 | } else if strings.Contains(fn, inputFn) { // partially match 138 | matches = append(matches, Match{n, true, &prompt.Suggest{fn, ""}}) 139 | } 140 | } 141 | 142 | return 143 | } 144 | func (n *File) Exec() { n.exec(n.fn) } 145 | -------------------------------------------------------------------------------- /util/hex_dump.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | /* 11 | Code copied from Golang `hex.Dump` 12 | Modified to support printing hex dump from specified offset 13 | */ 14 | 15 | // Hex dump with custom printing `offset` instead of 0 16 | func HexDumpEx(data []byte, offset uint) string { 17 | if len(data) == 0 { 18 | return "" 19 | } 20 | 21 | var buf strings.Builder 22 | // Dumper will write 79 bytes per complete 16 byte chunk, and at least 23 | // 64 bytes for whatever remains. Round the allocation up, since only a 24 | // maximum of 15 bytes will be wasted. 25 | buf.Grow((1 + ((len(data) - 1) / 16)) * 79) 26 | 27 | dumper := DumperEx(&buf, offset) 28 | dumper.Write(data) 29 | dumper.Close() 30 | return buf.String() 31 | } 32 | 33 | // Dumper returns a WriteCloser that writes a hex dump of all written data to 34 | // w. The format of the dump matches the output of `hexdump -C` on the command 35 | // line. 36 | func DumperEx(w io.Writer, offset uint) io.WriteCloser { 37 | return &dumper{w: w, offset: offset} 38 | } 39 | 40 | type dumper struct { 41 | w io.Writer 42 | rightChars [18]byte 43 | buf [14]byte 44 | used int // number of bytes in the current line 45 | n uint // number of bytes, total 46 | closed bool 47 | 48 | offset uint // start offset 49 | } 50 | 51 | func toChar(b byte) byte { 52 | if b < 32 || b > 126 { 53 | return '.' 54 | } 55 | return b 56 | } 57 | 58 | func (h *dumper) Write(data []byte) (n int, err error) { 59 | if h.closed { 60 | return 0, errors.New("encoding/hex: dumper closed") 61 | } 62 | 63 | // Output lines look like: 64 | // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| 65 | // ^ offset ^ extra space ^ ASCII of line. 66 | for i := range data { 67 | if h.used == 0 { 68 | // At the beginning of a line we print the current 69 | // offset in hex. 70 | h.buf[0] = byte((h.n + h.offset) >> 24) 71 | h.buf[1] = byte((h.n + h.offset) >> 16) 72 | h.buf[2] = byte((h.n + h.offset) >> 8) 73 | h.buf[3] = byte((h.n + h.offset)) 74 | hex.Encode(h.buf[4:], h.buf[:4]) 75 | h.buf[12] = ' ' 76 | h.buf[13] = ' ' 77 | _, err = h.w.Write(h.buf[4:]) 78 | if err != nil { 79 | return 80 | } 81 | } 82 | hex.Encode(h.buf[:], data[i:i+1]) 83 | h.buf[2] = ' ' 84 | l := 3 85 | if h.used == 7 { 86 | // There's an additional space after the 8th byte. 87 | h.buf[3] = ' ' 88 | l = 4 89 | } else if h.used == 15 { 90 | // At the end of the line there's an extra space and 91 | // the bar for the right column. 92 | h.buf[3] = ' ' 93 | h.buf[4] = '|' 94 | l = 5 95 | } 96 | _, err = h.w.Write(h.buf[:l]) 97 | if err != nil { 98 | return 99 | } 100 | n++ 101 | h.rightChars[h.used] = toChar(data[i]) 102 | h.used++ 103 | h.n++ 104 | if h.used == 16 { 105 | h.rightChars[16] = '|' 106 | h.rightChars[17] = '\n' 107 | _, err = h.w.Write(h.rightChars[:]) 108 | if err != nil { 109 | return 110 | } 111 | h.used = 0 112 | } 113 | } 114 | return 115 | } 116 | 117 | func (h *dumper) Close() (err error) { 118 | // See the comments in Write() for the details of this format. 119 | if h.closed { 120 | return 121 | } 122 | h.closed = true 123 | if h.used == 0 { 124 | return 125 | } 126 | h.buf[0] = ' ' 127 | h.buf[1] = ' ' 128 | h.buf[2] = ' ' 129 | h.buf[3] = ' ' 130 | h.buf[4] = '|' 131 | nBytes := h.used 132 | for h.used < 16 { 133 | l := 3 134 | if h.used == 7 { 135 | l = 4 136 | } else if h.used == 15 { 137 | l = 5 138 | } 139 | _, err = h.w.Write(h.buf[:l]) 140 | if err != nil { 141 | return 142 | } 143 | h.used++ 144 | } 145 | h.rightChars[nBytes] = '|' 146 | h.rightChars[nBytes+1] = '\n' 147 | _, err = h.w.Write(h.rightChars[:nBytes+2]) 148 | return 149 | } 150 | -------------------------------------------------------------------------------- /gas.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/params" 5 | ) 6 | 7 | type gasFunc func(*Context) uint64 8 | 9 | func fixedGas(n uint64) gasFunc { 10 | return func(*Context) uint64 { return n } 11 | } 12 | 13 | /* 14 | (exp == 0) ? 10 : (10 + 10 * (1 + log256(exp))) 15 | If exponent is 0, gas used is 10 16 | If exponent is greater than 0, gas used is 10 plus 10 times a factor related to how large the log of the exponent is. 17 | */ 18 | func gasExp(ctx *Context) uint64 { 19 | stack := ctx.Stack() 20 | exponent := stack.PeekI(1) 21 | 22 | expByteLen := uint64((exponent.BitLen() + 7) / 8) 23 | 24 | return expByteLen*params.ExpByteEIP158 + 10 25 | } 26 | 27 | /* 28 | 30 + 6 * (size of input in words) 29 | 30 is the paid for the operation plus 30 | 6 paid for each word (rounded up) for the input data. 31 | */ 32 | func gasSha3(ctx *Context) uint64 { 33 | stack := ctx.Stack() 34 | 35 | length := stack.PeekI(1).Uint64() // stack: [ data, length 36 | return 30 + (toWordSize(length) * 6) 37 | } 38 | 39 | func toWordSize(bytesLen uint64) uint64 { 40 | return (bytesLen + 31) / 32 41 | } 42 | 43 | /* 44 | ((value != 0) && (storage_location == 0)) ? 20000 : 5000 45 | 20000 is paid when storage value is set to non-zero from zero. 46 | 5000 is paid when the storage value's zeroness remains unchanged or is set to zero. 47 | */ 48 | func gasSStore(ctx *Context) uint64 { 49 | // gasCost is different when value changes or not 50 | stack := ctx.Stack() 51 | this := ctx.Call().This 52 | slot, new_val := stack.PeekI(0), stack.PeekI(1) 53 | 54 | old_val, e := ensure_storage(ctx, this, slot) 55 | if e != nil { 56 | // TODO find a better way to stop running 57 | return 0xffffffffffffffff 58 | } 59 | 60 | if !old_val.IsZero() && new_val.IsZero() { 61 | return 20000 62 | } 63 | return 5000 64 | } 65 | 66 | // calculates gas for memory expansion. 67 | // only calculates the memory region that is expanded, not the total memory. 68 | func memoryGasCost(currMemSize, newMemSize uint64) uint64 { 69 | if newMemSize == 0 { 70 | return 0 71 | } 72 | newMemSizeWords := toWordSize(newMemSize) 73 | newMemSize = newMemSizeWords * 32 74 | 75 | if newMemSize > currMemSize { 76 | square := newMemSizeWords * newMemSizeWords 77 | linCoef := newMemSizeWords * params.MemoryGas 78 | quadCoef := square / params.QuadCoeffDiv 79 | newTotalFee := linCoef + quadCoef 80 | return newTotalFee 81 | 82 | } 83 | return 0 84 | } 85 | 86 | func memoryCopierGas(baseGas uint64, offsetPos, lenPos int) gasFunc { 87 | return func(ctx *Context) uint64 { 88 | stack := ctx.Stack() 89 | offset, length := stack.PeekI(offsetPos).Uint64(), stack.PeekI(lenPos).Uint64() 90 | 91 | newMemSize := offset + length 92 | currMemSize := ctx.Memory().Len() 93 | 94 | // Gas for expanding the memory 95 | gasExpand := memoryGasCost(currMemSize, newMemSize) 96 | 97 | // And gas for copying data, charged per word at param.CopyGas 98 | gasCopy := toWordSize(length) * params.CopyGas 99 | 100 | fee := gasExpand + gasCopy 101 | return baseGas + fee 102 | } 103 | } 104 | 105 | // baseGas + 3 * (number of words copied, rounded up) 106 | // baseGas is paid for the operation, plus 3 for each word copied (rounded up). 107 | var ( 108 | gasCallDataCopy = memoryCopierGas(3, 0, 2) 109 | gasCodeCopy = memoryCopierGas(3, 0, 2) 110 | gasExtCodeCopy = memoryCopierGas(700, 1, 3) 111 | gasReturnDataCopy = memoryCopierGas(3, 0, 2) 112 | ) 113 | 114 | /* 115 | 375 + 8 * (number of bytes in log data) + n * 375 116 | 375 is paid for operation plus 8 for each byte in data to be logged 117 | plus n * 375 for the n topics to be logged. 118 | */ 119 | func makeGasLog(n uint64) gasFunc { 120 | return func(ctx *Context) uint64 { 121 | size := ctx.Stack().PeekI(1).Uint64() 122 | return 375 + 8*size + n*375 123 | } 124 | } 125 | 126 | func gasTodo(ctx *Context) uint64 { 127 | return 0 128 | } 129 | -------------------------------------------------------------------------------- /hooks/low_level_tracer.go: -------------------------------------------------------------------------------- 1 | package hooks 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/aj3423/edb" 10 | "github.com/ethereum/go-ethereum/core/vm" 11 | "github.com/fatih/color" 12 | "github.com/holiman/uint256" 13 | ) 14 | 15 | type LowLevelTracer struct { 16 | *ParamTracer 17 | } 18 | 19 | func NewLowLevelTracer() *LowLevelTracer { 20 | return &LowLevelTracer{ 21 | ParamTracer: &ParamTracer{}, 22 | } 23 | } 24 | func (t *LowLevelTracer) PreRun(call *edb.Call, line *edb.Line) error { 25 | 26 | t.ParamTracer.PreRun(call, line) // save stack/mem params for PostRun 27 | return nil 28 | } 29 | 30 | func (t *LowLevelTracer) PostRun(call *edb.Call, line *edb.Line) error { 31 | opcode := line.Op.OpCode 32 | 33 | t.ParamTracer.PostRun(call, line) 34 | 35 | switch opcode { 36 | case vm.SHA3: 37 | // get result from stack 38 | color.Magenta("\nSHA3 memory (") 39 | // mem := 40 | offset, size := t.StackPre.PeekI(0).ToBig().Uint64(), t.StackPre.PeekI(1).ToBig().Uint64() 41 | mem := t.MemPre[offset : offset+size] 42 | 43 | // pretty print 44 | switch len(mem) { 45 | case 0x20: // some index 46 | fmt.Println(" " + new(uint256.Int).SetBytes(mem).String()) 47 | case 0x40: // some nested index 48 | fmt.Println(" " + new(uint256.Int).SetBytes(mem[0:0x20]).String()) 49 | fmt.Println(" " + new(uint256.Int).SetBytes(mem[0x20:]).String()) 50 | default: 51 | fmt.Println(hex.Dump(mem)) 52 | } 53 | color.Magenta(") -> %s\n\n", t.StackPost.PeekI(0).String()) 54 | case vm.MLOAD: 55 | color.White(" %s = mem[%s]", t.StackPost.PeekI(0).String(), t.StackPre.PeekI(0).String()) 56 | case vm.MSTORE, vm.MSTORE8: 57 | color.White(" mem[%s] = %s", t.StackPre.PeekI(0).String(), t.StackPre.PeekI(1).String()) 58 | case vm.SLOAD: 59 | color.White(" %s = storage[%s]", t.StackPost.PeekI(0).String(), t.StackPre.PeekI(0).String()) 60 | case vm.SSTORE: 61 | color.White(" storage[%s] = %s", t.StackPre.PeekI(0).String(), t.StackPre.PeekI(1).String()) 62 | case vm.CALL, vm.DELEGATECALL, vm.STATICCALL: 63 | var callee, value, inOffset, inSize *uint256.Int 64 | if opcode == vm.CALL { 65 | callee, value, inOffset, inSize = 66 | t.StackPre.PeekI(1), t.StackPre.PeekI(2), t.StackPre.PeekI(3), t.StackPre.PeekI(4) 67 | 68 | if inSize.IsZero() { // must be CALL, normal tranfer, addr.call{value:...}("") 69 | color.HiCyan("transfer value: %s -> %s", 70 | value.ToBig().String(), callee.String()) 71 | return nil 72 | } 73 | } else { 74 | callee, inOffset, inSize = 75 | t.StackPre.PeekI(1), t.StackPre.PeekI(2), t.StackPre.PeekI(3) 76 | } 77 | data := t.MemPre[inOffset.ToBig().Uint64() : inOffset.ToBig().Uint64()+inSize.ToBig().Uint64()] 78 | 79 | fn := data[0:4] 80 | color.HiCyan("%s -> %s, fn: %x", 81 | opcode.String(), callee.String(), fn) 82 | 83 | case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: 84 | _, _ = t.StackPre.Pop(), t.StackPre.Pop() 85 | n := opcode - vm.LOG0 86 | topics := []string{} 87 | for i := 0; i < int(n); i++ { 88 | topic := t.StackPre.Pop() 89 | topics = append(topics, topic.String()) 90 | } 91 | color.Magenta("%s (%s)", 92 | opcode.String(), strings.Join(topics, ",")) 93 | 94 | // 0 arg 95 | case vm.TIMESTAMP, vm.NUMBER, vm.ADDRESS, vm.ORIGIN, vm.CALLER, vm.CALLVALUE, 96 | vm.GASPRICE, vm.COINBASE, vm.DIFFICULTY, vm.GASLIMIT, vm.CHAINID, 97 | vm.SELFBALANCE, vm.BASEFEE, vm.PC, vm.MSIZE, vm.GAS: 98 | color.White(" %s = %s", t.StackPost.Peek().String(), opcode.String()) 99 | 100 | // 1 arg 101 | case vm.ISZERO, vm.NOT, vm.EXTCODEHASH, vm.BLOCKHASH: 102 | color.White( 103 | "%s (%s) -> %s\n", 104 | opcode.String(), t.StackPre.PeekI(0).String(), t.StackPost.Peek().String()) 105 | // 2 arg 106 | case vm.ADD, vm.MUL, vm.SUB, vm.DIV, vm.SDIV, vm.MOD, vm.SMOD, vm.EXP, 107 | vm.SHL, vm.SHR, vm.SAR, vm.LT, vm.GT, vm.SLT, vm.SGT, vm.EQ, 108 | vm.SIGNEXTEND, vm.AND, vm.OR, vm.XOR, vm.BYTE: 109 | color.White( 110 | "%s (%s, %s) -> %s\n", 111 | opcode.String(), t.StackPre.PeekI(0).String(), t.StackPre.PeekI(1).String(), t.StackPost.Peek().String()) 112 | // 3 arg 113 | case vm.ADDMOD, vm.MULMOD: 114 | color.White( 115 | "%s (%s, %s, %s) -> %s\n", 116 | opcode.String(), t.StackPre.PeekI(0).String(), t.StackPre.PeekI(1).String(), t.StackPre.PeekI(2).String(), t.StackPost.Peek().String()) 117 | } 118 | return nil 119 | } 120 | 121 | // full evm trace log, eg: 122 | // 0 PUSH 80 123 | // 2 PUSH 40 124 | // 4 MSTORE 125 | // ... 126 | type EvmLog struct { 127 | edb.EmptyHook 128 | Fd *os.File 129 | } 130 | 131 | func (t *EvmLog) PreRun(call *edb.Call, line *edb.Line) error { 132 | fmt.Fprintf(t.Fd, "%d\t %s\n", line.Pc, line.Op.OpCode.String()) 133 | return nil 134 | } 135 | -------------------------------------------------------------------------------- /hooks/symbolic/optimize.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/core/vm" 5 | "github.com/holiman/uint256" 6 | ) 7 | 8 | type optimizer interface { 9 | // return true if the node is modified 10 | Do(c *Cursor) (modified bool) 11 | } 12 | 13 | type Optimizers []optimizer 14 | 15 | var DefaultOptimizers = []optimizer{ 16 | &FunSig{}, 17 | &CounterUnaryOp{}, 18 | &CounterBinaryOp{}, 19 | &ProxyEIP1967{}, 20 | &SignCast{}, 21 | } 22 | 23 | // replace 24 | // `Const(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)` 25 | // -> 26 | // `PROXY_EIP1967_SLOT` 27 | var PROXY_EIP1967_SLOT, _ = uint256.FromHex("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc") 28 | var PROXY_EIP1967_ADMIN, _ = uint256.FromHex("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103") 29 | 30 | type ProxyEIP1967 struct { 31 | sample Node 32 | } 33 | 34 | func (op *ProxyEIP1967) Do(c *Cursor) (modified bool) { 35 | if n, ok := c.Node.(*Const); ok { 36 | if n.Value().Eq(PROXY_EIP1967_SLOT) { 37 | c.Replace(&Label{"PROXY_EIP1967_SLOT"}) 38 | modified = true 39 | } else if n.Value().Eq(PROXY_EIP1967_ADMIN) { 40 | c.Replace(&Label{"PROXY_EIP1967_ADMIN"}) 41 | modified = true 42 | } 43 | } 44 | return 45 | } 46 | 47 | // Evaluate the Node value 48 | func EvaluateConst(n Node) (uint256.Int, bool) { 49 | switch n := n.(type) { 50 | case *Const: 51 | return *n.Value(), true 52 | case *UnaryOp: 53 | switch n.OpCode { 54 | case vm.NOT: 55 | v, ok := EvaluateConst(n.X) 56 | if !ok { 57 | return uint256.Int{}, false 58 | } 59 | v.Not(&v) 60 | return v, true 61 | } 62 | case *BinaryOp: // y-x, y< 94 | // `x` 95 | var ( 96 | U20, _ = uint256.FromHex("0xffffffffffffffffffffffffffffffffffffffff") 97 | U20High, _ = uint256.FromHex("0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000") 98 | U16, _ = uint256.FromHex("0xffffffffffffffffffffffffffffffff") 99 | U16High, _ = uint256.FromHex("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000") 100 | U32, _ = uint256.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") 101 | ) 102 | 103 | type SignCast struct{} 104 | 105 | func (op *SignCast) match(x_or_y Node) bool { 106 | // Sometimes it's not simply 0xffffffffffffffffffffffffffffffffffffffff, 107 | // it may also be `((0x1 << 0xa0) - 0x1)` 108 | // So evaluate it 109 | if val, ok := EvaluateConst(x_or_y); ok { 110 | if val.Eq(U20) || val.Eq(U20High) || 111 | val.Eq(U32) || 112 | val.Eq(U16) || val.Eq(U16High) { 113 | return true 114 | } 115 | } 116 | return false 117 | } 118 | 119 | func (op *SignCast) Do(c *Cursor) (modified bool) { 120 | if bn, ok := c.Node.(*BinaryOp); ok { 121 | if bn.OpCode == vm.AND { 122 | if op.match(bn.X) { 123 | c.Replace(bn.Y) 124 | modified = true 125 | } 126 | if op.match(bn.Y) { 127 | c.Replace(bn.X) 128 | modified = true 129 | } 130 | } 131 | } 132 | return 133 | } 134 | 135 | // replace 136 | // `(CALLDATALOAD(0x0) >> 0xe0)` 137 | // -> 138 | // `func_sig` 139 | type FunSig struct { 140 | } 141 | 142 | var funSigSample = &BinaryOp{ 143 | OpNode: OpNode{OpCode: vm.SHR}, 144 | X: &UnaryOp{ 145 | OpNode: OpNode{OpCode: vm.CALLDATALOAD}, 146 | X: NewConst(uint256.NewInt(0)), 147 | }, 148 | Y: NewConst(uint256.NewInt(0xe0)), 149 | } 150 | 151 | func (op *FunSig) Do(c *Cursor) (modified bool) { 152 | if Equal(funSigSample, c.Node) { 153 | c.Replace(&Label{Str: "func_sig"}) 154 | 155 | modified = true 156 | } 157 | return 158 | } 159 | 160 | func is_counter_op(op1, op2 vm.OpCode) bool { 161 | if op1 == vm.ADD && op2 == vm.SUB { 162 | return true 163 | } 164 | if op1 == vm.SUB && op2 == vm.ADD { 165 | return true 166 | } 167 | 168 | return false 169 | } 170 | 171 | // replace 172 | // `ADD(0x4, SUB(x, 0x4))` 173 | // -> 174 | // `x` 175 | type CounterBinaryOp struct{} 176 | 177 | func (op *CounterBinaryOp) Do(c *Cursor) (modified bool) { 178 | n1, ok := c.Node.(*BinaryOp) 179 | if !ok { // the `ADD` 180 | return 181 | } 182 | n2, ok := n1.Y.(*BinaryOp) 183 | if !ok { // the `SUB` 184 | return 185 | } 186 | if !is_counter_op(n1.OpCode, n2.OpCode) { 187 | return 188 | } 189 | if _, ok = n1.X.(*Const); ok { // it's const number 190 | if Equal(n1.X, n2.Y) { 191 | c.Replace(n2.X) 192 | modified = true 193 | } 194 | } 195 | 196 | return 197 | } 198 | 199 | // replace 200 | // `!(!(x))` 201 | // -> 202 | // `x` 203 | type CounterUnaryOp struct{} 204 | 205 | func (op *CounterUnaryOp) Do(c *Cursor) (modified bool) { 206 | outer, ok := c.Node.(*UnaryOp) 207 | if !ok { // the outer 208 | return 209 | } 210 | inner, ok := outer.X.(*UnaryOp) 211 | if !ok { // the inner 212 | return 213 | } 214 | if outer.OpCode == inner.OpCode { 215 | switch outer.OpCode { 216 | case vm.ISZERO, vm.NOT: 217 | c.Replace(inner.X) 218 | modified = true 219 | } 220 | } 221 | return 222 | } 223 | 224 | // Returns the optimized node 225 | // and if it's modified 226 | func Optimize( 227 | root Node, 228 | opts Optimizers, 229 | ) (newNode Node, modified bool) { 230 | 231 | newNode = Walk(root, func(c *Cursor) { 232 | 233 | for _, o := range opts { 234 | if o.Do(c) { 235 | modified = true 236 | } 237 | } 238 | }) 239 | 240 | return 241 | } 242 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # edb - An EVM debugger and tool for predicting NFT 2 | 3 | ### Features 4 | 5 | 1. Basic debugger like "gdb", with debugging features such as "breakpoint" and "single step". 6 | 2. Low level instruction tracer, which logs all EVM operations, printing input/output arguments. 7 | 3. High level tracer to make the it more readable. 8 | 9 | ### Screenshot 10 | 11 | ![demo](https://user-images.githubusercontent.com/4710875/174415815-58b66113-57ce-4436-9033-fb8b42b68226.gif) 12 | 13 | Video tutorial: 14 | [1. Basic Usage](https://youtu.be/8kGbPFE2QFM) 15 | [2. Predict NFT](https://youtu.be/Znf5LowqVLs) 16 | 17 | ### How to "Predict NFTs"? 18 | Many NFTs use very simple algorithm to randomize the minting result, or the upgrading. This is a demo NFT that used in above screenshot: 19 | ```solidity 20 | contract NFT { 21 | uint tokenId; 22 | 23 | function mint() external returns(bool) { 24 | tokenId ++; 25 | uint x = uint(keccak256(abi.encodePacked( 26 | block.timestamp, tokenId, msg.sender))) % 100; 27 | if (x > 5) { 28 | return false; // Common class 29 | } else { 30 | return true; // Rare class 31 | } 32 | } 33 | } 34 | ``` 35 | It hashes `sha3(block.timestamp, tokenId, msg.sender)` and then `MOD 100`. If the result is less than 5 then it's a "Rare" one, so a user has 95% chance to mint a "Common" token. 36 | 37 | But this is predictable, because: 38 | 1. The `block.timestamp` increases by 3 every 3 seconds(on BSC). 39 | 2. `tokenId` can be read from Storage. 40 | 3. `msg.sender` is just wallet address. 41 | 42 | Many similar params: `DIFFICULTY`, `NUMBER`, etc. 43 | 44 | **To predict this**: 45 | 1. Generate 1k+ wallets 46 | 2. For each wallet, calculate `sha3(timestamp+6, tokenId, walletAddress) % 100`. Because on BSC, transaction always mined after 2 blocks, which is 6 seconds. Do this on every block. 47 | 3. If wallet N got a "Rare" result, first, send enough Ether(or token) to N for minting(with higher gas fee to make sure it runs before the minting TX), and then send minting TX with N. 48 | 4. You will always get a "Rare" one. 49 | 50 | ### Why they still using simple algorithm? 51 | 52 | Maybe because there is no perfect decompiler. The best one seems to be "panoramix", that used by "etherscan.com", but it still fails on many contracts. 53 | 54 | ### How to trace the algo: 55 | 56 | 1. Download Tx from an **Archive Node**, save it to json file: 57 | 58 | ``` 59 | >>> tx 0x__transaction_hash__ https://archive-node-rpc-url 60 | ``` 61 | If the archive node works, it will generate a "0x__transaction_hash__.json" 62 | 63 | 2. load the json 64 | ``` 65 | >>> load 0x__transaction_hash__.json 66 | ``` 67 | 3. Start low/high tracer 68 | ``` 69 | >>> low 70 | >>> hi 71 | ``` 72 | 4. Run the Tx 73 | ``` 74 | >>> c 75 | ``` 76 | 5. After it finishes executing, **op**timize it to high level code 77 | ``` 78 | >>> op 79 | ``` 80 | 81 | The low level instructions now printed in console and high level code saved to file. For the demo NFT, the result looks like: 82 | ![image](https://user-images.githubusercontent.com/4710875/174275874-dd449046-7823-4686-b5dd-f8d5e5d6c0e2.png) 83 | 84 | From the image, what it does is comparing `SHA3(...) % 100` to 5. 85 | 86 | It's also possible to stepping through the code and break at `SHA3` to check the memory input, but that's inefficient. 87 | 88 | ### About "Archive Node" 89 | 90 | [Described here](https://geth.ethereum.org/docs/dapp/tracing). The **Archive** means it stores all the historical data, all the input/output memory/stack/gas/... for every bytecode execution. The server requires much more resource than a normal **FullNode server**. Some provider enables the *tracing api* for visiting those data, but that is costy. 91 | 92 | Fortunately, some providers like nodereal.io/moralis.io/... provide free Archive Node without *tracing api* enabled, that's what we need for *edb*. Just register to get a free Archive Node for this. 93 | 94 | **Note**: *edb* doesn't work with Normal FullNode, it has to be **Archive Node** 95 | 96 | ### Solution 97 | The `blockhash` is "random" enough, but you can't get it in your code because your code executes before it's generated. Hence some NFT separates the `mint` to two steps `mint` and `open`. 98 | - When `mint`, it saves the current block number N 99 | - When `open`, get `blockhash(N)` and use this along with other params to calculate the `SHA3` 100 | You should limit the block number of `open` to the next 256 block since N, because you will always get 0 as block hash if it exceeds 256 block, which makes it predictable again. So if a user `open` after 256 block, always give him a "Common" class. 101 | 102 | But even so, there're still 256 blocks you can try, means you have 256 chances to `open` a preferrable NFT. In practice, an NFT with 6 level, L1 to L6, we always get L2/L3, L1 is actually pretty "rare", but that's just the case of that particular NFT. 103 | 104 | Maybe limit it to 128 block or less. 105 | 106 | Please fire an issure if any better solution. 107 | 108 | ### Install 109 | Just download the prebuilt executables from release page 110 | 111 | #### Or build it yourself: 112 | 1. Install Golang >= 1.18.1 113 | 2. Clone this repo: `git clone github.com/aj3423/edb` 114 | 3. Go to binary dir: `cd edb/main` 115 | 4. Run it with `go run .` or `go build .` to build. 116 | 117 | ### Command List 118 | 119 | help: Show this help 120 | mem [offset [size]]: Show memory 121 | sto: Show Storage 122 | s: Show Stack items 123 | p [pc]: Show asm at current/target PC 124 | load [.json]: Reload current .json file(default: sample.json) 125 | save [.json]: Save context to current .json file(default: sample.json) 126 | tx : Generate .json file from archive node 127 | low: start low level trace 128 | hi: start high level trace 129 | op: Optimize and print result of high-level-trace 130 | log: Log every executed EVM instruction to file 131 | n: Single step 132 | c: Continue 133 | b l|d|op|pc: Breakpoint list|delete|by opcode|by pc 134 | 135 | 136 | ### Why this? 137 | 138 | This was made to: 139 | 1. Learn EVM. 140 | 2. Learn Symbolic Execution. 141 | 3. Predict NFTs :) 142 | 143 | ### TODO 144 | 1. gas calculation (This is much more complex than I thought, pretty hopeless) 145 | -------------------------------------------------------------------------------- /hooks/symbolic/node_util.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/ethereum/go-ethereum/core/vm" 8 | "github.com/holiman/uint256" 9 | ) 10 | 11 | // ---- Compare ---- 12 | // `Equal` compares 13 | // UnaryOp/BinaryOp/uint256.Int/string/vm.OpCode 14 | func Equal(n1, n2 any) bool { 15 | e1 := reflect.Indirect(reflect.ValueOf(n1)) 16 | e2 := reflect.Indirect(reflect.ValueOf(n2)) 17 | 18 | if e1.Type() != e2.Type() { 19 | return false 20 | } 21 | 22 | switch n1.(type) { 23 | case *UnaryOp: 24 | v1 := n1.(*UnaryOp) 25 | v2 := n2.(*UnaryOp) 26 | return Equal(v1.OpCode, v2.OpCode) && Equal(v1.X, v2.X) 27 | case *BinaryOp: 28 | v1 := n1.(*BinaryOp) 29 | v2 := n2.(*BinaryOp) 30 | return Equal(v1.OpCode, v2.OpCode) && Equal(v1.X, v2.X) && Equal(v1.Y, v2.Y) 31 | case *Const: 32 | v1 := n1.(*Const) 33 | v2 := n2.(*Const) 34 | return Equal(v1.Val, v2.Val) 35 | case *Label: 36 | v1 := n1.(*Label) 37 | v2 := n2.(*Label) 38 | return Equal(v1.Str, v2.Str) 39 | case uint256.Int: 40 | v1 := n1.(uint256.Int) 41 | v2 := n2.(uint256.Int) 42 | return v1.Eq(&v2) 43 | case string: 44 | v1 := n1.(string) 45 | v2 := n2.(string) 46 | return v1 == v2 47 | case vm.OpCode: 48 | v1 := n1.(vm.OpCode) 49 | v2 := n2.(vm.OpCode) 50 | return v1 == v2 51 | } 52 | 53 | return false 54 | } 55 | 56 | // ---- Walk ---- 57 | // code from Go astutil package 58 | type iterator struct { 59 | index, step int 60 | } 61 | 62 | type Cursor struct { 63 | Parent Node 64 | Name string // the name of the parent Node field that contains the current Node. 65 | Iter *iterator // valid if non-nil 66 | Node Node 67 | } 68 | 69 | // Index reports the index >= 0 of the current Node in the slice of Nodes that 70 | // contains it, or a value < 0 if the current Node is not part of a slice. 71 | // The index of the current node changes if InsertBefore is called while 72 | // processing the current node. 73 | func (c *Cursor) Index() int { 74 | if c.Iter != nil { 75 | return c.Iter.index 76 | } 77 | return -1 78 | } 79 | 80 | // field returns the current node's parent field value. 81 | func (c *Cursor) field() reflect.Value { 82 | return reflect.Indirect(reflect.ValueOf(c.Parent)).FieldByName(c.Name) 83 | } 84 | 85 | // Replace replaces the current Node with n. 86 | // The replacement node is not walked by Walk(). 87 | func (c *Cursor) Replace(n Node) { 88 | v := c.field() 89 | if i := c.Index(); i >= 0 { 90 | v = v.Index(i) 91 | } 92 | v.Set(reflect.ValueOf(n)) 93 | } 94 | 95 | // Delete deletes the current Node from its containing slice. 96 | // If the current Node is not part of a slice, Delete panics. 97 | // As a special case, if the current node is a package file, 98 | // Delete removes it from the package's Files map. 99 | func (c *Cursor) Delete() { 100 | i := c.Index() 101 | if i < 0 { 102 | panic("Delete node not contained in slice") 103 | } 104 | v := c.field() 105 | l := v.Len() 106 | reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) 107 | v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) 108 | v.SetLen(l - 1) 109 | c.Iter.step-- 110 | } 111 | 112 | // InsertAfter inserts n after the current Node in its containing slice. 113 | // If the current Node is not part of a slice, InsertAfter panics. 114 | // Walk does not walk n. 115 | func (c *Cursor) InsertAfter(n Node) { 116 | i := c.Index() 117 | if i < 0 { 118 | panic("InsertAfter node not contained in slice") 119 | } 120 | v := c.field() 121 | v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 122 | l := v.Len() 123 | reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) 124 | v.Index(i + 1).Set(reflect.ValueOf(n)) 125 | c.Iter.step++ 126 | } 127 | 128 | // InsertBefore inserts n before the current Node in its containing slice. 129 | // If the current Node is not part of a slice, InsertBefore panics. 130 | // Walk will not walk n. 131 | func (c *Cursor) InsertBefore(n Node) { 132 | i := c.Index() 133 | if i < 0 { 134 | panic("InsertBefore node not contained in slice") 135 | } 136 | v := c.field() 137 | v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 138 | l := v.Len() 139 | reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) 140 | v.Index(i).Set(reflect.ValueOf(n)) 141 | c.Iter.index++ 142 | } 143 | 144 | type WalkFunc func(*Cursor) 145 | 146 | type walker struct { 147 | walkFn WalkFunc 148 | cursor Cursor 149 | iter iterator 150 | } 151 | 152 | func (a *walker) walkList(parent Node, name string) { 153 | // avoid heap-allocating a new iterator for each walkList call; reuse a.iter instead 154 | saved := a.iter 155 | a.iter.index = 0 156 | for { 157 | // must reload parent.name each time, since cursor modifications might change it 158 | v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) 159 | if a.iter.index >= v.Len() { 160 | break 161 | } 162 | 163 | // element x may be nil 164 | var x Node 165 | if e := v.Index(a.iter.index); e.IsValid() { 166 | x = e.Interface().(Node) 167 | } 168 | 169 | a.iter.step = 1 170 | a.walk(parent, name, &a.iter, x) 171 | a.iter.index += a.iter.step 172 | } 173 | a.iter = saved 174 | } 175 | 176 | func (a *walker) walk(parent Node, name string, iter *iterator, n Node) { 177 | 178 | saved := a.cursor 179 | a.cursor.Parent = parent 180 | a.cursor.Name = name 181 | a.cursor.Iter = iter 182 | a.cursor.Node = n 183 | 184 | // walk children 185 | switch n := n.(type) { 186 | case nil, *Label, *MoneyTransfer, *ReturnValue: 187 | // nothing to do 188 | 189 | case *Memory: 190 | a.walk(n, "Offset", nil, n.Offset) 191 | a.walk(n, "Val", nil, n.Val) 192 | case *MemoryWrite: 193 | a.walk(n, "Memory", nil, n.Memory) 194 | case *Storage: 195 | a.walk(n, "Slot", nil, n.Slot) 196 | a.walk(n, "Val", nil, n.Val) 197 | case *StorageWrite: 198 | a.walk(n, "Storage", nil, n.Storage) 199 | case *Const, *NullaryOp: 200 | // do nothing 201 | case *UnaryOp: 202 | a.walk(n, "X", nil, n.X) 203 | case *BinaryOp: 204 | a.walk(n, "X", nil, n.X) 205 | a.walk(n, "Y", nil, n.Y) 206 | case *TernaryOp: 207 | a.walk(n, "X", nil, n.X) 208 | a.walk(n, "Y", nil, n.Y) 209 | a.walk(n, "Z", nil, n.Z) 210 | case *If: 211 | a.walk(n, "Cond", nil, n.Cond) 212 | case *Sha3: 213 | a.walkList(n, "Input") 214 | case *Log: 215 | a.walkList(n, "Topics") 216 | a.walkList(n, "Mem") 217 | case *Sha3Calc: 218 | a.walk(n, "Sha3", nil, n.Sha3) 219 | case *Return: 220 | a.walk(n, "ReturnValue", nil, n.ReturnValue) 221 | a.walk(n, "Memory", nil, n.Memory) 222 | case *Precompiled: 223 | a.walk(n, "Input", nil, n.Input) 224 | case *Block, *Call: 225 | a.walkList(n, "List") 226 | 227 | default: 228 | panic(fmt.Sprintf("Walk: unexpected node type %T", n)) 229 | } 230 | 231 | a.walkFn(&a.cursor) 232 | 233 | a.cursor = saved 234 | } 235 | 236 | func Walk( 237 | root Node, 238 | fn func(*Cursor), 239 | ) Node { 240 | parent := &struct{ Node }{root} 241 | a := &walker{walkFn: fn} 242 | a.walk(parent, "Node", nil, root) 243 | return parent.Node 244 | } 245 | -------------------------------------------------------------------------------- /context.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "math/big" 7 | 8 | "github.com/aj3423/edb/util" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/core/vm" 11 | "github.com/ethereum/go-ethereum/ethclient" 12 | "github.com/holiman/uint256" 13 | ) 14 | 15 | type Msg struct { 16 | Data util.ByteSlice 17 | Gas uint64 // gasleft() 18 | Sender common.Address 19 | Value *big.Int 20 | } 21 | 22 | type Tx struct { 23 | Hash common.Hash // if provided, storage would be auto fetched online when SLOAD 24 | Origin common.Address 25 | GasPrice uint64 26 | } 27 | type Block struct { 28 | Number uint64 // block.number 29 | Timestamp uint64 // block.timestamp 30 | Difficulty uint64 // block.difficulty 31 | Coinbase common.Address // block.coinbase 32 | GasLimit uint64 // block.gaslimit 33 | BaseFee uint64 34 | } 35 | type Chain struct { 36 | Id uint64 37 | NodeUrl string // should be archive node 38 | } 39 | 40 | type Code struct { 41 | Binary util.ByteSlice // 60806040... 42 | Asm *Asm `json:"-"` 43 | } 44 | 45 | func (c *Code) Disasm(code []byte) error { 46 | if c.Asm != nil { // already done disasm 47 | return nil 48 | } 49 | asm := NewAsm() 50 | e := asm.Disasm(code) 51 | if e != nil { 52 | return e 53 | } 54 | c.Asm = asm 55 | return nil 56 | } 57 | 58 | func (c *Code) Set(code []byte) error { 59 | e := c.Disasm(code) 60 | if e != nil { 61 | return e 62 | } 63 | c.Binary = code 64 | return nil 65 | } 66 | 67 | type Contract struct { 68 | Code *Code 69 | Balance *big.Int 70 | Storage map[common.Hash]*uint256.Int 71 | } 72 | 73 | func NewContract() *Contract { 74 | return &Contract{ 75 | Code: &Code{}, 76 | Storage: map[common.Hash]*uint256.Int{}, 77 | } 78 | } 79 | 80 | // call context environment, for both: 81 | // 1. the main contract execution 82 | // 2. any inner CALL/DELEGATECALL 83 | type Call struct { 84 | Msg Msg 85 | 86 | This common.Address // address(this) 87 | 88 | // The `CodePtr` only used for `delegatecall`. 89 | // In most cases, the `CodePtr` is nil and `This` is used for finding the code 90 | // But When A.delegatecall(B), in B, `This` is A and `CodePtr` is B 91 | CodePtr *common.Address 92 | 93 | Memory Memory 94 | Stack Stack[uint256.Int] 95 | 96 | Pc uint64 // program counter 97 | 98 | // For return value of inner calls 99 | // Maybe these values should be defined in Context instead 100 | OuterReturnOffset uint64 101 | OuterReturnSize uint64 102 | InnerReturnVal util.ByteSlice // returned value from inner CALL/DELEGATECALL 103 | } 104 | 105 | // when in delegatecall, `ctx.This` references to the caller 106 | // CodePtr points to the real code 107 | func (c *Call) CodeAddress() common.Address { 108 | if c.CodePtr != nil { // only in delegatecall 109 | return *c.CodePtr 110 | } 111 | return c.This 112 | } 113 | 114 | type Context struct { 115 | IsDone bool 116 | ethClient *ethclient.Client 117 | 118 | Chain Chain 119 | Tx Tx 120 | Block Block 121 | 122 | Contracts map[common.Address]*Contract 123 | 124 | CallStack Stack[*Call] 125 | 126 | Hooks Hooks 127 | 128 | // `map[blockNum]blockHash`, replace with `map[blockNum]Block` if necessary 129 | BlockHashes map[uint64]common.Hash 130 | } 131 | 132 | /* 133 | steps n: 134 | > 0: run n lines 135 | ==0: stop running 136 | < 0: run til death 137 | */ 138 | func (ctx *Context) Run(steps int) error { 139 | // first step always executed, no matter breakpoint or not 140 | is_first_step := true 141 | 142 | for steps != 0 && !ctx.IsDone { 143 | call := ctx.Call() 144 | 145 | line, e := ctx.Line() 146 | if e != nil { 147 | return e 148 | } 149 | opcode := line.Op.OpCode 150 | op := OpTable[opcode] 151 | 152 | // 1. run hooks before executing current line 153 | if e = ctx.Hooks.PreRunAll(call, line); e != nil && !is_first_step { 154 | return e 155 | } 156 | is_first_step = false 157 | 158 | e = op.Exec(ctx) // execute the asm line 159 | if e != nil { 160 | return e 161 | } 162 | 163 | // increase pc by 1 164 | // JUMPs handle pc themselves so ignore them 165 | if opcode != vm.JUMP && opcode != vm.JUMPI { 166 | call.Pc += 1 // +1 for 1-byte-opcode 167 | } 168 | 169 | // 2. run hooks after executing current line 170 | if e := ctx.Hooks.PostRunAll(call, line); e != nil { 171 | return e 172 | } 173 | 174 | steps-- 175 | } 176 | return nil 177 | } 178 | 179 | // get current Call 180 | func (ctx *Context) Call() *Call { 181 | return *ctx.CallStack.Peek() 182 | } 183 | 184 | // get current Code 185 | func (ctx *Context) Code() *Code { 186 | addr := ctx.Call().CodeAddress() 187 | return ctx.Contracts[addr].Code 188 | } 189 | 190 | // get current asm line to execute 191 | func (ctx *Context) Line() (*Line, error) { 192 | return ctx.Code().Asm.LineAtPc(ctx.Pc()) 193 | } 194 | 195 | // get address(this) of current call 196 | func (ctx *Context) This() common.Address { 197 | return ctx.Call().This 198 | } 199 | 200 | // get *Msg of current call 201 | func (ctx *Context) Msg() *Msg { 202 | return &ctx.Call().Msg 203 | } 204 | 205 | // get *Stack of current call 206 | func (ctx *Context) Stack() *Stack[uint256.Int] { 207 | return &ctx.Call().Stack 208 | } 209 | 210 | // get *Memory of current call 211 | func (ctx *Context) Memory() *Memory { 212 | return &ctx.Call().Memory 213 | } 214 | 215 | // get current executing pc 216 | func (ctx *Context) Pc() uint64 { 217 | return ctx.Call().Pc 218 | } 219 | 220 | // get current executing *Contract 221 | func (ctx *Context) Contract() *Contract { 222 | return ctx.Contracts[ctx.This()] 223 | } 224 | 225 | func (ctx *Context) String() string { 226 | bs, _ := json.MarshalIndent(ctx, "", " ") 227 | return string(bs) 228 | } 229 | func (ctx *Context) Save(fn string) error { 230 | return ioutil.WriteFile(fn, []byte(ctx.String()), 0666) 231 | } 232 | func (ctx *Context) Load(fn string) error { 233 | bs, e := ioutil.ReadFile(fn) 234 | if e != nil { 235 | return e 236 | } 237 | e = json.Unmarshal(bs, ctx) 238 | if e != nil { 239 | return e 240 | } 241 | 242 | // asm not saved in .json since it's too large 243 | // so disassemble all contracts after loaded 244 | for _, contract := range ctx.Contracts { 245 | e = contract.Code.Disasm(contract.Code.Binary) 246 | if e != nil { 247 | return e 248 | } 249 | } 250 | 251 | // ethClient 252 | if ctx.Chain.NodeUrl != "" { 253 | ctx.ethClient, e = ethclient.Dial(ctx.Chain.NodeUrl) 254 | if e != nil { 255 | return e 256 | } 257 | } 258 | return nil 259 | } 260 | 261 | func NewContext() *Context { 262 | ctx := &Context{ 263 | BlockHashes: map[uint64]common.Hash{}, 264 | Contracts: map[common.Address]*Contract{}, 265 | } 266 | ctx.CallStack.Push(&Call{Msg: Msg{Value: big.NewInt(0)}}) 267 | return ctx 268 | } 269 | func NewSampleContext() *Context { 270 | ctx := NewContext() 271 | 272 | contract := NewContract() 273 | contract.Code.Set(util.HexDec("608060405234801561001057600080fd5b50600436106100365760003560e01c80633bc5de301461003b5780635b4b73a914610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220e5f07a97a4abeb88a5fcf07910fb20896f7f95326c9a7a8f1f2a2686532f5a3164736f6c634300080d0033")) 274 | contract.Storage[common.HexToHash("0x0")] = uint256.NewInt(0x1) 275 | contract.Storage[common.HexToHash("0xc0fee")] = uint256.NewInt(0xdead) 276 | ctx.Contracts[ctx.This()] = contract 277 | 278 | ctx.Msg().Data = util.HexDec("3bc5de30") // getData() 279 | return ctx 280 | } 281 | -------------------------------------------------------------------------------- /eth_client.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/big" 7 | 8 | "github.com/aj3423/edb/util" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/core/types" 11 | "github.com/ethereum/go-ethereum/ethclient" 12 | "github.com/holiman/uint256" 13 | "github.com/pkg/errors" 14 | ) 15 | 16 | func get_online_block_hash( 17 | client *ethclient.Client, 18 | blockNum uint64, 19 | ) (common.Hash, error) { 20 | var hash common.Hash 21 | 22 | if client == nil { 23 | return hash, fmt.Errorf("no block hash for: %d", blockNum) 24 | } 25 | // color.Blue("get block hash: %d", blockNum) 26 | 27 | block, e := client.BlockByNumber( 28 | context.Background(), 29 | new(big.Int).SetUint64(blockNum), 30 | ) 31 | if e != nil { 32 | return hash, e 33 | } 34 | hash = block.Hash() 35 | // color.Green("value: %s", hash.Hex()) 36 | 37 | return hash, nil 38 | } 39 | func get_online_storage( 40 | client *ethclient.Client, 41 | address common.Address, 42 | slot *uint256.Int, 43 | blockNum uint64, 44 | ) (*uint256.Int, error) { 45 | 46 | if client == nil { 47 | return nil, fmt.Errorf("no storage for: %s", address.String()) 48 | } 49 | // color.Blue("get storage slot: %s, contract: %s", 50 | // slot.String(), address.String()) 51 | 52 | if address == util.ZeroAddress || blockNum == 0 { 53 | return nil, errors.New("invalid AddressThis or Block.Number") 54 | } 55 | 56 | bs, e := client.StorageAt( 57 | context.Background(), 58 | address, 59 | common.BigToHash(slot.ToBig()), 60 | new(big.Int).SetUint64(blockNum), 61 | ) 62 | if e != nil { 63 | return nil, e 64 | } 65 | val := uint256.NewInt(0).SetBytes(bs) 66 | // color.Green("value: %s", val.Hex()) 67 | 68 | return val, nil 69 | } 70 | 71 | func get_online_code( 72 | client *ethclient.Client, 73 | address common.Address, 74 | blockNum uint64, 75 | ) ([]byte, error) { 76 | 77 | if client == nil { 78 | return nil, fmt.Errorf("no code for: %s", address.String()) 79 | } 80 | // color.Blue("get contract code, address: %s, blockNum: %d", 81 | // address.Hex(), blockNum) 82 | if address == util.ZeroAddress || blockNum == 0 { 83 | return nil, errors.New("invalid AddressThis or Block.Number") 84 | } 85 | code, e := client.CodeAt( 86 | context.Background(), address, big.NewInt(int64(blockNum))) 87 | if e != nil { 88 | return nil, e 89 | } 90 | // color.Green("got %d bytes of code", len(code)) 91 | return code, nil 92 | } 93 | func get_online_balance( 94 | client *ethclient.Client, 95 | address common.Address, 96 | blockNum uint64, 97 | ) (*big.Int, error) { 98 | if client == nil { 99 | return nil, fmt.Errorf("no balance for: %s", address.String()) 100 | } 101 | // color.Blue("get balance, address: %s", 102 | // address.Hex()) 103 | if address == util.ZeroAddress || blockNum == 0 { 104 | return nil, errors.New("invalid AddressThis or Block.Number") 105 | } 106 | 107 | bal, e := client.BalanceAt(context.Background(), address, big.NewInt(int64(blockNum))) 108 | if e != nil { 109 | return nil, e 110 | } 111 | 112 | // color.Green("blance: %s", bal.String()) 113 | 114 | return bal, nil 115 | } 116 | 117 | func ContextFromTx( 118 | node_url string, 119 | tx_hash string, 120 | ) (*Context, error) { 121 | 122 | client, e := ethclient.Dial(node_url) 123 | if e != nil { 124 | return nil, e 125 | } 126 | 127 | chain_id, e := client.ChainID(context.Background()) 128 | if e != nil { 129 | return nil, e 130 | } 131 | 132 | tx, _, e := client.TransactionByHash(context.Background(), common.HexToHash(tx_hash)) 133 | if e != nil { 134 | return nil, e 135 | } 136 | receipt, e := client.TransactionReceipt(context.Background(), common.HexToHash(tx_hash)) 137 | if e != nil { 138 | return nil, e 139 | } 140 | msg, e := tx.AsMessage(types.NewLondonSigner(big.NewInt(int64(chain_id.Uint64()))), nil) 141 | if e != nil { 142 | return nil, e 143 | } 144 | blockNum := receipt.BlockNumber 145 | block, e := client.BlockByNumber(context.Background(), blockNum) 146 | if e != nil { 147 | return nil, e 148 | } 149 | 150 | ctx := NewContext() 151 | 152 | ctx.ethClient = client 153 | 154 | ctx.Tx = Tx{ 155 | Hash: tx.Hash(), 156 | Origin: msg.From(), 157 | GasPrice: tx.GasPrice().Uint64(), 158 | } 159 | baseFee := big.NewInt(0) 160 | if block.BaseFee() != nil { 161 | baseFee = block.BaseFee() 162 | } 163 | ctx.Block = Block{ 164 | Number: block.NumberU64(), 165 | Timestamp: block.Time(), 166 | Difficulty: block.Difficulty().Uint64(), 167 | Coinbase: block.Coinbase(), 168 | GasLimit: block.GasLimit(), 169 | BaseFee: baseFee.Uint64(), 170 | } 171 | ctx.BlockHashes[block.NumberU64()] = block.Hash() 172 | 173 | ctx.Chain = Chain{ 174 | Id: chain_id.Uint64(), 175 | NodeUrl: node_url, 176 | } 177 | to := *tx.To() 178 | 179 | ctx.Call().This = to 180 | ctx.Call().Msg = Msg{ 181 | Data: tx.Data(), 182 | Gas: tx.Gas(), 183 | Sender: msg.From(), 184 | Value: msg.Value(), 185 | } 186 | 187 | _, e = ensure_code(ctx, to) 188 | if e != nil { 189 | return nil, e 190 | } 191 | 192 | return ctx, nil 193 | } 194 | 195 | // get *Contract at addr, create if not exists 196 | func ensure_contract_at(ctx *Context, addr common.Address) *Contract { 197 | contract, ok := ctx.Contracts[addr] 198 | if !ok { 199 | contract = NewContract() 200 | ctx.Contracts[addr] = contract 201 | } 202 | return contract 203 | } 204 | 205 | // get from local map first 206 | // fetch online if not exists 207 | func ensure_balance(ctx *Context, address common.Address) (*big.Int, error) { 208 | 209 | contract := ensure_contract_at(ctx, address) 210 | 211 | if contract.Balance != nil { // if code exists in local cache 212 | return contract.Balance, nil 213 | } 214 | 215 | bal, e := get_online_balance(ctx.ethClient, address, ctx.Block.Number-1) // block - 1 216 | if e != nil { 217 | return nil, e 218 | } 219 | 220 | // cache it 221 | contract.Balance = bal 222 | 223 | return bal, nil 224 | } 225 | 226 | // get from local map first 227 | // fetch online if not exists 228 | func ensure_code(ctx *Context, address common.Address) ([]byte, error) { 229 | var binary []byte 230 | 231 | contract := ensure_contract_at(ctx, address) 232 | 233 | if len(contract.Code.Binary) > 0 { // if code exists in local cache 234 | return contract.Code.Binary, nil 235 | } 236 | 237 | var e error 238 | binary, e = get_online_code(ctx.ethClient, address, ctx.Block.Number) 239 | if e != nil { 240 | return nil, e 241 | } 242 | 243 | // cache it 244 | if e := contract.Code.Set(binary); e != nil { 245 | return nil, e 246 | } 247 | 248 | return binary, nil 249 | } 250 | 251 | // get from local map first 252 | // fetch online if not exists 253 | func ensure_storage( 254 | ctx *Context, 255 | address common.Address, 256 | slot *uint256.Int, 257 | ) (*uint256.Int, error) { 258 | 259 | contract := ensure_contract_at(ctx, address) 260 | 261 | slotHash := common.BigToHash(slot.ToBig()) 262 | 263 | val, ok := contract.Storage[slotHash] 264 | if ok { // if code exists in local cache 265 | return val, nil 266 | } 267 | 268 | var e error 269 | // from archive node we only get storage values after the block executed 270 | // so we need to query block-1 to get the storage before executed 271 | val, e = get_online_storage( 272 | ctx.ethClient, address, slot, ctx.Block.Number-1) // block.number-1 273 | if e != nil { 274 | return nil, e 275 | } 276 | 277 | // cache it 278 | contract.Storage[slotHash] = val 279 | 280 | return val, nil 281 | } 282 | 283 | // get from local map first 284 | // fetch online if not exists 285 | func ensure_block_hash( 286 | ctx *Context, 287 | blockNum uint64, 288 | ) (common.Hash, error) { 289 | 290 | hash, ok := ctx.BlockHashes[blockNum] 291 | if ok { // if code exists in local cache 292 | return hash, nil 293 | } 294 | 295 | var e error 296 | hash, e = get_online_block_hash(ctx.ethClient, blockNum) 297 | if e != nil { 298 | return hash, e 299 | } 300 | 301 | // cache it 302 | ctx.BlockHashes[blockNum] = hash 303 | 304 | return hash, nil 305 | } 306 | -------------------------------------------------------------------------------- /hooks/symbolic/node.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "sort" 7 | "strings" 8 | "unicode/utf8" 9 | 10 | "github.com/aj3423/edb" 11 | "github.com/aj3423/edb/util" 12 | "github.com/ethereum/go-ethereum/common" 13 | "github.com/ethereum/go-ethereum/core/vm" 14 | "github.com/holiman/uint256" 15 | ) 16 | 17 | // ---- interfaces ---- 18 | type Node interface { 19 | // for printing node formular 20 | String() string 21 | } 22 | 23 | // node with value 24 | type valueNode interface { 25 | Node 26 | Value() *uint256.Int 27 | } 28 | type opNode interface { // for opcode with operands, eg: BinaryOp 29 | Node 30 | Op() vm.OpCode 31 | } 32 | type pcNode interface { // pc is used to optimize "for loop" 33 | Node 34 | Pc() uint64 35 | } 36 | 37 | // ---- basic types ---- 38 | 39 | // Node that have an output value on stack 40 | type ValueNode struct { 41 | Val uint256.Int 42 | } 43 | 44 | func (n *ValueNode) Value() *uint256.Int { 45 | return &n.Val 46 | } 47 | 48 | type PcNode struct { 49 | Pc uint64 50 | } 51 | 52 | func (n *PcNode) PC() uint64 { 53 | return n.Pc 54 | } 55 | 56 | // Node like `ADD` would use OpCode for printing 57 | type OpNode struct { 58 | OpCode vm.OpCode 59 | } 60 | 61 | func (n *OpNode) Op() vm.OpCode { 62 | return n.OpCode 63 | } 64 | 65 | // ---- concrete nodes ---- 66 | 67 | // for printing simple string like "func_sig" 68 | type Label struct { 69 | Str string 70 | } 71 | 72 | func (n *Label) String() string { 73 | return n.Str 74 | } 75 | 76 | // For PUSHed values 77 | type Const struct { // 0xe0, 0xff00, ... 78 | ValueNode 79 | } 80 | 81 | func NewConst(v *uint256.Int) *Const { 82 | c := &Const{} 83 | c.Val = *v 84 | return c 85 | } 86 | 87 | func (n *Const) String() string { 88 | return n.Val.String() 89 | } 90 | 91 | // These op codes have no input param from stack 92 | // and output 1 value to stack 93 | // eg: vm.ADDRESS, vm.BALANCE 94 | type NullaryOp struct { 95 | OpNode 96 | ValueNode 97 | } 98 | 99 | func (n *NullaryOp) String() string { 100 | return PrettifyOp(n.OpCode) 101 | } 102 | 103 | // op with 1 input and 1 output on stack 104 | type UnaryOp struct { 105 | OpNode 106 | X Node 107 | ValueNode 108 | } 109 | 110 | func (n *UnaryOp) String() string { 111 | return fmt.Sprintf("%s(%s)", 112 | PrettifyOp(n.OpCode), n.X.String()) 113 | } 114 | 115 | // op with 2 input and 1 output on stack 116 | type BinaryOp struct { 117 | OpNode 118 | X Node 119 | Y Node // Y is first operand, eg: Y-X 120 | ValueNode 121 | } 122 | 123 | func (n *BinaryOp) String() string { 124 | return fmt.Sprintf("(%s %s %s)", 125 | n.X.String(), PrettifyOp(n.OpCode), n.Y.String()) 126 | } 127 | 128 | // op with 3 input and 1 output on stack 129 | type TernaryOp struct { 130 | OpNode 131 | 132 | X Node 133 | Y Node 134 | Z Node 135 | ValueNode 136 | } 137 | 138 | func (n *TernaryOp) String() string { 139 | return fmt.Sprintf("%s(%s, %s, %s)", 140 | PrettifyOp(n.OpCode), n.X.String(), n.Y.String(), n.Z.String()) 141 | } 142 | 143 | // `If` is simply `JUMPI` 144 | type If struct { 145 | PcNode 146 | Cond Node 147 | Taken bool 148 | } 149 | 150 | func (n *If) String() string { 151 | if n.Taken { 152 | return "if " + n.Cond.String() + " " 153 | } else { 154 | return "if " + n.Cond.String() + " " 155 | } 156 | } 157 | 158 | // A block of lines, currently only used for `Call`, 159 | // will be used for "for loop"(TODO) 160 | type Block struct { 161 | List []Node 162 | } 163 | 164 | func (b *Block) String() string { 165 | sb := strings.Builder{} 166 | sb.WriteString("{\n") 167 | for _, n := range b.List { 168 | sb.WriteString("\t" + n.String() + "\n") 169 | } 170 | sb.WriteString("}\n") 171 | return sb.String() 172 | } 173 | 174 | // A CALL/DELEGATECALL/STATICCALL 175 | type Call struct { 176 | OpNode 177 | *Block 178 | Stack edb.Stack[Node] // symbolic stack 179 | 180 | // keep track of all *Memory/*Storage 181 | MemMap map[uint64]*Memory // no need to iterate through when `Apply` 182 | StorageMap map[uint256.Int]*Storage // no need to iterate through when `Apply` 183 | 184 | // for printing target/func_sig 185 | Target *common.Address 186 | Input []byte 187 | } 188 | 189 | func NewCall( 190 | op vm.OpCode, 191 | target *common.Address, 192 | input []byte, 193 | ) *Call { 194 | return &Call{ 195 | Target: target, 196 | Input: util.CloneSlice(input), 197 | Block: &Block{}, 198 | OpNode: OpNode{op}, 199 | MemMap: make(map[uint64]*Memory), 200 | StorageMap: make(map[uint256.Int]*Storage), 201 | } 202 | } 203 | 204 | // Logs a line, these lines will be optimized and printed 205 | func (c *Call) AddTrace(n Node) { 206 | c.List = append(c.List, n) 207 | } 208 | func (c *Call) String() string { 209 | return "use `printer` to print *Call" 210 | } 211 | 212 | // TODO decode func name using 4bytes database: 213 | // https://github.com/ethereum-lists/4bytes 214 | func (c *Call) FuncSig() string { 215 | if len(c.Input) >= 4 { 216 | return fmt.Sprintf("%x", c.Input[0:4]) 217 | } 218 | return "" 219 | } 220 | 221 | type Precompiled struct { 222 | To common.Address 223 | Input *Memory 224 | } 225 | 226 | func (n *Precompiled) String() string { 227 | return fmt.Sprintf( 228 | "Call Precompiled %s, input: [\n%s]", 229 | n.To.String(), 230 | // The hex dump here is more readable than symbolic value 231 | hex.Dump(n.Input.VmBytes), 232 | ) 233 | } 234 | 235 | type MoneyTransfer struct { 236 | To common.Address 237 | Amount uint256.Int 238 | } 239 | 240 | func (n *MoneyTransfer) String() string { 241 | return fmt.Sprintf( 242 | "Transfer %s(%s) -> %s\n", 243 | n.Amount.ToBig().String(), // dec format 244 | n.Amount.String(), // hex format 245 | n.To.String(), 246 | ) 247 | } 248 | 249 | type ReturnValue struct{} 250 | 251 | func (n *ReturnValue) String() string { 252 | return fmt.Sprintf("ReturnVal_%p", n) 253 | } 254 | 255 | type Return struct { 256 | *ReturnValue 257 | *Memory 258 | } 259 | 260 | func (n *Return) String() string { 261 | return fmt.Sprintf("%s: [\n%s]", 262 | n.ReturnValue.String(), 263 | hex.Dump(n.VmBytes), 264 | ) 265 | } 266 | 267 | // Represents a Storage read(SLOAD) 268 | type Storage struct { 269 | Slot Node 270 | Val Node // result of get, or value to set 271 | } 272 | 273 | func (s *Storage) String() string { 274 | return fmt.Sprintf("Storage[%s]", s.Slot.String()) 275 | } 276 | 277 | // Normally it represents a Storage write access(SSTORE) 278 | // But it's also considered as write access 279 | // for SLOAD when value not found locally and fetched from remote server, 280 | type StorageWrite struct { 281 | IsGetOnline bool 282 | *Storage 283 | } 284 | 285 | func (n *StorageWrite) String() string { 286 | if n.IsGetOnline { 287 | return fmt.Sprintf("%s = online %s", n.Val.String(), n.Storage.String()) 288 | } else { 289 | s := fmt.Sprintf("%s = %s", n.Storage.String(), n.Val.String()) 290 | // if it can be evaluated, also show the value number 291 | if eval, ok := EvaluateConst(n.Val); ok { 292 | if eval.String() != n.Val.String() { // don't show if they are same 293 | s += fmt.Sprintf(" (%s)", eval.String()) 294 | } 295 | } 296 | return s 297 | } 298 | } 299 | 300 | type Log struct { 301 | Topics []Node 302 | Mem []*Memory 303 | } 304 | 305 | func (n *Log) String() string { 306 | sb := &strings.Builder{} 307 | 308 | arr := []string{} 309 | for _, top := range n.Topics { 310 | arr = append(arr, top.String()) 311 | } 312 | fmt.Fprintf(sb, "Log (%s)\n", strings.Join(arr, ", ")) 313 | // Ascending sort "Input" by offset 314 | // so it can be printed in order 315 | sort.Slice(n.Mem, func(i, j int) bool { 316 | return n.Mem[i].VmOffset < n.Mem[j].VmOffset 317 | }) 318 | 319 | sb.WriteString("Memory: [\n") 320 | for _, mem := range n.Mem { 321 | sb.WriteString(mem.Val.String() + ":\n") 322 | sb.WriteString(util.HexDumpEx( 323 | mem.VmBytes, uint(mem.VmOffset))) 324 | } 325 | sb.WriteString("]\n") 326 | 327 | return sb.String() 328 | } 329 | 330 | // A block of memory, not the whole memory 331 | type Memory struct { 332 | Offset Node // the symbolic offset of total memory 333 | Val Node 334 | VmOffset uint64 // the offset of total memory 335 | VmBytes []byte 336 | } 337 | 338 | func (n *Memory) String() string { 339 | return fmt.Sprintf("Memory[%s]", n.Offset.String()) 340 | } 341 | 342 | // for op codes that writes memory, eg: MSTORE, RETURN, ... 343 | type MemoryWrite struct { 344 | *Memory 345 | // show memory dump or not, useful for ReturnVal 346 | dump bool 347 | } 348 | 349 | func (n *MemoryWrite) String() string { 350 | s := fmt.Sprintf("Memory[%s] = %s", 351 | n.Offset.String(), n.Val.String()) 352 | 353 | // Sometimes the value is string like: "SafeMath: subtraction overflow" 354 | // show it as string. 355 | if hs, e := uint256.FromHex(n.Val.String()); e == nil { 356 | if utf8.Valid(hs.Bytes()) { // is utf8 string 357 | s += ` ("` + string(hs.Bytes()) + `")` 358 | } 359 | } 360 | if n.dump { 361 | s += "\n" 362 | s += hex.Dump(n.VmBytes) 363 | } 364 | return s 365 | } 366 | 367 | // Conatains all input/output of an SHA3 operation 368 | type Sha3 struct { 369 | Input []*Memory 370 | 371 | Offset, Size uint64 // raw memory offset/size 372 | 373 | ValueNode 374 | } 375 | 376 | func (n *Sha3) String() string { 377 | // Show as variable like "sha3_0x11223344" 378 | // use pointer address as variable name 379 | return fmt.Sprintf("Sha3_%p", n) 380 | } 381 | 382 | // For printing `SHA3` calculation in detail 383 | type Sha3Calc struct { 384 | *Sha3 385 | } 386 | 387 | func (n *Sha3Calc) String() string { 388 | // Ascending sort "Input" by memory offset 389 | // so it can be printed in order 390 | sort.Slice(n.Input, func(i, j int) bool { 391 | return n.Input[i].VmOffset < n.Input[j].VmOffset 392 | }) 393 | 394 | sb := &strings.Builder{} 395 | sb.WriteString("\n") 396 | sb.WriteString(n.Sha3.String() + " = [") 397 | sb.WriteString("\n") 398 | 399 | // build the input memory regions 400 | for _, mem := range n.Input { 401 | sb.WriteString(mem.Val.String() + ":\n") 402 | sb.WriteString(util.HexDumpEx( 403 | mem.VmBytes, uint(mem.VmOffset))) 404 | } 405 | 406 | sb.WriteString("] -> " + n.Value().String()) 407 | sb.WriteString("\n") 408 | return sb.String() 409 | } 410 | -------------------------------------------------------------------------------- /main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | "strings" 10 | 11 | "github.com/aj3423/edb" 12 | "github.com/aj3423/edb/hooks" 13 | "github.com/aj3423/edb/hooks/symbolic" 14 | "github.com/aj3423/edb/util" 15 | "github.com/c-bata/go-prompt" 16 | "github.com/ethereum/go-ethereum/common" 17 | "github.com/ethereum/go-ethereum/core/vm" 18 | "github.com/fatih/color" 19 | ) 20 | 21 | // global value 22 | var G = struct { 23 | JsonFile string 24 | ctx *edb.Context 25 | HiTracer *symbolic.HighLevelTracer 26 | }{ 27 | JsonFile: "sample.json", 28 | } 29 | 30 | var suggestions = []prompt.Suggest{ 31 | {Text: "help", Description: "Show all commands"}, 32 | {Text: "mem [offset [size]]", Description: "Show memory"}, 33 | {Text: "sto", Description: "Show Storage"}, 34 | {Text: "s", Description: "Show Stack items"}, 35 | {Text: "p [pc]", Description: "Show asm at current/target PC"}, 36 | {Text: "load [.json]", Description: "Reload current .json file(default: sample.json)"}, 37 | {Text: "save [.json]", Description: "Save context to current .json file(default: sample.json)"}, 38 | {Text: "tx ", Description: "Generate .json file from archive node"}, 39 | {Text: "low", Description: "start low level trace"}, 40 | {Text: "hi", Description: "start high level trace"}, 41 | {Text: "op", Description: "Optimize and print result of high-level-trace"}, 42 | {Text: "log", Description: "Log every executed EVM instruction to file"}, 43 | {Text: "n", Description: "Single step"}, 44 | {Text: "c", Description: "Continue"}, 45 | {Text: "b", Description: "Breakpoint"}, 46 | } 47 | 48 | func completer(in prompt.Document) []prompt.Suggest { 49 | if in.Text == "" { 50 | return nil 51 | } 52 | args := strings.Split(in.Text, " ") 53 | if len(args) == 1 { 54 | return prompt.FilterHasPrefix( 55 | suggestions, in.GetWordBeforeCursor(), true) 56 | } else { 57 | return nil 58 | } 59 | } 60 | 61 | func show_disasm(pc uint64) { 62 | 63 | addr := G.ctx.Call().CodeAddress() 64 | fmt.Println("---- " + addr.String()) 65 | 66 | asm := G.ctx.Code().Asm 67 | 68 | line, e := asm.LineAtPc(pc) 69 | if e != nil { 70 | color.Red(e.Error()) 71 | return 72 | } 73 | lineNum := line.LineNum 74 | 75 | beg := util.Max(int(lineNum)-4, 0) // show 4 lines above pc 76 | end := util.Min(int(lineNum)+4, asm.LineCount()) // show 4 lines below pc 77 | 78 | for row := beg; row < end; row++ { 79 | line := asm.AtRow(row) 80 | if line.Pc == pc { 81 | color.Blue(line.String()) 82 | } else { 83 | fmt.Println(line) 84 | } 85 | } 86 | } 87 | 88 | func executor(in string) { 89 | in = strings.TrimSpace(in) 90 | 91 | if in == "" { 92 | in = "n" // press enter -> single step 93 | } 94 | 95 | arg := strings.Split(in, " ") 96 | argc := len(arg) 97 | 98 | cmd := arg[0] 99 | 100 | if G.ctx == nil && 101 | (cmd != "load" && cmd != "tx" && cmd != "help") { 102 | 103 | color.Red("'load' first") 104 | return 105 | } 106 | 107 | switch cmd { 108 | case "help": 109 | for _, s := range suggestions { 110 | color.HiBlue("%s \t %s", s.Text, color.WhiteString(s.Description)) 111 | } 112 | return 113 | 114 | case "ctx", "context": 115 | fmt.Println(to_pretty_json(G.ctx)) 116 | return 117 | 118 | case "m", "mem", "memory": 119 | switch argc { 120 | case 1: 121 | fmt.Println(hex.Dump(G.ctx.Memory().Data())) 122 | return 123 | case 3: 124 | offset, e2 := parse_any_int(arg[1]) 125 | len_, e3 := parse_any_int(arg[2]) 126 | 127 | if e2 != nil || e3 != nil { 128 | color.Red("wrong format, usage: memory ") 129 | return 130 | } 131 | 132 | mem := G.ctx.Memory().Data() 133 | 134 | if offset+len_ > uint64(len(mem)) { 135 | color.Red("invalid memory region, %d > %d", offset+len_, len(mem)) 136 | return 137 | } 138 | 139 | chunk := mem[offset : offset+len_] 140 | fmt.Println(hex.Dump(chunk)) 141 | return 142 | } 143 | 144 | case "storage": 145 | fmt.Println(to_pretty_json(G.ctx.Contract().Storage)) 146 | return 147 | case "s", "stack": 148 | fmt.Println(to_pretty_json(G.ctx.Stack())) 149 | return 150 | 151 | case "p", "print": // show disasm 152 | var pc = G.ctx.Pc() 153 | 154 | if argc == 2 { // show disasm at target pc 155 | pc_, e := parse_any_int(arg[1]) 156 | if e != nil { 157 | color.Red(e.Error()) 158 | return 159 | } 160 | pc = uint64(pc_) 161 | } 162 | 163 | show_disasm(pc) 164 | return 165 | 166 | case "save": 167 | var fn = G.JsonFile 168 | if argc == 2 { 169 | fn = arg[1] 170 | } 171 | if e := G.ctx.Save(fn); e != nil { 172 | color.Red("fail save json: " + e.Error()) 173 | return 174 | } 175 | color.Green("saved to '%s' ", fn) 176 | return 177 | case "load", "reload": 178 | if argc > 1 { 179 | G.JsonFile = arg[1] 180 | } 181 | 182 | ctx := &edb.Context{} 183 | if e := ctx.Load(G.JsonFile); e != nil { 184 | color.Red(e.Error()) 185 | return 186 | } 187 | color.Green("loaded: %s", G.JsonFile) 188 | G.ctx = ctx 189 | 190 | show_disasm(G.ctx.Pc()) 191 | 192 | return 193 | 194 | case "tx": 195 | var node_url string 196 | var tx_hash string 197 | 198 | _, e := fmt.Sscanf(in, 199 | "tx %s %s", 200 | &tx_hash, &node_url) 201 | 202 | if e != nil { 203 | color.Red("usage: tx ") 204 | return 205 | } 206 | 207 | ctx, e := edb.ContextFromTx(node_url, tx_hash) 208 | if e != nil { 209 | color.Red("fail: " + e.Error()) 210 | return 211 | } 212 | fn := tx_hash + ".json" 213 | e = ctx.Save(fn) 214 | if e != nil { 215 | color.Red("fail save json: " + e.Error()) 216 | return 217 | } 218 | G.ctx = ctx 219 | color.Green("saved to '%s' ", fn) 220 | return 221 | 222 | case "low", "lowleveltrace": // trace input/output data for all algorithms 223 | G.ctx.Hooks.Attach(hooks.NewLowLevelTracer()) 224 | color.Yellow("tracing low-level operations") 225 | return 226 | case "hi", "high", "highleveltrace": 227 | if G.HiTracer != nil { 228 | color.Yellow("already tracing high-level operations") 229 | return 230 | } 231 | G.HiTracer = symbolic.NewHighLevelTracer(G.ctx) 232 | G.ctx.Hooks.Attach(G.HiTracer) 233 | color.Yellow("tracing high-level operations") 234 | return 235 | case "hic", "high-level-callstack": // for debugging only 236 | fmt.Println(*G.HiTracer.CallStack.Peek()) 237 | return 238 | case "his", "high-level-stack": // for debugging only 239 | for _, s := range (*G.HiTracer.CallStack.Peek()).Stack.Data { 240 | fmt.Println(s) 241 | } 242 | return 243 | case "op", "optimize": // show optimized result of high-level-tracer 244 | if G.HiTracer == nil { 245 | color.Red("no HighLevelTracer, restart with command 'hi' to enable high level ") 246 | return 247 | } 248 | rootCall := G.HiTracer.CallStack.Data[0] 249 | symbolic.Optimize(rootCall, symbolic.DefaultOptimizers) 250 | 251 | // print result 252 | x := symbolic.PrintNode(rootCall) 253 | fmt.Println(x) 254 | fn := strings.ReplaceAll(G.JsonFile, ".json", "") + ".high" 255 | util.FileWriteStr(fn, x) 256 | color.Yellow("Written to file '%s'", fn) 257 | return 258 | 259 | case "log", "evm_log": 260 | fn := strings.Replace(G.JsonFile, ".json", ".log", 1) 261 | 262 | fd, e := os.OpenFile( 263 | fn, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) 264 | if e != nil { 265 | color.Red(e.Error()) 266 | return 267 | } 268 | G.ctx.Hooks.Attach(&hooks.EvmLog{Fd: fd}) 269 | color.Yellow("logging to '%s'", fn) 270 | return 271 | 272 | case "n", "next": 273 | e := G.ctx.Run(1) 274 | if e != nil { 275 | color.Red(e.Error()) 276 | } 277 | show_disasm(G.ctx.Pc()) 278 | return 279 | 280 | case "c", "continue", "r", "run": 281 | e := G.ctx.Run(-1) 282 | if e != nil { 283 | if errors.Is(e, hooks.ErrBreakpoint) { 284 | color.Yellow("interrupted: %s", e.Error()) 285 | } else { 286 | color.Red(e.Error()) 287 | } 288 | } else { 289 | color.Green("\nall done.\n\n") 290 | } 291 | show_disasm(G.ctx.Pc()) 292 | return 293 | 294 | case "b", "bp", "breakpoint": 295 | if argc == 2 { 296 | if arg[1] == "l" { // list all breakpoints/tracers 297 | for i, cp := range G.ctx.Hooks.List() { 298 | fmt.Printf("%d: %v\n", i, cp) 299 | } 300 | return 301 | } 302 | } 303 | if argc == 3 { 304 | if arg[1] == "d" { // del n'th 305 | if i, e := strconv.Atoi(arg[2]); e == nil { 306 | G.ctx.Hooks.Detach(i) 307 | return 308 | } 309 | } 310 | } 311 | 312 | if argc >= 3 { // eg: b op SHA3 0x1122334455... 313 | var contract *common.Address = nil 314 | if argc == 4 { 315 | x := common.HexToAddress(arg[3]) 316 | contract = &x 317 | } 318 | 319 | switch arg[1] { 320 | case "op": // break by op code 321 | 322 | opStr := strings.ToUpper(arg[2]) 323 | op := vm.StringToOp(opStr) 324 | 325 | // the above StringToOp returns STOP for any invalid input 326 | if op == vm.STOP && opStr != "STOP" { 327 | color.Red("wrong op string") 328 | return 329 | } 330 | bp := &hooks.BpOpCode{ 331 | Contract: contract, 332 | OpCode: op, 333 | } 334 | G.ctx.Hooks.Attach(bp) 335 | color.Yellow("bp added: %v", bp) 336 | return 337 | 338 | case "pc": // break by pc 339 | pc, e := parse_any_int(arg[2]) 340 | if e != nil { 341 | color.Red("wrong pc format") 342 | return 343 | } 344 | bp := &hooks.BpPc{ 345 | Contract: contract, 346 | Pc: uint64(pc), 347 | } 348 | G.ctx.Hooks.Attach(bp) 349 | color.Yellow("bp added: %v", bp) 350 | return 351 | } 352 | } 353 | } 354 | color.Red("unknown command") 355 | } 356 | 357 | func main() { 358 | if !util.FileExist(G.JsonFile) { 359 | edb.NewSampleContext().Save(G.JsonFile) 360 | fmt.Printf( 361 | "A sample config '%s' generated, load it with '%s'\n", 362 | color.MagentaString(G.JsonFile), color.CyanString("load")) 363 | } 364 | 365 | p := prompt.New( 366 | executor, 367 | completer, 368 | prompt.OptionPrefix(">>> "), 369 | ) 370 | p.Run() 371 | } 372 | 373 | func main2() { // only for quick testing 374 | G.JsonFile = "1.json" 375 | 376 | var e error 377 | G.ctx = &edb.Context{} 378 | if e = G.ctx.Load(G.JsonFile); e != nil { 379 | color.Red(e.Error()) 380 | return 381 | } 382 | color.Green("loaded: %s", G.JsonFile) 383 | 384 | { 385 | G.ctx.Hooks.Attach(&hooks.BpPc{Pc: 11257}) 386 | color.Yellow("tracing low-level operations") 387 | } 388 | 389 | e = G.ctx.Run(-1) 390 | if e != nil { 391 | if errors.Is(e, hooks.ErrBreakpoint) { 392 | color.Yellow("interrupted: %s", e.Error()) 393 | } else { 394 | color.Red(e.Error()) 395 | } 396 | } else { 397 | color.Green("\nall done.\n\n") 398 | } 399 | G.ctx.Run(-1) 400 | // show_disasm(G.ctx.Pc()) 401 | 402 | } 403 | -------------------------------------------------------------------------------- /hooks/symbolic/high_level_tracer.go: -------------------------------------------------------------------------------- 1 | package symbolic 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aj3423/edb" 7 | "github.com/aj3423/edb/hooks" 8 | "github.com/aj3423/edb/util" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/core/vm" 11 | "github.com/holiman/uint256" 12 | "github.com/pkg/errors" 13 | ) 14 | 15 | var TODO = errors.New("HighLevelTracer TODO") 16 | 17 | func init() { 18 | edb.Register((*HighLevelTracer)(nil)) 19 | } 20 | 21 | type HighLevelTracer struct { 22 | *hooks.ParamTracer 23 | 24 | ctx *edb.Context 25 | CallStack edb.Stack[*Call] 26 | } 27 | 28 | func NewHighLevelTracer(ctx *edb.Context) *HighLevelTracer { 29 | t := &HighLevelTracer{ 30 | ctx: ctx, 31 | ParamTracer: &hooks.ParamTracer{}, 32 | } 33 | vmCall := ctx.Call() 34 | t.CallStack.Push( 35 | NewCall(vm.CALL, &vmCall.This, vmCall.Msg.Data)) 36 | return t 37 | } 38 | 39 | // Record every asm param to its symbolic form 40 | // Here just record, no optimize, optimization will be done later 41 | func (t *HighLevelTracer) PostRun(vmCall *edb.Call, line *edb.Line) error { 42 | t.ParamTracer.PostRun(vmCall, line) 43 | 44 | call := *t.CallStack.Peek() 45 | stack := &call.Stack 46 | 47 | defer func() { // for debugging only 48 | if vmCall.Stack.Len() != stack.Len() { 49 | panic(fmt.Sprintf( 50 | "HiLevelTracer: symbolic stack is different from vmStack @pc: %d", 51 | t.PcPre)) 52 | } 53 | }() 54 | 55 | opcode := line.Op.OpCode 56 | 57 | switch opcode { 58 | 59 | // Nullary operations, no stack input, 1 output 60 | case vm.ADDRESS, vm.BALANCE, vm.ORIGIN, vm.CALLER, vm.CALLVALUE, vm.CALLDATASIZE, vm.CODESIZE, vm.GASPRICE, vm.COINBASE, vm.TIMESTAMP, vm.NUMBER, vm.DIFFICULTY, vm.GASLIMIT, vm.CHAINID, vm.SELFBALANCE, vm.BASEFEE, vm.GAS, vm.PC, vm.MSIZE: 61 | 62 | n := &NullaryOp{} 63 | n.OpCode = opcode 64 | n.Val = t.StackPost.Pop() 65 | 66 | stack.Push(n) 67 | return nil 68 | 69 | // unary operation, 1 stack input, 1 output 70 | case vm.ISZERO, vm.NOT, vm.CALLDATALOAD, vm.EXTCODESIZE, vm.EXTCODEHASH, vm.BLOCKHASH: 71 | 72 | sym := stack.Pop() 73 | 74 | n := &UnaryOp{X: sym} 75 | n.OpCode = opcode 76 | n.Val = t.StackPost.Pop() 77 | 78 | stack.Push(n) 79 | return nil 80 | 81 | // binary operation, 2 stack input, 1 output 82 | case vm.ADD, vm.MUL, vm.SUB, vm.DIV, vm.SDIV, vm.MOD, vm.SMOD, vm.EXP, vm.SIGNEXTEND, vm.LT, vm.GT, vm.SLT, vm.SGT, vm.EQ, vm.AND, vm.OR, vm.XOR, vm.SHL, vm.SHR, vm.SAR, vm.BYTE: 83 | // sub: x-y, shl: y<= vmOffset && ofst < (vmOffset+vmSize) { 137 | sha3.Input = append(sha3.Input, mem) 138 | } 139 | } 140 | 141 | stack.Push(sha3) 142 | call.AddTrace(&Sha3Calc{ 143 | Sha3: sha3, 144 | }) 145 | 146 | return nil 147 | case vm.MLOAD: 148 | _ = stack.Pop() 149 | 150 | offset := t.StackPre.Peek().Uint64() 151 | mem, ok := call.MemMap[offset] 152 | if !ok { 153 | // Op code "RETURN" copies a large chunk of memory 154 | // Maybe this `offset` is not the begining of it, but inside the region 155 | // So find which block contains this offset 156 | for _, m := range call.MemMap { 157 | if offset >= m.VmOffset && (offset-m.VmOffset+32 <= uint64(len(m.VmBytes))) { 158 | // Build a new *Memory, increase the "offset" 159 | // eg: for offset==0x10 160 | // old: Memory[0x20] 161 | // new: Memory[0x20 + 0x10] 162 | mem = &Memory{ 163 | Offset: &BinaryOp{ // old offset + new offet 164 | OpNode: OpNode{vm.ADD}, 165 | X: m.Offset, 166 | Y: NewConst(uint256.NewInt(offset - m.VmOffset)), 167 | }, 168 | Val: m.Val, 169 | VmOffset: offset, 170 | VmBytes: m.VmBytes[offset-m.VmOffset:], 171 | } 172 | call.MemMap[offset] = mem 173 | } 174 | } 175 | } 176 | // if still not found, create a new *Memory 177 | if mem == nil { 178 | mem = &Memory{ 179 | Offset: NewConst(uint256.NewInt(offset)), 180 | Val: &Label{"Unknown_Memory"}, 181 | VmOffset: offset, 182 | } 183 | if offset < uint64(len(t.MemPre)) { 184 | mem.VmBytes = t.MemPre[offset : offset+32] 185 | } 186 | } 187 | 188 | stack.Push(mem) 189 | 190 | return nil 191 | case vm.MSTORE, vm.MSTORE8: 192 | offset, val := stack.Pop(), stack.Pop() 193 | vmOffset := t.StackPre.Peek().Uint64() 194 | vmSize := 32 195 | if opcode == vm.MSTORE8 { 196 | vmSize = 1 197 | } 198 | 199 | mem := &Memory{ 200 | Offset: offset, 201 | Val: val, 202 | VmOffset: vmOffset, 203 | VmBytes: vmCall.Memory.GetCopy( 204 | int64(vmOffset), 205 | int64(vmSize), 206 | ), 207 | } 208 | call.MemMap[vmOffset] = mem 209 | call.AddTrace(&MemoryWrite{ 210 | Memory: mem, 211 | }) 212 | return nil 213 | 214 | case vm.SLOAD: 215 | slot := stack.Pop() 216 | 217 | vmSlot := t.StackPre.Pop() 218 | 219 | sto, ok := call.StorageMap[vmSlot] 220 | if ok { 221 | stack.Push(sto) 222 | } else { 223 | // If it not exists in cache, 224 | // then the value is got from online server 225 | // so it's actually a StorageWrite 226 | sto := &Storage{ 227 | Slot: slot, 228 | Val: NewConst(t.StackPost.Peek()), 229 | } 230 | call.StorageMap[vmSlot] = sto 231 | stack.Push(sto) 232 | call.AddTrace(&StorageWrite{ 233 | IsGetOnline: true, 234 | Storage: sto, 235 | }) 236 | } 237 | 238 | return nil 239 | case vm.SSTORE: 240 | slot, val := stack.Pop(), stack.Pop() 241 | vmSlot := t.StackPre.Pop() 242 | 243 | sto := &Storage{Slot: slot, Val: val} 244 | 245 | call.StorageMap[vmSlot] = sto 246 | call.AddTrace(&StorageWrite{ 247 | Storage: sto, 248 | }) 249 | return nil 250 | 251 | case vm.JUMP: 252 | stack.Pop() 253 | return nil 254 | case vm.JUMPI: 255 | _, cond := stack.Pop(), stack.Pop() 256 | vmCond := t.StackPre.PeekI(1) 257 | 258 | n := &If{Cond: cond, Taken: !vmCond.IsZero()} 259 | call.AddTrace(n) 260 | return nil 261 | 262 | case vm.JUMPDEST: 263 | return nil 264 | 265 | case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32: 266 | n := &Const{} 267 | n.Val = t.StackPost.Pop() 268 | stack.Push(n) 269 | return nil 270 | 271 | case vm.DUP1, vm.DUP2, vm.DUP3, vm.DUP4, vm.DUP5, vm.DUP6, vm.DUP7, vm.DUP8, vm.DUP9, vm.DUP10, vm.DUP11, vm.DUP12, vm.DUP13, vm.DUP14, vm.DUP15, vm.DUP16: 272 | size := line.Op.OpCode - vm.DUP1 + 1 273 | stack.Dup(int(size)) 274 | return nil 275 | case vm.SWAP1, vm.SWAP2, vm.SWAP3, vm.SWAP4, vm.SWAP5, vm.SWAP6, vm.SWAP7, vm.SWAP8, vm.SWAP9, vm.SWAP10, vm.SWAP11, vm.SWAP12, vm.SWAP13, vm.SWAP14, vm.SWAP15, vm.SWAP16: 276 | size := opcode - vm.SWAP1 + 1 277 | size++ 278 | stack.Swap(int(size)) 279 | return nil 280 | 281 | case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: 282 | vmStart, vmSize := t.StackPre.PeekI(0).Uint64(), t.StackPre.PeekI(1).Uint64() 283 | _, _ = stack.Pop(), stack.Pop() 284 | topicCount := opcode - vm.LOG0 285 | 286 | n := &Log{} 287 | for i := 0; i < int(topicCount); i++ { 288 | n.Topics = append(n.Topics, stack.Pop()) 289 | } 290 | // all MemoryWrite inside [vmStart: vmStart+vmSize] 291 | for ofst, mem := range call.MemMap { 292 | if ofst >= vmStart && ofst <= (vmStart+vmSize) { 293 | n.Mem = append(n.Mem, mem) 294 | } 295 | } 296 | call.AddTrace(n) 297 | return nil 298 | 299 | case vm.CALL, vm.DELEGATECALL, vm.STATICCALL: 300 | _, _, _, _, _, _ = stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() 301 | 302 | newVmCall := t.ctx.Call() 303 | 304 | addr := common.Address(t.StackPre.PeekI(1).Bytes20()) 305 | if opcode == vm.CALL { 306 | stack.Pop() // one more param for CALL 307 | 308 | // check if it's transfer by checking "inSize == 0" 309 | if inSize := t.StackPre.PeekI(4); inSize.IsZero() { // 310 | call.AddTrace(&MoneyTransfer{ 311 | To: addr, 312 | Amount: *t.StackPre.PeekI(2), 313 | }) 314 | // just assume it succeeded 315 | stack.Push(NewConst(uint256.NewInt(1))) 316 | return nil 317 | } 318 | } 319 | 320 | // check if it's precompiled 321 | if _, ok := vm.PrecompiledContractsBerlin[addr]; ok { 322 | 323 | inOffset := t.StackPre.PeekI(2).Uint64() 324 | inMem := call.MemMap[inOffset] 325 | call.AddTrace(&Precompiled{To: addr, Input: inMem}) 326 | 327 | retOffset, retSize := t.StackPre.PeekI(4).Uint64(), t.StackPre.PeekI(5).Uint64() 328 | 329 | retVal := &ReturnValue{} 330 | mem := &Memory{ 331 | Offset: NewConst(uint256.NewInt(retOffset)), 332 | Val: retVal, 333 | VmOffset: retOffset, 334 | VmBytes: util.CloneSlice(t.MemPost[retOffset : retOffset+retSize]), 335 | } 336 | call.MemMap[retOffset] = mem 337 | call.AddTrace(&Return{ 338 | ReturnValue: retVal, 339 | Memory: mem, 340 | }) 341 | stack.Push(NewConst(uint256.NewInt(1))) 342 | return nil 343 | } 344 | 345 | toAddr := newVmCall.CodeAddress() 346 | newCall := NewCall(opcode, &toAddr, newVmCall.Msg.Data) 347 | t.CallStack.Push(newCall) 348 | call.AddTrace(newCall) 349 | return nil 350 | 351 | case vm.STOP: 352 | if t.CallStack.Len() > 1 { 353 | t.CallStack.Pop() 354 | 355 | // Get it again becauses above `CallStack.Pop()` 356 | call = *t.CallStack.Peek() 357 | stack_ := &call.Stack 358 | stack_.Push(NewConst(uint256.NewInt(1))) 359 | } 360 | return nil 361 | 362 | case vm.RETURN: 363 | _, _ = stack.Pop(), stack.Pop() 364 | if t.CallStack.Len() == 1 { // return from main call 365 | return nil 366 | } 367 | t.CallStack.Pop() 368 | 369 | // Get it again becauses above `CallStack.Pop()` 370 | call = *t.CallStack.Peek() 371 | stack_ := &call.Stack 372 | 373 | // copy return value to outer Call.Memory 374 | offset, size := vmCall.OuterReturnOffset, vmCall.OuterReturnSize 375 | 376 | newVmCall := t.ctx.Call() 377 | 378 | mem := &Memory{ 379 | Offset: NewConst(uint256.NewInt(offset)), 380 | Val: &ReturnValue{}, 381 | VmOffset: offset, 382 | VmBytes: newVmCall.Memory.GetCopy( 383 | int64(offset), 384 | int64(size), 385 | ), 386 | } 387 | call.MemMap[offset] = mem 388 | call.AddTrace(&MemoryWrite{ 389 | Memory: mem, 390 | }) 391 | 392 | stack_.Push(NewConst(uint256.NewInt(1))) 393 | return nil 394 | 395 | case vm.RETURNDATASIZE: 396 | stack.Push(&Label{"ReturnDataSize"}) 397 | return nil 398 | case vm.RETURNDATACOPY, vm.CODECOPY: 399 | _, _, _ = stack.Pop(), stack.Pop(), stack.Pop() 400 | 401 | memOffset, dataOffset, length := 402 | t.StackPre.PeekI(0).Uint64(), t.StackPre.PeekI(1).Uint64(), t.StackPre.PeekI(2).Uint64() 403 | mem := &Memory{ 404 | Offset: NewConst(uint256.NewInt(memOffset)), 405 | VmOffset: memOffset, 406 | VmBytes: t.MemPost[memOffset : memOffset+length], 407 | } 408 | 409 | switch opcode { 410 | case vm.RETURNDATACOPY: 411 | mem.Val = &Label{"ReturnValue"} 412 | case vm.CODECOPY: 413 | mem.Val = &Label{"CodeCopy"} 414 | } 415 | 416 | call.MemMap[dataOffset] = mem 417 | 418 | call.AddTrace(&MemoryWrite{ 419 | Memory: mem, 420 | }) 421 | 422 | return nil 423 | case vm.EXTCODECOPY: 424 | 425 | case vm.REVERT: 426 | call.AddTrace(&Label{"Reverted"}) 427 | return nil 428 | case vm.SELFDESTRUCT: 429 | case vm.CREATE: 430 | case vm.CREATE2: 431 | case vm.CALLCODE: 432 | } 433 | 434 | return errors.Wrap(TODO, opcode.String()) 435 | } 436 | -------------------------------------------------------------------------------- /opcode.go: -------------------------------------------------------------------------------- 1 | package edb 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "math/big" 7 | 8 | "github.com/aj3423/edb/util" 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/core/vm" 11 | "github.com/fatih/color" 12 | "github.com/holiman/uint256" 13 | "github.com/pkg/errors" 14 | ) 15 | 16 | type executionFunc func(*Context) error 17 | 18 | type Operation struct { 19 | OpCode vm.OpCode 20 | OpSize uint64 // size of required data, eg: opSize for push3 == 3 21 | GasCost gasFunc 22 | Exec executionFunc 23 | NStackIn uint8 // count of args that popup from stack 24 | NStackOut uint8 // count of new items pushed to stack 25 | } 26 | 27 | func make_op( 28 | opCode vm.OpCode, 29 | opSize uint64, 30 | gasCost gasFunc, 31 | nStackIn uint8, 32 | nStackOut uint8, 33 | exec executionFunc, 34 | ) *Operation { 35 | return &Operation{ 36 | OpCode: opCode, 37 | OpSize: opSize, 38 | GasCost: gasCost, 39 | NStackIn: nStackIn, 40 | NStackOut: nStackOut, 41 | Exec: exec, 42 | } 43 | } 44 | 45 | var OpTable map[vm.OpCode]*Operation 46 | 47 | func init() { 48 | OpTable = map[vm.OpCode]*Operation{ 49 | vm.STOP: make_op(vm.STOP, 0, fixedGas(0), 0, 0, opStop), // 0x0 50 | vm.ADD: make_op(vm.ADD, 0, fixedGas(3), 2, 1, opAdd), // 0x1 51 | vm.MUL: make_op(vm.MUL, 0, fixedGas(5), 2, 1, opMul), // 0x2 52 | vm.SUB: make_op(vm.SUB, 0, fixedGas(3), 2, 1, opSub), // 0x3 53 | vm.DIV: make_op(vm.DIV, 0, fixedGas(5), 2, 1, opDiv), // 0x4 54 | vm.SDIV: make_op(vm.SDIV, 0, fixedGas(5), 2, 1, opSdiv), // 0x5 55 | vm.MOD: make_op(vm.MOD, 0, fixedGas(5), 2, 1, opMod), // 0x6 56 | vm.SMOD: make_op(vm.SMOD, 0, fixedGas(5), 2, 1, opSmod), // 0x7 57 | vm.ADDMOD: make_op(vm.ADDMOD, 0, fixedGas(8), 2, 1, opAddmod), // 0x8 58 | vm.MULMOD: make_op(vm.MULMOD, 0, fixedGas(8), 2, 1, opMulmod), // 0x9 59 | vm.EXP: make_op(vm.EXP, 0, gasExp, 2, 1, opExp), // 0xa 60 | vm.SIGNEXTEND: make_op(vm.SIGNEXTEND, 0, fixedGas(5), 2, 1, opSignExtend), // 0xb 61 | vm.LT: make_op(vm.LT, 0, fixedGas(3), 2, 1, opLt), // 0x10 62 | vm.GT: make_op(vm.GT, 0, fixedGas(3), 2, 1, opGt), // 0x11 63 | vm.SLT: make_op(vm.SLT, 0, fixedGas(3), 2, 1, opSlt), // 0x12 64 | vm.SGT: make_op(vm.SGT, 0, fixedGas(3), 2, 1, opSgt), // 0x13 65 | vm.EQ: make_op(vm.EQ, 0, fixedGas(3), 2, 1, opEq), // 0x14 66 | vm.ISZERO: make_op(vm.ISZERO, 0, fixedGas(3), 1, 1, opIszero), // 0x15 67 | vm.AND: make_op(vm.AND, 0, fixedGas(3), 2, 1, opAnd), // 0x16 68 | vm.OR: make_op(vm.OR, 0, fixedGas(3), 2, 1, opOr), // 0x17 69 | vm.XOR: make_op(vm.XOR, 0, fixedGas(3), 2, 1, opXor), // 0x18 70 | vm.NOT: make_op(vm.NOT, 0, fixedGas(3), 1, 1, opNot), // 0x19 71 | vm.BYTE: make_op(vm.BYTE, 0, fixedGas(3), 2, 1, opByte), // 0x1a 72 | vm.SHL: make_op(vm.SHL, 0, fixedGas(3), 2, 1, opSHL), // 0x1b 73 | vm.SHR: make_op(vm.SHR, 0, fixedGas(3), 2, 1, opSHR), // 0x1c 74 | vm.SAR: make_op(vm.SAR, 0, fixedGas(3), 2, 1, opSAR), // 0x1d 75 | vm.SHA3: make_op(vm.SHA3, 0, gasSha3, 2, 1, opSha3), // 0x20 76 | vm.ADDRESS: make_op(vm.ADDRESS, 0, fixedGas(2), 0, 1, opAddress), // 0x30 77 | vm.BALANCE: make_op(vm.BALANCE, 0, fixedGas(20), 1, 1, opBalance), // 0x31 78 | vm.ORIGIN: make_op(vm.ORIGIN, 0, fixedGas(2), 0, 1, opOrigin), // 0x32 79 | vm.CALLER: make_op(vm.CALLER, 0, fixedGas(2), 0, 1, opCaller), // 0x33 80 | vm.CALLVALUE: make_op(vm.CALLVALUE, 0, fixedGas(2), 0, 1, opCallValue), // 0x34 81 | vm.CALLDATALOAD: make_op(vm.CALLDATALOAD, 0, fixedGas(3), 0, 1, opCallDataLoad), // 0x35 82 | vm.CALLDATASIZE: make_op(vm.CALLDATASIZE, 0, fixedGas(2), 0, 1, opCallDataSize), // 0x36 83 | vm.CALLDATACOPY: make_op(vm.CALLDATACOPY, 0, gasCallDataCopy, 3, 0, opCallDataCopy), // 0x37 84 | vm.CODESIZE: make_op(vm.CODESIZE, 0, fixedGas(2), 0, 1, opCodeSize), // 0x38 85 | vm.CODECOPY: make_op(vm.CODECOPY, 0, gasCodeCopy, 3, 0, opCodeCopy), // 0x39 86 | vm.GASPRICE: make_op(vm.GASPRICE, 0, fixedGas(2), 0, 1, opGasprice), // 0x3a 87 | vm.EXTCODESIZE: make_op(vm.EXTCODESIZE, 0, fixedGas(700), 0, 1, opExtCodeSize), // 0x3b 88 | vm.EXTCODECOPY: make_op(vm.EXTCODECOPY, 0, gasExtCodeCopy, 4, 0, opExtCodeCopy), // 0x3c 89 | vm.RETURNDATASIZE: make_op(vm.RETURNDATASIZE, 0, fixedGas(2), 0, 1, opReturnDataSize), // 0x3d 90 | vm.RETURNDATACOPY: make_op(vm.RETURNDATACOPY, 0, gasReturnDataCopy, 3, 0, opReturnDataCopy), // 0x3e 91 | vm.EXTCODEHASH: make_op(vm.EXTCODEHASH, 0, fixedGas(700), 1, 1, opExtCodeHash), // 0x3f 92 | vm.BLOCKHASH: make_op(vm.BLOCKHASH, 0, fixedGas(20), 1, 1, opBlockhash), // 0x40 93 | vm.COINBASE: make_op(vm.COINBASE, 0, fixedGas(2), 0, 1, opCoinbase), // 0x41 94 | vm.TIMESTAMP: make_op(vm.TIMESTAMP, 0, fixedGas(2), 0, 1, opTimestamp), // 0x42 95 | vm.NUMBER: make_op(vm.NUMBER, 0, fixedGas(2), 0, 1, opNumber), // 0x43 96 | vm.DIFFICULTY: make_op(vm.DIFFICULTY, 0, fixedGas(2), 0, 1, opDifficulty), // 0x44 97 | vm.GASLIMIT: make_op(vm.GASLIMIT, 0, fixedGas(2), 0, 1, opGasLimit), // 0x45 98 | vm.CHAINID: make_op(vm.CHAINID, 0, fixedGas(2), 0, 1, opChainID), // 0x46 99 | vm.SELFBALANCE: make_op(vm.SELFBALANCE, 0, fixedGas(5), 0, 1, opSelfBalance), // 0x47 100 | vm.BASEFEE: make_op(vm.BASEFEE, 0, fixedGas(2), 0, 1, opBaseFee), // 0x48 101 | vm.POP: make_op(vm.POP, 0, fixedGas(2), 1, 0, opPop), // 0x50 102 | vm.MLOAD: make_op(vm.MLOAD, 0, fixedGas(3), 1, 1, opMload), // 0x51 103 | vm.MSTORE: make_op(vm.MSTORE, 0, fixedGas(3), 2, 0, opMstore), // 0x52 104 | vm.MSTORE8: make_op(vm.MSTORE8, 0, fixedGas(3), 2, 0, opMstore8), // 0x53 105 | vm.SLOAD: make_op(vm.SLOAD, 0, fixedGas(800), 1, 1, opSload), // 0x54 106 | vm.SSTORE: make_op(vm.SSTORE, 0, gasSStore, 2, 0, opSstore), // 0x55 107 | vm.JUMP: make_op(vm.JUMP, 0, fixedGas(8), 1, 0, opJump), // 0x56 108 | vm.JUMPI: make_op(vm.JUMPI, 0, fixedGas(10), 2, 0, opJumpi), // 0x57 109 | vm.PC: make_op(vm.PC, 0, fixedGas(2), 0, 1, opPc), // 0x58 110 | vm.MSIZE: make_op(vm.MSIZE, 0, fixedGas(2), 0, 1, opMsize), // 0x59 111 | vm.GAS: make_op(vm.GAS, 0, fixedGas(2), 0, 1, opGas), // 0x5a 112 | vm.JUMPDEST: make_op(vm.JUMPDEST, 0, fixedGas(1), 0, 0, opJumpdest), // 0x5b 113 | vm.PUSH1: make_op(vm.PUSH1, 1, fixedGas(3), 0, 1, makePush(1)), // 0x60 114 | vm.PUSH2: make_op(vm.PUSH2, 2, fixedGas(3), 0, 1, makePush(2)), // 0x61 115 | vm.PUSH3: make_op(vm.PUSH3, 3, fixedGas(3), 0, 1, makePush(3)), // 0x62 116 | vm.PUSH4: make_op(vm.PUSH4, 4, fixedGas(3), 0, 1, makePush(4)), // 0x63 117 | vm.PUSH5: make_op(vm.PUSH5, 5, fixedGas(3), 0, 1, makePush(5)), // 0x64 118 | vm.PUSH6: make_op(vm.PUSH6, 6, fixedGas(3), 0, 1, makePush(6)), // 0x65 119 | vm.PUSH7: make_op(vm.PUSH7, 7, fixedGas(3), 0, 1, makePush(7)), // 0x66 120 | vm.PUSH8: make_op(vm.PUSH8, 8, fixedGas(3), 0, 1, makePush(8)), // 0x67 121 | vm.PUSH9: make_op(vm.PUSH9, 9, fixedGas(3), 0, 1, makePush(9)), // 0x68 122 | vm.PUSH10: make_op(vm.PUSH10, 10, fixedGas(3), 0, 1, makePush(10)), // 0x69 123 | vm.PUSH11: make_op(vm.PUSH11, 11, fixedGas(3), 0, 1, makePush(11)), // 0x6a 124 | vm.PUSH12: make_op(vm.PUSH12, 12, fixedGas(3), 0, 1, makePush(12)), // 0x6b 125 | vm.PUSH13: make_op(vm.PUSH13, 13, fixedGas(3), 0, 1, makePush(13)), // 0x6c 126 | vm.PUSH14: make_op(vm.PUSH14, 14, fixedGas(3), 0, 1, makePush(14)), // 0x6d 127 | vm.PUSH15: make_op(vm.PUSH15, 15, fixedGas(3), 0, 1, makePush(15)), // 0x6e 128 | vm.PUSH16: make_op(vm.PUSH16, 16, fixedGas(3), 0, 1, makePush(16)), // 0x6f 129 | vm.PUSH17: make_op(vm.PUSH17, 17, fixedGas(3), 0, 1, makePush(17)), // 0x70 130 | vm.PUSH18: make_op(vm.PUSH18, 18, fixedGas(3), 0, 1, makePush(18)), // 0x71 131 | vm.PUSH19: make_op(vm.PUSH19, 19, fixedGas(3), 0, 1, makePush(19)), // 0x72 132 | vm.PUSH20: make_op(vm.PUSH20, 20, fixedGas(3), 0, 1, makePush(20)), // 0x73 133 | vm.PUSH21: make_op(vm.PUSH21, 21, fixedGas(3), 0, 1, makePush(21)), // 0x74 134 | vm.PUSH22: make_op(vm.PUSH22, 22, fixedGas(3), 0, 1, makePush(22)), // 0x75 135 | vm.PUSH23: make_op(vm.PUSH23, 23, fixedGas(3), 0, 1, makePush(23)), // 0x76 136 | vm.PUSH24: make_op(vm.PUSH24, 24, fixedGas(3), 0, 1, makePush(24)), // 0x77 137 | vm.PUSH25: make_op(vm.PUSH25, 25, fixedGas(3), 0, 1, makePush(25)), // 0x78 138 | vm.PUSH26: make_op(vm.PUSH26, 26, fixedGas(3), 0, 1, makePush(26)), // 0x79 139 | vm.PUSH27: make_op(vm.PUSH27, 27, fixedGas(3), 0, 1, makePush(27)), // 0x7a 140 | vm.PUSH28: make_op(vm.PUSH28, 28, fixedGas(3), 0, 1, makePush(28)), // 0x7b 141 | vm.PUSH29: make_op(vm.PUSH29, 29, fixedGas(3), 0, 1, makePush(29)), // 0x7c 142 | vm.PUSH30: make_op(vm.PUSH30, 30, fixedGas(3), 0, 1, makePush(30)), // 0x7d 143 | vm.PUSH31: make_op(vm.PUSH31, 31, fixedGas(3), 0, 1, makePush(31)), // 0x7e 144 | vm.PUSH32: make_op(vm.PUSH32, 32, fixedGas(3), 0, 1, makePush(32)), // 0x7f 145 | vm.DUP1: make_op(vm.DUP1, 0, fixedGas(3), 0, 1, makeDup(1)), // 0x80 146 | vm.DUP2: make_op(vm.DUP2, 0, fixedGas(3), 0, 1, makeDup(2)), // 0x81 147 | vm.DUP3: make_op(vm.DUP3, 0, fixedGas(3), 0, 1, makeDup(3)), // 0x82 148 | vm.DUP4: make_op(vm.DUP4, 0, fixedGas(3), 0, 1, makeDup(4)), // 0x83 149 | vm.DUP5: make_op(vm.DUP5, 0, fixedGas(3), 0, 1, makeDup(5)), // 0x84 150 | vm.DUP6: make_op(vm.DUP6, 0, fixedGas(3), 0, 1, makeDup(6)), // 0x85 151 | vm.DUP7: make_op(vm.DUP7, 0, fixedGas(3), 0, 1, makeDup(7)), // 0x86 152 | vm.DUP8: make_op(vm.DUP8, 0, fixedGas(3), 0, 1, makeDup(8)), // 0x87 153 | vm.DUP9: make_op(vm.DUP9, 0, fixedGas(3), 0, 1, makeDup(9)), // 0x88 154 | vm.DUP10: make_op(vm.DUP10, 0, fixedGas(3), 0, 1, makeDup(10)), // 0x89 155 | vm.DUP11: make_op(vm.DUP11, 0, fixedGas(3), 0, 1, makeDup(11)), // 0x8a 156 | vm.DUP12: make_op(vm.DUP12, 0, fixedGas(3), 0, 1, makeDup(12)), // 0x8b 157 | vm.DUP13: make_op(vm.DUP13, 0, fixedGas(3), 0, 1, makeDup(13)), // 0x8c 158 | vm.DUP14: make_op(vm.DUP14, 0, fixedGas(3), 0, 1, makeDup(14)), // 0x8d 159 | vm.DUP15: make_op(vm.DUP15, 0, fixedGas(3), 0, 1, makeDup(15)), // 0x8e 160 | vm.DUP16: make_op(vm.DUP16, 0, fixedGas(3), 0, 1, makeDup(16)), // 0x8f 161 | vm.SWAP1: make_op(vm.SWAP1, 0, fixedGas(3), 0, 0, makeSwap(1)), // 0x90 162 | vm.SWAP2: make_op(vm.SWAP2, 0, fixedGas(3), 0, 0, makeSwap(2)), // 0x91 163 | vm.SWAP3: make_op(vm.SWAP3, 0, fixedGas(3), 0, 0, makeSwap(3)), // 0x92 164 | vm.SWAP4: make_op(vm.SWAP4, 0, fixedGas(3), 0, 0, makeSwap(4)), // 0x93 165 | vm.SWAP5: make_op(vm.SWAP5, 0, fixedGas(3), 0, 0, makeSwap(5)), // 0x94 166 | vm.SWAP6: make_op(vm.SWAP6, 0, fixedGas(3), 0, 0, makeSwap(6)), // 0x95 167 | vm.SWAP7: make_op(vm.SWAP7, 0, fixedGas(3), 0, 0, makeSwap(7)), // 0x96 168 | vm.SWAP8: make_op(vm.SWAP8, 0, fixedGas(3), 0, 0, makeSwap(8)), // 0x97 169 | vm.SWAP9: make_op(vm.SWAP9, 0, fixedGas(3), 0, 0, makeSwap(9)), // 0x98 170 | vm.SWAP10: make_op(vm.SWAP10, 0, fixedGas(3), 0, 0, makeSwap(10)), // 0x99 171 | vm.SWAP11: make_op(vm.SWAP11, 0, fixedGas(3), 0, 0, makeSwap(11)), // 0x9a 172 | vm.SWAP12: make_op(vm.SWAP12, 0, fixedGas(3), 0, 0, makeSwap(12)), // 0x9b 173 | vm.SWAP13: make_op(vm.SWAP13, 0, fixedGas(3), 0, 0, makeSwap(13)), // 0x9c 174 | vm.SWAP14: make_op(vm.SWAP14, 0, fixedGas(3), 0, 0, makeSwap(14)), // 0x9d 175 | vm.SWAP15: make_op(vm.SWAP15, 0, fixedGas(3), 0, 0, makeSwap(15)), // 0x9e 176 | vm.SWAP16: make_op(vm.SWAP16, 0, fixedGas(3), 0, 0, makeSwap(16)), // 0x9f 177 | vm.LOG0: make_op(vm.LOG0, 0, makeGasLog(0), 2+0, 0, makeLog(0)), // 0xa0 178 | vm.LOG1: make_op(vm.LOG1, 0, makeGasLog(1), 2+1, 0, makeLog(1)), // 0xa1 179 | vm.LOG2: make_op(vm.LOG2, 0, makeGasLog(2), 2+2, 0, makeLog(2)), // 0xa2 180 | vm.LOG3: make_op(vm.LOG3, 0, makeGasLog(3), 2+3, 0, makeLog(3)), // 0xa3 181 | vm.LOG4: make_op(vm.LOG4, 0, makeGasLog(4), 2+4, 0, makeLog(4)), // 0xa4 182 | vm.CREATE: make_op(vm.CREATE, 0, gasTodo, 0, 0, opCreate), // 0xf0 183 | vm.CALL: make_op(vm.CALL, 0, gasTodo, 7, 0, opCall), // 0xf1 184 | vm.CALLCODE: make_op(vm.CALLCODE, 0, gasTodo, 0, 0, opCallCode), // 0xf2 185 | vm.RETURN: make_op(vm.RETURN, 0, fixedGas(0), 2, 0, opReturn), // 0xf3 186 | vm.DELEGATECALL: make_op(vm.DELEGATECALL, 0, gasTodo, 6, 0, opDelegateCall), // 0xf4 187 | vm.CREATE2: make_op(vm.CREATE2, 0, gasTodo, 0, 0, opCreate2), // 0xf5 188 | vm.STATICCALL: make_op(vm.STATICCALL, 0, gasTodo, 6, 0, opStaticCall), // 0xfa 189 | vm.REVERT: make_op(vm.REVERT, 0, fixedGas(0), 2, 0, opRevert), // 0xfd 190 | vm.OpCode(0xfe): make_op(vm.OpCode(0xfe), 0, gasTodo, 1, 0, opAssert), // 0xfe 191 | vm.SELFDESTRUCT: make_op(vm.SELFDESTRUCT, 0, gasTodo, 1, 0, opSuicide), // 0xff 192 | } 193 | } 194 | 195 | func opInvalid(ctx *Context) error { 196 | return errors.New("invalid op") 197 | //return nil 198 | } 199 | 200 | func opAdd(ctx *Context) error { 201 | stack := ctx.Stack() 202 | x, y := stack.Pop(), stack.Peek() 203 | y.Add(&x, y) 204 | return nil 205 | } 206 | 207 | func opSub(ctx *Context) error { 208 | stack := ctx.Stack() 209 | x, y := stack.Pop(), stack.Peek() 210 | y.Sub(&x, y) 211 | return nil 212 | } 213 | 214 | func opMul(ctx *Context) error { 215 | stack := ctx.Stack() 216 | x, y := stack.Pop(), stack.Peek() 217 | y.Mul(&x, y) 218 | return nil 219 | } 220 | 221 | func opDiv(ctx *Context) error { 222 | stack := ctx.Stack() 223 | x, y := stack.Pop(), stack.Peek() 224 | y.Div(&x, y) 225 | return nil 226 | } 227 | 228 | func opSdiv(ctx *Context) error { 229 | stack := ctx.Stack() 230 | x, y := stack.Pop(), stack.Peek() 231 | y.SDiv(&x, y) 232 | return nil 233 | } 234 | 235 | func opMod(ctx *Context) error { 236 | stack := ctx.Stack() 237 | x, y := stack.Pop(), stack.Peek() 238 | y.Mod(&x, y) 239 | return nil 240 | } 241 | 242 | func opSmod(ctx *Context) error { 243 | stack := ctx.Stack() 244 | x, y := stack.Pop(), stack.Peek() 245 | y.SMod(&x, y) 246 | return nil 247 | } 248 | 249 | func opExp(ctx *Context) error { 250 | stack := ctx.Stack() 251 | base, exponent := stack.Pop(), stack.Peek() 252 | exponent.Exp(&base, exponent) 253 | return nil 254 | } 255 | 256 | // b, x -> y = SIGNEXTEND(x, b) 257 | // sign extends x from (b + 1) * 8 bits to 256 bits. 258 | func opSignExtend(ctx *Context) error { 259 | stack := ctx.Stack() 260 | back, num := stack.Pop(), stack.Peek() 261 | num.ExtendSign(num, &back) 262 | return nil 263 | } 264 | 265 | func opNot(ctx *Context) error { 266 | x := ctx.Stack().Peek() 267 | x.Not(x) 268 | return nil 269 | } 270 | 271 | func opLt(ctx *Context) error { 272 | stack := ctx.Stack() 273 | x, y := stack.Pop(), stack.Peek() 274 | if x.Lt(y) { 275 | y.SetOne() 276 | } else { 277 | y.Clear() 278 | } 279 | return nil 280 | } 281 | 282 | func opGt(ctx *Context) error { 283 | stack := ctx.Stack() 284 | x, y := stack.Pop(), stack.Peek() 285 | if x.Gt(y) { 286 | y.SetOne() 287 | } else { 288 | y.Clear() 289 | } 290 | return nil 291 | } 292 | 293 | func opSlt(ctx *Context) error { 294 | stack := ctx.Stack() 295 | x, y := stack.Pop(), stack.Peek() 296 | if x.Slt(y) { 297 | y.SetOne() 298 | } else { 299 | y.Clear() 300 | } 301 | return nil 302 | } 303 | 304 | func opSgt(ctx *Context) error { 305 | stack := ctx.Stack() 306 | x, y := stack.Pop(), stack.Peek() 307 | if x.Sgt(y) { 308 | y.SetOne() 309 | } else { 310 | y.Clear() 311 | } 312 | return nil 313 | } 314 | 315 | func opEq(ctx *Context) error { 316 | stack := ctx.Stack() 317 | x, y := stack.Pop(), stack.Peek() 318 | if x.Eq(y) { 319 | y.SetOne() 320 | } else { 321 | y.Clear() 322 | } 323 | return nil 324 | } 325 | 326 | func opIszero(ctx *Context) error { 327 | x := ctx.Stack().Peek() 328 | if x.IsZero() { 329 | x.SetOne() 330 | } else { 331 | x.Clear() 332 | } 333 | return nil 334 | } 335 | 336 | func opAnd(ctx *Context) error { 337 | stack := ctx.Stack() 338 | x, y := stack.Pop(), stack.Peek() 339 | y.And(&x, y) 340 | return nil 341 | } 342 | 343 | func opOr(ctx *Context) error { 344 | stack := ctx.Stack() 345 | x, y := stack.Pop(), stack.Peek() 346 | y.Or(&x, y) 347 | return nil 348 | } 349 | 350 | func opXor(ctx *Context) error { 351 | stack := ctx.Stack() 352 | x, y := stack.Pop(), stack.Peek() 353 | y.Xor(&x, y) 354 | return nil 355 | } 356 | 357 | // i'th byte of (u)int256 x, counting from most significant byte 358 | func opByte(ctx *Context) error { 359 | stack := ctx.Stack() 360 | th, val := stack.Pop(), stack.Peek() 361 | val.Byte(&th) 362 | return nil 363 | } 364 | 365 | func opAddmod(ctx *Context) error { 366 | stack := ctx.Stack() 367 | x, y, z := stack.Pop(), stack.Pop(), stack.Peek() 368 | if z.IsZero() { 369 | z.Clear() 370 | } else { 371 | z.AddMod(&x, &y, z) 372 | } 373 | return nil 374 | } 375 | 376 | func opMulmod(ctx *Context) error { 377 | stack := ctx.Stack() 378 | x, y, z := stack.Pop(), stack.Pop(), stack.Peek() 379 | z.MulMod(&x, &y, z) 380 | return nil 381 | } 382 | 383 | // opSHL implements Shift Left 384 | // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, 385 | // and pushes on the stack arg2 shifted to the left by arg1 number of bits. 386 | func opSHL(ctx *Context) error { 387 | stack := ctx.Stack() 388 | // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards 389 | shift, value := stack.Pop(), stack.Peek() 390 | if shift.LtUint64(256) { 391 | value.Lsh(value, uint(shift.Uint64())) 392 | } else { 393 | value.Clear() 394 | } 395 | return nil 396 | } 397 | 398 | // opSHR implements Logical Shift Right 399 | // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, 400 | // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. 401 | func opSHR(ctx *Context) error { 402 | stack := ctx.Stack() 403 | // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards 404 | shift, value := stack.Pop(), stack.Peek() 405 | if shift.LtUint64(256) { 406 | value.Rsh(value, uint(shift.Uint64())) 407 | } else { 408 | value.Clear() 409 | } 410 | return nil 411 | } 412 | 413 | // opSAR implements Arithmetic Shift Right 414 | // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, 415 | // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. 416 | func opSAR(ctx *Context) error { 417 | stack := ctx.Stack() 418 | shift, value := stack.Pop(), stack.Peek() 419 | if shift.GtUint64(256) { 420 | if value.Sign() >= 0 { 421 | value.Clear() 422 | } else { 423 | // Max negative shift: all bits set 424 | value.SetAllOne() 425 | } 426 | return nil 427 | } 428 | n := uint(shift.Uint64()) 429 | value.SRsh(value, n) 430 | return nil 431 | } 432 | 433 | func opSha3(ctx *Context) error { 434 | stack := ctx.Stack() 435 | offset, size := stack.Pop(), stack.Peek() 436 | data := ctx.Memory().GetPtr(int64(offset.Uint64()), int64(size.Uint64())) 437 | 438 | bs := util.Sha3(data) 439 | 440 | size.SetBytes(bs) 441 | return nil 442 | } 443 | func opAddress(ctx *Context) error { 444 | ctx.Stack().Push(*new(uint256.Int).SetBytes(ctx.This().Bytes())) 445 | return nil 446 | } 447 | 448 | func opBalance(ctx *Context) error { 449 | slot := ctx.Stack().Peek() 450 | address := common.Address(slot.Bytes20()) 451 | bal, e := ensure_balance(ctx, address) 452 | if e != nil { 453 | return e 454 | } 455 | slot.SetFromBig(bal) 456 | return nil 457 | } 458 | 459 | func opOrigin(ctx *Context) error { 460 | ctx.Stack().Push(*new(uint256.Int).SetBytes(ctx.Tx.Origin.Bytes())) 461 | return nil 462 | } 463 | func opCaller(ctx *Context) error { 464 | ctx.Stack().Push(*new(uint256.Int).SetBytes(ctx.Msg().Sender.Bytes())) 465 | return nil 466 | } 467 | 468 | func opCallValue(ctx *Context) error { 469 | v, _ := uint256.FromBig(ctx.Msg().Value) 470 | ctx.Stack().Push(*v) 471 | return nil 472 | } 473 | 474 | // getData returns a slice from the data based on the start and size and pads 475 | // up to size with zero's. This function is overflow safe. 476 | func getData(data []byte, start uint64, size uint64) []byte { 477 | length := uint64(len(data)) 478 | if start > length { 479 | start = length 480 | } 481 | end := start + size 482 | if end > length { 483 | end = length 484 | } 485 | return common.RightPadBytes(data[start:end], int(size)) 486 | } 487 | 488 | // reads a (u)int256 from message data 489 | // 490 | // msg.data[i:i+32] 491 | func opCallDataLoad(ctx *Context) error { 492 | off := ctx.Stack().Peek() 493 | if offset, overflow := off.Uint64WithOverflow(); !overflow { 494 | data := getData(ctx.Msg().Data, offset, 32) 495 | off.SetBytes(data) 496 | } else { 497 | off.Clear() 498 | } 499 | return nil 500 | } 501 | 502 | func opCallDataSize(ctx *Context) error { 503 | ctx.Stack().Push(*new(uint256.Int).SetUint64(uint64(len(ctx.Msg().Data)))) 504 | return nil 505 | } 506 | 507 | func opCallDataCopy(ctx *Context) error { 508 | stack := ctx.Stack() 509 | var ( 510 | memOffset = stack.Pop() 511 | dataOffset = stack.Pop() 512 | length = stack.Pop() 513 | ) 514 | dataOffset64, overflow := dataOffset.Uint64WithOverflow() 515 | if overflow { 516 | dataOffset64 = 0xffffffffffffffff 517 | } 518 | // These values are checked for overflow during gas cost calculation 519 | memOffset64 := memOffset.Uint64() 520 | length64 := length.Uint64() 521 | ctx.Memory().Set(memOffset64, length64, getData(ctx.Msg().Data, dataOffset64, length64)) 522 | 523 | return nil 524 | } 525 | 526 | func opReturnDataSize(ctx *Context) error { 527 | ctx.Stack().Push(*new(uint256.Int).SetUint64( 528 | uint64(len(ctx.Call().InnerReturnVal)))) 529 | return nil 530 | } 531 | 532 | // memory[memOffset : memOffset+length] = 533 | // 534 | // RETURNDATA[dataOffset : dataOffset+length] 535 | func opReturnDataCopy(ctx *Context) error { 536 | stack := ctx.Stack() 537 | var ( 538 | memOffset = stack.Pop() 539 | dataOffset = stack.Pop() 540 | length = stack.Pop() 541 | ) 542 | 543 | offset64, overflow := dataOffset.Uint64WithOverflow() 544 | if overflow { 545 | return vm.ErrReturnDataOutOfBounds 546 | } 547 | // we can reuse dataOffset now (aliasing it for clarity) 548 | var end = dataOffset 549 | end.Add(&dataOffset, &length) 550 | end64, overflow := end.Uint64WithOverflow() 551 | if overflow || uint64(len(ctx.Call().InnerReturnVal)) < end64 { 552 | return vm.ErrReturnDataOutOfBounds 553 | } 554 | ctx.Memory().Set(memOffset.Uint64(), length.Uint64(), ctx.Call().InnerReturnVal[offset64:end64]) 555 | return nil 556 | } 557 | 558 | func opExtCodeSize(ctx *Context) error { 559 | slot := ctx.Stack().Peek() 560 | addr := common.Address(slot.Bytes20()) 561 | 562 | code, e := ensure_code(ctx, addr) 563 | if e != nil { 564 | return e 565 | } 566 | 567 | slot.SetUint64(uint64(len(code))) 568 | return nil 569 | } 570 | 571 | // address(this).code.size 572 | func opCodeSize(ctx *Context) error { 573 | addr := ctx.This() 574 | 575 | code, e := ensure_code(ctx, addr) 576 | if e != nil { 577 | return e 578 | } 579 | 580 | l := new(uint256.Int) 581 | l.SetUint64(uint64(len(code))) 582 | ctx.Stack().Push(*l) 583 | return nil 584 | } 585 | 586 | func opCodeCopy(ctx *Context) error { 587 | stack := ctx.Stack() 588 | var ( 589 | memOffset = stack.Pop() 590 | codeOffset = stack.Pop() 591 | length = stack.Pop() 592 | ) 593 | uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() 594 | if overflow { 595 | uint64CodeOffset = 0xffffffffffffffff 596 | } 597 | 598 | addr := ctx.This() 599 | code, e := ensure_code(ctx, addr) 600 | if e != nil { 601 | return e 602 | } 603 | 604 | codeToCopy := getData(code, uint64CodeOffset, length.Uint64()) 605 | ctx.Memory().Set(memOffset.Uint64(), length.Uint64(), codeToCopy) 606 | 607 | return nil 608 | } 609 | 610 | func opExtCodeCopy(ctx *Context) error { 611 | var ( 612 | stack = ctx.Stack() 613 | 614 | a = stack.Pop() 615 | memOffset = stack.Pop() 616 | codeOffset = stack.Pop() 617 | length = stack.Pop() 618 | ) 619 | uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() 620 | if overflow { 621 | uint64CodeOffset = 0xffffffffffffffff 622 | } 623 | addr := common.Address(a.Bytes20()) 624 | 625 | code, e := ensure_code(ctx, addr) 626 | if e != nil { 627 | return e 628 | } 629 | 630 | codeToCopy := getData(code, uint64CodeOffset, length.Uint64()) 631 | ctx.Memory().Set(memOffset.Uint64(), length.Uint64(), codeToCopy) 632 | 633 | return nil 634 | } 635 | 636 | // hash = address(addr).exists ? keccak256(address(addr).code) : 0 637 | func opExtCodeHash(ctx *Context) error { 638 | slot := ctx.Stack().Peek() 639 | addr := common.Address(slot.Bytes20()) 640 | 641 | code, e := ensure_code(ctx, addr) 642 | if e != nil { 643 | return e 644 | } 645 | 646 | slot.SetBytes(util.Sha3(code)) 647 | return nil 648 | } 649 | 650 | func opGasprice(ctx *Context) error { 651 | v := uint256.NewInt(ctx.Tx.GasPrice) 652 | ctx.Stack().Push(*v) 653 | return nil 654 | } 655 | 656 | // hash = block.blockHash(blockNumber) 657 | func opBlockhash(ctx *Context) error { 658 | num := ctx.Stack().Peek() 659 | num64, overflow := num.Uint64WithOverflow() 660 | if overflow { 661 | return errors.New("block hash overflow: " + num.String()) 662 | } 663 | 664 | var upper, lower uint64 665 | upper = ctx.Block.Number 666 | if upper < 257 { 667 | lower = 0 668 | } else { 669 | lower = upper - 256 670 | } 671 | if num64 >= lower && num64 < upper { 672 | hash, e := ensure_block_hash(ctx, num64) 673 | if e != nil { 674 | return e 675 | } 676 | num.SetBytes(hash.Bytes()) 677 | } else { 678 | num.Clear() 679 | } 680 | return nil 681 | } 682 | 683 | func opCoinbase(ctx *Context) error { 684 | ctx.Stack().Push(*new(uint256.Int).SetBytes(ctx.Block.Coinbase.Bytes())) 685 | return nil 686 | } 687 | 688 | // block.timestamp 689 | func opTimestamp(ctx *Context) error { 690 | v, _ := uint256.FromBig(big.NewInt(int64(ctx.Block.Timestamp))) 691 | ctx.Stack().Push(*v) 692 | return nil 693 | } 694 | 695 | // block.number 696 | func opNumber(ctx *Context) error { 697 | v, _ := uint256.FromBig(big.NewInt(int64(ctx.Block.Number))) 698 | ctx.Stack().Push(*v) 699 | return nil 700 | } 701 | 702 | func opDifficulty(ctx *Context) error { 703 | v, _ := uint256.FromBig(big.NewInt(int64(ctx.Block.Difficulty))) 704 | ctx.Stack().Push(*v) 705 | return nil 706 | } 707 | 708 | // block.gaslimit, current block's gaslimit 709 | func opGasLimit(ctx *Context) error { 710 | ctx.Stack().Push(*new(uint256.Int).SetUint64(ctx.Block.GasLimit)) 711 | return nil 712 | } 713 | 714 | func opPop(ctx *Context) error { 715 | ctx.Stack().Pop() 716 | return nil 717 | } 718 | 719 | func opMload(ctx *Context) error { 720 | v := ctx.Stack().Peek() 721 | offset := int64(v.Uint64()) 722 | v.SetBytes(ctx.Memory().GetPtr(offset, 32)) 723 | return nil 724 | } 725 | 726 | func opMstore(ctx *Context) error { 727 | stack := ctx.Stack() 728 | // pop value of the stack 729 | ptr, val := stack.Pop(), stack.Pop() 730 | ctx.Memory().Set32(ptr.Uint64(), &val) 731 | return nil 732 | } 733 | 734 | // mstore(offset value) -> memory[offset] = value & 0xFF 735 | func opMstore8(ctx *Context) error { 736 | stack := ctx.Stack() 737 | ptr, val := stack.Pop(), stack.Pop() 738 | ctx.Memory().Set(ptr.Uint64(), 1, []byte{byte(val.Uint64())}) 739 | return nil 740 | } 741 | 742 | func opSload(ctx *Context) error { 743 | slot := ctx.Stack().Peek() 744 | 745 | this := ctx.Call().This 746 | 747 | val, e := ensure_storage(ctx, this, slot) 748 | if e != nil { 749 | return e 750 | } 751 | 752 | slot.SetBytes(val.Bytes()) 753 | return nil 754 | } 755 | 756 | // sstore(key, value) 757 | func opSstore(ctx *Context) error { 758 | stack := ctx.Stack() 759 | slot, val := stack.Pop(), stack.Pop() 760 | ctx.Contract().Storage[common.BigToHash(slot.ToBig())] = &val 761 | return nil 762 | } 763 | 764 | func opJump(ctx *Context) error { 765 | pos := ctx.Stack().Pop() 766 | code := ctx.Code().Binary 767 | codeLen := uint64(len(code)) 768 | if pos.Uint64() >= codeLen { 769 | return vm.ErrInvalidJump 770 | } 771 | ctx.Call().Pc = pos.Uint64() 772 | return nil 773 | } 774 | 775 | func opJumpi(ctx *Context) error { 776 | stack := ctx.Stack() 777 | pos, cond := stack.Pop(), stack.Pop() 778 | if !cond.IsZero() { 779 | code := ctx.Code().Binary 780 | codeLen := uint64(len(code)) 781 | if pos.Uint64() >= codeLen { 782 | return vm.ErrInvalidJump 783 | } 784 | ctx.Call().Pc = pos.Uint64() 785 | } else { 786 | ctx.Call().Pc++ 787 | } 788 | return nil 789 | } 790 | 791 | func opJumpdest(ctx *Context) error { 792 | return nil 793 | } 794 | 795 | func opPc(ctx *Context) error { 796 | ctx.Stack().Push(*new(uint256.Int).SetUint64(ctx.Pc())) 797 | return nil 798 | } 799 | 800 | func opMsize(ctx *Context) error { 801 | ctx.Stack().Push(*new(uint256.Int).SetUint64(uint64(ctx.Memory().Len()))) 802 | return nil 803 | } 804 | 805 | // gas remaining 806 | func opGas(ctx *Context) error { 807 | ctx.Stack().Push(*new(uint256.Int).SetUint64(ctx.Msg().Gas)) 808 | return nil 809 | } 810 | 811 | func opCreate(ctx *Context) error { 812 | return errors.New("TODO opCreate") 813 | } 814 | 815 | func opCreate2(ctx *Context) error { 816 | return errors.New("TODO opCreate2") 817 | } 818 | 819 | /* 820 | A send tx -> B -> call(C), in C: 821 | msg.sender inside C is B. msg.value is passed by argument 822 | C.storage == C.storage, C.address(this) == C 823 | */ 824 | 825 | func do_opcall( 826 | ctx *Context, 827 | gas, addr, value, inOffset, inSize, retOffset, retSize uint256.Int, 828 | ) error { 829 | _ = gas 830 | 831 | toAddr := common.Address(addr.Bytes20()) 832 | 833 | input := ctx.Memory().GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) 834 | 835 | if precompiled, ok := vm.PrecompiledContractsBerlin[toAddr]; ok { 836 | output, e := precompiled.Run(input) 837 | if e != nil { 838 | return errors.Wrap(e, "Precompiled") 839 | } 840 | 841 | ctx.Call().InnerReturnVal = output 842 | 843 | ctx.Memory().Set(retOffset.Uint64(), retSize.Uint64(), output) 844 | 845 | ctx.Stack().Push(*uint256.NewInt(1)) 846 | return nil 847 | } 848 | 849 | _, e := ensure_code(ctx, toAddr) // fetch code + disasm for new Contract 850 | if e != nil { 851 | color.Red("ensure code fail") 852 | return e 853 | } 854 | 855 | var bigVal = big.NewInt(0) 856 | if !value.IsZero() { 857 | //gas += params.CallStipend 858 | bigVal = value.ToBig() 859 | } 860 | 861 | currCall := ctx.Call() 862 | 863 | // add a newCall to CallStack 864 | newCall := &Call{ 865 | Msg: Msg{ 866 | Data: input, 867 | Sender: currCall.This, 868 | Value: bigVal, 869 | Gas: currCall.Msg.Gas, 870 | }, 871 | This: toAddr, 872 | OuterReturnOffset: retOffset.Uint64(), 873 | OuterReturnSize: retSize.Uint64(), 874 | } 875 | ctx.CallStack.Push(newCall) 876 | return nil 877 | } 878 | func opCall(ctx *Context) error { 879 | stack := ctx.Stack() 880 | 881 | gas, addr, value, inOffset, inSize, retOffset, retSize := 882 | stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() 883 | 884 | // when input is empty, it's transfer: `addr.call{value:xxx}("")` 885 | if inSize.IsZero() { 886 | fromAddr := ctx.Call().This 887 | toAddr := common.Address(addr.Bytes20()) 888 | fromBalance := ctx.Contracts[fromAddr].Balance 889 | toBalance := ctx.Contracts[toAddr].Balance 890 | 891 | fromBalance.Sub(fromBalance, value.ToBig()) 892 | toBalance.Sub(toBalance, value.ToBig()) 893 | 894 | // just assume it succeeded 895 | stack.Push(*uint256.NewInt(1)) 896 | 897 | return nil 898 | } 899 | 900 | return do_opcall(ctx, 901 | gas, addr, value, inOffset, inSize, retOffset, retSize) 902 | } 903 | 904 | func opCallCode(ctx *Context) error { 905 | return errors.New("TODO opCallCode") 906 | } 907 | 908 | /* 909 | A send tx -> B -> delegatecall(C), in C: 910 | 911 | C.msg == B.msg (msg.sender inside C is A, C has same msg.sender/msg.value as B) 912 | C.storage == B.storage 913 | */ 914 | func opDelegateCall(ctx *Context) error { 915 | stack := ctx.Stack() 916 | gas, addr, inOffset, inSize, retOffset, retSize := 917 | stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() 918 | 919 | _ = gas 920 | 921 | toAddr := common.Address(addr.Bytes20()) 922 | 923 | _, e := ensure_code(ctx, toAddr) // fetch code + disasm for new Contract 924 | if e != nil { 925 | return e 926 | } 927 | 928 | currCall := ctx.Call() 929 | 930 | args := ctx.Memory().GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) 931 | newCall := &Call{ 932 | Msg: Msg{ 933 | Data: args, 934 | Sender: currCall.Msg.Sender, 935 | Value: currCall.Msg.Value, 936 | Gas: currCall.Msg.Gas, 937 | }, 938 | This: currCall.This, // address(this) doesn't change in delegatecall 939 | CodePtr: &toAddr, // `Contract` is required for delegatecall, which used to find the correct disasm code 940 | 941 | OuterReturnOffset: retOffset.Uint64(), 942 | OuterReturnSize: retSize.Uint64(), 943 | } 944 | ctx.CallStack.Push(newCall) 945 | return nil 946 | } 947 | 948 | /* 949 | STATICCALL functions equivalently to a CALL, 950 | except it takes only 6 arguments 951 | (the “value” argument is not included and taken to be zero). 952 | */ 953 | func opStaticCall(ctx *Context) error { 954 | stack := ctx.Stack() 955 | 956 | gas, addr, inOffset, inSize, retOffset, retSize := 957 | stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() 958 | 959 | var value uint256.Int // 0 960 | 961 | return do_opcall(ctx, 962 | gas, addr, value, inOffset, inSize, retOffset, retSize) 963 | } 964 | 965 | func opReturn(ctx *Context) error { 966 | stack := ctx.Stack() 967 | offset, size := stack.Pop(), stack.Pop() 968 | output := ctx.Memory().GetPtr(int64(offset.Uint64()), int64(size.Uint64())) 969 | 970 | call := ctx.Call() 971 | 972 | if ctx.CallStack.Len() > 1 { // returning from inner call, not main call 973 | // popup current call from CallStack 974 | ctx.CallStack.Pop() 975 | 976 | // after pop(), now it points to the outer call 977 | ctx.Call().InnerReturnVal = output 978 | 979 | // copy memory[retOffset:retSize] to the outer Call.Memory 980 | // Note: This copying is supposed to be done in xxCALL operations, 981 | // but we can't do that when single step, so copy it in RETURN 982 | ctx.Memory().Set( 983 | call.OuterReturnOffset, call.OuterReturnSize, output) 984 | 985 | ctx.Stack().Push(*uint256.NewInt(1)) // outerStack 986 | } else { 987 | ctx.IsDone = true 988 | } 989 | 990 | return nil 991 | } 992 | 993 | func opRevert(ctx *Context) error { 994 | stack := ctx.Stack() 995 | offset, size := stack.Pop(), stack.Pop() 996 | ret := ctx.Memory().GetPtr(int64(offset.Uint64()), int64(size.Uint64())) 997 | _ = ret 998 | 999 | //ctx.CurrentCall().ReturnVal = ret 1000 | color.Red(hex.Dump(ret)) 1001 | return errors.New("Reverted") 1002 | } 1003 | func opAssert(ctx *Context) error { 1004 | // stack := ctx.Stack() 1005 | // stack.Pop() 1006 | return errors.New("TODO: opcode Assert") 1007 | } 1008 | 1009 | // return from function with no return value 1010 | func opStop(ctx *Context) error { 1011 | if ctx.CallStack.Len() > 1 { // return from inner call, not main call 1012 | // popup current call from CallStack 1013 | ctx.CallStack.Pop() 1014 | 1015 | ctx.Stack().Push(*uint256.NewInt(1)) 1016 | } else { 1017 | ctx.IsDone = true 1018 | } 1019 | return nil 1020 | } 1021 | 1022 | // SELFDESTRUCT 1023 | func opSuicide(ctx *Context) error { 1024 | beneficiary := ctx.Stack().Pop() 1025 | return fmt.Errorf("opSuicide -> %s", beneficiary.ToBig().String()) 1026 | } 1027 | 1028 | // following functions are used by the instruction jump table 1029 | 1030 | func opChainID(ctx *Context) error { 1031 | ctx.Stack().Push(*uint256.NewInt(ctx.Chain.Id)) 1032 | return nil 1033 | } 1034 | 1035 | // address(this).balance 1036 | func opSelfBalance(ctx *Context) error { 1037 | bal, e := ensure_balance(ctx, ctx.Call().This) 1038 | if e != nil { 1039 | return e 1040 | } 1041 | balance, _ := uint256.FromBig(bal) 1042 | 1043 | ctx.Stack().Push(*balance) 1044 | return nil 1045 | } 1046 | 1047 | func opBaseFee(ctx *Context) error { 1048 | ctx.Stack().Push(*uint256.NewInt(ctx.Block.BaseFee)) 1049 | return nil 1050 | } 1051 | 1052 | // make push instruction function 1053 | func makePush(n uint64) executionFunc { 1054 | return func(ctx *Context) error { 1055 | code := ctx.Code().Binary 1056 | codeLen := uint64(len(code)) 1057 | 1058 | pc := &ctx.Call().Pc 1059 | 1060 | if *pc+1+n > codeLen { 1061 | return errors.New("opPushN not enough data") 1062 | } 1063 | 1064 | integer := new(uint256.Int) 1065 | ctx.Stack().Push(*integer.SetBytes( 1066 | code[*pc+1 : *pc+1+n])) 1067 | 1068 | *pc += n 1069 | return nil 1070 | } 1071 | } 1072 | 1073 | // make dup instruction function 1074 | func makeDup(size int64) executionFunc { 1075 | return func(ctx *Context) error { 1076 | ctx.Stack().Dup(int(size)) 1077 | return nil 1078 | } 1079 | } 1080 | 1081 | // make swap instruction function 1082 | func makeSwap(size int64) executionFunc { 1083 | // switch n + 1 otherwise n would be swapped with n 1084 | size++ 1085 | return func(ctx *Context) error { 1086 | ctx.Stack().Swap(int(size)) 1087 | return nil 1088 | } 1089 | } 1090 | 1091 | func makeLog(size int) executionFunc { 1092 | return func(ctx *Context) error { 1093 | stack := ctx.Stack() 1094 | stack.Pop() 1095 | stack.Pop() 1096 | 1097 | for i := 0; i < size; i++ { 1098 | ctx.Stack().Pop() 1099 | } 1100 | 1101 | return nil 1102 | } 1103 | } 1104 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= 5 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 6 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= 11 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 12 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 13 | cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= 14 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 15 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 16 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 17 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 18 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 19 | collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= 20 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 21 | github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= 22 | github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= 23 | github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= 24 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 25 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 26 | github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 27 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 28 | github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= 29 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 30 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 31 | github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= 32 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 33 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 34 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 35 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 36 | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 37 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 38 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= 39 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 40 | github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= 41 | github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= 42 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 43 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 44 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 45 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 46 | github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= 47 | github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 48 | github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= 49 | github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= 50 | github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= 51 | github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= 52 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= 53 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= 54 | github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= 55 | github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= 56 | github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= 57 | github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= 58 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 59 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 60 | github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= 61 | github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 62 | github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= 63 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 64 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 65 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 66 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 67 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 68 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 69 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 70 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 71 | github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= 72 | github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= 73 | github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= 74 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 75 | github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= 76 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 77 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 78 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 79 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 80 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 81 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 82 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 83 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 84 | github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= 85 | github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= 86 | github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= 87 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 88 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 89 | github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 90 | github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= 91 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 92 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 93 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 94 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 95 | github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= 96 | github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= 97 | github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= 98 | github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= 99 | github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= 100 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 101 | github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= 102 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 103 | github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 104 | github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 105 | github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= 106 | github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= 107 | github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= 108 | github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= 109 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 110 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 111 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 112 | github.com/ethereum/go-ethereum v1.10.12 h1:el/KddB3gLEsnNgGQ3SQuZuiZjwnFTYHe5TwUet5Om4= 113 | github.com/ethereum/go-ethereum v1.10.12/go.mod h1:W3yfrFyL9C1pHcwY5hmRHVDaorTiQxhYBkKyu5mEDHw= 114 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 115 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 116 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 117 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= 118 | github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= 119 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 120 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 121 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 122 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= 123 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= 124 | github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= 125 | github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= 126 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 127 | github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 128 | github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 129 | github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= 130 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 131 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 132 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 133 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 134 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 135 | github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= 136 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= 137 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 138 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 139 | github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= 140 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 141 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 142 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 143 | github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 144 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 145 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 146 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 147 | github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= 148 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 149 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 150 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 151 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 152 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 153 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 154 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 155 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 156 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 157 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 158 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 159 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 160 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 161 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 162 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 163 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 164 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 165 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 166 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 167 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 168 | github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= 169 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 170 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 171 | github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 172 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 173 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 174 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 175 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 176 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 177 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 178 | github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 179 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 180 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 181 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 182 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 183 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 184 | github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= 185 | github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 186 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 187 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 188 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 189 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 190 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 191 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 192 | github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= 193 | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= 194 | github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= 195 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 196 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 197 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= 198 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 199 | github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= 200 | github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= 201 | github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= 202 | github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= 203 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 204 | github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= 205 | github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= 206 | github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= 207 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 208 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 209 | github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= 210 | github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= 211 | github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= 212 | github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= 213 | github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= 214 | github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= 215 | github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= 216 | github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= 217 | github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= 218 | github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= 219 | github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= 220 | github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= 221 | github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= 222 | github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= 223 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 224 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 225 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 226 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 227 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 228 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 229 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 230 | github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= 231 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 232 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 233 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 234 | github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= 235 | github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= 236 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 237 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 238 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 239 | github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 240 | github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 241 | github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= 242 | github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 243 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 244 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 245 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 246 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 247 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 248 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 249 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 250 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 251 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 252 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 253 | github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= 254 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 255 | github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= 256 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 257 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 258 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 259 | github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= 260 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 261 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 262 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 263 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 264 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 265 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= 266 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 267 | github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= 268 | github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= 269 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 270 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 271 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 272 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 273 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 274 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 275 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 276 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 277 | github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 278 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 279 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 280 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 281 | github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= 282 | github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= 283 | github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= 284 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 285 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 286 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 287 | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= 288 | github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= 289 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 290 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 291 | github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= 292 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 293 | github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= 294 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= 295 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 296 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 297 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 298 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 299 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 300 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 301 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 302 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 303 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 304 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 305 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 306 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 307 | github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 308 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 309 | github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= 310 | github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= 311 | github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= 312 | github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 313 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 314 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 315 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 316 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 317 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 318 | github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= 319 | github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= 320 | github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= 321 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 322 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 323 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 324 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 325 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 326 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 327 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 328 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 329 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 330 | github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= 331 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 332 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 333 | github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= 334 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 335 | github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= 336 | github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= 337 | github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= 338 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 339 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= 340 | github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= 341 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 342 | github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 343 | github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= 344 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 345 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= 346 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 347 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 348 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 349 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 350 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 351 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 352 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 353 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 354 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 355 | github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= 356 | github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= 357 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 358 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 359 | github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 360 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 361 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 362 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 363 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 364 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 365 | github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= 366 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 367 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= 368 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= 369 | github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 370 | github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= 371 | github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= 372 | github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= 373 | github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= 374 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= 375 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= 376 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 377 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 378 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 379 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 380 | github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 381 | github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= 382 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 383 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 384 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 385 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 386 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 387 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 388 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 389 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 390 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 391 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 392 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 393 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 394 | golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 395 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 396 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 397 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 398 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 399 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 400 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= 401 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 402 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 403 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 404 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 405 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 406 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 407 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 408 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 409 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 410 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 411 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 412 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 413 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 414 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 415 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 416 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 417 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 418 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 419 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 420 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 421 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 422 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 423 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 424 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 425 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 426 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 427 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 428 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 429 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 430 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 431 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 432 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 433 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 434 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 435 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 436 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 437 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 438 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 439 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 440 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 441 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 442 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 443 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 444 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 445 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 446 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 447 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 448 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 449 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 450 | golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 451 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 452 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 453 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 454 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 455 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 456 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 457 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 458 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 459 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 460 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 461 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 462 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 463 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 464 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 465 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 466 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 467 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 468 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 469 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 470 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 471 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 472 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 473 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 474 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 475 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 476 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 477 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 478 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 479 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 480 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 481 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 482 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 483 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 484 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 485 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 486 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 487 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 488 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 489 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 490 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 491 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 492 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 493 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 494 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 495 | golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 496 | golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 497 | golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 498 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 499 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 500 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 501 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 502 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 503 | golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 504 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 505 | golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 506 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 507 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 508 | golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 509 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= 510 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 511 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 512 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 513 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 514 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 515 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 516 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 517 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 518 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 519 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 520 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 521 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 522 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 523 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 524 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= 525 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 526 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 527 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 528 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 529 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 530 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 531 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 532 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 533 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 534 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 535 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 536 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 537 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 538 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 539 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 540 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 541 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 542 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 543 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 544 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 545 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 546 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 547 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 548 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 549 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 550 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 551 | golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 552 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 553 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 554 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 555 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 556 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 557 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 558 | gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 559 | gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= 560 | gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 561 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 562 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 563 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 564 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 565 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 566 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 567 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 568 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 569 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 570 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 571 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 572 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 573 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 574 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 575 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 576 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 577 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 578 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 579 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 580 | google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 581 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 582 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 583 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 584 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 585 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 586 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 587 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 588 | google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 589 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 590 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 591 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 592 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 593 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 594 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 595 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 596 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 597 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 598 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 599 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 600 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 601 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 602 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 603 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 604 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 605 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 606 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 607 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= 608 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= 609 | gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= 610 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 611 | gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= 612 | gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= 613 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 614 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 615 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 616 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 617 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 618 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 619 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 620 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 621 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 622 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 623 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 624 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 625 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 626 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 627 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 628 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 629 | honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= 630 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 631 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 632 | --------------------------------------------------------------------------------