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  }