/
types.go
243 lines (207 loc) · 6.11 KB
/
types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package common
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"github.com/jackc/pgx/v5/pgtype"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
)
// Arbitrary-precision integer. Wrapper around big.Int to allow for
// custom JSON marshaling.
type BigInt struct {
big.Int
}
func NewBigInt(v int64) BigInt {
return BigInt{*big.NewInt(v)}
}
func (b BigInt) Plus(other BigInt) BigInt {
result := big.Int{}
result.Set(&b.Int) // creates a copy of b.Int
result.Add(&result, &other.Int)
return BigInt{result}
}
func (b BigInt) Minus(other BigInt) BigInt {
result := big.Int{}
result.Set(&b.Int) // creates a copy of b.Int
result.Sub(&result, &other.Int)
return BigInt{result}
}
func (b BigInt) Times(other BigInt) BigInt {
result := big.Int{}
result.Set(&b.Int) // creates a copy of b.Int
result.Mul(&result, &other.Int)
return BigInt{result}
}
func (b BigInt) IsZero() bool {
return b.Sign() == 0
}
func (b BigInt) Eq(other BigInt) bool {
return b.Minus(other).IsZero()
}
func (b BigInt) MarshalText() ([]byte, error) {
return b.Int.MarshalText()
}
func (b *BigInt) UnmarshalText(text []byte) error {
return b.Int.UnmarshalText(text)
}
// Used by the `cbor` library.
func (b BigInt) MarshalBinary() ([]byte, error) {
var sign byte = 1
if b.Int.Sign() == -1 {
sign = 255
}
return append([]byte{sign}, b.Bytes()...), nil // big.Int only supports serializing the abs value
}
func (b *BigInt) UnmarshalBinary(data []byte) error {
if len(data) == 0 {
return errors.New("empty data")
}
var inner big.Int
inner.SetBytes(data[1:])
switch data[0] {
case 1:
// do nothing
case 255:
inner.Neg(&inner)
default:
return fmt.Errorf("invalid sign byte: %d", data[0])
}
b.Int = inner
return nil
}
func (b BigInt) MarshalJSON() ([]byte, error) {
t, err := b.MarshalText()
if err != nil {
return nil, err
}
return json.Marshal(string(t))
}
func (b *BigInt) UnmarshalJSON(text []byte) error {
var s string
err := json.Unmarshal(text, &s)
if err != nil {
return err
}
return b.UnmarshalText([]byte(s))
}
func (b BigInt) String() string {
// *big.Int does have a String() method. But the way the Go language
// works, that method on a pointer receiver doesn't get included in
// non-pointer BigInt's method set. In some places this doesn't matter,
// because *big.Int's methods are included in pointer *BigInt's method
// set, and a completely different part of the language set says that
// writing b.String() is fine; it's shorthand for (&b).String(). But
// reflection-driven code like fmt.Printf only looks at method sets and
// not shorthand trickery, so we need this method to make
// fmt.Printf("%v\n", b) show a number instead of dumping the internal
// bytes.
return b.Int.String()
}
func BigIntFromQuantity(q quantity.Quantity) BigInt {
return BigInt{*q.ToBigInt()}
}
// Implement NumericValuer interface for BigInt.
func (b BigInt) NumericValue() (pgtype.Numeric, error) {
return pgtype.Numeric{Int: &b.Int, Exp: 0, NaN: false, Valid: true, InfinityModifier: pgtype.Finite}, nil
}
// Implement NumericDecoder interface for BigInt.
func (b *BigInt) ScanNumeric(n pgtype.Numeric) error {
if !n.Valid {
return fmt.Errorf("NULL values can't be decoded. Scan into a **BigInt to handle NULLs")
}
bigInt, err := NumericToBigInt(n)
*b = bigInt
return err
}
// NumericToBigInt converts a pgtype.Numeric to a BigInt similar to the
// private method found at https://github.com/jackc/pgtype/blob/master/numeric.go#L398
func NumericToBigInt(n pgtype.Numeric) (BigInt, error) {
if n.Exp == 0 {
return BigInt{Int: *n.Int}, nil
}
big0 := big.NewInt(0)
big10 := big.NewInt(10)
bi := &big.Int{}
bi.Set(n.Int)
if n.Exp > 0 {
mul := &big.Int{}
mul.Exp(big10, big.NewInt(int64(n.Exp)), nil)
bi.Mul(bi, mul)
return BigInt{Int: *bi}, nil
}
div := &big.Int{}
div.Exp(big10, big.NewInt(int64(-n.Exp)), nil)
remainder := &big.Int{}
bi.DivMod(bi, div, remainder)
if remainder.Cmp(big0) != 0 {
return BigInt{Int: *big0}, fmt.Errorf("cannot convert %v to integer", n)
}
return BigInt{Int: *big0}, nil
}
func Ptr[T any](v T) *T {
return &v
}
// Returns `v` as a JSON string. If `v` cannot be marshaled,
// returns the string "null" instead.
func TryAsJSON(v interface{}) json.RawMessage {
encoded, err := json.Marshal(v)
if err != nil {
return json.RawMessage("null")
}
return json.RawMessage(encoded)
}
func StringOrNil[T fmt.Stringer](v *T) *string {
if v == nil {
return nil
}
return Ptr((*v).String())
}
// Key used to set values in a web request context. API uses this to set
// values, backend uses this to retrieve values.
type ContextKey string
const (
// RuntimeContextKey is used to set the relevant runtime name
// in a request context.
RuntimeContextKey ContextKey = "runtime"
// RequestIDContextKey is used to set a request id for tracing
// in a request context.
RequestIDContextKey ContextKey = "request_id"
)
var (
// ErrNetworkUnknown is returned if a chain context does not correspond
// to a known network identifier.
ErrNetworkUnknown = errors.New("network unknown")
// ErrRuntimeUnknown is returned if a chain context does not correspond
// to a known runtime identifier.
ErrRuntimeUnknown = errors.New("runtime unknown")
)
// ChainName is a name given to a sequence of networks. Used to index
// config.DefaultChains and sdkConfig.DefaultNetworks.All.
type ChainName string
const (
// ChainNameTestnet is the identifier for testnet.
ChainNameTestnet ChainName = "testnet"
// ChainNameMainnet is the identifier for mainnet.
ChainNameMainnet ChainName = "mainnet"
// ChainNameUnknown is the identifier for an unknown network.
ChainNameUnknown ChainName = "unknown"
)
// Layer is an identifier for either Consensus or a network runtime.
type Layer string
const (
LayerConsensus Layer = "consensus"
LayerEmerald Layer = "emerald"
LayerCipher Layer = "cipher"
LayerSapphire Layer = "sapphire"
LayerPontusx Layer = "pontusx"
)
// Runtime is an identifier for a runtime on the Oasis Network.
type Runtime string
const (
RuntimeEmerald Runtime = "emerald"
RuntimeCipher Runtime = "cipher"
RuntimeSapphire Runtime = "sapphire"
RuntimePontusx Runtime = "pontusx"
)
type CallFormat string