-
Notifications
You must be signed in to change notification settings - Fork 79
/
param_type.go
295 lines (270 loc) · 7.15 KB
/
param_type.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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
package smartcontract
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// ParamType represents the Type of the smart contract parameter.
type ParamType int
// A list of supported smart contract parameter types.
const (
UnknownType ParamType = -1
AnyType ParamType = 0x00
BoolType ParamType = 0x10
IntegerType ParamType = 0x11
ByteArrayType ParamType = 0x12
StringType ParamType = 0x13
Hash160Type ParamType = 0x14
Hash256Type ParamType = 0x15
PublicKeyType ParamType = 0x16
SignatureType ParamType = 0x17
ArrayType ParamType = 0x20
MapType ParamType = 0x22
InteropInterfaceType ParamType = 0x30
VoidType ParamType = 0xff
)
// fileBytesParamType is a string representation of `filebytes` parameter type used in cli.
const fileBytesParamType string = "filebytes"
// validParamTypes contains a map of known ParamTypes.
var validParamTypes = map[ParamType]bool{
UnknownType: true,
AnyType: true,
BoolType: true,
IntegerType: true,
ByteArrayType: true,
StringType: true,
Hash160Type: true,
Hash256Type: true,
PublicKeyType: true,
SignatureType: true,
ArrayType: true,
MapType: true,
InteropInterfaceType: true,
VoidType: true,
}
// String implements the stringer interface.
func (pt ParamType) String() string {
switch pt {
case SignatureType:
return "Signature"
case BoolType:
return "Boolean"
case IntegerType:
return "Integer"
case Hash160Type:
return "Hash160"
case Hash256Type:
return "Hash256"
case ByteArrayType:
return "ByteArray"
case PublicKeyType:
return "PublicKey"
case StringType:
return "String"
case ArrayType:
return "Array"
case MapType:
return "Map"
case InteropInterfaceType:
return "InteropInterface"
case VoidType:
return "Void"
case AnyType:
return "Any"
default:
return ""
}
}
// MarshalJSON implements the json.Marshaler interface.
func (pt ParamType) MarshalJSON() ([]byte, error) {
return []byte(`"` + pt.String() + `"`), nil
}
// UnmarshalJSON implements json.Unmarshaler interface.
func (pt *ParamType) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
p, err := ParseParamType(s)
if err != nil {
return err
}
*pt = p
return nil
}
// MarshalYAML implements the YAML Marshaler interface.
func (pt ParamType) MarshalYAML() (interface{}, error) {
return pt.String(), nil
}
// UnmarshalYAML implements the YAML Unmarshaler interface.
func (pt *ParamType) UnmarshalYAML(unmarshal func(interface{}) error) error {
var name string
err := unmarshal(&name)
if err != nil {
return err
}
*pt, err = ParseParamType(name)
return err
}
// EncodeBinary implements io.Serializable interface.
func (pt ParamType) EncodeBinary(w *io.BinWriter) {
w.WriteB(byte(pt))
}
// DecodeBinary implements io.Serializable interface.
func (pt *ParamType) DecodeBinary(r *io.BinReader) {
*pt = ParamType(r.ReadB())
}
// ParseParamType is a user-friendly string to ParamType converter, it's
// case-insensitive and makes the following conversions:
// signature -> SignatureType
// bool, boolean -> BoolType
// int, integer -> IntegerType
// hash160 -> Hash160Type
// hash256 -> Hash256Type
// bytes, bytearray, filebytes -> ByteArrayType
// key, publickey -> PublicKeyType
// string -> StringType
// array, struct -> ArrayType
// map -> MapType
// interopinterface -> InteropInterfaceType
// void -> VoidType
// anything else generates an error.
func ParseParamType(typ string) (ParamType, error) {
switch strings.ToLower(typ) {
case "signature":
return SignatureType, nil
case "bool", "boolean":
return BoolType, nil
case "int", "integer":
return IntegerType, nil
case "hash160":
return Hash160Type, nil
case "hash256":
return Hash256Type, nil
case "bytes", "bytearray", "bytestring", fileBytesParamType:
return ByteArrayType, nil
case "key", "publickey":
return PublicKeyType, nil
case "string":
return StringType, nil
case "array", "struct":
return ArrayType, nil
case "map":
return MapType, nil
case "interopinterface":
return InteropInterfaceType, nil
case "void":
return VoidType, nil
case "any":
return AnyType, nil
default:
return UnknownType, fmt.Errorf("bad parameter type: %s", typ)
}
}
// adjustValToType is a value type-checker and converter.
func adjustValToType(typ ParamType, val string) (interface{}, error) {
switch typ {
case SignatureType:
b, err := hex.DecodeString(val)
if err != nil {
return nil, err
}
if len(b) != 64 {
return nil, errors.New("not a signature")
}
return b, nil
case BoolType:
switch val {
case "true":
return true, nil
case "false":
return false, nil
default:
return nil, errors.New("invalid boolean value")
}
case IntegerType:
return strconv.ParseInt(val, 10, 64)
case Hash160Type:
u, err := address.StringToUint160(val)
if err == nil {
return u, nil
}
u, err = util.Uint160DecodeStringLE(val)
if err != nil {
return nil, err
}
return u, nil
case Hash256Type:
u, err := util.Uint256DecodeStringLE(val)
if err != nil {
return nil, err
}
return u, nil
case ByteArrayType:
return hex.DecodeString(val)
case PublicKeyType:
pub, err := keys.NewPublicKeyFromString(val)
if err != nil {
return nil, err
}
return pub.Bytes(), nil
case StringType:
return val, nil
default:
return nil, errors.New("unsupported parameter type")
}
}
// inferParamType tries to infer the value type from its contents. It returns
// IntegerType for anything that looks like decimal integer (can be converted
// with strconv.Atoi), BoolType for true and false values, Hash160Type for
// addresses and hex strings encoding 20 bytes long values, PublicKeyType for
// valid hex-encoded public keys, Hash256Type for hex-encoded 32 bytes values,
// SignatureType for hex-encoded 64 bytes values, ByteArrayType for any other
// valid hex-encoded values and StringType for anything else.
func inferParamType(val string) ParamType {
var err error
_, err = strconv.Atoi(val)
if err == nil {
return IntegerType
}
if val == "true" || val == "false" {
return BoolType
}
_, err = address.StringToUint160(val)
if err == nil {
return Hash160Type
}
_, err = keys.NewPublicKeyFromString(val)
if err == nil {
return PublicKeyType
}
unhexed, err := hex.DecodeString(val)
if err == nil {
switch len(unhexed) {
case 20:
return Hash160Type
case 32:
return Hash256Type
case 64:
return SignatureType
default:
return ByteArrayType
}
}
// Anything can be a string.
return StringType
}
// ConvertToParamType converts provided value to parameter type if it's a valid type.
func ConvertToParamType(val int) (ParamType, error) {
if validParamTypes[ParamType(val)] {
return ParamType(val), nil
}
return UnknownType, errors.New("unknown parameter type")
}