github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/transaction/witness_condition.go (about)

     1  package transaction
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"math/big"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
     9  	"github.com/nspcc-dev/neo-go/pkg/io"
    10  	"github.com/nspcc-dev/neo-go/pkg/util"
    11  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    12  )
    13  
    14  //go:generate stringer -type=WitnessConditionType -linecomment
    15  
    16  // WitnessConditionType encodes a type of witness condition.
    17  type WitnessConditionType byte
    18  
    19  const (
    20  	// WitnessBoolean is a generic boolean condition.
    21  	WitnessBoolean WitnessConditionType = 0x00 // Boolean
    22  	// WitnessNot reverses another condition.
    23  	WitnessNot WitnessConditionType = 0x01 // Not
    24  	// WitnessAnd means that all conditions must be met.
    25  	WitnessAnd WitnessConditionType = 0x02 // And
    26  	// WitnessOr means that any of conditions must be met.
    27  	WitnessOr WitnessConditionType = 0x03 // Or
    28  	// WitnessScriptHash matches executing contract's script hash.
    29  	WitnessScriptHash WitnessConditionType = 0x18 // ScriptHash
    30  	// WitnessGroup matches executing contract's group key.
    31  	WitnessGroup WitnessConditionType = 0x19 // Group
    32  	// WitnessCalledByEntry matches when current script is an entry script or is called by an entry script.
    33  	WitnessCalledByEntry WitnessConditionType = 0x20 // CalledByEntry
    34  	// WitnessCalledByContract matches when current script is called by the specified contract.
    35  	WitnessCalledByContract WitnessConditionType = 0x28 // CalledByContract
    36  	// WitnessCalledByGroup matches when current script is called by contract belonging to the specified group.
    37  	WitnessCalledByGroup WitnessConditionType = 0x29 // CalledByGroup
    38  
    39  	// MaxConditionNesting limits the maximum allowed level of condition nesting.
    40  	MaxConditionNesting = 2
    41  )
    42  
    43  // WitnessCondition is a condition of WitnessRule.
    44  type WitnessCondition interface {
    45  	// Type returns a type of this condition.
    46  	Type() WitnessConditionType
    47  	// Match checks whether this condition matches current context.
    48  	Match(MatchContext) (bool, error)
    49  	// EncodeBinary allows to serialize condition to its binary
    50  	// representation (including type data).
    51  	EncodeBinary(*io.BinWriter)
    52  	// DecodeBinarySpecific decodes type-specific binary data from the given
    53  	// reader (not including type data).
    54  	DecodeBinarySpecific(*io.BinReader, int)
    55  	// ToStackItem converts WitnessCondition to stackitem.Item.
    56  	ToStackItem() stackitem.Item
    57  	// Copy returns a deep copy of the condition.
    58  	Copy() WitnessCondition
    59  
    60  	json.Marshaler
    61  }
    62  
    63  // MatchContext is a set of methods from execution engine needed to perform the
    64  // witness check.
    65  type MatchContext interface {
    66  	GetCallingScriptHash() util.Uint160
    67  	GetCurrentScriptHash() util.Uint160
    68  	CallingScriptHasGroup(*keys.PublicKey) (bool, error)
    69  	CurrentScriptHasGroup(*keys.PublicKey) (bool, error)
    70  	IsCalledByEntry() bool
    71  }
    72  
    73  type (
    74  	// ConditionBoolean is a boolean condition type.
    75  	ConditionBoolean bool
    76  	// ConditionNot inverses the meaning of contained condition.
    77  	ConditionNot struct {
    78  		Condition WitnessCondition
    79  	}
    80  	// ConditionAnd is a set of conditions required to match.
    81  	ConditionAnd []WitnessCondition
    82  	// ConditionOr is a set of conditions one of which is required to match.
    83  	ConditionOr []WitnessCondition
    84  	// ConditionScriptHash is a condition matching executing script hash.
    85  	ConditionScriptHash util.Uint160
    86  	// ConditionGroup is a condition matching executing script group.
    87  	ConditionGroup keys.PublicKey
    88  	// ConditionCalledByEntry is a condition matching entry script or one directly called by it.
    89  	ConditionCalledByEntry struct{}
    90  	// ConditionCalledByContract is a condition matching calling script hash.
    91  	ConditionCalledByContract util.Uint160
    92  	// ConditionCalledByGroup is a condition matching calling script group.
    93  	ConditionCalledByGroup keys.PublicKey
    94  )
    95  
    96  // conditionAux is used for JSON marshaling/unmarshaling.
    97  type conditionAux struct {
    98  	Expression  json.RawMessage   `json:"expression,omitempty"` // Can be either boolean or conditionAux.
    99  	Expressions []json.RawMessage `json:"expressions,omitempty"`
   100  	Group       *keys.PublicKey   `json:"group,omitempty"`
   101  	Hash        *util.Uint160     `json:"hash,omitempty"`
   102  	Type        string            `json:"type"`
   103  }
   104  
   105  // Type implements the WitnessCondition interface and returns condition type.
   106  func (c *ConditionBoolean) Type() WitnessConditionType {
   107  	return WitnessBoolean
   108  }
   109  
   110  // Match implements the WitnessCondition interface checking whether this condition
   111  // matches given context.
   112  func (c *ConditionBoolean) Match(_ MatchContext) (bool, error) {
   113  	return bool(*c), nil
   114  }
   115  
   116  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   117  func (c *ConditionBoolean) EncodeBinary(w *io.BinWriter) {
   118  	w.WriteB(byte(c.Type()))
   119  	w.WriteBool(bool(*c))
   120  }
   121  
   122  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   123  // deserialize condition-specific data.
   124  func (c *ConditionBoolean) DecodeBinarySpecific(r *io.BinReader, maxDepth int) {
   125  	*c = ConditionBoolean(r.ReadBool())
   126  }
   127  
   128  // MarshalJSON implements the json.Marshaler interface.
   129  func (c *ConditionBoolean) MarshalJSON() ([]byte, error) {
   130  	boolJSON, _ := json.Marshal(bool(*c)) // Simple boolean can't fail.
   131  	aux := conditionAux{
   132  		Type:       c.Type().String(),
   133  		Expression: json.RawMessage(boolJSON),
   134  	}
   135  	return json.Marshal(aux)
   136  }
   137  
   138  // ToStackItem implements WitnessCondition interface allowing to convert
   139  // to stackitem.Item.
   140  func (c *ConditionBoolean) ToStackItem() stackitem.Item {
   141  	return condToStackItem(c.Type(), bool(*c))
   142  }
   143  
   144  // Copy returns a deep copy of the condition.
   145  func (c *ConditionBoolean) Copy() WitnessCondition {
   146  	cc := *c
   147  	return &cc
   148  }
   149  
   150  // Type implements the WitnessCondition interface and returns condition type.
   151  func (c *ConditionNot) Type() WitnessConditionType {
   152  	return WitnessNot
   153  }
   154  
   155  // Match implements the WitnessCondition interface checking whether this condition
   156  // matches given context.
   157  func (c *ConditionNot) Match(ctx MatchContext) (bool, error) {
   158  	res, err := c.Condition.Match(ctx)
   159  	return ((err == nil) && !res), err
   160  }
   161  
   162  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   163  func (c *ConditionNot) EncodeBinary(w *io.BinWriter) {
   164  	w.WriteB(byte(c.Type()))
   165  	c.Condition.EncodeBinary(w)
   166  }
   167  
   168  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   169  // deserialize condition-specific data.
   170  func (c *ConditionNot) DecodeBinarySpecific(r *io.BinReader, maxDepth int) {
   171  	c.Condition = decodeBinaryCondition(r, maxDepth-1)
   172  }
   173  
   174  // MarshalJSON implements the json.Marshaler interface.
   175  func (c *ConditionNot) MarshalJSON() ([]byte, error) {
   176  	condJSON, err := json.Marshal(c.Condition)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	aux := conditionAux{
   181  		Type:       c.Type().String(),
   182  		Expression: json.RawMessage(condJSON),
   183  	}
   184  	return json.Marshal(aux)
   185  }
   186  
   187  // ToStackItem implements the WitnessCondition interface allowing to convert
   188  // to stackitem.Item.
   189  func (c *ConditionNot) ToStackItem() stackitem.Item {
   190  	return condToStackItem(c.Type(), c.Condition)
   191  }
   192  
   193  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   194  func (c *ConditionNot) Copy() WitnessCondition {
   195  	cp := *c
   196  	return &cp
   197  }
   198  
   199  // Type implements the WitnessCondition interface and returns condition type.
   200  func (c *ConditionAnd) Type() WitnessConditionType {
   201  	return WitnessAnd
   202  }
   203  
   204  // Match implements the WitnessCondition interface checking whether this condition
   205  // matches given context.
   206  func (c *ConditionAnd) Match(ctx MatchContext) (bool, error) {
   207  	for _, cond := range *c {
   208  		res, err := cond.Match(ctx)
   209  		if err != nil {
   210  			return false, err
   211  		}
   212  		if !res {
   213  			return false, nil
   214  		}
   215  	}
   216  	return true, nil
   217  }
   218  
   219  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   220  func (c *ConditionAnd) EncodeBinary(w *io.BinWriter) {
   221  	w.WriteB(byte(c.Type()))
   222  	w.WriteArray([]WitnessCondition(*c))
   223  }
   224  
   225  func readArrayOfConditions(r *io.BinReader, maxDepth int) []WitnessCondition {
   226  	l := r.ReadVarUint()
   227  	if l == 0 {
   228  		r.Err = errors.New("empty array of conditions")
   229  		return nil
   230  	}
   231  	if l > maxSubitems {
   232  		r.Err = errors.New("too many elements")
   233  		return nil
   234  	}
   235  	a := make([]WitnessCondition, l)
   236  	for i := 0; i < int(l); i++ {
   237  		a[i] = decodeBinaryCondition(r, maxDepth-1)
   238  	}
   239  	if r.Err != nil {
   240  		return nil
   241  	}
   242  	return a
   243  }
   244  
   245  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   246  // deserialize condition-specific data.
   247  func (c *ConditionAnd) DecodeBinarySpecific(r *io.BinReader, maxDepth int) {
   248  	a := readArrayOfConditions(r, maxDepth)
   249  	if r.Err == nil {
   250  		*c = a
   251  	}
   252  }
   253  
   254  func arrayToJSON(c WitnessCondition, a []WitnessCondition) ([]byte, error) {
   255  	exprs := make([]json.RawMessage, len(a))
   256  	for i := 0; i < len(a); i++ {
   257  		b, err := a[i].MarshalJSON()
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  		exprs[i] = json.RawMessage(b)
   262  	}
   263  	aux := conditionAux{
   264  		Type:        c.Type().String(),
   265  		Expressions: exprs,
   266  	}
   267  	return json.Marshal(aux)
   268  }
   269  
   270  // MarshalJSON implements the json.Marshaler interface.
   271  func (c *ConditionAnd) MarshalJSON() ([]byte, error) {
   272  	return arrayToJSON(c, []WitnessCondition(*c))
   273  }
   274  
   275  // ToStackItem implements the WitnessCondition interface allowing to convert
   276  // to stackitem.Item.
   277  func (c *ConditionAnd) ToStackItem() stackitem.Item {
   278  	return condToStackItem(c.Type(), []WitnessCondition(*c))
   279  }
   280  
   281  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   282  func (c *ConditionAnd) Copy() WitnessCondition {
   283  	cp := make(ConditionAnd, len(*c))
   284  	for i, cond := range *c {
   285  		cp[i] = cond.Copy()
   286  	}
   287  	return &cp
   288  }
   289  
   290  // Type implements the WitnessCondition interface and returns condition type.
   291  func (c *ConditionOr) Type() WitnessConditionType {
   292  	return WitnessOr
   293  }
   294  
   295  // Match implements the WitnessCondition interface checking whether this condition
   296  // matches given context.
   297  func (c *ConditionOr) Match(ctx MatchContext) (bool, error) {
   298  	for _, cond := range *c {
   299  		res, err := cond.Match(ctx)
   300  		if err != nil {
   301  			return false, err
   302  		}
   303  		if res {
   304  			return true, nil
   305  		}
   306  	}
   307  	return false, nil
   308  }
   309  
   310  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   311  func (c *ConditionOr) EncodeBinary(w *io.BinWriter) {
   312  	w.WriteB(byte(c.Type()))
   313  	w.WriteArray([]WitnessCondition(*c))
   314  }
   315  
   316  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   317  // deserialize condition-specific data.
   318  func (c *ConditionOr) DecodeBinarySpecific(r *io.BinReader, maxDepth int) {
   319  	a := readArrayOfConditions(r, maxDepth)
   320  	if r.Err == nil {
   321  		*c = a
   322  	}
   323  }
   324  
   325  // MarshalJSON implements the json.Marshaler interface.
   326  func (c *ConditionOr) MarshalJSON() ([]byte, error) {
   327  	return arrayToJSON(c, []WitnessCondition(*c))
   328  }
   329  
   330  // ToStackItem implements the WitnessCondition interface allowing to convert
   331  // to stackitem.Item.
   332  func (c *ConditionOr) ToStackItem() stackitem.Item {
   333  	return condToStackItem(c.Type(), []WitnessCondition(*c))
   334  }
   335  
   336  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   337  func (c *ConditionOr) Copy() WitnessCondition {
   338  	cp := make(ConditionOr, len(*c))
   339  	for i, cond := range *c {
   340  		cp[i] = cond.Copy()
   341  	}
   342  	return &cp
   343  }
   344  
   345  // Type implements the WitnessCondition interface and returns condition type.
   346  func (c *ConditionScriptHash) Type() WitnessConditionType {
   347  	return WitnessScriptHash
   348  }
   349  
   350  // Match implements the WitnessCondition interface checking whether this condition
   351  // matches given context.
   352  func (c *ConditionScriptHash) Match(ctx MatchContext) (bool, error) {
   353  	return util.Uint160(*c).Equals(ctx.GetCurrentScriptHash()), nil
   354  }
   355  
   356  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   357  func (c *ConditionScriptHash) EncodeBinary(w *io.BinWriter) {
   358  	w.WriteB(byte(c.Type()))
   359  	w.WriteBytes(c[:])
   360  }
   361  
   362  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   363  // deserialize condition-specific data.
   364  func (c *ConditionScriptHash) DecodeBinarySpecific(r *io.BinReader, _ int) {
   365  	r.ReadBytes(c[:])
   366  }
   367  
   368  // MarshalJSON implements the json.Marshaler interface.
   369  func (c *ConditionScriptHash) MarshalJSON() ([]byte, error) {
   370  	aux := conditionAux{
   371  		Type: c.Type().String(),
   372  		Hash: (*util.Uint160)(c),
   373  	}
   374  	return json.Marshal(aux)
   375  }
   376  
   377  // ToStackItem implements the WitnessCondition interface allowing to convert
   378  // to stackitem.Item.
   379  func (c *ConditionScriptHash) ToStackItem() stackitem.Item {
   380  	return condToStackItem(c.Type(), util.Uint160(*c))
   381  }
   382  
   383  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   384  func (c *ConditionScriptHash) Copy() WitnessCondition {
   385  	cc := *c
   386  	return &cc
   387  }
   388  
   389  // Type implements the WitnessCondition interface and returns condition type.
   390  func (c *ConditionGroup) Type() WitnessConditionType {
   391  	return WitnessGroup
   392  }
   393  
   394  // Match implements the WitnessCondition interface checking whether this condition
   395  // matches given context.
   396  func (c *ConditionGroup) Match(ctx MatchContext) (bool, error) {
   397  	return ctx.CurrentScriptHasGroup((*keys.PublicKey)(c))
   398  }
   399  
   400  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   401  func (c *ConditionGroup) EncodeBinary(w *io.BinWriter) {
   402  	w.WriteB(byte(c.Type()))
   403  	(*keys.PublicKey)(c).EncodeBinary(w)
   404  }
   405  
   406  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   407  // deserialize condition-specific data.
   408  func (c *ConditionGroup) DecodeBinarySpecific(r *io.BinReader, _ int) {
   409  	(*keys.PublicKey)(c).DecodeBinary(r)
   410  }
   411  
   412  // MarshalJSON implements the json.Marshaler interface.
   413  func (c *ConditionGroup) MarshalJSON() ([]byte, error) {
   414  	aux := conditionAux{
   415  		Type:  c.Type().String(),
   416  		Group: (*keys.PublicKey)(c),
   417  	}
   418  	return json.Marshal(aux)
   419  }
   420  
   421  // ToStackItem implements the WitnessCondition interface allowing to convert
   422  // to stackitem.Item.
   423  func (c *ConditionGroup) ToStackItem() stackitem.Item {
   424  	return condToStackItem(c.Type(), keys.PublicKey(*c))
   425  }
   426  
   427  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   428  func (c *ConditionGroup) Copy() WitnessCondition {
   429  	cp := *c
   430  	return &cp
   431  }
   432  
   433  // Type implements the WitnessCondition interface and returns condition type.
   434  func (c ConditionCalledByEntry) Type() WitnessConditionType {
   435  	return WitnessCalledByEntry
   436  }
   437  
   438  // Match implements the WitnessCondition interface checking whether this condition
   439  // matches given context.
   440  func (c ConditionCalledByEntry) Match(ctx MatchContext) (bool, error) {
   441  	return ctx.IsCalledByEntry(), nil
   442  }
   443  
   444  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   445  func (c ConditionCalledByEntry) EncodeBinary(w *io.BinWriter) {
   446  	w.WriteB(byte(c.Type()))
   447  }
   448  
   449  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   450  // deserialize condition-specific data.
   451  func (c ConditionCalledByEntry) DecodeBinarySpecific(_ *io.BinReader, _ int) {
   452  }
   453  
   454  // MarshalJSON implements the json.Marshaler interface.
   455  func (c ConditionCalledByEntry) MarshalJSON() ([]byte, error) {
   456  	aux := conditionAux{
   457  		Type: c.Type().String(),
   458  	}
   459  	return json.Marshal(aux)
   460  }
   461  
   462  // ToStackItem implements the WitnessCondition interface allowing to convert
   463  // to stackitem.Item.
   464  func (c ConditionCalledByEntry) ToStackItem() stackitem.Item {
   465  	return condToStackItem(c.Type(), nil)
   466  }
   467  
   468  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   469  func (c ConditionCalledByEntry) Copy() WitnessCondition {
   470  	return ConditionCalledByEntry{}
   471  }
   472  
   473  // Type implements the WitnessCondition interface and returns condition type.
   474  func (c *ConditionCalledByContract) Type() WitnessConditionType {
   475  	return WitnessCalledByContract
   476  }
   477  
   478  // Match implements the WitnessCondition interface checking whether this condition
   479  // matches given context.
   480  func (c *ConditionCalledByContract) Match(ctx MatchContext) (bool, error) {
   481  	return util.Uint160(*c).Equals(ctx.GetCallingScriptHash()), nil
   482  }
   483  
   484  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   485  func (c *ConditionCalledByContract) EncodeBinary(w *io.BinWriter) {
   486  	w.WriteB(byte(c.Type()))
   487  	w.WriteBytes(c[:])
   488  }
   489  
   490  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   491  // deserialize condition-specific data.
   492  func (c *ConditionCalledByContract) DecodeBinarySpecific(r *io.BinReader, _ int) {
   493  	r.ReadBytes(c[:])
   494  }
   495  
   496  // MarshalJSON implements the json.Marshaler interface.
   497  func (c *ConditionCalledByContract) MarshalJSON() ([]byte, error) {
   498  	aux := conditionAux{
   499  		Type: c.Type().String(),
   500  		Hash: (*util.Uint160)(c),
   501  	}
   502  	return json.Marshal(aux)
   503  }
   504  
   505  // ToStackItem implements the WitnessCondition interface allowing to convert
   506  // to stackitem.Item.
   507  func (c *ConditionCalledByContract) ToStackItem() stackitem.Item {
   508  	return condToStackItem(c.Type(), util.Uint160(*c))
   509  }
   510  
   511  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   512  func (c *ConditionCalledByContract) Copy() WitnessCondition {
   513  	cc := *c
   514  	return &cc
   515  }
   516  
   517  // Type implements the WitnessCondition interface and returns condition type.
   518  func (c *ConditionCalledByGroup) Type() WitnessConditionType {
   519  	return WitnessCalledByGroup
   520  }
   521  
   522  // Match implements the WitnessCondition interface checking whether this condition
   523  // matches given context.
   524  func (c *ConditionCalledByGroup) Match(ctx MatchContext) (bool, error) {
   525  	return ctx.CallingScriptHasGroup((*keys.PublicKey)(c))
   526  }
   527  
   528  // EncodeBinary implements the WitnessCondition interface allowing to serialize condition.
   529  func (c *ConditionCalledByGroup) EncodeBinary(w *io.BinWriter) {
   530  	w.WriteB(byte(c.Type()))
   531  	(*keys.PublicKey)(c).EncodeBinary(w)
   532  }
   533  
   534  // DecodeBinarySpecific implements the WitnessCondition interface allowing to
   535  // deserialize condition-specific data.
   536  func (c *ConditionCalledByGroup) DecodeBinarySpecific(r *io.BinReader, _ int) {
   537  	(*keys.PublicKey)(c).DecodeBinary(r)
   538  }
   539  
   540  // MarshalJSON implements the json.Marshaler interface.
   541  func (c *ConditionCalledByGroup) MarshalJSON() ([]byte, error) {
   542  	aux := conditionAux{
   543  		Type:  c.Type().String(),
   544  		Group: (*keys.PublicKey)(c),
   545  	}
   546  	return json.Marshal(aux)
   547  }
   548  
   549  // ToStackItem implements WitnessCondition interface allowing to convert
   550  // to stackitem.Item.
   551  func (c *ConditionCalledByGroup) ToStackItem() stackitem.Item {
   552  	return condToStackItem(c.Type(), keys.PublicKey(*c))
   553  }
   554  
   555  // Copy implements the WitnessCondition interface and returns a deep copy of the condition.
   556  func (c *ConditionCalledByGroup) Copy() WitnessCondition {
   557  	cp := *c
   558  	return &cp
   559  }
   560  
   561  // DecodeBinaryCondition decodes and returns condition from the given binary stream.
   562  func DecodeBinaryCondition(r *io.BinReader) WitnessCondition {
   563  	return decodeBinaryCondition(r, MaxConditionNesting)
   564  }
   565  
   566  func decodeBinaryCondition(r *io.BinReader, maxDepth int) WitnessCondition {
   567  	if maxDepth <= 0 {
   568  		r.Err = errors.New("too many nesting levels")
   569  		return nil
   570  	}
   571  	t := WitnessConditionType(r.ReadB())
   572  	if r.Err != nil {
   573  		return nil
   574  	}
   575  	var res WitnessCondition
   576  	switch t {
   577  	case WitnessBoolean:
   578  		var v ConditionBoolean
   579  		res = &v
   580  	case WitnessNot:
   581  		res = &ConditionNot{}
   582  	case WitnessAnd:
   583  		res = &ConditionAnd{}
   584  	case WitnessOr:
   585  		res = &ConditionOr{}
   586  	case WitnessScriptHash:
   587  		res = &ConditionScriptHash{}
   588  	case WitnessGroup:
   589  		res = &ConditionGroup{}
   590  	case WitnessCalledByEntry:
   591  		res = ConditionCalledByEntry{}
   592  	case WitnessCalledByContract:
   593  		res = &ConditionCalledByContract{}
   594  	case WitnessCalledByGroup:
   595  		res = &ConditionCalledByGroup{}
   596  	default:
   597  		r.Err = errors.New("invalid condition type")
   598  		return nil
   599  	}
   600  	res.DecodeBinarySpecific(r, maxDepth)
   601  	if r.Err != nil {
   602  		return nil
   603  	}
   604  	return res
   605  }
   606  
   607  func unmarshalArrayOfConditionJSONs(arr []json.RawMessage, maxDepth int) ([]WitnessCondition, error) {
   608  	l := len(arr)
   609  	if l == 0 {
   610  		return nil, errors.New("empty array of conditions")
   611  	}
   612  	if l > maxSubitems {
   613  		return nil, errors.New("too many elements")
   614  	}
   615  	res := make([]WitnessCondition, l)
   616  	for i := range arr {
   617  		v, err := unmarshalConditionJSON(arr[i], maxDepth-1)
   618  		if err != nil {
   619  			return nil, err
   620  		}
   621  		res[i] = v
   622  	}
   623  	return res, nil
   624  }
   625  
   626  // UnmarshalConditionJSON unmarshalls condition from the given JSON data.
   627  func UnmarshalConditionJSON(data []byte) (WitnessCondition, error) {
   628  	return unmarshalConditionJSON(data, MaxConditionNesting)
   629  }
   630  
   631  func unmarshalConditionJSON(data []byte, maxDepth int) (WitnessCondition, error) {
   632  	if maxDepth <= 0 {
   633  		return nil, errors.New("too many nesting levels")
   634  	}
   635  	aux := &conditionAux{}
   636  	err := json.Unmarshal(data, aux)
   637  	if err != nil {
   638  		return nil, err
   639  	}
   640  	var res WitnessCondition
   641  	switch aux.Type {
   642  	case WitnessBoolean.String():
   643  		var v bool
   644  		err = json.Unmarshal(aux.Expression, &v)
   645  		if err != nil {
   646  			return nil, err
   647  		}
   648  		res = (*ConditionBoolean)(&v)
   649  	case WitnessNot.String():
   650  		v, err := unmarshalConditionJSON(aux.Expression, maxDepth-1)
   651  		if err != nil {
   652  			return nil, err
   653  		}
   654  		res = &ConditionNot{Condition: v}
   655  	case WitnessAnd.String():
   656  		v, err := unmarshalArrayOfConditionJSONs(aux.Expressions, maxDepth)
   657  		if err != nil {
   658  			return nil, err
   659  		}
   660  		res = (*ConditionAnd)(&v)
   661  	case WitnessOr.String():
   662  		v, err := unmarshalArrayOfConditionJSONs(aux.Expressions, maxDepth)
   663  		if err != nil {
   664  			return nil, err
   665  		}
   666  		res = (*ConditionOr)(&v)
   667  	case WitnessScriptHash.String():
   668  		if aux.Hash == nil {
   669  			return nil, errors.New("no hash specified")
   670  		}
   671  		res = (*ConditionScriptHash)(aux.Hash)
   672  	case WitnessGroup.String():
   673  		if aux.Group == nil {
   674  			return nil, errors.New("no group specified")
   675  		}
   676  		res = (*ConditionGroup)(aux.Group)
   677  	case WitnessCalledByEntry.String():
   678  		res = ConditionCalledByEntry{}
   679  	case WitnessCalledByContract.String():
   680  		if aux.Hash == nil {
   681  			return nil, errors.New("no hash specified")
   682  		}
   683  		res = (*ConditionCalledByContract)(aux.Hash)
   684  	case WitnessCalledByGroup.String():
   685  		if aux.Group == nil {
   686  			return nil, errors.New("no group specified")
   687  		}
   688  		res = (*ConditionCalledByGroup)(aux.Group)
   689  	default:
   690  		return nil, errors.New("invalid condition type")
   691  	}
   692  	return res, nil
   693  }
   694  
   695  func condToStackItem(typ WitnessConditionType, c any) stackitem.Item {
   696  	res := make([]stackitem.Item, 0, 2)
   697  	res = append(res, stackitem.NewBigInteger(big.NewInt(int64(typ))))
   698  	switch typ {
   699  	case WitnessBoolean:
   700  		res = append(res, stackitem.NewBool(c.(bool)))
   701  	case WitnessNot:
   702  		res = append(res, c.(WitnessCondition).ToStackItem())
   703  	case WitnessAnd, WitnessOr:
   704  		v := c.([]WitnessCondition)
   705  		operands := make([]stackitem.Item, len(v))
   706  		for i, op := range v {
   707  			operands[i] = op.ToStackItem()
   708  		}
   709  		res = append(res, stackitem.NewArray(operands))
   710  	case WitnessScriptHash, WitnessCalledByContract:
   711  		res = append(res, stackitem.NewByteArray(c.(util.Uint160).BytesBE()))
   712  	case WitnessGroup, WitnessCalledByGroup:
   713  		g := c.(keys.PublicKey)
   714  		res = append(res, stackitem.NewByteArray((&g).Bytes()))
   715  	case WitnessCalledByEntry:
   716  		// No additional item should be added.
   717  	}
   718  	return stackitem.NewArray(res)
   719  }