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  }