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

     1  package actor
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync/atomic"
     7  	"testing"
     8  
     9  	"github.com/google/uuid"
    10  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    11  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    12  	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
    13  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    14  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    15  	"github.com/nspcc-dev/neo-go/pkg/util"
    16  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    17  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  type RPCClient struct {
    22  	err     error
    23  	invRes  *result.Invoke
    24  	netFee  int64
    25  	bCount  atomic.Uint32
    26  	version *result.Version
    27  	hash    util.Uint256
    28  	appLog  *result.ApplicationLog
    29  	context context.Context
    30  }
    31  
    32  func (r *RPCClient) InvokeContractVerify(contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) {
    33  	return r.invRes, r.err
    34  }
    35  func (r *RPCClient) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) {
    36  	return r.invRes, r.err
    37  }
    38  func (r *RPCClient) InvokeScript(script []byte, signers []transaction.Signer) (*result.Invoke, error) {
    39  	return r.invRes, r.err
    40  }
    41  func (r *RPCClient) CalculateNetworkFee(tx *transaction.Transaction) (int64, error) {
    42  	return r.netFee, r.err
    43  }
    44  func (r *RPCClient) GetBlockCount() (uint32, error) {
    45  	return r.bCount.Load(), r.err
    46  }
    47  func (r *RPCClient) GetVersion() (*result.Version, error) {
    48  	verCopy := *r.version
    49  	return &verCopy, r.err
    50  }
    51  func (r *RPCClient) SendRawTransaction(tx *transaction.Transaction) (util.Uint256, error) {
    52  	return r.hash, r.err
    53  }
    54  func (r *RPCClient) TerminateSession(sessionID uuid.UUID) (bool, error) {
    55  	return false, nil // Just a stub, unused by actor.
    56  }
    57  func (r *RPCClient) TraverseIterator(sessionID, iteratorID uuid.UUID, maxItemsCount int) ([]stackitem.Item, error) {
    58  	return nil, nil // Just a stub, unused by actor.
    59  }
    60  func (r *RPCClient) Context() context.Context {
    61  	if r.context == nil {
    62  		return context.Background()
    63  	}
    64  	return r.context
    65  }
    66  
    67  func (r *RPCClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) {
    68  	if r.appLog != nil {
    69  		return r.appLog, nil
    70  	}
    71  	return nil, errors.New("not found")
    72  }
    73  func testRPCAndAccount(t *testing.T) (*RPCClient, *wallet.Account) {
    74  	client := &RPCClient{
    75  		version: &result.Version{
    76  			Protocol: result.Protocol{
    77  				Network:              netmode.UnitTestNet,
    78  				MillisecondsPerBlock: 1000,
    79  				ValidatorsCount:      7,
    80  			},
    81  		},
    82  	}
    83  	acc, err := wallet.NewAccount()
    84  	require.NoError(t, err)
    85  	return client, acc
    86  }
    87  
    88  func TestNew(t *testing.T) {
    89  	client, acc := testRPCAndAccount(t)
    90  
    91  	// No signers.
    92  	_, err := New(client, nil)
    93  	require.Error(t, err)
    94  
    95  	_, err = New(client, []SignerAccount{})
    96  	require.Error(t, err)
    97  
    98  	_, err = NewTuned(client, []SignerAccount{}, NewDefaultOptions())
    99  	require.Error(t, err)
   100  
   101  	// Good simple.
   102  	a, err := NewSimple(client, acc)
   103  	require.NoError(t, err)
   104  	require.Equal(t, 1, len(a.signers))
   105  	require.Equal(t, 1, len(a.txSigners))
   106  	require.Equal(t, transaction.CalledByEntry, a.signers[0].Signer.Scopes)
   107  	require.Equal(t, transaction.CalledByEntry, a.txSigners[0].Scopes)
   108  
   109  	// Contractless account.
   110  	badAcc, err := wallet.NewAccount()
   111  	require.NoError(t, err)
   112  	badAccHash := badAcc.Contract.ScriptHash()
   113  	badAcc.Contract = nil
   114  
   115  	signers := []SignerAccount{{
   116  		Signer: transaction.Signer{
   117  			Account: acc.Contract.ScriptHash(),
   118  			Scopes:  transaction.None,
   119  		},
   120  		Account: acc,
   121  	}, {
   122  		Signer: transaction.Signer{
   123  			Account: badAccHash,
   124  			Scopes:  transaction.CalledByEntry,
   125  		},
   126  		Account: badAcc,
   127  	}}
   128  
   129  	_, err = New(client, signers)
   130  	require.Error(t, err)
   131  
   132  	// GetVersion returning error.
   133  	client.err = errors.New("bad")
   134  	_, err = NewSimple(client, acc)
   135  	require.Error(t, err)
   136  	client.err = nil
   137  
   138  	// Account mismatch.
   139  	acc2, err := wallet.NewAccount()
   140  	require.NoError(t, err)
   141  	signers = []SignerAccount{{
   142  		Signer: transaction.Signer{
   143  			Account: acc2.Contract.ScriptHash(),
   144  			Scopes:  transaction.None,
   145  		},
   146  		Account: acc,
   147  	}, {
   148  		Signer: transaction.Signer{
   149  			Account: acc2.Contract.ScriptHash(),
   150  			Scopes:  transaction.CalledByEntry,
   151  		},
   152  		Account: acc2,
   153  	}}
   154  	_, err = New(client, signers)
   155  	require.Error(t, err)
   156  
   157  	// Good multiaccount.
   158  	signers[0].Signer.Account = acc.Contract.ScriptHash()
   159  	a, err = New(client, signers)
   160  	require.NoError(t, err)
   161  	require.Equal(t, 2, len(a.signers))
   162  	require.Equal(t, 2, len(a.txSigners))
   163  
   164  	// Good tuned
   165  	opts := Options{
   166  		Attributes: []transaction.Attribute{{Type: transaction.HighPriority}},
   167  	}
   168  	a, err = NewTuned(client, signers, opts)
   169  	require.NoError(t, err)
   170  	require.Equal(t, 1, len(a.opts.Attributes))
   171  }
   172  
   173  func TestSimpleWrappers(t *testing.T) {
   174  	client, acc := testRPCAndAccount(t)
   175  	origVer := *client.version
   176  
   177  	a, err := NewSimple(client, acc)
   178  	require.NoError(t, err)
   179  
   180  	client.netFee = 42
   181  	nf, err := a.CalculateNetworkFee(new(transaction.Transaction))
   182  	require.NoError(t, err)
   183  	require.Equal(t, int64(42), nf)
   184  
   185  	client.bCount.Store(100500)
   186  	bc, err := a.GetBlockCount()
   187  	require.NoError(t, err)
   188  	require.Equal(t, uint32(100500), bc)
   189  
   190  	require.Equal(t, netmode.UnitTestNet, a.GetNetwork())
   191  	client.version.Protocol.Network = netmode.TestNet
   192  	require.Equal(t, netmode.UnitTestNet, a.GetNetwork())
   193  	require.Equal(t, origVer, a.GetVersion())
   194  
   195  	a, err = NewSimple(client, acc)
   196  	require.NoError(t, err)
   197  	require.Equal(t, netmode.TestNet, a.GetNetwork())
   198  	require.Equal(t, *client.version, a.GetVersion())
   199  
   200  	client.hash = util.Uint256{1, 2, 3}
   201  	h, vub, err := a.Send(&transaction.Transaction{ValidUntilBlock: 123})
   202  	require.NoError(t, err)
   203  	require.Equal(t, client.hash, h)
   204  	require.Equal(t, uint32(123), vub)
   205  }
   206  
   207  func TestSign(t *testing.T) {
   208  	client, acc := testRPCAndAccount(t)
   209  	acc2, err := wallet.NewAccount()
   210  	require.NoError(t, err)
   211  
   212  	a, err := New(client, []SignerAccount{{
   213  		Signer: transaction.Signer{
   214  			Account: acc.Contract.ScriptHash(),
   215  			Scopes:  transaction.None,
   216  		},
   217  		Account: acc,
   218  	}, {
   219  		Signer: transaction.Signer{
   220  			Account: acc2.Contract.ScriptHash(),
   221  			Scopes:  transaction.CalledByEntry,
   222  		},
   223  		Account: &wallet.Account{ // Looks like acc2, but has no private key.
   224  			Address:      acc2.Address,
   225  			EncryptedWIF: acc2.EncryptedWIF,
   226  			Contract:     acc2.Contract,
   227  		},
   228  	}})
   229  	require.NoError(t, err)
   230  
   231  	script := []byte{1, 2, 3}
   232  	client.hash = util.Uint256{2, 5, 6}
   233  	client.invRes = &result.Invoke{State: "HALT", GasConsumed: 3, Script: script}
   234  
   235  	tx, err := a.MakeUnsignedRun(script, nil)
   236  	require.NoError(t, err)
   237  	require.Error(t, a.Sign(tx))
   238  	_, _, err = a.SignAndSend(tx)
   239  	require.Error(t, err)
   240  }
   241  
   242  func TestSenders(t *testing.T) {
   243  	client, acc := testRPCAndAccount(t)
   244  	a, err := NewSimple(client, acc)
   245  	require.NoError(t, err)
   246  	script := []byte{1, 2, 3}
   247  
   248  	// Bad.
   249  	client.invRes = &result.Invoke{State: "FAULT", GasConsumed: 3, Script: script}
   250  	_, _, err = a.SendCall(util.Uint160{1}, "method", 42)
   251  	require.Error(t, err)
   252  	_, _, err = a.SendTunedCall(util.Uint160{1}, "method", nil, nil, 42)
   253  	require.Error(t, err)
   254  	_, _, err = a.SendRun(script)
   255  	require.Error(t, err)
   256  	_, _, err = a.SendTunedRun(script, nil, nil)
   257  	require.Error(t, err)
   258  	_, _, err = a.SendUncheckedRun(script, 1, nil, func(t *transaction.Transaction) error {
   259  		return errors.New("bad")
   260  	})
   261  	require.Error(t, err)
   262  
   263  	// Good.
   264  	client.hash = util.Uint256{2, 5, 6}
   265  	client.invRes = &result.Invoke{State: "HALT", GasConsumed: 3, Script: script}
   266  	h, vub, err := a.SendCall(util.Uint160{1}, "method", 42)
   267  	require.NoError(t, err)
   268  	require.Equal(t, client.hash, h)
   269  	require.Equal(t, uint32(8), vub)
   270  
   271  	h, vub, err = a.SendTunedCall(util.Uint160{1}, "method", nil, nil, 42)
   272  	require.NoError(t, err)
   273  	require.Equal(t, client.hash, h)
   274  	require.Equal(t, uint32(8), vub)
   275  
   276  	h, vub, err = a.SendRun(script)
   277  	require.NoError(t, err)
   278  	require.Equal(t, client.hash, h)
   279  	require.Equal(t, uint32(8), vub)
   280  
   281  	h, vub, err = a.SendTunedRun(script, nil, nil)
   282  	require.NoError(t, err)
   283  	require.Equal(t, client.hash, h)
   284  	require.Equal(t, uint32(8), vub)
   285  
   286  	h, vub, err = a.SendUncheckedRun(script, 1, nil, nil)
   287  	require.NoError(t, err)
   288  	require.Equal(t, client.hash, h)
   289  	require.Equal(t, uint32(8), vub)
   290  }
   291  
   292  func TestSender(t *testing.T) {
   293  	client, acc := testRPCAndAccount(t)
   294  	a, err := NewSimple(client, acc)
   295  	require.NoError(t, err)
   296  	require.Equal(t, acc.ScriptHash(), a.Sender())
   297  }