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

     1  package invoker_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
     8  	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
     9  	"github.com/nspcc-dev/neo-go/pkg/rpcclient"
    10  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
    11  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
    12  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
    13  	"github.com/nspcc-dev/neo-go/pkg/util"
    14  	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
    15  )
    16  
    17  func ExampleInvoker() {
    18  	// No error checking done at all, intentionally.
    19  	c, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})
    20  
    21  	// A simple invoker with no signers, perfectly fine for reads from safe methods.
    22  	inv := invoker.New(c, nil)
    23  
    24  	// Get the NEO token supply (notice that unwrap is used to get the result).
    25  	supply, _ := unwrap.BigInt(inv.Call(neo.Hash, "totalSupply"))
    26  	_ = supply
    27  
    28  	acc, _ := address.StringToUint160("NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq")
    29  	// Get the NEO balance for account NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq.
    30  	balance, _ := unwrap.BigInt(inv.Call(neo.Hash, "balanceOf", acc))
    31  	_ = balance
    32  
    33  	// Test-invoke transfer call.
    34  	res, _ := inv.Call(neo.Hash, "transfer", acc, util.Uint160{1, 2, 3}, 1, nil)
    35  	if res.State == vmstate.Halt.String() {
    36  		panic("NEO is broken!") // inv has no signers and transfer requires a witness to be performed.
    37  	} else { // nolint:revive // superfluous-else: if block ends with call to panic function, so drop this else and outdent its block (revive)
    38  		println("ok") // this actually should fail
    39  	}
    40  
    41  	// A historic invoker with no signers at block 1000000.
    42  	inv = invoker.NewHistoricAtHeight(1000000, c, nil)
    43  
    44  	// It's the same call as above, but the data is for a state at block 1000000.
    45  	balance, _ = unwrap.BigInt(inv.Call(neo.Hash, "balanceOf", acc))
    46  	_ = balance
    47  
    48  	// This invoker has a signer for NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq account with
    49  	// CalledByEntry scope, which is sufficient for most operation. It uses current
    50  	// state which is exactly what you need if you want to then create a transaction
    51  	// with the same action.
    52  	inv = invoker.New(c, []transaction.Signer{{Account: acc, Scopes: transaction.CalledByEntry}})
    53  
    54  	// Now test invocation should be fine (if NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq has 1 NEO of course).
    55  	res, _ = inv.Call(neo.Hash, "transfer", acc, util.Uint160{1, 2, 3}, 1, nil)
    56  	if res.State == vmstate.Halt.String() {
    57  		// transfer actually returns a value, so check it too.
    58  		ok, _ := unwrap.Bool(res, nil)
    59  		if ok {
    60  			// OK, as expected.
    61  			// res.Script contains the corresponding script.
    62  			_ = res.Script
    63  			// res.GasConsumed has an appropriate system fee required for a transaction.
    64  			_ = res.GasConsumed
    65  		}
    66  	}
    67  
    68  	// Now let's try working with iterators.
    69  	nep11Contract := util.Uint160{1, 2, 3}
    70  
    71  	var tokens [][]byte
    72  
    73  	// Try doing it the right way, by traversing the iterator.
    74  	sess, iter, err := unwrap.SessionIterator(inv.Call(nep11Contract, "tokensOf", acc))
    75  
    76  	// The server doesn't support sessions and doesn't perform iterator expansion,
    77  	// iterators can't be used.
    78  	if err != nil {
    79  		if errors.Is(err, unwrap.ErrNoSessionID) {
    80  			// But if we expect some low number of elements, CallAndExpandIterator
    81  			// can help us in this case. If the account has more than 10 elements,
    82  			// some of them will be missing from the response.
    83  			tokens, _ = unwrap.ArrayOfBytes(inv.CallAndExpandIterator(nep11Contract, "tokensOf", 10, acc))
    84  		} else {
    85  			panic("some error")
    86  		}
    87  	} else {
    88  		items, err := inv.TraverseIterator(sess, &iter, 100)
    89  		// Keep going until there are no more elements
    90  		for err == nil && len(items) != 0 {
    91  			for _, itm := range items {
    92  				tokenID, _ := itm.TryBytes()
    93  				tokens = append(tokens, tokenID)
    94  			}
    95  			items, err = inv.TraverseIterator(sess, &iter, 100)
    96  		}
    97  		// Let the server release the session.
    98  		_ = inv.TerminateSession(sess)
    99  	}
   100  	_ = tokens
   101  }