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

     1  package state
     2  
     3  import (
     4  	"errors"
     5  	"math"
     6  	"math/big"
     7  
     8  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
     9  	"github.com/nspcc-dev/neo-go/pkg/io"
    10  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
    11  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
    12  	"github.com/nspcc-dev/neo-go/pkg/util"
    13  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    14  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    15  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    16  )
    17  
    18  // Contract holds information about a smart contract in the Neo blockchain.
    19  type Contract struct {
    20  	ContractBase
    21  	UpdateCounter uint16 `json:"updatecounter"`
    22  }
    23  
    24  // ContractBase represents a part shared by native and user-deployed contracts.
    25  type ContractBase struct {
    26  	ID       int32             `json:"id"`
    27  	Hash     util.Uint160      `json:"hash"`
    28  	NEF      nef.File          `json:"nef"`
    29  	Manifest manifest.Manifest `json:"manifest"`
    30  }
    31  
    32  // ToStackItem converts state.Contract to stackitem.Item.
    33  func (c *Contract) ToStackItem() (stackitem.Item, error) {
    34  	// Do not skip the NEF size check, it won't affect native Management related
    35  	// states as the same checked is performed during contract deploy/update.
    36  	rawNef, err := c.NEF.Bytes()
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	m, err := c.Manifest.ToStackItem()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	return stackitem.NewArray([]stackitem.Item{
    45  		stackitem.Make(c.ID),
    46  		stackitem.Make(c.UpdateCounter),
    47  		stackitem.NewByteArray(c.Hash.BytesBE()),
    48  		stackitem.NewByteArray(rawNef),
    49  		m,
    50  	}), nil
    51  }
    52  
    53  // FromStackItem fills Contract's data from the given stack itemized contract
    54  // representation.
    55  func (c *Contract) FromStackItem(item stackitem.Item) error {
    56  	arr, ok := item.Value().([]stackitem.Item)
    57  	if !ok {
    58  		return errors.New("not an array")
    59  	}
    60  	if len(arr) != 5 {
    61  		return errors.New("invalid structure")
    62  	}
    63  	bi, ok := arr[0].Value().(*big.Int)
    64  	if !ok {
    65  		return errors.New("ID is not an integer")
    66  	}
    67  	if !bi.IsInt64() || bi.Int64() > math.MaxInt32 || bi.Int64() < math.MinInt32 {
    68  		return errors.New("ID not in int32 range")
    69  	}
    70  	c.ID = int32(bi.Int64())
    71  	bi, ok = arr[1].Value().(*big.Int)
    72  	if !ok {
    73  		return errors.New("UpdateCounter is not an integer")
    74  	}
    75  	if !bi.IsUint64() || bi.Uint64() > math.MaxUint16 {
    76  		return errors.New("UpdateCounter not in uint16 range")
    77  	}
    78  	c.UpdateCounter = uint16(bi.Uint64())
    79  	bytes, err := arr[2].TryBytes()
    80  	if err != nil {
    81  		return err
    82  	}
    83  	c.Hash, err = util.Uint160DecodeBytesBE(bytes)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	bytes, err = arr[3].TryBytes()
    88  	if err != nil {
    89  		return err
    90  	}
    91  	c.NEF, err = nef.FileFromBytes(bytes)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	m := new(manifest.Manifest)
    96  	err = m.FromStackItem(arr[4])
    97  	if err != nil {
    98  		return err
    99  	}
   100  	c.Manifest = *m
   101  	return nil
   102  }
   103  
   104  // CreateContractHash creates a deployed contract hash from the transaction sender
   105  // and the contract script.
   106  func CreateContractHash(sender util.Uint160, checksum uint32, name string) util.Uint160 {
   107  	w := io.NewBufBinWriter()
   108  	emit.Opcodes(w.BinWriter, opcode.ABORT)
   109  	emit.Bytes(w.BinWriter, sender.BytesBE())
   110  	emit.Int(w.BinWriter, int64(checksum))
   111  	emit.String(w.BinWriter, name)
   112  	if w.Err != nil {
   113  		panic(w.Err)
   114  	}
   115  	return hash.Hash160(w.Bytes())
   116  }
   117  
   118  // CreateNativeContractHash calculates the hash for the native contract with the
   119  // given name.
   120  func CreateNativeContractHash(name string) util.Uint160 {
   121  	return CreateContractHash(util.Uint160{}, 0, name)
   122  }