github.com/mavryk-network/mvgo@v1.19.9/micheline/key.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 "sort" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/mavryk-network/mvgo/mavryk" 17 "golang.org/x/crypto/blake2b" 18 ) 19 20 // Comparable key as used in bigmaps and maps 21 type Key struct { 22 Type Type 23 // TODO: refactor into simple Prim 24 IntKey *big.Int 25 StringKey string 26 BytesKey []byte 27 BoolKey bool 28 AddrKey mavryk.Address 29 KeyKey mavryk.Key 30 SignatureKey mavryk.Signature 31 TimeKey time.Time 32 PrimKey Prim 33 } 34 35 func NewKey(typ Type, key Prim) (Key, error) { 36 k := Key{ 37 Type: typ, 38 } 39 switch typ.OpCode { 40 case T_INT, T_NAT, T_MUMAV: 41 k.IntKey = key.Int 42 case T_STRING: 43 if isASCII(key.String) { 44 k.StringKey = key.String 45 } else { 46 // k.Type.OpCode = T_BYTES 47 key.Bytes = []byte(key.String) 48 } 49 // convert empty and non-ascii strings to bytes 50 if len(k.StringKey) == 0 && len(key.Bytes) > 0 { 51 k.Type.OpCode = T_BYTES 52 k.BytesKey = key.Bytes 53 } 54 case T_BYTES: 55 k.BytesKey = key.Bytes 56 case T_BOOL: 57 switch key.OpCode { 58 case D_TRUE: 59 k.BoolKey = true 60 case D_FALSE: 61 k.BoolKey = false 62 default: 63 return Key{}, fmt.Errorf("micheline: invalid bool big_map key opcode %s (%[1]d)", key.OpCode) 64 } 65 case T_TIMESTAMP: 66 // in some cases (originated contract storage) timestamps are strings 67 if key.Int == nil { 68 t, err := time.Parse(time.RFC3339, key.String) 69 if err != nil { 70 if num, err2 := strconv.ParseInt(key.String, 10, 64); err2 == nil { 71 t = time.Unix(num, 0) 72 } else { 73 return Key{}, fmt.Errorf("micheline: invalid big_map key for string timestamp: %w", err) 74 } 75 } 76 k.TimeKey = t 77 } else { 78 k.TimeKey = time.Unix(key.Int.Int64(), 0).UTC() 79 } 80 case T_KEY_HASH, T_ADDRESS: 81 // in some cases (originated contract storage) addresses are strings 82 if len(key.Bytes) == 0 && len(key.String) > 0 { 83 a, err := mavryk.ParseAddress(strings.Split(key.String, "%")[0]) 84 if err != nil { 85 return Key{}, fmt.Errorf("micheline: invalid big_map key for string type address: %w", err) 86 } 87 k.AddrKey = a 88 } else { 89 a := mavryk.Address{} 90 if err := a.Decode(key.Bytes); err != nil { 91 return Key{}, fmt.Errorf("micheline: invalid big_map key for type address: %w", err) 92 } 93 k.AddrKey = a 94 } 95 case T_KEY: 96 if len(key.Bytes) == 0 && len(key.String) > 0 { 97 kk, err := mavryk.ParseKey(key.String) 98 if err != nil { 99 return Key{}, fmt.Errorf("micheline: invalid big_map key for string type key: %w", err) 100 } 101 k.KeyKey = kk 102 } else { 103 kk := mavryk.Key{} 104 if err := kk.UnmarshalBinary(key.Bytes); err != nil { 105 return Key{}, fmt.Errorf("micheline: invalid big_map key for type key: %w", err) 106 } 107 k.KeyKey = kk 108 } 109 case T_SIGNATURE: 110 if len(key.Bytes) == 0 && len(key.String) > 0 { 111 sk, err := mavryk.ParseSignature(key.String) 112 if err != nil { 113 return Key{}, fmt.Errorf("micheline: invalid big_map key for string type signature: %w", err) 114 } 115 k.SignatureKey = sk 116 } else { 117 sk := mavryk.Signature{} 118 if err := sk.UnmarshalBinary(key.Bytes); err != nil { 119 return Key{}, fmt.Errorf("micheline: invalid big_map key for type signature: %w", err) 120 } 121 k.SignatureKey = sk 122 } 123 case T_PAIR, T_OPTION, T_OR, T_CHAIN_ID, T_UNIT, T_OPERATION: 124 k.PrimKey = key 125 // build type details when missing 126 if len(k.Type.Args) == 0 { 127 k.Type = key.BuildType() 128 } 129 130 default: 131 k.PrimKey = key 132 // build type details when missing 133 if len(k.Type.Args) == 0 { 134 k.Type = key.BuildType() 135 } 136 return k, fmt.Errorf("micheline: big_map key type '%s' is not implemented", typ.OpCode) 137 } 138 return k, nil 139 } 140 141 func NewKeyPtr(typ Type, key Prim) (*Key, error) { 142 k, err := NewKey(typ, key) 143 return &k, err 144 } 145 146 func (k Key) IsPacked() bool { 147 return k.Type.OpCode == T_BYTES && (isPackedBytes(k.BytesKey) || 148 mavryk.IsAddressBytes(k.BytesKey) || 149 isASCIIBytes(k.BytesKey)) 150 } 151 152 func (k Key) UnpackPrim() (p Prim, err error) { 153 return Prim{ 154 Type: PrimBytes, 155 Bytes: k.BytesKey, 156 }.Unpack() 157 } 158 159 func (k Key) Unpack() (Key, error) { 160 if !k.IsPacked() { 161 return k, nil 162 } 163 p, err := k.UnpackPrim() 164 if err != nil { 165 return Key{}, err 166 } 167 return Key{ 168 Type: p.BuildType(), 169 IntKey: p.Int, 170 StringKey: p.String, 171 BytesKey: p.Bytes, 172 PrimKey: p, 173 }, nil 174 } 175 176 func ParseKeyType(typ string) (OpCode, error) { 177 t, err := ParseOpCode(typ) 178 if err != nil { 179 return t, fmt.Errorf("micheline: invalid big_map key type '%s'", typ) 180 } 181 switch t { 182 case T_INT, T_NAT, T_MUMAV, T_STRING, T_BYTES, T_BOOL, 183 T_KEY_HASH, T_TIMESTAMP, T_ADDRESS, T_PAIR, T_KEY, T_SIGNATURE, 184 T_OPTION, T_OR, T_CHAIN_ID, T_UNIT: 185 return t, nil 186 default: 187 return t, fmt.Errorf("micheline: unsupported big_map key type %s", t) 188 } 189 } 190 191 // query string parsing used for lookup 192 func ParseKey(typ OpCode, val string) (Key, error) { 193 key := Key{Type: Type{}} 194 if typ.IsTypeCode() { 195 key.Type.OpCode = typ 196 } else { 197 key.Type.OpCode = InferKeyType(val) 198 } 199 var err error 200 switch key.Type.OpCode { 201 case T_INT, T_NAT, T_MUMAV: 202 key.Type.Type = PrimInt 203 key.IntKey = big.NewInt(0) 204 err = key.IntKey.UnmarshalText([]byte(val)) 205 case T_STRING: 206 key.Type.Type = PrimString 207 key.StringKey = val 208 case T_BYTES: 209 key.Type.Type = PrimBytes 210 key.BytesKey, err = hex.DecodeString(val) 211 case T_BOOL: 212 key.Type.Type = PrimNullary 213 key.BoolKey, err = strconv.ParseBool(val) 214 case T_TIMESTAMP: 215 // either RFC3339 or UNIX seconds 216 key.Type.Type = PrimInt 217 if strings.Contains(val, "T") { 218 key.TimeKey, err = time.Parse(time.RFC3339, val) 219 } else { 220 var i int64 221 i, err = strconv.ParseInt(val, 10, 64) 222 key.TimeKey = time.Unix(i, 0).UTC() 223 } 224 case T_KEY_HASH, T_ADDRESS: 225 key.Type.Type = PrimBytes 226 key.AddrKey, err = mavryk.ParseAddress(val) 227 case T_KEY: 228 key.Type.Type = PrimBytes 229 key.KeyKey, err = mavryk.ParseKey(val) 230 case T_SIGNATURE: 231 key.Type.Type = PrimBytes 232 key.SignatureKey, err = mavryk.ParseSignature(val) 233 case T_PAIR: 234 // parse comma-separated list into a right-hand pair tree 235 prims := []Prim{} 236 for _, v := range strings.Split(val, ",") { 237 parsed, err := ParseKey(InferKeyType(v), v) 238 if err != nil { 239 return Key{}, fmt.Errorf("micheline: decoding bigmap pair key element %s: %w", v, err) 240 } 241 prims = append(prims, parsed.Prim()) 242 } 243 switch len(prims) { 244 case 0: 245 return Key{}, fmt.Errorf("micheline: empty bigmap pair key: %s", val) 246 case 1: 247 return Key{}, fmt.Errorf("micheline: single-value bigmap pair key: %s", val) 248 default: 249 key.PrimKey = NewSeq(prims...).FoldPair() 250 key.Type.Type = PrimBinary 251 } 252 case T_UNIT: 253 if val != D_UNIT.String() { 254 return Key{}, fmt.Errorf("micheline: invalid bigmap pair key for Unit type: %s", val) 255 } 256 key.PrimKey = NewCode(D_UNIT) 257 key.Type.Type = PrimNullary 258 259 default: 260 return Key{}, fmt.Errorf("micheline: unsupported big_map key type %s", typ) 261 } 262 263 if err != nil { 264 return Key{}, fmt.Errorf("micheline: decoding bigmap key %s as %s: %w", val, typ, err) 265 } 266 return key, nil 267 } 268 269 func InferKeyType(val string) OpCode { 270 if val == D_UNIT.String() { 271 return T_UNIT 272 } 273 if _, err := mavryk.ParseAddress(val); err == nil { 274 // Note: can also be KEY_HASH, but used inconsistently 275 return T_ADDRESS 276 } 277 if _, err := mavryk.ParseKey(val); err == nil { 278 return T_KEY 279 } 280 if _, err := mavryk.ParseSignature(val); err == nil { 281 return T_SIGNATURE 282 } 283 if _, err := time.Parse(time.RFC3339, val); err == nil { 284 return T_TIMESTAMP 285 } 286 i := big.NewInt(0) 287 if err := i.UnmarshalText([]byte(val)); err == nil { 288 // can also be T_MUMAV, T_NAT 289 return T_INT 290 } 291 if _, err := hex.DecodeString(val); err == nil { 292 return T_BYTES 293 } 294 if strings.Contains(val, ",") { 295 return T_PAIR 296 } 297 if _, err := strconv.ParseBool(val); err == nil { 298 return T_BOOL 299 } 300 return T_STRING 301 } 302 303 func DecodeKey(typ Type, b []byte) (Key, error) { 304 key := Prim{} 305 if err := key.UnmarshalBinary(b); err != nil { 306 return Key{}, err 307 } 308 return NewKey(typ, key) 309 } 310 311 func (k Key) Bytes() []byte { 312 p := Prim{} 313 switch k.Type.OpCode { 314 case T_INT, T_NAT, T_MUMAV: 315 p.Type = PrimInt 316 p.Int = k.IntKey 317 case T_STRING: 318 p.Type = PrimString 319 p.String = k.StringKey 320 case T_BYTES: 321 p.Type = PrimBytes 322 p.Bytes = k.BytesKey 323 case T_BOOL: 324 p.Type = PrimNullary 325 if k.BoolKey { 326 p.OpCode = D_TRUE 327 } else { 328 p.OpCode = D_FALSE 329 } 330 case T_TIMESTAMP: 331 var z mavryk.Z 332 z.SetInt64(k.TimeKey.Unix()) 333 p.Type = PrimInt 334 p.Int = z.Big() 335 case T_ADDRESS: 336 p.Type = PrimBytes 337 p.Bytes = k.AddrKey.EncodePadded() // 22 byte padded version 338 case T_KEY_HASH: 339 p.Type = PrimBytes 340 p.Bytes = k.AddrKey.Encode() // 21 byte version for implicit accounts 341 case T_KEY: 342 p.Type = PrimBytes 343 p.Bytes, _ = k.KeyKey.MarshalBinary() 344 case T_SIGNATURE: 345 p.Type = PrimBytes 346 p.Bytes, _ = k.SignatureKey.MarshalBinary() 347 default: 348 // anthing else comes from prim tree 349 if !k.PrimKey.IsValid() { 350 return nil 351 } 352 b, _ := k.PrimKey.MarshalBinary() 353 return b 354 } 355 buf, _ := p.MarshalBinary() 356 return buf 357 } 358 359 func (k Key) MarshalBinary() ([]byte, error) { 360 return k.Bytes(), nil 361 } 362 363 func (k Key) Hash() mavryk.ExprHash { 364 return KeyHash(k.Bytes()) 365 } 366 367 func KeyHash(buf []byte) mavryk.ExprHash { 368 // blake2b with digest size 32 byte 369 h, _ := blake2b.New(32, nil) 370 371 // encode with pack byte 372 h.Write([]byte{0x5}) 373 h.Write(buf) 374 375 // wrap in exprhash 376 return mavryk.NewExprHash(h.Sum(nil)) 377 } 378 379 func (k Key) String() string { 380 switch k.Type.OpCode { 381 case T_INT, T_NAT, T_MUMAV: 382 return k.IntKey.Text(10) 383 case T_STRING: 384 return k.StringKey 385 case T_BYTES: 386 return hex.EncodeToString(k.BytesKey) 387 case T_BOOL: 388 return strconv.FormatBool(k.BoolKey) 389 case T_TIMESTAMP: 390 return k.TimeKey.Format(time.RFC3339) 391 case T_KEY_HASH, T_ADDRESS: 392 return k.AddrKey.String() 393 case T_KEY: 394 return k.KeyKey.String() 395 case T_SIGNATURE: 396 return k.SignatureKey.String() 397 case T_PAIR: 398 type lv struct { 399 l string 400 v string 401 } 402 parts := make([]lv, 0) 403 404 val := Value{ 405 Type: k.Type, // real or guessed type tree 406 Value: k.PrimKey, 407 } 408 409 // walk produces a non-deterministic order 410 val.Walk("", func(label string, v interface{}) error { 411 part := lv{l: label} 412 if stringer, ok := v.(fmt.Stringer); ok { 413 part.v = stringer.String() 414 } else { 415 if str, ok := v.(string); ok { 416 part.v = str 417 } else { 418 part.v = fmt.Sprint(v) 419 } 420 } 421 parts = append(parts, part) 422 return nil 423 }) 424 425 // sort by label (works up to 10 pair values) 426 sort.Slice(parts, func(i, j int) bool { return parts[i].l < parts[j].l }) 427 428 var b strings.Builder 429 for i, v := range parts { 430 if i > 0 { 431 b.WriteRune(',') 432 } 433 b.WriteString(v.v) 434 } 435 return b.String() 436 437 // TODO: simpler, but requires value tree decoration 438 // return fmt.Sprint(k.PrimKey.Value(T_PAIR) 439 440 case T_UNIT: 441 return D_UNIT.String() 442 default: 443 if k.PrimKey.IsValid() { 444 return k.PrimKey.OpCode.String() 445 } 446 return "" 447 } 448 } 449 450 func (k Key) Prim() Prim { 451 p := Prim{} 452 switch k.Type.OpCode { 453 case T_INT, T_NAT, T_MUMAV: 454 p.Int = k.IntKey 455 p.Type = PrimInt 456 case T_TIMESTAMP: 457 p.Int = big.NewInt(k.TimeKey.Unix()) 458 p.Type = PrimInt 459 case T_STRING: 460 p.String = k.StringKey 461 p.Type = PrimString 462 case T_BYTES: 463 p.Bytes = k.BytesKey 464 p.Type = PrimBytes 465 case T_ADDRESS: 466 p.Bytes = k.AddrKey.EncodePadded() 467 p.Type = PrimBytes 468 case T_KEY_HASH: 469 p.Bytes = k.AddrKey.Encode() 470 p.Type = PrimBytes 471 case T_KEY: 472 p.Bytes, _ = k.KeyKey.MarshalBinary() 473 p.Type = PrimBytes 474 case T_SIGNATURE: 475 p.Bytes, _ = k.SignatureKey.MarshalBinary() 476 p.Type = PrimBytes 477 case T_BOOL: 478 p.Type = PrimNullary 479 if k.BoolKey { 480 p.OpCode = D_TRUE 481 } else { 482 p.OpCode = D_FALSE 483 } 484 case T_PAIR, T_UNIT: 485 p = k.PrimKey 486 default: 487 if k.PrimKey.IsValid() { 488 p = k.PrimKey 489 break 490 } 491 if k.BytesKey != nil { 492 if err := p.UnmarshalBinary(k.BytesKey); err == nil { 493 break 494 } 495 } 496 p.Bytes = k.Bytes() 497 p.Type = PrimBytes 498 } 499 return p 500 } 501 502 func (k Key) PrimPtr() *Prim { 503 p := k.Prim() 504 return &p 505 } 506 507 func (k Key) MarshalJSON() ([]byte, error) { 508 switch k.Type.OpCode { 509 case T_INT, T_NAT, T_MUMAV: 510 return []byte(strconv.Quote(k.IntKey.Text(10))), nil 511 case T_STRING: 512 return []byte(strconv.Quote(k.StringKey)), nil 513 case T_BYTES: 514 return []byte(strconv.Quote(hex.EncodeToString(k.BytesKey))), nil 515 case T_BOOL: 516 return []byte(strconv.FormatBool(k.BoolKey)), nil 517 case T_TIMESTAMP: 518 if y := k.TimeKey.Year(); y < 0 || y >= 10000 { 519 return []byte(strconv.Quote(strconv.FormatInt(k.TimeKey.Unix(), 10))), nil 520 } 521 return []byte(strconv.Quote(k.TimeKey.Format(time.RFC3339))), nil 522 case T_KEY_HASH, T_ADDRESS: 523 return []byte(strconv.Quote(k.AddrKey.String())), nil 524 case T_KEY: 525 return []byte(strconv.Quote(k.KeyKey.String())), nil 526 case T_SIGNATURE: 527 return []byte(strconv.Quote(k.SignatureKey.String())), nil 528 default: 529 val := &Value{ 530 Type: k.Type, 531 Value: k.PrimKey, 532 } 533 return json.Marshal(val) 534 } 535 }