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

     1  package transaction
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"math"
    10  	"math/big"
    11  	"math/rand"
    12  
    13  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    14  	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
    15  	"github.com/nspcc-dev/neo-go/pkg/io"
    16  	"github.com/nspcc-dev/neo-go/pkg/util"
    17  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    18  )
    19  
    20  const (
    21  	// MaxScriptLength is the limit for transaction's script length.
    22  	MaxScriptLength = math.MaxUint16
    23  	// MaxTransactionSize is the upper limit size in bytes that a transaction can reach. It is
    24  	// set to be 102400.
    25  	MaxTransactionSize = 102400
    26  	// MaxAttributes is maximum number of attributes including signers that can be contained
    27  	// within a transaction. It is set to be 16.
    28  	MaxAttributes = 16
    29  )
    30  
    31  // ErrInvalidWitnessNum returns when the number of witnesses does not match signers.
    32  var ErrInvalidWitnessNum = errors.New("number of signers doesn't match witnesses")
    33  
    34  // Transaction is a process recorded in the Neo blockchain.
    35  type Transaction struct {
    36  	// The trading version which is currently 0.
    37  	Version uint8
    38  
    39  	// Random number to avoid hash collision.
    40  	Nonce uint32
    41  
    42  	// Fee to be burned.
    43  	SystemFee int64
    44  
    45  	// Fee to be distributed to consensus nodes.
    46  	NetworkFee int64
    47  
    48  	// Maximum blockchain height exceeding which
    49  	// transaction should fail verification. E.g. if VUB=N, then transaction
    50  	// can be accepted to block with index N, but not to block with index N+1.
    51  	ValidUntilBlock uint32
    52  
    53  	// Code to run in NeoVM for this transaction.
    54  	Script []byte
    55  
    56  	// Transaction attributes.
    57  	Attributes []Attribute
    58  
    59  	// Transaction signers list (starts with Sender).
    60  	Signers []Signer
    61  
    62  	// The scripts that comes with this transaction.
    63  	// Scripts exist out of the verification script
    64  	// and invocation script.
    65  	Scripts []Witness
    66  
    67  	// size is transaction's serialized size.
    68  	size int
    69  
    70  	// Hash of the transaction (double SHA256).
    71  	hash util.Uint256
    72  
    73  	// Whether hash is correct.
    74  	hashed bool
    75  
    76  	// Trimmed indicates this is a transaction from trimmed
    77  	// data.
    78  	Trimmed bool
    79  }
    80  
    81  // NewTrimmedTX returns a trimmed transaction with only its hash
    82  // and Trimmed to true.
    83  func NewTrimmedTX(hash util.Uint256) *Transaction {
    84  	return &Transaction{
    85  		hash:    hash,
    86  		hashed:  true,
    87  		Trimmed: true,
    88  	}
    89  }
    90  
    91  // New returns a new transaction to execute given script and pay given system
    92  // fee.
    93  func New(script []byte, gas int64) *Transaction {
    94  	return &Transaction{
    95  		Version:    0,
    96  		Nonce:      rand.Uint32(),
    97  		Script:     script,
    98  		SystemFee:  gas,
    99  		Attributes: []Attribute{},
   100  		Signers:    []Signer{},
   101  		Scripts:    []Witness{},
   102  	}
   103  }
   104  
   105  // Hash returns the hash of the transaction.
   106  func (t *Transaction) Hash() util.Uint256 {
   107  	if !t.hashed {
   108  		if t.createHash() != nil {
   109  			panic("failed to compute hash!")
   110  		}
   111  	}
   112  	return t.hash
   113  }
   114  
   115  // HasAttribute returns true iff t has an attribute of type typ.
   116  func (t *Transaction) HasAttribute(typ AttrType) bool {
   117  	for i := range t.Attributes {
   118  		if t.Attributes[i].Type == typ {
   119  			return true
   120  		}
   121  	}
   122  	return false
   123  }
   124  
   125  // GetAttributes returns the list of transaction's attributes of the given type.
   126  // Returns nil in case if attributes not found.
   127  func (t *Transaction) GetAttributes(typ AttrType) []Attribute {
   128  	var result []Attribute
   129  	for _, attr := range t.Attributes {
   130  		if attr.Type == typ {
   131  			result = append(result, attr)
   132  		}
   133  	}
   134  	return result
   135  }
   136  
   137  // decodeHashableFields decodes the fields that are used for signing the
   138  // transaction, which are all fields except the scripts.
   139  func (t *Transaction) decodeHashableFields(br *io.BinReader, buf []byte) {
   140  	var start, end int
   141  
   142  	if buf != nil {
   143  		start = len(buf) - br.Len()
   144  	}
   145  	t.Version = uint8(br.ReadB())
   146  	t.Nonce = br.ReadU32LE()
   147  	t.SystemFee = int64(br.ReadU64LE())
   148  	t.NetworkFee = int64(br.ReadU64LE())
   149  	t.ValidUntilBlock = br.ReadU32LE()
   150  	nsigners := br.ReadVarUint()
   151  	if br.Err != nil {
   152  		return
   153  	}
   154  	if nsigners > MaxAttributes {
   155  		br.Err = errors.New("too many signers")
   156  		return
   157  	} else if nsigners == 0 {
   158  		br.Err = errors.New("missing signers")
   159  		return
   160  	}
   161  	t.Signers = make([]Signer, nsigners)
   162  	for i := 0; i < int(nsigners); i++ {
   163  		t.Signers[i].DecodeBinary(br)
   164  	}
   165  	nattrs := br.ReadVarUint()
   166  	if nattrs > MaxAttributes-nsigners {
   167  		br.Err = errors.New("too many attributes")
   168  		return
   169  	}
   170  	t.Attributes = make([]Attribute, nattrs)
   171  	for i := 0; i < int(nattrs); i++ {
   172  		t.Attributes[i].DecodeBinary(br)
   173  	}
   174  	t.Script = br.ReadVarBytes(MaxScriptLength)
   175  	if br.Err == nil {
   176  		br.Err = t.isValid()
   177  	}
   178  	if buf != nil {
   179  		end = len(buf) - br.Len()
   180  		t.hash = hash.Sha256(buf[start:end])
   181  		t.hashed = true
   182  	}
   183  }
   184  
   185  func (t *Transaction) decodeBinaryNoSize(br *io.BinReader, buf []byte) {
   186  	t.decodeHashableFields(br, buf)
   187  	if br.Err != nil {
   188  		return
   189  	}
   190  	nscripts := br.ReadVarUint()
   191  	if nscripts > MaxAttributes {
   192  		br.Err = errors.New("too many witnesses")
   193  		return
   194  	} else if int(nscripts) != len(t.Signers) {
   195  		br.Err = fmt.Errorf("%w: %d vs %d", ErrInvalidWitnessNum, len(t.Signers), nscripts)
   196  		return
   197  	}
   198  	t.Scripts = make([]Witness, nscripts)
   199  	for i := 0; i < int(nscripts); i++ {
   200  		t.Scripts[i].DecodeBinary(br)
   201  	}
   202  
   203  	// Create the hash of the transaction at decode, so we dont need
   204  	// to do it anymore.
   205  	if br.Err == nil && buf == nil {
   206  		br.Err = t.createHash()
   207  	}
   208  }
   209  
   210  // DecodeBinary implements the Serializable interface.
   211  func (t *Transaction) DecodeBinary(br *io.BinReader) {
   212  	t.decodeBinaryNoSize(br, nil)
   213  
   214  	if br.Err == nil {
   215  		_ = t.Size()
   216  	}
   217  }
   218  
   219  // EncodeBinary implements the Serializable interface.
   220  func (t *Transaction) EncodeBinary(bw *io.BinWriter) {
   221  	t.encodeHashableFields(bw)
   222  	bw.WriteVarUint(uint64(len(t.Scripts)))
   223  	for i := range t.Scripts {
   224  		t.Scripts[i].EncodeBinary(bw)
   225  	}
   226  }
   227  
   228  // encodeHashableFields encodes the fields that are not used for
   229  // signing the transaction, which are all fields except the scripts.
   230  func (t *Transaction) encodeHashableFields(bw *io.BinWriter) {
   231  	bw.WriteB(byte(t.Version))
   232  	bw.WriteU32LE(t.Nonce)
   233  	bw.WriteU64LE(uint64(t.SystemFee))
   234  	bw.WriteU64LE(uint64(t.NetworkFee))
   235  	bw.WriteU32LE(t.ValidUntilBlock)
   236  	bw.WriteVarUint(uint64(len(t.Signers)))
   237  	for i := range t.Signers {
   238  		t.Signers[i].EncodeBinary(bw)
   239  	}
   240  	bw.WriteVarUint(uint64(len(t.Attributes)))
   241  	for i := range t.Attributes {
   242  		t.Attributes[i].EncodeBinary(bw)
   243  	}
   244  	bw.WriteVarBytes(t.Script)
   245  }
   246  
   247  // EncodeHashableFields returns serialized transaction's fields which are hashed.
   248  func (t *Transaction) EncodeHashableFields() ([]byte, error) {
   249  	bw := io.NewBufBinWriter()
   250  	t.encodeHashableFields(bw.BinWriter)
   251  	if bw.Err != nil {
   252  		return nil, bw.Err
   253  	}
   254  	return bw.Bytes(), nil
   255  }
   256  
   257  // createHash creates the hash of the transaction.
   258  func (t *Transaction) createHash() error {
   259  	shaHash := sha256.New()
   260  	bw := io.NewBinWriterFromIO(shaHash)
   261  	t.encodeHashableFields(bw)
   262  	if bw.Err != nil {
   263  		return bw.Err
   264  	}
   265  
   266  	shaHash.Sum(t.hash[:0])
   267  	t.hashed = true
   268  	return nil
   269  }
   270  
   271  // DecodeHashableFields decodes a part of transaction which should be hashed.
   272  func (t *Transaction) DecodeHashableFields(buf []byte) error {
   273  	r := io.NewBinReaderFromBuf(buf)
   274  	t.decodeHashableFields(r, buf)
   275  	if r.Err != nil {
   276  		return r.Err
   277  	}
   278  	// Ensure all the data was read.
   279  	if r.Len() != 0 {
   280  		return errors.New("additional data after the signed part")
   281  	}
   282  	t.Scripts = make([]Witness, 0)
   283  	return nil
   284  }
   285  
   286  // Bytes converts the transaction to []byte.
   287  func (t *Transaction) Bytes() []byte {
   288  	buf := io.NewBufBinWriter()
   289  	t.EncodeBinary(buf.BinWriter)
   290  	if buf.Err != nil {
   291  		return nil
   292  	}
   293  	return buf.Bytes()
   294  }
   295  
   296  // NewTransactionFromBytes decodes byte array into *Transaction.
   297  func NewTransactionFromBytes(b []byte) (*Transaction, error) {
   298  	tx := &Transaction{}
   299  	r := io.NewBinReaderFromBuf(b)
   300  	tx.decodeBinaryNoSize(r, b)
   301  	if r.Err != nil {
   302  		return nil, r.Err
   303  	}
   304  	if r.Len() != 0 {
   305  		return nil, errors.New("additional data after the transaction")
   306  	}
   307  	tx.size = len(b)
   308  	return tx, nil
   309  }
   310  
   311  // FeePerByte returns NetworkFee of the transaction divided by
   312  // its size.
   313  func (t *Transaction) FeePerByte() int64 {
   314  	return t.NetworkFee / int64(t.Size())
   315  }
   316  
   317  // Size returns size of the serialized transaction.
   318  func (t *Transaction) Size() int {
   319  	if t.size == 0 {
   320  		t.size = io.GetVarSize(t)
   321  	}
   322  	return t.size
   323  }
   324  
   325  // Sender returns the sender of the transaction which is always on the first place
   326  // in the transaction's signers list.
   327  func (t *Transaction) Sender() util.Uint160 {
   328  	if len(t.Signers) == 0 {
   329  		panic("transaction does not have signers")
   330  	}
   331  	return t.Signers[0].Account
   332  }
   333  
   334  // transactionJSON is a wrapper for Transaction and
   335  // used for correct marhalling of transaction.Data.
   336  type transactionJSON struct {
   337  	TxID            util.Uint256 `json:"hash"`
   338  	Size            int          `json:"size"`
   339  	Version         uint8        `json:"version"`
   340  	Nonce           uint32       `json:"nonce"`
   341  	Sender          string       `json:"sender"`
   342  	SystemFee       int64        `json:"sysfee,string"`
   343  	NetworkFee      int64        `json:"netfee,string"`
   344  	ValidUntilBlock uint32       `json:"validuntilblock"`
   345  	Attributes      []Attribute  `json:"attributes"`
   346  	Signers         []Signer     `json:"signers"`
   347  	Script          []byte       `json:"script"`
   348  	Scripts         []Witness    `json:"witnesses"`
   349  }
   350  
   351  // MarshalJSON implements the json.Marshaler interface.
   352  func (t *Transaction) MarshalJSON() ([]byte, error) {
   353  	tx := transactionJSON{
   354  		TxID:            t.Hash(),
   355  		Size:            t.Size(),
   356  		Version:         t.Version,
   357  		Nonce:           t.Nonce,
   358  		Sender:          address.Uint160ToString(t.Sender()),
   359  		ValidUntilBlock: t.ValidUntilBlock,
   360  		Attributes:      t.Attributes,
   361  		Signers:         t.Signers,
   362  		Script:          t.Script,
   363  		Scripts:         t.Scripts,
   364  		SystemFee:       t.SystemFee,
   365  		NetworkFee:      t.NetworkFee,
   366  	}
   367  	return json.Marshal(tx)
   368  }
   369  
   370  // UnmarshalJSON implements the json.Unmarshaler interface.
   371  func (t *Transaction) UnmarshalJSON(data []byte) error {
   372  	tx := new(transactionJSON)
   373  	if err := json.Unmarshal(data, tx); err != nil {
   374  		return err
   375  	}
   376  	t.Version = tx.Version
   377  	t.Nonce = tx.Nonce
   378  	t.ValidUntilBlock = tx.ValidUntilBlock
   379  	t.Attributes = tx.Attributes
   380  	t.Signers = tx.Signers
   381  	t.Scripts = tx.Scripts
   382  	t.SystemFee = tx.SystemFee
   383  	t.NetworkFee = tx.NetworkFee
   384  	t.Script = tx.Script
   385  	if t.Hash() != tx.TxID {
   386  		return errors.New("txid doesn't match transaction hash")
   387  	}
   388  	if t.Size() != tx.Size {
   389  		return errors.New("'size' doesn't match transaction size")
   390  	}
   391  
   392  	return t.isValid()
   393  }
   394  
   395  // Various errors for transaction validation.
   396  var (
   397  	ErrInvalidVersion     = errors.New("only version 0 is supported")
   398  	ErrNegativeSystemFee  = errors.New("negative system fee")
   399  	ErrNegativeNetworkFee = errors.New("negative network fee")
   400  	ErrTooBigFees         = errors.New("too big fees: int64 overflow")
   401  	ErrEmptySigners       = errors.New("signers array should contain sender")
   402  	ErrNonUniqueSigners   = errors.New("transaction signers should be unique")
   403  	ErrInvalidAttribute   = errors.New("invalid attribute")
   404  	ErrEmptyScript        = errors.New("no script")
   405  )
   406  
   407  // isValid checks whether decoded/unmarshalled transaction has all fields valid.
   408  func (t *Transaction) isValid() error {
   409  	if t.Version > 0 {
   410  		return ErrInvalidVersion
   411  	}
   412  	if t.SystemFee < 0 {
   413  		return ErrNegativeSystemFee
   414  	}
   415  	if t.NetworkFee < 0 {
   416  		return ErrNegativeNetworkFee
   417  	}
   418  	if t.NetworkFee+t.SystemFee < t.SystemFee {
   419  		return ErrTooBigFees
   420  	}
   421  	if len(t.Signers) == 0 {
   422  		return ErrEmptySigners
   423  	}
   424  	for i := 0; i < len(t.Signers); i++ {
   425  		for j := i + 1; j < len(t.Signers); j++ {
   426  			if t.Signers[i].Account.Equals(t.Signers[j].Account) {
   427  				return ErrNonUniqueSigners
   428  			}
   429  		}
   430  	}
   431  	attrs := map[AttrType]bool{}
   432  	for i := range t.Attributes {
   433  		typ := t.Attributes[i].Type
   434  		if !typ.allowMultiple() {
   435  			if attrs[typ] {
   436  				return fmt.Errorf("%w: multiple '%s' attributes", ErrInvalidAttribute, typ.String())
   437  			}
   438  			attrs[typ] = true
   439  		}
   440  	}
   441  	if len(t.Script) == 0 {
   442  		return ErrEmptyScript
   443  	}
   444  	return nil
   445  }
   446  
   447  // HasSigner returns true in case if hash is present in the list of signers.
   448  func (t *Transaction) HasSigner(hash util.Uint160) bool {
   449  	for _, h := range t.Signers {
   450  		if h.Account.Equals(hash) {
   451  			return true
   452  		}
   453  	}
   454  	return false
   455  }
   456  
   457  // ToStackItem converts Transaction to stackitem.Item.
   458  func (t *Transaction) ToStackItem() stackitem.Item {
   459  	return stackitem.NewArray([]stackitem.Item{
   460  		stackitem.NewByteArray(t.Hash().BytesBE()),
   461  		stackitem.NewBigInteger(big.NewInt(int64(t.Version))),
   462  		stackitem.NewBigInteger(big.NewInt(int64(t.Nonce))),
   463  		stackitem.NewByteArray(t.Sender().BytesBE()),
   464  		stackitem.NewBigInteger(big.NewInt(int64(t.SystemFee))),
   465  		stackitem.NewBigInteger(big.NewInt(int64(t.NetworkFee))),
   466  		stackitem.NewBigInteger(big.NewInt(int64(t.ValidUntilBlock))),
   467  		stackitem.NewByteArray(t.Script),
   468  	})
   469  }
   470  
   471  // Copy creates a deep copy of the Transaction, including all slice fields. Cached values like
   472  // 'hashed' and 'size' are reset to ensure the copy can be modified independently of the original.
   473  func (t *Transaction) Copy() *Transaction {
   474  	if t == nil {
   475  		return nil
   476  	}
   477  	cp := *t
   478  	if t.Attributes != nil {
   479  		cp.Attributes = make([]Attribute, len(t.Attributes))
   480  		for i, attr := range t.Attributes {
   481  			cp.Attributes[i] = *attr.Copy()
   482  		}
   483  	}
   484  	if t.Signers != nil {
   485  		cp.Signers = make([]Signer, len(t.Signers))
   486  		for i, signer := range t.Signers {
   487  			cp.Signers[i] = *signer.Copy()
   488  		}
   489  	}
   490  	if t.Scripts != nil {
   491  		cp.Scripts = make([]Witness, len(t.Scripts))
   492  		for i, script := range t.Scripts {
   493  			cp.Scripts[i] = script.Copy()
   494  		}
   495  	}
   496  	cp.Script = bytes.Clone(t.Script)
   497  
   498  	cp.hashed = false
   499  	cp.size = 0
   500  	cp.hash = util.Uint256{}
   501  	return &cp
   502  }