github.com/mavryk-network/mvgo@v1.19.9/micheline/value.go (about) 1 // Copyright (c) 2020-2021 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package micheline 5 6 import ( 7 "encoding/hex" 8 "encoding/json" 9 "fmt" 10 "math/big" 11 "strconv" 12 "time" 13 14 "github.com/mavryk-network/mvgo/mavryk" 15 ) 16 17 const ( 18 EMPTY_LABEL = `@%%@` // illegal Michelson annotation value 19 RENDER_TYPE_PRIM = 0 // silently output primitive tree instead if human-readable 20 RENDER_TYPE_FAIL = 1 // return error if human-readable formatting fails 21 RENDER_TYPE_PANIC = 2 // panic with error if human-readable formatting fails 22 RENDER_TYPE_DEBUG = 3 // return error and primitives 23 ) 24 25 type Value struct { 26 Type Type 27 Value Prim 28 Render int 29 mapped interface{} 30 } 31 32 func NewValue(typ Type, val Prim) Value { 33 return Value{ 34 Type: typ, 35 Value: val, 36 Render: RENDER_TYPE_PRIM, 37 } 38 } 39 40 func NewValuePtr(typ Type, val Prim) *Value { 41 v := NewValue(typ, val) 42 return &v 43 } 44 45 func (v *Value) Decode(buf []byte) error { 46 return v.Value.UnmarshalBinary(buf) 47 } 48 49 func (v Value) IsPacked() bool { 50 return v.Value.IsPacked() 51 } 52 53 func (v Value) IsPackedAny() bool { 54 return v.Value.IsPackedAny() 55 } 56 57 func (v Value) Unpack() (Value, error) { 58 if !v.Value.IsPacked() { 59 return v, nil 60 } 61 up, err := v.Value.Unpack() 62 if err != nil { 63 return v, err 64 } 65 vv := Value{ 66 Type: v.Type.Clone(), 67 Value: up, 68 Render: v.Render, 69 } 70 return vv, nil 71 } 72 73 func (v Value) UnpackAll() (Value, error) { 74 if !v.Value.IsPackedAny() { 75 return v, nil 76 } 77 up, err := v.Value.UnpackAll() 78 if err != nil { 79 return v, err 80 } 81 vv := Value{ 82 Type: v.Type.Clone(), 83 Value: up, 84 Render: v.Render, 85 } 86 return vv, nil 87 } 88 89 func (v Value) UnpackAllAsciiStrings() Value { 90 return Value{ 91 Type: v.Type.Clone(), 92 Value: v.Value.UnpackAllAsciiStrings(), 93 Render: v.Render, 94 } 95 } 96 97 func (e *Value) FixType() { 98 labels := e.Type.Anno 99 e.Type = e.Value.BuildType() 100 e.Type.WasPacked = true 101 e.Type.Anno = labels 102 } 103 104 func (e *Value) Map() (interface{}, error) { 105 if e.mapped != nil { 106 return e.mapped, nil 107 } 108 m := make(map[string]interface{}) 109 if err := walkTree(m, EMPTY_LABEL, e.Type, NewStack(e.Value), 0); err != nil { 110 return nil, err 111 } 112 e.mapped = m 113 114 // lift scalar values 115 if len(m) == 1 { 116 for n, v := range m { 117 if n == "0" { 118 e.mapped = v 119 } 120 } 121 } 122 123 return e.mapped, nil 124 } 125 126 func (e Value) MarshalJSON() ([]byte, error) { 127 m, err := e.Map() 128 if err != nil { 129 switch e.Render { 130 case RENDER_TYPE_PRIM: 131 // render the plain prim tree 132 return json.Marshal(e.Value) 133 case RENDER_TYPE_FAIL: 134 // render the plain prim tree, but fail with render error 135 buf, _ := json.Marshal(e.Value) 136 return buf, err 137 case RENDER_TYPE_PANIC: 138 // panic with render error 139 panic(err) 140 case RENDER_TYPE_DEBUG: 141 // wrap type and value with error 142 type ErrorMessage struct { 143 Message string `json:"message"` 144 Type Prim `json:"type"` 145 Value Prim `json:"value"` 146 } 147 resp := struct { 148 Error ErrorMessage `json:"error"` 149 }{ 150 Error: ErrorMessage{ 151 Message: err.Error(), 152 Type: e.Type.Prim, 153 Value: e.Value, 154 }, 155 } 156 // FIXME: this is a good place to plug in an error reporting facility 157 return json.Marshal(resp) 158 default: 159 return nil, nil 160 } 161 } 162 return json.Marshal(m) 163 } 164 165 func (p Prim) matchOpCode(oc OpCode) bool { 166 mismatch := false 167 switch p.Type { 168 case PrimSequence: 169 switch oc { 170 case T_LIST, T_MAP, T_BIG_MAP, T_SET, T_LAMBDA, T_OR, T_OPTION, T_PAIR, 171 T_SAPLING_STATE, T_TICKET: 172 default: 173 mismatch = true 174 } 175 176 case PrimInt: 177 switch oc { 178 case T_INT, T_NAT, T_MUMAV, T_TIMESTAMP, T_BIG_MAP, T_OR, T_OPTION, T_SAPLING_STATE, 179 T_BLS12_381_G1, T_BLS12_381_G2, T_BLS12_381_FR, // maybe stored as bytes 180 T_TICKET: 181 // accept references to bigmap and sapling states 182 default: 183 mismatch = true 184 } 185 186 case PrimString: 187 // sometimes timestamps and addresses can be strings 188 switch oc { 189 case T_BYTES, T_STRING, T_ADDRESS, T_CONTRACT, T_KEY_HASH, T_KEY, 190 T_SIGNATURE, T_TIMESTAMP, T_OR, T_CHAIN_ID, T_OPTION, 191 T_TICKET, T_TX_ROLLUP_L2_ADDRESS: 192 default: 193 mismatch = true 194 } 195 196 case PrimBytes: 197 switch oc { 198 case T_BYTES, T_STRING, T_BOOL, T_ADDRESS, T_KEY_HASH, T_KEY, 199 T_CONTRACT, T_SIGNATURE, T_OPERATION, T_LAMBDA, T_OR, 200 T_CHAIN_ID, T_OPTION, T_SAPLING_STATE, T_SAPLING_TRANSACTION, 201 T_BLS12_381_G1, T_BLS12_381_G2, T_BLS12_381_FR, // maybe stored as bytes 202 T_TICKET, // allow ticket since first value is ticketer address 203 T_CHEST, T_CHEST_KEY, 204 T_TX_ROLLUP_L2_ADDRESS: 205 default: 206 mismatch = true 207 } 208 209 default: 210 switch p.OpCode { 211 case D_PAIR: 212 switch oc { 213 case T_PAIR, T_OR, T_LIST, T_OPTION, T_TICKET: 214 default: 215 mismatch = true 216 } 217 case D_SOME, D_NONE: 218 switch oc { 219 case T_OPTION: 220 default: 221 mismatch = true 222 } 223 case D_UNIT: 224 switch oc { 225 case T_UNIT, K_PARAMETER: 226 default: 227 mismatch = true 228 } 229 case D_LEFT, D_RIGHT: 230 switch oc { 231 case T_OR: 232 default: 233 mismatch = true 234 } 235 } 236 } 237 238 return !mismatch 239 } 240 241 func (v *Value) GetValue(label string) (interface{}, bool) { 242 if m, err := v.Map(); err == nil { 243 if vv, ok := getPath(m, label); ok { 244 return vv, ok 245 } 246 } 247 return nil, false 248 } 249 250 func (v *Value) GetString(label string) (string, bool) { 251 if m, err := v.Map(); err == nil { 252 if vv, ok := getPath(m, label); ok { 253 if s, ok := vv.(string); ok { 254 return s, true 255 } else { 256 return fmt.Sprint(s), true 257 } 258 } 259 } 260 return "", false 261 } 262 263 func (v *Value) GetBytes(label string) ([]byte, bool) { 264 if m, err := v.Map(); err == nil { 265 if vv, ok := getPath(m, label); ok { 266 // hex string or nil 267 if vv == nil { 268 return nil, ok 269 } 270 if s, ok := vv.(string); ok { 271 h, err := hex.DecodeString(s) 272 if err == nil { 273 return h, true 274 } 275 } 276 } 277 } 278 return nil, false 279 } 280 281 func (v *Value) GetInt64(label string) (int64, bool) { 282 if m, err := v.Map(); err == nil { 283 if vv, ok := getPath(m, label); ok { 284 // big, string or nil 285 if vv == nil { 286 return 0, ok 287 } 288 switch t := vv.(type) { 289 case int: 290 return int64(t), true 291 case int64: 292 return t, true 293 case *big.Int: 294 return t.Int64(), true 295 case mavryk.Z: 296 return t.Int64(), true 297 case string: 298 i, err := strconv.ParseInt(t, 10, 64) 299 if err == nil { 300 return i, true 301 } 302 } 303 } 304 } 305 return 0, false 306 } 307 308 func (v *Value) GetBig(label string) (*big.Int, bool) { 309 if m, err := v.Map(); err == nil { 310 if vv, ok := getPath(m, label); ok { 311 // big, string or nil 312 if vv == nil { 313 return big.NewInt(0), ok 314 } 315 switch t := vv.(type) { 316 case *big.Int: 317 return t, true 318 case mavryk.Z: 319 return t.Big(), true 320 case string: 321 return big.NewInt(0).SetString(t, 10) 322 } 323 } 324 } 325 return nil, false 326 } 327 328 func (v *Value) GetZ(label string) (*mavryk.Z, bool) { 329 if m, err := v.Map(); err == nil { 330 if vv, ok := getPath(m, label); ok { 331 // big, string or nil 332 var z mavryk.Z 333 if vv == nil { 334 return &z, ok 335 } 336 switch t := vv.(type) { 337 case *big.Int: 338 return z.SetBig(t), true 339 case mavryk.Z: 340 return &t, true 341 case string: 342 b, ok := big.NewInt(0).SetString(t, 10) 343 return z.SetBig(b), ok 344 } 345 } 346 } 347 return nil, false 348 } 349 350 func (v *Value) GetBool(label string) (bool, bool) { 351 if m, err := v.Map(); err == nil { 352 if vv, ok := getPath(m, label); ok { 353 // bool, string or nil 354 if vv == nil { 355 return false, ok 356 } 357 switch t := vv.(type) { 358 case bool: 359 return t, true 360 case string: 361 if b, err := strconv.ParseBool(t); err == nil { 362 return b, true 363 } 364 } 365 } 366 } 367 return false, false 368 } 369 370 func (v *Value) GetTime(label string) (time.Time, bool) { 371 if m, err := v.Map(); err == nil { 372 if vv, ok := getPath(m, label); ok { 373 // time, string or nil 374 if vv == nil { 375 return time.Time{}, ok 376 } 377 switch t := vv.(type) { 378 case time.Time: 379 return t, true 380 case string: 381 if b, err := time.Parse(t, time.RFC3339); err == nil { 382 return b, true 383 } 384 } 385 } 386 } 387 return time.Time{}, false 388 } 389 390 func (v *Value) GetAddress(label string) (mavryk.Address, bool) { 391 if m, err := v.Map(); err == nil { 392 if vv, ok := getPath(m, label); ok { 393 // Adddress, string or nil 394 if vv == nil { 395 return mavryk.InvalidAddress, ok 396 } 397 switch t := vv.(type) { 398 case mavryk.Address: 399 return t, true 400 case string: 401 if b, err := mavryk.ParseAddress(t); err == nil { 402 return b, true 403 } 404 } 405 } 406 } 407 return mavryk.InvalidAddress, false 408 } 409 410 func (v *Value) GetKey(label string) (mavryk.Key, bool) { 411 if m, err := v.Map(); err == nil { 412 if vv, ok := getPath(m, label); ok { 413 // Key, string or nil 414 if vv == nil { 415 return mavryk.InvalidKey, ok 416 } 417 switch t := vv.(type) { 418 case mavryk.Key: 419 return t, true 420 case string: 421 if b, err := mavryk.ParseKey(t); err == nil { 422 return b, true 423 } 424 } 425 } 426 } 427 return mavryk.InvalidKey, false 428 } 429 430 func (v *Value) GetSignature(label string) (mavryk.Signature, bool) { 431 if m, err := v.Map(); err == nil { 432 if vv, ok := getPath(m, label); ok { 433 // Signature, string or nil 434 if vv == nil { 435 return mavryk.InvalidSignature, ok 436 } 437 switch t := vv.(type) { 438 case mavryk.Signature: 439 return t, true 440 case string: 441 if b, err := mavryk.ParseSignature(t); err == nil { 442 return b, true 443 } 444 } 445 } 446 } 447 return mavryk.InvalidSignature, false 448 } 449 450 func (v *Value) Unmarshal(val interface{}) error { 451 if m, err := v.Map(); err == nil { 452 buf, _ := json.Marshal(m) 453 return json.Unmarshal(buf, val) 454 } else { 455 return err 456 } 457 } 458 459 type ValueWalkerFunc func(label string, value interface{}) error 460 461 func (v *Value) Walk(label string, fn ValueWalkerFunc) error { 462 val, ok := v.GetValue(label) 463 if !ok { 464 return nil 465 } 466 return walkValueMap(label, val, fn) 467 }