github.com/mavryk-network/mvgo@v1.19.9/micheline/type.go (about) 1 // Copyright (c) 2020-2023 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package micheline 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "strconv" 10 "strings" 11 "time" 12 13 "github.com/mavryk-network/mvgo/mavryk" 14 "golang.org/x/exp/slices" 15 ) 16 17 type Type struct { 18 Prim 19 } 20 21 // Extra Types 22 const ( 23 TypeStruct = "struct" 24 TypeUnion = "union" 25 ) 26 27 // Default names 28 const ( 29 CONST_ENTRYPOINT = "@entrypoint" 30 CONST_KEY = "@key" 31 CONST_VALUE = "@value" 32 CONST_ITEM = "@item" 33 CONST_PARAM = "@param" 34 CONST_RETURN = "@return" 35 CONST_UNION_LEFT = "@or_0" 36 CONST_UNION_RIGHT = "@or_1" 37 ) 38 39 type Typedef struct { 40 Name string `json:"name"` // annotation label | @key | @value | @item | @params | @return 41 Type string `json:"type"` // opcode or struct | union 42 Optional bool `json:"optional,omitempty"` // Union only 43 Args []Typedef `json:"args,omitempty"` 44 Path []int `json:"path"` // type tree original path to this element 45 } 46 47 func (a Typedef) IsValid() bool { 48 return a.Name != "" || a.Type != "" || len(a.Args) > 0 49 } 50 51 func (a Typedef) Equal(b Typedef) bool { 52 if a.Type != b.Type { 53 return false 54 } 55 if a.Optional != b.Optional { 56 return false 57 } 58 if len(a.Args) != len(b.Args) { 59 return false 60 } 61 for i, av := range a.Args { 62 if !av.Equal(b.Args[i]) { 63 return false 64 } 65 } 66 return true 67 } 68 69 func (a Typedef) Similar(b Typedef) bool { 70 if a.Optional != b.Optional { 71 return false 72 } 73 if ((a.Type == "list" || a.Type == "set") && len(a.Args) == 0 && b.Type == "map") || 74 ((b.Type == "list" || b.Type == "set") && len(b.Args) == 0 && a.Type == "map") { 75 return true 76 } 77 if a.Type != b.Type && !a.Optional { 78 return false 79 } 80 if len(a.Args) != len(b.Args) && !a.Optional { 81 return false 82 } 83 if len(a.Args) == len(b.Args) { 84 for i, av := range a.Args { 85 if !av.Similar(b.Args[i]) { 86 return false 87 } 88 } 89 } 90 return true 91 } 92 93 func (t Typedef) Unfold() Typedef { 94 b := Typedef{ 95 Name: t.Name, 96 Type: t.Type, 97 Optional: t.Optional, 98 } 99 for _, v := range t.Args { 100 b.Args = append(b.Args, v.unfold()...) 101 } 102 return b 103 } 104 105 func (t Typedef) unfold() []Typedef { 106 switch t.Type { 107 case TypeStruct: 108 // unfold nested structs 109 args := make([]Typedef, 0, len(t.Args)) 110 for _, v := range t.Args { 111 args = append(args, v.unfold()...) 112 } 113 if t.Optional { 114 // keep struct header when optional 115 t.Args = args 116 return []Typedef{t} 117 } else { 118 return args 119 } 120 case TypeUnion: 121 // unfold each arg independently 122 for i, v := range t.Args { 123 args := make([]Typedef, 0, len(v.Args)) 124 for _, vv := range v.Args { 125 args = append(args, vv.unfold()...) 126 } 127 t.Args[i].Args = args 128 } 129 case "list", "set": 130 // unfold nested structs inside list 131 args := make([]Typedef, 0, len(t.Args)) 132 for _, v := range t.Args { 133 args = append(args, v.unfold()...) 134 } 135 t.Args = args 136 case "map": 137 // unfold nested structs inside map key and map value independently 138 if t.Args[0].Name == CONST_KEY && t.Args[0].Type == TypeStruct { 139 t.Args[0].Args = t.Args[0].unfold() 140 } 141 if t.Args[1].Name == CONST_VALUE && t.Args[1].Type == TypeStruct { 142 t.Args[1].Args = t.Args[1].unfold() 143 } 144 case "lambda": 145 // unfold arg and result structs inside independently 146 if len(t.Args) == 2 { 147 if t.Args[0].Name == CONST_PARAM && t.Args[0].Type == TypeStruct { 148 t.Args[0].Args = t.Args[0].unfold() 149 } 150 if t.Args[1].Name == CONST_RETURN && t.Args[1].Type == TypeStruct { 151 t.Args[1].Args = t.Args[1].unfold() 152 } 153 } 154 } 155 return []Typedef{t} 156 } 157 158 func (t Typedef) StrictEqual(v Typedef) bool { 159 if t.Name != v.Name { 160 return false 161 } 162 return t.Equal(v) 163 } 164 165 func (t Typedef) Left() Typedef { 166 if len(t.Args) > 0 { 167 return t.Args[0] 168 } 169 return Typedef{} 170 } 171 172 func (t Typedef) Right() Typedef { 173 if len(t.Args) > 1 { 174 return t.Args[1] 175 } 176 return Typedef{} 177 } 178 179 func (t Typedef) OpCode() OpCode { 180 switch t.Type { 181 case TypeStruct: 182 return T_PAIR 183 case TypeUnion: 184 return T_OR 185 default: 186 oc, _ := ParseOpCode(t.Type) 187 return oc 188 } 189 } 190 191 func (t Typedef) String() string { 192 var b strings.Builder 193 if t.Name != "" { 194 b.WriteString(t.Name) 195 b.WriteString(": ") 196 } 197 if t.Optional { 198 b.WriteByte('?') 199 } 200 switch t.Type { 201 case "map": 202 b.WriteString("map[") 203 n := t.Args[0].Name 204 t.Args[0].Name = "" 205 b.WriteString(t.Args[0].String()) 206 t.Args[0].Name = n 207 b.WriteString("](") 208 n = t.Args[1].Name 209 t.Args[1].Name = "" 210 b.WriteString(t.Args[1].String()) 211 t.Args[1].Name = n 212 b.WriteString(")") 213 case "set", "list": 214 b.WriteByte('[') 215 for i, v := range t.Args { 216 if i > 0 { 217 b.WriteString(", ") 218 } 219 n := v.Name 220 v.Name = "" 221 b.WriteString(v.String()) 222 v.Name = n 223 } 224 b.WriteByte(']') 225 case "struct": 226 b.WriteByte('{') 227 for i, v := range t.Args { 228 if i > 0 { 229 b.WriteString(", ") 230 } 231 b.WriteString(v.String()) 232 } 233 b.WriteByte('}') 234 case "union": 235 b.WriteByte('(') 236 for i, v := range t.Args { 237 if i > 0 { 238 b.WriteString(" | ") 239 } 240 b.WriteString(v.String()) 241 } 242 b.WriteByte(')') 243 case "contract": 244 b.WriteString(t.Type) 245 b.WriteByte('(') 246 for i, v := range t.Args { 247 if i > 0 { 248 b.WriteString(", ") 249 } 250 b.WriteString(v.String()) 251 } 252 b.WriteByte(')') 253 default: 254 b.WriteString(t.Type) 255 if len(t.Args) > 0 { 256 b.WriteByte('(') 257 for i, v := range t.Args { 258 if i > 0 { 259 b.WriteString(", ") 260 } 261 b.WriteString(v.String()) 262 } 263 b.WriteByte(')') 264 } 265 } 266 // if len(t.Path) > 0 { 267 // b.WriteString(" [") 268 // for i, v := range t.Path { 269 // if i > 0 { 270 // b.WriteString(", ") 271 // } 272 // b.WriteString(strconv.Itoa(v)) 273 // } 274 // b.WriteByte(']') 275 // } 276 return b.String() 277 } 278 279 func NewType(p Prim) Type { 280 return Type{p.Clone()} 281 } 282 283 func NewTypePtr(p Prim) *Type { 284 return &Type{p.Clone()} 285 } 286 287 func ParseType(s string) (t Type, err error) { 288 err = t.UnmarshalJSON([]byte(s)) 289 return 290 } 291 292 func MustParseType(s string) (t Type) { 293 if err := t.UnmarshalJSON([]byte(s)); err != nil { 294 panic(err) 295 } 296 return 297 } 298 299 func (t *Type) UnmarshalJSON(buf []byte) error { 300 return t.Prim.UnmarshalJSON(buf) 301 } 302 303 func (t *Type) UnmarshalBinary(buf []byte) error { 304 return t.Prim.UnmarshalBinary(buf) 305 } 306 307 func (t Type) Clone() Type { 308 return Type{t.Prim.Clone()} 309 } 310 311 func (t Type) Label() string { 312 return t.GetVarAnnoAny() 313 } 314 315 func (t Type) HasLabel() bool { 316 return t.HasAnno() 317 } 318 319 func (t Type) IsEqual(t2 Type) bool { 320 return IsEqualPrim(t.Prim, t2.Prim, false) 321 } 322 323 func (t Type) IsEqualWithAnno(t2 Type) bool { 324 return IsEqualPrim(t.Prim, t2.Prim, true) 325 } 326 327 func (t Type) Left() Type { 328 if len(t.Args) > 0 { 329 return Type{t.Args[0]} 330 } 331 return Type{} 332 } 333 334 func (t Type) Right() Type { 335 if len(t.Args) > 1 { 336 return Type{t.Args[1]} 337 } 338 return Type{} 339 } 340 341 func (t Type) Typedef(name string) Typedef { 342 return buildTypedef(name, t.Prim, []int{}) 343 } 344 345 func (t Type) TypedefPtr(name string) *Typedef { 346 td := buildTypedef(name, t.Prim, []int{}) 347 return &td 348 } 349 350 func (t Type) IsSimilar(t2 Type) bool { 351 u1 := t.Typedef("").Unfold() 352 u2 := t2.Typedef("").Unfold() 353 return u1.Similar(u2) 354 } 355 356 func (t Type) MarshalJSON() ([]byte, error) { 357 if !t.IsValid() { 358 return []byte("{}"), nil 359 } 360 return json.Marshal(buildTypedef("", t.Prim, []int{})) 361 } 362 363 func (p Prim) Implements(t Type) bool { 364 td := buildTypedef("", t.Prim, []int{}) 365 return p.ImplementsType(td) 366 } 367 368 func (p Prim) ImplementsType(t Typedef) bool { 369 err := p.Walk(func(p Prim) error { 370 // fmt.Printf("CMP typ=%#v val=%s\n", t, p.Dump()) 371 switch p.OpCode { 372 case D_PAIR: 373 if t.Type == TypeStruct { 374 // fmt.Println("> handle struct") 375 for i, v := range p.UnfoldPair(Type{}) { 376 if i >= len(t.Args) || !v.ImplementsType(t.Args[i]) { 377 // fmt.Println("> BAD struct elem") 378 return ErrTypeMismatch 379 } 380 } 381 return PrimSkip 382 } 383 case D_SOME, D_NONE: 384 if t.Optional { 385 // fmt.Println("> OK optional") 386 return PrimSkip 387 } 388 case D_TRUE, D_FALSE: 389 if t.Type == T_BOOL.String() { 390 // fmt.Println("> OK bool") 391 return PrimSkip 392 } 393 case D_UNIT: 394 if t.Type == T_UNIT.String() { 395 // fmt.Println("> OK unit") 396 return PrimSkip 397 } 398 case D_ELT: 399 if len(t.Args) == 2 && p.Args[0].ImplementsType(t.Args[0]) && p.Args[1].ImplementsType(t.Args[1]) { 400 // fmt.Println("> OK map") 401 return PrimSkip 402 } 403 case D_LEFT: 404 // walk left tree by clipping off right handled types 405 if t.Type == TypeUnion { 406 // fmt.Println("> UNION left") 407 if len(t.Args) == 1 { 408 t = t.Args[0] 409 } else { 410 t.Args = t.Args[:len(t.Args)-1] 411 } 412 if p.Args[0].ImplementsType(t) { 413 // fmt.Println("> OK union left") 414 return PrimSkip 415 } 416 } 417 case D_RIGHT: 418 if t.Type == TypeUnion && p.Args[0].ImplementsType(t.Args[len(t.Args)-1]) { 419 // fmt.Println("> OK union right") 420 return PrimSkip 421 } 422 default: 423 oc, err := ParseOpCode(t.Type) 424 if err != nil { 425 return err 426 } 427 // fmt.Printf("> handle %s in %s prim\n", oc, p.Type) 428 switch p.Type { 429 case PrimSequence: 430 switch oc { 431 case T_MAP: 432 for _, v := range p.Args { 433 if !v.ImplementsType(t) { 434 // fmt.Println("> BAD map elem") 435 return ErrTypeMismatch 436 } 437 } 438 return PrimSkip 439 case T_SET: 440 for _, v := range p.Args { 441 if !v.ImplementsType(t) { 442 // fmt.Println("> BAD set elem") 443 return ErrTypeMismatch 444 } 445 } 446 return PrimSkip 447 case T_LIST: 448 for _, v := range p.Args { 449 if !v.ImplementsType(t.Args[0]) { 450 // fmt.Println("> BAD list elem") 451 return ErrTypeMismatch 452 } 453 } 454 return PrimSkip 455 case T_LAMBDA: 456 if len(p.Args) > 0 && p.Args[0].IsInstruction() { 457 // fmt.Println("> OK lambda") 458 return PrimSkip 459 } 460 } 461 462 case PrimInt: 463 switch oc { 464 case T_INT, T_NAT, T_MUMAV, T_TIMESTAMP, T_BIG_MAP: 465 // fmt.Println("> OK int") 466 return PrimSkip 467 } 468 469 case PrimString: 470 // sometimes timestamps and addresses can be strings 471 switch oc { 472 case T_STRING, T_ADDRESS, T_CONTRACT, T_KEY_HASH, T_KEY, 473 T_SIGNATURE, T_TIMESTAMP, T_CHAIN_ID, T_TX_ROLLUP_L2_ADDRESS: 474 // fmt.Println("> OK string") 475 return PrimSkip 476 } 477 478 case PrimBytes: 479 switch oc { 480 case T_BYTES, T_ADDRESS, T_KEY_HASH, T_KEY, 481 T_CONTRACT, T_SIGNATURE, T_CHAIN_ID, 482 T_BLS12_381_G1, T_BLS12_381_G2, T_BLS12_381_FR, 483 T_CHEST, T_CHEST_KEY, 484 T_TX_ROLLUP_L2_ADDRESS: 485 // fmt.Println("> OK bytes") 486 return PrimSkip 487 } 488 default: 489 // FIXME 490 // T_SAPLING_STATE, T_SAPLING_TRANSACTION, 491 // T_TICKET 492 return PrimSkip 493 494 } 495 } 496 // fmt.Printf("> no case matched\n") 497 return ErrTypeMismatch 498 }) 499 return err == nil 500 } 501 502 func buildTypedef(name string, typ Prim, path []int) Typedef { 503 if typ.HasAnno() { 504 n := typ.GetVarAnnoAny() 505 if n != "" { 506 name = n 507 } 508 } 509 td := Typedef{ 510 Name: name, 511 Type: typ.OpCode.String(), 512 Path: slices.Clone(path), 513 } 514 515 switch typ.OpCode { 516 case T_LIST, T_SET: 517 if len(typ.Args) > 0 { 518 td.Args = []Typedef{ 519 buildTypedef(CONST_ITEM, typ.Args[0], append(path, 0)), 520 } 521 } 522 523 case T_MAP, T_BIG_MAP: 524 td.Args = []Typedef{ 525 buildTypedef(CONST_KEY, typ.Args[0], []int{0}), 526 buildTypedef(CONST_VALUE, typ.Args[1], []int{1}), 527 } 528 529 case T_CONTRACT: 530 td.Args = make([]Typedef, len(typ.Args)) 531 for i, v := range typ.Args { 532 td.Args[i] = buildTypedef(strconv.Itoa(i), v, append(path, i)) 533 } 534 535 case T_TICKET: 536 td.Args = []Typedef{ 537 buildTypedef(CONST_VALUE, typ.Args[0], append(path, 0)), 538 } 539 540 case T_LAMBDA: 541 td.Args = make([]Typedef, len(typ.Args)) 542 if len(typ.Args) > 0 { 543 td.Args[0] = buildTypedef(CONST_PARAM, typ.Args[0], []int{0}) 544 } 545 if len(typ.Args) > 1 { 546 td.Args[1] = buildTypedef(CONST_RETURN, typ.Args[1], []int{1}) 547 } 548 549 case T_PAIR: 550 args := typ.UnfoldTypeRecursive(path) 551 td.Type = TypeStruct 552 td.Args = make([]Typedef, len(args)) 553 for i, v := range args { 554 td.Args[i] = buildTypedef(strconv.Itoa(i), v, v.Path) 555 } 556 557 case T_OPTION: 558 td.Optional = true 559 if len(typ.Args) > 0 { 560 child := buildTypedef(name, typ.Args[0], append(path, 0)) 561 td.Type = child.Type 562 td.Args = child.Args 563 } else { 564 td.Type = "unknown" 565 } 566 567 case T_OR: 568 td.Type = TypeUnion 569 td.Args = make([]Typedef, 0) 570 label := CONST_UNION_LEFT 571 for i, v := range typ.Args { 572 child := buildTypedef(label, v, append(path, i)) 573 if child.Type == TypeUnion { 574 td.Args = append(td.Args, child.Args...) 575 } else { 576 td.Args = append(td.Args, child) 577 } 578 label = CONST_UNION_RIGHT 579 } 580 581 case T_SAPLING_STATE, T_SAPLING_TRANSACTION: 582 td.Type += fmt.Sprintf("(%d)", typ.Args[0].Int.Int64()) 583 584 default: 585 // int 586 // nat 587 // string 588 // bytes 589 // mumav 590 // bool 591 // key_hash 592 // timestamp 593 // address 594 // key 595 // unit 596 // signature 597 // operation 598 // chain_id 599 // unit 600 // bls12_381_g1 601 // bls12_381_g2 602 // bls12_381_fr 603 // sapling_state 604 // sapling_transaction 605 // never 606 return Typedef{ 607 Name: name, 608 Type: typ.OpCode.String(), 609 Path: slices.Clone(path), 610 } 611 } 612 613 return td 614 } 615 616 // build matching type tree for value 617 func (p Prim) BuildType() Type { 618 // Note: don't set WasPacked flag recursively on all children; we set this flag 619 // once on the top level type during dynamic type detection so that comb unfolding 620 // works 621 t := Prim{} 622 // t := Prim{WasPacked: true} 623 if p.OpCode.IsTypeCode() { 624 t.OpCode = p.OpCode 625 } 626 switch p.Type { 627 case PrimInt: 628 t.OpCode = p.Type.TypeCode() 629 t.Type = PrimNullary 630 631 case PrimBytes: 632 t.Type = PrimNullary 633 // detect address encoding first 634 var addr mavryk.Address 635 if err := addr.Decode(p.Bytes); err == nil { 636 if addr.IsRollup() { 637 t.OpCode = T_TX_ROLLUP_L2_ADDRESS 638 } else { 639 t.OpCode = T_ADDRESS 640 } 641 } 642 if t.OpCode == 0 { 643 t.OpCode = p.Type.TypeCode() 644 } 645 646 case PrimString: 647 t.Type = PrimNullary 648 if len(p.String) > 0 { 649 // detect timestamp and address encoding first 650 if _, err := time.Parse(time.RFC3339, p.String); err == nil { 651 t.OpCode = T_TIMESTAMP 652 } else if addr, err := mavryk.ParseAddress(p.String); err == nil { 653 if addr.IsRollup() { 654 t.OpCode = T_TX_ROLLUP_L2_ADDRESS 655 } else { 656 t.OpCode = T_ADDRESS 657 } 658 } else if _, err := mavryk.ParseSignature(p.String); err == nil { 659 t.OpCode = T_SIGNATURE 660 } 661 } 662 // fallback to string 663 if t.OpCode == 0 { 664 t.OpCode = p.Type.TypeCode() 665 } 666 667 case PrimSequence: 668 switch { 669 case p.LooksLikeCode(): 670 t.Type = PrimNullary // we don't know in/out types 671 t.OpCode = T_LAMBDA 672 case p.LooksLikeMap(): 673 t.OpCode = T_MAP 674 t.Type = PrimBinary 675 t.Args = []Prim{ 676 p.Args[0].Args[0].BuildType().Prim, // key type 677 p.Args[0].Args[1].BuildType().Prim, // value type 678 } 679 case p.LooksLikeSet(): 680 t.OpCode = T_SET // guess, can also be LIST 681 t.Type = PrimUnary 682 t.Args = []Prim{ 683 p.Args[0].BuildType().Prim, // single set type 684 } 685 case len(p.Args) == 0: 686 t.OpCode = T_LIST // guess, can be MAP, SET, LIST 687 t.Type = PrimNullary 688 case len(p.Args) == 1: 689 t.OpCode = T_LIST // guess, can be SET, LIST 690 t.Type = PrimUnary 691 t.Args = []Prim{p.Args[0].BuildType().Prim} 692 case len(p.Args) == 2: 693 t.OpCode = T_PAIR 694 t.Type = PrimBinary 695 t.Args = []Prim{ 696 p.Args[0].BuildType().Prim, 697 p.Args[1].BuildType().Prim, 698 } 699 default: 700 // struct 701 t.OpCode = T_PAIR 702 t.Type = PrimVariadicAnno 703 t.Args = make([]Prim, len(p.Args)) 704 for i, v := range p.Args { 705 t.Args[i] = v.BuildType().Prim 706 } 707 } 708 case PrimNullary, PrimNullaryAnno: 709 t.Type = PrimNullary 710 t.OpCode = p.OpCode.TypeCode() 711 case PrimUnary, PrimUnaryAnno: 712 t.OpCode = p.OpCode.TypeCode() 713 switch t.OpCode { 714 case T_LAMBDA: 715 t.Type = PrimNullary 716 case T_OR: 717 // in data we only see one branch, so we have to guess the other type 718 t.Type = PrimBinary 719 inner := p.Args[0].BuildType().Prim 720 t.Args = []Prim{inner, inner} 721 case T_OPTION: 722 // we only know the embedded type on D_SOME 723 if p.OpCode == D_SOME { 724 t.Type = PrimUnary 725 t.Args = []Prim{p.Args[0].BuildType().Prim} 726 } else { 727 t.Type = PrimNullary 728 } 729 case T_BOOL, T_UNIT: 730 t.Type = PrimNullary 731 case T_TICKET: 732 t.Type = PrimUnary 733 t.Args = []Prim{p.Args[0].BuildType().Prim} 734 } 735 case PrimBinary, PrimBinaryAnno: 736 if p.OpCode == D_ELT { 737 t.OpCode = T_MAP 738 t.Type = PrimBinary 739 t.Args = []Prim{ 740 p.Args[0].BuildType().Prim, 741 p.Args[1].BuildType().Prim, 742 } 743 } else { 744 // probably a regular pair 745 t.Type = PrimBinary 746 t.OpCode = p.OpCode.TypeCode() 747 t.Args = []Prim{ 748 p.Args[0].BuildType().Prim, 749 p.Args[1].BuildType().Prim, 750 } 751 } 752 753 case PrimVariadicAnno: 754 // ? probably an operation 755 t.Type = PrimNullary 756 t.OpCode = p.OpCode.TypeCode() 757 } 758 return Type{t} 759 } 760 761 func (p Prim) CanUnfoldType() bool { 762 if p.IsPair() { 763 return true 764 } 765 if p.IsContainerType() || p.LooksLikeCode() { 766 return false 767 } 768 if p.IsSequence() { 769 return true 770 } 771 return false 772 } 773 774 func (p Prim) UnfoldTypeRecursive(path []int) []Prim { 775 flat := make([]Prim, 0) 776 for i, v := range p.Args { 777 v.Path = append(slices.Clone(path), i) 778 if !v.WasPacked && v.CanUnfoldType() && !v.HasAnno() { 779 flat = append(flat, v.UnfoldTypeRecursive(v.Path)...) 780 } else { 781 flat = append(flat, v) 782 } 783 } 784 return flat 785 }