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

     1  /*
     2  Package neo provides an RPC-based wrapper for the NEOToken contract.
     3  
     4  Safe methods are encapsulated into ContractReader structure while Contract provides
     5  various methods to perform state-changing calls.
     6  */
     7  package neo
     8  
     9  import (
    10  	"crypto/elliptic"
    11  	"fmt"
    12  	"math/big"
    13  
    14  	"github.com/google/uuid"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    18  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    19  	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
    20  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
    21  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
    22  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    23  	"github.com/nspcc-dev/neo-go/pkg/util"
    24  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    25  )
    26  
    27  const (
    28  	setGasMethod = "setGasPerBlock"
    29  	setRegMethod = "setRegisterPrice"
    30  )
    31  
    32  // Invoker is used by ContractReader to perform read-only calls.
    33  type Invoker interface {
    34  	nep17.Invoker
    35  
    36  	CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...any) (*result.Invoke, error)
    37  	TerminateSession(sessionID uuid.UUID) error
    38  	TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error)
    39  }
    40  
    41  // Actor is used by Contract to create and send transactions.
    42  type Actor interface {
    43  	nep17.Actor
    44  	Invoker
    45  
    46  	Run(script []byte) (*result.Invoke, error)
    47  	MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
    48  	MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
    49  	MakeUnsignedUncheckedRun(script []byte, sysFee int64, attrs []transaction.Attribute) (*transaction.Transaction, error)
    50  	SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
    51  	Sign(tx *transaction.Transaction) error
    52  	SignAndSend(tx *transaction.Transaction) (util.Uint256, uint32, error)
    53  }
    54  
    55  // ContractReader represents safe (read-only) methods of NEO. It can be
    56  // used to query various data.
    57  type ContractReader struct {
    58  	nep17.TokenReader
    59  
    60  	invoker Invoker
    61  }
    62  
    63  // Contract provides full NEO interface, both safe and state-changing methods.
    64  type Contract struct {
    65  	ContractReader
    66  	nep17.TokenWriter
    67  
    68  	actor Actor
    69  }
    70  
    71  // CandidateStateEvent represents a CandidateStateChanged NEO event.
    72  type CandidateStateEvent struct {
    73  	Key        *keys.PublicKey
    74  	Registered bool
    75  	Votes      *big.Int
    76  }
    77  
    78  // CommitteeChangedEvent represents a CommitteeChanged NEO event.
    79  type CommitteeChangedEvent struct {
    80  	Old []keys.PublicKey
    81  	New []keys.PublicKey
    82  }
    83  
    84  // VoteEvent represents a Vote NEO event.
    85  type VoteEvent struct {
    86  	Account util.Uint160
    87  	From    *keys.PublicKey
    88  	To      *keys.PublicKey
    89  	Amount  *big.Int
    90  }
    91  
    92  // ValidatorIterator is used for iterating over GetAllCandidates results.
    93  type ValidatorIterator struct {
    94  	client   Invoker
    95  	session  uuid.UUID
    96  	iterator result.Iterator
    97  }
    98  
    99  // Hash stores the hash of the native NEOToken contract.
   100  var Hash = nativehashes.NeoToken
   101  
   102  // NewReader creates an instance of ContractReader to get data from the NEO
   103  // contract.
   104  func NewReader(invoker Invoker) *ContractReader {
   105  	return &ContractReader{*nep17.NewReader(invoker, Hash), invoker}
   106  }
   107  
   108  // New creates an instance of Contract to perform state-changing actions in the
   109  // NEO contract.
   110  func New(actor Actor) *Contract {
   111  	nep := nep17.New(actor, Hash)
   112  	return &Contract{ContractReader{nep.TokenReader, actor}, nep.TokenWriter, actor}
   113  }
   114  
   115  // GetAccountState returns current NEO balance state for the account which
   116  // includes balance and voting data. It can return nil balance with no error
   117  // if the account given has no NEO.
   118  func (c *ContractReader) GetAccountState(account util.Uint160) (*state.NEOBalance, error) {
   119  	itm, err := unwrap.Item(c.invoker.Call(Hash, "getAccountState", account))
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	if _, ok := itm.(stackitem.Null); ok {
   124  		return nil, nil
   125  	}
   126  	res := new(state.NEOBalance)
   127  	err = res.FromStackItem(itm)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	return res, nil
   132  }
   133  
   134  // GetAllCandidates returns an iterator that allows to retrieve all registered
   135  // validators from it. It depends on the server to provide proper session-based
   136  // iterator, but can also work with expanded one.
   137  func (c *ContractReader) GetAllCandidates() (*ValidatorIterator, error) {
   138  	sess, iter, err := unwrap.SessionIterator(c.invoker.Call(Hash, "getAllCandidates"))
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return &ValidatorIterator{
   144  		client:   c.invoker,
   145  		iterator: iter,
   146  		session:  sess,
   147  	}, nil
   148  }
   149  
   150  // GetAllCandidatesExpanded is similar to GetAllCandidates (uses the same NEO
   151  // method), but can be useful if the server used doesn't support sessions and
   152  // doesn't expand iterators. It creates a script that will get num of result
   153  // items from the iterator right in the VM and return them to you. It's only
   154  // limited by VM stack and GAS available for RPC invocations.
   155  func (c *ContractReader) GetAllCandidatesExpanded(num int) ([]result.Validator, error) {
   156  	arr, err := unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "getAllCandidates", num))
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	return itemsToValidators(arr)
   161  }
   162  
   163  // Next returns the next set of elements from the iterator (up to num of them).
   164  // It can return less than num elements in case iterator doesn't have that many
   165  // or zero elements if the iterator has no more elements or the session is
   166  // expired.
   167  func (v *ValidatorIterator) Next(num int) ([]result.Validator, error) {
   168  	items, err := v.client.TraverseIterator(v.session, &v.iterator, num)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	return itemsToValidators(items)
   173  }
   174  
   175  // Terminate closes the iterator session used by ValidatorIterator (if it's
   176  // session-based).
   177  func (v *ValidatorIterator) Terminate() error {
   178  	if v.iterator.ID == nil {
   179  		return nil
   180  	}
   181  	return v.client.TerminateSession(v.session)
   182  }
   183  
   184  // GetCandidates returns the list of validators with their vote count. This
   185  // method is mostly useful for historic invocations because the RPC protocol
   186  // provides direct getcandidates call that returns more data and works faster.
   187  // The contract only returns up to 256 candidates in response to this method, so
   188  // if there are more of them on the network you will get a truncated result, use
   189  // GetAllCandidates to solve this problem.
   190  func (c *ContractReader) GetCandidates() ([]result.Validator, error) {
   191  	arr, err := unwrap.Array(c.invoker.Call(Hash, "getCandidates"))
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	return itemsToValidators(arr)
   196  }
   197  
   198  func itemsToValidators(arr []stackitem.Item) ([]result.Validator, error) {
   199  	res := make([]result.Validator, len(arr))
   200  	for i, itm := range arr {
   201  		str, ok := itm.Value().([]stackitem.Item)
   202  		if !ok {
   203  			return nil, fmt.Errorf("item #%d is not a structure", i)
   204  		}
   205  		if len(str) != 2 {
   206  			return nil, fmt.Errorf("item #%d has wrong length", i)
   207  		}
   208  		b, err := str[0].TryBytes()
   209  		if err != nil {
   210  			return nil, fmt.Errorf("item #%d has wrong key: %w", i, err)
   211  		}
   212  		k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
   213  		if err != nil {
   214  			return nil, fmt.Errorf("item #%d has wrong key: %w", i, err)
   215  		}
   216  		votes, err := str[1].TryInteger()
   217  		if err != nil {
   218  			return nil, fmt.Errorf("item #%d has wrong votes: %w", i, err)
   219  		}
   220  		if !votes.IsInt64() {
   221  			return nil, fmt.Errorf("item #%d has too big number of votes", i)
   222  		}
   223  		res[i].PublicKey = *k
   224  		res[i].Votes = votes.Int64()
   225  	}
   226  	return res, nil
   227  }
   228  
   229  // GetCommittee returns the list of committee member public keys. This
   230  // method is mostly useful for historic invocations because the RPC protocol
   231  // provides direct getcommittee call that works faster.
   232  func (c *ContractReader) GetCommittee() (keys.PublicKeys, error) {
   233  	return unwrap.ArrayOfPublicKeys(c.invoker.Call(Hash, "getCommittee"))
   234  }
   235  
   236  // GetCommitteeAddress returns the committee address.
   237  func (c *ContractReader) GetCommitteeAddress() (util.Uint160, error) {
   238  	return unwrap.Uint160(c.invoker.Call(Hash, "getCommitteeAddress"))
   239  }
   240  
   241  // GetNextBlockValidators returns the list of validator keys that will sign the
   242  // next block. This method is mostly useful for historic invocations because the
   243  // RPC protocol provides direct getnextblockvalidators call that provides more
   244  // data and works faster.
   245  func (c *ContractReader) GetNextBlockValidators() (keys.PublicKeys, error) {
   246  	return unwrap.ArrayOfPublicKeys(c.invoker.Call(Hash, "getNextBlockValidators"))
   247  }
   248  
   249  // GetGasPerBlock returns the amount of GAS generated in each block.
   250  func (c *ContractReader) GetGasPerBlock() (int64, error) {
   251  	return unwrap.Int64(c.invoker.Call(Hash, "getGasPerBlock"))
   252  }
   253  
   254  // GetRegisterPrice returns the price of candidate key registration.
   255  func (c *ContractReader) GetRegisterPrice() (int64, error) {
   256  	return unwrap.Int64(c.invoker.Call(Hash, "getRegisterPrice"))
   257  }
   258  
   259  // UnclaimedGas allows to calculate the amount of GAS that will be generated if
   260  // any NEO state change ("claim") is to happen for the given account at the given
   261  // block number. This method is mostly useful for historic invocations because
   262  // the RPC protocol provides direct getunclaimedgas method that works faster.
   263  func (c *ContractReader) UnclaimedGas(account util.Uint160, end uint32) (*big.Int, error) {
   264  	return unwrap.BigInt(c.invoker.Call(Hash, "unclaimedGas", account, end))
   265  }
   266  
   267  // RegisterCandidate creates and sends a transaction that adds the given key to
   268  // the list of candidates that can be voted for. The return result from the
   269  // "registerCandidate" method is checked to be true, so transaction fails (with
   270  // FAULT state) if not successful. Notice that for this call to work it must be
   271  // witnessed by the simple account derived from the given key, so use an
   272  // appropriate Actor. The returned values are transaction hash, its
   273  // ValidUntilBlock value and an error if any.
   274  //
   275  // Notice that unlike for all other methods the script for this one is not
   276  // test-executed in its final form because most networks have registration price
   277  // set to be much higher than typical RPC server allows to spend during
   278  // test-execution. This adds some risk that it might fail on-chain, but in
   279  // practice it's not likely to happen if signers are set up correctly.
   280  func (c *Contract) RegisterCandidate(k *keys.PublicKey) (util.Uint256, uint32, error) {
   281  	tx, err := c.RegisterCandidateUnsigned(k)
   282  	if err != nil {
   283  		return util.Uint256{}, 0, err
   284  	}
   285  	return c.actor.SignAndSend(tx)
   286  }
   287  
   288  // RegisterCandidateTransaction creates a transaction that adds the given key to
   289  // the list of candidates that can be voted for. The return result from the
   290  // "registerCandidate" method is checked to be true, so transaction fails (with
   291  // FAULT state) if not successful. Notice that for this call to work it must be
   292  // witnessed by the simple account derived from the given key, so use an
   293  // appropriate Actor. The transaction is signed, but not sent to the network,
   294  // instead it's returned to the caller.
   295  //
   296  // Notice that unlike for all other methods the script for this one is not
   297  // test-executed in its final form because most networks have registration price
   298  // set to be much higher than typical RPC server allows to spend during
   299  // test-execution. This adds some risk that it might fail on-chain, but in
   300  // practice it's not likely to happen if signers are set up correctly.
   301  func (c *Contract) RegisterCandidateTransaction(k *keys.PublicKey) (*transaction.Transaction, error) {
   302  	tx, err := c.RegisterCandidateUnsigned(k)
   303  	if err != nil {
   304  		return nil, err
   305  	}
   306  	err = c.actor.Sign(tx)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  	return tx, nil
   311  }
   312  
   313  // RegisterCandidateUnsigned creates a transaction that adds the given key to
   314  // the list of candidates that can be voted for. The return result from the
   315  // "registerCandidate" method is checked to be true, so transaction fails (with
   316  // FAULT state) if not successful. Notice that for this call to work it must be
   317  // witnessed by the simple account derived from the given key, so use an
   318  // appropriate Actor. The transaction is not signed and just returned to the
   319  // caller.
   320  //
   321  // Notice that unlike for all other methods the script for this one is not
   322  // test-executed in its final form because most networks have registration price
   323  // set to be much higher than typical RPC server allows to spend during
   324  // test-execution. This adds some risk that it might fail on-chain, but in
   325  // practice it's not likely to happen if signers are set up correctly.
   326  func (c *Contract) RegisterCandidateUnsigned(k *keys.PublicKey) (*transaction.Transaction, error) {
   327  	// It's an unregister script intentionally.
   328  	r, err := c.actor.Run(regScript(true, k))
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  	regPrice, err := c.GetRegisterPrice()
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  	return c.actor.MakeUnsignedUncheckedRun(regScript(false, k), r.GasConsumed+regPrice, nil)
   337  }
   338  
   339  // UnregisterCandidate creates and sends a transaction that removes the key from
   340  // the list of candidates that can be voted for. The return result from the
   341  // "unregisterCandidate" method is checked to be true, so transaction fails (with
   342  // FAULT state) if not successful. Notice that for this call to work it must be
   343  // witnessed by the simple account derived from the given key, so use an
   344  // appropriate Actor. The returned values are transaction hash, its
   345  // ValidUntilBlock value and an error if any.
   346  func (c *Contract) UnregisterCandidate(k *keys.PublicKey) (util.Uint256, uint32, error) {
   347  	return c.actor.SendRun(regScript(true, k))
   348  }
   349  
   350  // UnregisterCandidateTransaction creates a transaction that removes the key from
   351  // the list of candidates that can be voted for. The return result from the
   352  // "unregisterCandidate" method is checked to be true, so transaction fails (with
   353  // FAULT state) if not successful. Notice that for this call to work it must be
   354  // witnessed by the simple account derived from the given key, so use an
   355  // appropriate Actor. The transaction is signed, but not sent to the network,
   356  // instead it's returned to the caller.
   357  func (c *Contract) UnregisterCandidateTransaction(k *keys.PublicKey) (*transaction.Transaction, error) {
   358  	return c.actor.MakeRun(regScript(true, k))
   359  }
   360  
   361  // UnregisterCandidateUnsigned creates a transaction that removes the key from
   362  // the list of candidates that can be voted for. The return result from the
   363  // "unregisterCandidate" method is checked to be true, so transaction fails (with
   364  // FAULT state) if not successful. Notice that for this call to work it must be
   365  // witnessed by the simple account derived from the given key, so use an
   366  // appropriate Actor. The transaction is not signed and just returned to the
   367  // caller.
   368  func (c *Contract) UnregisterCandidateUnsigned(k *keys.PublicKey) (*transaction.Transaction, error) {
   369  	return c.actor.MakeUnsignedRun(regScript(true, k), nil)
   370  }
   371  
   372  func regScript(unreg bool, k *keys.PublicKey) []byte {
   373  	var method = "registerCandidate"
   374  
   375  	if unreg {
   376  		method = "unregisterCandidate"
   377  	}
   378  
   379  	// We know parameters exactly (unlike with nep17.Transfer), so this can't fail.
   380  	script, _ := smartcontract.CreateCallWithAssertScript(Hash, method, k.Bytes())
   381  	return script
   382  }
   383  
   384  // Vote creates and sends a transaction that casts a vote from the given account
   385  // to the given key which can be nil (in which case any previous vote is removed).
   386  // The return result from the "vote" method is checked to be true, so transaction
   387  // fails (with FAULT state) if voting is not successful. The returned values are
   388  // transaction hash, its ValidUntilBlock value and an error if any.
   389  func (c *Contract) Vote(account util.Uint160, voteTo *keys.PublicKey) (util.Uint256, uint32, error) {
   390  	return c.actor.SendRun(voteScript(account, voteTo))
   391  }
   392  
   393  // VoteTransaction creates a transaction that casts a vote from the given account
   394  // to the given key which can be nil (in which case any previous vote is removed).
   395  // The return result from the "vote" method is checked to be true, so transaction
   396  // fails (with FAULT state) if voting is not successful. The transaction is signed,
   397  // but not sent to the network, instead it's returned to the caller.
   398  func (c *Contract) VoteTransaction(account util.Uint160, voteTo *keys.PublicKey) (*transaction.Transaction, error) {
   399  	return c.actor.MakeRun(voteScript(account, voteTo))
   400  }
   401  
   402  // VoteUnsigned creates a transaction that casts a vote from the given account
   403  // to the given key which can be nil (in which case any previous vote is removed).
   404  // The return result from the "vote" method is checked to be true, so transaction
   405  // fails (with FAULT state) if voting is not successful. The transaction is not
   406  // signed and just returned to the caller.
   407  func (c *Contract) VoteUnsigned(account util.Uint160, voteTo *keys.PublicKey) (*transaction.Transaction, error) {
   408  	return c.actor.MakeUnsignedRun(voteScript(account, voteTo), nil)
   409  }
   410  
   411  func voteScript(account util.Uint160, voteTo *keys.PublicKey) []byte {
   412  	var param any
   413  
   414  	if voteTo != nil {
   415  		param = voteTo.Bytes()
   416  	}
   417  	// We know parameters exactly (unlike with nep17.Transfer), so this can't fail.
   418  	script, _ := smartcontract.CreateCallWithAssertScript(Hash, "vote", account, param)
   419  	return script
   420  }
   421  
   422  // SetGasPerBlock creates and sends a transaction that sets the new amount of
   423  // GAS to be generated in each block. The action is successful when transaction
   424  // ends in HALT state. Notice that this setting can be changed only by the
   425  // network's committee, so use an appropriate Actor. The returned values are
   426  // transaction hash, its ValidUntilBlock value and an error if any.
   427  func (c *Contract) SetGasPerBlock(gas int64) (util.Uint256, uint32, error) {
   428  	return c.actor.SendCall(Hash, setGasMethod, gas)
   429  }
   430  
   431  // SetGasPerBlockTransaction creates a transaction that sets the new amount of
   432  // GAS to be generated in each block. The action is successful when transaction
   433  // ends in HALT state. Notice that this setting can be changed only by the
   434  // network's committee, so use an appropriate Actor. The transaction is signed,
   435  // but not sent to the network, instead it's returned to the caller.
   436  func (c *Contract) SetGasPerBlockTransaction(gas int64) (*transaction.Transaction, error) {
   437  	return c.actor.MakeCall(Hash, setGasMethod, gas)
   438  }
   439  
   440  // SetGasPerBlockUnsigned creates a transaction that sets the new amount of
   441  // GAS to be generated in each block. The action is successful when transaction
   442  // ends in HALT state. Notice that this setting can be changed only by the
   443  // network's committee, so use an appropriate Actor. The transaction is not
   444  // signed and just returned to the caller.
   445  func (c *Contract) SetGasPerBlockUnsigned(gas int64) (*transaction.Transaction, error) {
   446  	return c.actor.MakeUnsignedCall(Hash, setGasMethod, nil, gas)
   447  }
   448  
   449  // SetRegisterPrice creates and sends a transaction that sets the new candidate
   450  // registration price (in GAS). The action is successful when transaction
   451  // ends in HALT state. Notice that this setting can be changed only by the
   452  // network's committee, so use an appropriate Actor. The returned values are
   453  // transaction hash, its ValidUntilBlock value and an error if any.
   454  func (c *Contract) SetRegisterPrice(price int64) (util.Uint256, uint32, error) {
   455  	return c.actor.SendCall(Hash, setRegMethod, price)
   456  }
   457  
   458  // SetRegisterPriceTransaction creates a transaction that sets the new candidate
   459  // registration price (in GAS). The action is successful when transaction
   460  // ends in HALT state. Notice that this setting can be changed only by the
   461  // network's committee, so use an appropriate Actor. The transaction is signed,
   462  // but not sent to the network, instead it's returned to the caller.
   463  func (c *Contract) SetRegisterPriceTransaction(price int64) (*transaction.Transaction, error) {
   464  	return c.actor.MakeCall(Hash, setRegMethod, price)
   465  }
   466  
   467  // SetRegisterPriceUnsigned creates a transaction that sets the new candidate
   468  // registration price (in GAS). The action is successful when transaction
   469  // ends in HALT state. Notice that this setting can be changed only by the
   470  // network's committee, so use an appropriate Actor. The transaction is not
   471  // signed and just returned to the caller.
   472  func (c *Contract) SetRegisterPriceUnsigned(price int64) (*transaction.Transaction, error) {
   473  	return c.actor.MakeUnsignedCall(Hash, setRegMethod, nil, price)
   474  }