github.com/mavryk-network/mvgo@v1.19.9/rpc/utils.go (about) 1 // Copyright (c) 2020-2022 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package rpc 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "strconv" 11 ) 12 13 // private constants strings 14 var ( 15 null = []byte(`null`) 16 ) 17 18 const CONTRACT = "contract" 19 20 // BlockID is an interface to abstract different kinds of block addressing modes 21 type BlockID interface { 22 fmt.Stringer 23 Int64() int64 24 } 25 26 // BlockLevel is a block addressing mode that uses the blocks sequence number a.k.a level 27 type BlockLevel int64 28 29 func (b BlockLevel) String() string { 30 return strconv.FormatInt(int64(b), 10) 31 } 32 33 func (b BlockLevel) Int64() int64 { 34 return int64(b) 35 } 36 37 // BlockAlias is a block addressing mode that uses a constant string 38 type BlockAlias string 39 40 const ( 41 Genesis BlockAlias = "genesis" 42 Head BlockAlias = "head" 43 ) 44 45 func (b BlockAlias) String() string { 46 return string(b) 47 } 48 49 func (b BlockAlias) Int64() int64 { 50 if b == Genesis { 51 return 0 52 } 53 return -1 54 } 55 56 // BlockOffset is a block addressing mode that uses relative addressing from a given 57 // base block. 58 type BlockOffset struct { 59 Base BlockID 60 Offset int64 61 } 62 63 func NewBlockOffset(id BlockID, n int64) BlockOffset { 64 return BlockOffset{ 65 Base: id, 66 Offset: n, 67 } 68 } 69 70 func (o BlockOffset) String() string { 71 ref := o.Base.String() 72 if o.Offset > 0 { 73 ref += "+" + strconv.FormatInt(o.Offset, 10) 74 } else if o.Offset < 0 { 75 ref += "~" + strconv.FormatInt(-o.Offset, 10) 76 } 77 return ref 78 } 79 80 func (b BlockOffset) Int64() int64 { 81 base := b.Base.Int64() 82 if base >= 0 { 83 return base + b.Offset 84 } 85 return -1 86 } 87 88 func unmarshalMultiTypeJSONArray(data []byte, vals ...interface{}) (err error) { 89 dec := json.NewDecoder(bytes.NewBuffer(data)) 90 91 // read open bracket 92 _, err = dec.Token() 93 if err != nil { 94 return 95 } 96 97 // while the array contains values 98 var i int 99 for dec.More() { 100 if i >= len(vals) { 101 return fmt.Errorf("short JSON data") 102 } 103 err = dec.Decode(vals[i]) 104 if err != nil { 105 return 106 } 107 i++ 108 } 109 110 // read closing bracket 111 _, err = dec.Token() 112 return 113 } 114 115 func marshalMultiTypeJSONArray(vals ...interface{}) (data []byte, err error) { 116 buf := bytes.NewBuffer(nil) 117 enc := json.NewEncoder(buf) 118 buf.WriteByte('[') 119 for i, v := range vals { 120 if i > 0 { 121 buf.WriteByte(',') 122 } 123 err = enc.Encode(v) 124 if err != nil { 125 return 126 } 127 } 128 buf.WriteByte(']') 129 data = buf.Bytes() 130 return 131 } 132 133 type Int64orString int64 134 135 func (i *Int64orString) UnmarshalJSON(data []byte) error { 136 if len(data) == 0 { 137 return nil 138 } 139 if data[0] == '"' { 140 data = data[1 : len(data)-1] 141 } 142 num, err := strconv.ParseInt(string(data), 10, 64) 143 if err != nil { 144 return err 145 } 146 *i = Int64orString(num) 147 return nil 148 } 149 150 func (i Int64orString) MarshalJSON() ([]byte, error) { 151 return []byte(strconv.Quote(i.String())), nil 152 } 153 154 func (i Int64orString) Int64() int64 { 155 return int64(i) 156 } 157 158 func (i Int64orString) Int() int { 159 return int(i) 160 } 161 162 func (i Int64orString) String() string { 163 return strconv.FormatInt(int64(i), 10) 164 }