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

     1  package rpcsrv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/base64"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"fmt"
    10  	"math/big"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"sort"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/google/uuid"
    20  	"github.com/gorilla/websocket"
    21  	"github.com/nspcc-dev/neo-go/internal/basicchain"
    22  	"github.com/nspcc-dev/neo-go/internal/testchain"
    23  	"github.com/nspcc-dev/neo-go/pkg/config"
    24  	"github.com/nspcc-dev/neo-go/pkg/core"
    25  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    26  	"github.com/nspcc-dev/neo-go/pkg/core/fee"
    27  	"github.com/nspcc-dev/neo-go/pkg/core/native"
    28  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
    29  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    30  	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
    31  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    32  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    33  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    34  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    35  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
    36  	"github.com/nspcc-dev/neo-go/pkg/io"
    37  	"github.com/nspcc-dev/neo-go/pkg/neorpc"
    38  	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
    39  	"github.com/nspcc-dev/neo-go/pkg/network"
    40  	"github.com/nspcc-dev/neo-go/pkg/rpcclient"
    41  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
    42  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
    43  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
    44  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
    45  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
    46  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
    47  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
    48  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/neptoken"
    49  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/nns"
    50  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/notary"
    51  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/oracle"
    52  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/policy"
    53  	"github.com/nspcc-dev/neo-go/pkg/rpcclient/rolemgmt"
    54  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    55  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    56  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
    57  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    58  	"github.com/nspcc-dev/neo-go/pkg/util"
    59  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    60  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    61  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    62  	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
    63  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    64  	"github.com/stretchr/testify/assert"
    65  	"github.com/stretchr/testify/require"
    66  )
    67  
    68  func TestClient_NEP17(t *testing.T) {
    69  	_, _, httpSrv := initServerWithInMemoryChain(t)
    70  
    71  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
    72  	require.NoError(t, err)
    73  	t.Cleanup(c.Close)
    74  	require.NoError(t, c.Init())
    75  
    76  	h, err := util.Uint160DecodeStringLE(testContractHash)
    77  	require.NoError(t, err)
    78  	rub := nep17.NewReader(invoker.New(c, nil), h)
    79  
    80  	t.Run("Decimals", func(t *testing.T) {
    81  		d, err := rub.Decimals()
    82  		require.NoError(t, err)
    83  		require.EqualValues(t, 2, d)
    84  	})
    85  	t.Run("TotalSupply", func(t *testing.T) {
    86  		s, err := rub.TotalSupply()
    87  		require.NoError(t, err)
    88  		require.EqualValues(t, big.NewInt(1_000_000), s)
    89  	})
    90  	t.Run("Symbol", func(t *testing.T) {
    91  		sym, err := rub.Symbol()
    92  		require.NoError(t, err)
    93  		require.Equal(t, "RUB", sym)
    94  	})
    95  	t.Run("TokenInfo", func(t *testing.T) {
    96  		tok, err := neptoken.Info(c, h)
    97  		require.NoError(t, err)
    98  		require.Equal(t, h, tok.Hash)
    99  		require.Equal(t, "Rubl", tok.Name)
   100  		require.Equal(t, "RUB", tok.Symbol)
   101  		require.EqualValues(t, 2, tok.Decimals)
   102  	})
   103  	t.Run("BalanceOf", func(t *testing.T) {
   104  		acc := testchain.PrivateKeyByID(0).GetScriptHash()
   105  		b, err := rub.BalanceOf(acc)
   106  		require.NoError(t, err)
   107  		require.EqualValues(t, big.NewInt(877), b)
   108  	})
   109  }
   110  
   111  func TestClientRoleManagement(t *testing.T) {
   112  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   113  
   114  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   115  	require.NoError(t, err)
   116  	t.Cleanup(c.Close)
   117  	require.NoError(t, c.Init())
   118  
   119  	act, err := actor.New(c, []actor.SignerAccount{{
   120  		Signer: transaction.Signer{
   121  			Account: testchain.CommitteeScriptHash(),
   122  			Scopes:  transaction.CalledByEntry,
   123  		},
   124  		Account: &wallet.Account{
   125  			Address: testchain.CommitteeAddress(),
   126  			Contract: &wallet.Contract{
   127  				Script: testchain.CommitteeVerificationScript(),
   128  			},
   129  		},
   130  	}})
   131  	require.NoError(t, err)
   132  
   133  	height, err := c.GetBlockCount()
   134  	require.NoError(t, err)
   135  
   136  	rm := rolemgmt.New(act)
   137  	ks, err := rm.GetDesignatedByRole(noderoles.Oracle, height)
   138  	require.NoError(t, err)
   139  	require.Equal(t, 0, len(ks))
   140  
   141  	testKeys := keys.PublicKeys{
   142  		testchain.PrivateKeyByID(0).PublicKey(),
   143  		testchain.PrivateKeyByID(1).PublicKey(),
   144  		testchain.PrivateKeyByID(2).PublicKey(),
   145  		testchain.PrivateKeyByID(3).PublicKey(),
   146  	}
   147  
   148  	tx, err := rm.DesignateAsRoleUnsigned(noderoles.Oracle, testKeys)
   149  	require.NoError(t, err)
   150  
   151  	tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
   152  	bl := testchain.NewBlock(t, chain, 1, 0, tx)
   153  	_, err = c.SubmitBlock(*bl)
   154  	require.NoError(t, err)
   155  
   156  	sort.Sort(testKeys)
   157  	ks, err = rm.GetDesignatedByRole(noderoles.Oracle, height+1)
   158  	require.NoError(t, err)
   159  	require.Equal(t, testKeys, ks)
   160  }
   161  
   162  func TestClientPolicyContract(t *testing.T) {
   163  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   164  
   165  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   166  	require.NoError(t, err)
   167  	t.Cleanup(c.Close)
   168  	require.NoError(t, c.Init())
   169  
   170  	polizei := policy.NewReader(invoker.New(c, nil))
   171  
   172  	val, err := polizei.GetExecFeeFactor()
   173  	require.NoError(t, err)
   174  	require.Equal(t, int64(30), val)
   175  
   176  	val, err = polizei.GetFeePerByte()
   177  	require.NoError(t, err)
   178  	require.Equal(t, int64(1000), val)
   179  
   180  	val, err = polizei.GetStoragePrice()
   181  	require.NoError(t, err)
   182  	require.Equal(t, int64(100000), val)
   183  
   184  	val, err = polizei.GetAttributeFee(transaction.NotaryAssistedT)
   185  	require.NoError(t, err)
   186  	require.Equal(t, int64(1000_0000), val)
   187  
   188  	ret, err := polizei.IsBlocked(util.Uint160{})
   189  	require.NoError(t, err)
   190  	require.False(t, ret)
   191  
   192  	act, err := actor.New(c, []actor.SignerAccount{{
   193  		Signer: transaction.Signer{
   194  			Account: testchain.CommitteeScriptHash(),
   195  			Scopes:  transaction.CalledByEntry,
   196  		},
   197  		Account: &wallet.Account{
   198  			Address: testchain.CommitteeAddress(),
   199  			Contract: &wallet.Contract{
   200  				Script: testchain.CommitteeVerificationScript(),
   201  			},
   202  		},
   203  	}})
   204  	require.NoError(t, err)
   205  
   206  	polis := policy.New(act)
   207  
   208  	txexec, err := polis.SetExecFeeFactorUnsigned(100)
   209  	require.NoError(t, err)
   210  
   211  	txnetfee, err := polis.SetFeePerByteUnsigned(500)
   212  	require.NoError(t, err)
   213  
   214  	txstorage, err := polis.SetStoragePriceUnsigned(100500)
   215  	require.NoError(t, err)
   216  
   217  	txattr, err := polis.SetAttributeFeeUnsigned(transaction.NotaryAssistedT, 100500)
   218  	require.NoError(t, err)
   219  
   220  	txblock, err := polis.BlockAccountUnsigned(util.Uint160{1, 2, 3})
   221  	require.NoError(t, err)
   222  
   223  	for _, tx := range []*transaction.Transaction{txattr, txblock, txstorage, txnetfee, txexec} {
   224  		tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
   225  	}
   226  
   227  	bl := testchain.NewBlock(t, chain, 1, 0, txattr, txblock, txstorage, txnetfee, txexec)
   228  	_, err = c.SubmitBlock(*bl)
   229  	require.NoError(t, err)
   230  
   231  	val, err = polizei.GetExecFeeFactor()
   232  	require.NoError(t, err)
   233  	require.Equal(t, int64(100), val)
   234  
   235  	val, err = polizei.GetFeePerByte()
   236  	require.NoError(t, err)
   237  	require.Equal(t, int64(500), val)
   238  
   239  	val, err = polizei.GetStoragePrice()
   240  	require.NoError(t, err)
   241  	require.Equal(t, int64(100500), val)
   242  
   243  	val, err = polizei.GetAttributeFee(transaction.NotaryAssistedT)
   244  	require.NoError(t, err)
   245  	require.Equal(t, int64(100500), val)
   246  
   247  	ret, err = polizei.IsBlocked(util.Uint160{1, 2, 3})
   248  	require.NoError(t, err)
   249  	require.True(t, ret)
   250  }
   251  
   252  func TestClientManagementContract(t *testing.T) {
   253  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   254  
   255  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   256  	require.NoError(t, err)
   257  	t.Cleanup(c.Close)
   258  	require.NoError(t, c.Init())
   259  
   260  	manReader := management.NewReader(invoker.New(c, nil))
   261  
   262  	fee, err := manReader.GetMinimumDeploymentFee()
   263  	require.NoError(t, err)
   264  	require.Equal(t, big.NewInt(10*1_0000_0000), fee)
   265  
   266  	cs1, err := manReader.GetContract(gas.Hash)
   267  	require.NoError(t, err)
   268  	cs2, err := c.GetContractStateByHash(gas.Hash)
   269  	require.NoError(t, err)
   270  	require.Equal(t, cs2, cs1)
   271  	cs1, err = manReader.GetContractByID(-6)
   272  	require.NoError(t, err)
   273  	require.Equal(t, cs2, cs1)
   274  
   275  	ret, err := manReader.HasMethod(gas.Hash, "transfer", 4)
   276  	require.NoError(t, err)
   277  	require.True(t, ret)
   278  
   279  	act, err := actor.New(c, []actor.SignerAccount{{
   280  		Signer: transaction.Signer{
   281  			Account: testchain.CommitteeScriptHash(),
   282  			Scopes:  transaction.CalledByEntry,
   283  		},
   284  		Account: &wallet.Account{
   285  			Address: testchain.CommitteeAddress(),
   286  			Contract: &wallet.Contract{
   287  				Script: testchain.CommitteeVerificationScript(),
   288  			},
   289  		},
   290  	}})
   291  	require.NoError(t, err)
   292  
   293  	ids, err := manReader.GetContractHashesExpanded(10)
   294  	require.NoError(t, err)
   295  	ctrs := make([]management.IDHash, 0)
   296  	for i, s := range []string{testContractHash, verifyContractHash, verifyWithArgsContractHash, nnsContractHash, nfsoContractHash, storageContractHash} {
   297  		h, err := util.Uint160DecodeStringLE(s)
   298  		require.NoError(t, err)
   299  		ctrs = append(ctrs, management.IDHash{ID: int32(i) + 1, Hash: h})
   300  	}
   301  	require.Equal(t, ctrs, ids)
   302  
   303  	iter, err := manReader.GetContractHashes()
   304  	require.NoError(t, err)
   305  	ids, err = iter.Next(3)
   306  	require.NoError(t, err)
   307  	require.Equal(t, ctrs[:3], ids)
   308  	ids, err = iter.Next(10)
   309  	require.NoError(t, err)
   310  	require.Equal(t, ctrs[3:], ids)
   311  
   312  	man := management.New(act)
   313  
   314  	txfee, err := man.SetMinimumDeploymentFeeUnsigned(big.NewInt(1 * 1_0000_0000))
   315  	require.NoError(t, err)
   316  	txdepl, err := man.DeployUnsigned(&cs1.NEF, &cs1.Manifest, nil) // Redeploy from a different account.
   317  	require.NoError(t, err)
   318  
   319  	for _, tx := range []*transaction.Transaction{txfee, txdepl} {
   320  		tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
   321  	}
   322  
   323  	bl := testchain.NewBlock(t, chain, 1, 0, txfee, txdepl)
   324  	_, err = c.SubmitBlock(*bl)
   325  	require.NoError(t, err)
   326  
   327  	fee, err = manReader.GetMinimumDeploymentFee()
   328  	require.NoError(t, err)
   329  	require.Equal(t, big.NewInt(1_0000_0000), fee)
   330  
   331  	appLog, err := c.GetApplicationLog(txdepl.Hash(), nil)
   332  	require.NoError(t, err)
   333  	require.Equal(t, vmstate.Halt, appLog.Executions[0].VMState)
   334  	require.Equal(t, 1, len(appLog.Executions[0].Events))
   335  }
   336  
   337  func TestClientNEOContract(t *testing.T) {
   338  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   339  
   340  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   341  	require.NoError(t, err)
   342  	t.Cleanup(c.Close)
   343  	require.NoError(t, c.Init())
   344  
   345  	neoR := neo.NewReader(invoker.New(c, nil))
   346  
   347  	sym, err := neoR.Symbol()
   348  	require.NoError(t, err)
   349  	require.Equal(t, "NEO", sym)
   350  
   351  	dec, err := neoR.Decimals()
   352  	require.NoError(t, err)
   353  	require.Equal(t, 0, dec)
   354  
   355  	ts, err := neoR.TotalSupply()
   356  	require.NoError(t, err)
   357  	require.Equal(t, big.NewInt(1_0000_0000), ts)
   358  
   359  	comm, err := neoR.GetCommittee()
   360  	require.NoError(t, err)
   361  	commScript, err := smartcontract.CreateMajorityMultiSigRedeemScript(comm)
   362  	require.NoError(t, err)
   363  	require.Equal(t, testchain.CommitteeScriptHash(), hash.Hash160(commScript))
   364  
   365  	vals, err := neoR.GetNextBlockValidators()
   366  	require.NoError(t, err)
   367  	valsScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(vals)
   368  	require.NoError(t, err)
   369  	require.Equal(t, testchain.MultisigScriptHash(), hash.Hash160(valsScript))
   370  
   371  	gpb, err := neoR.GetGasPerBlock()
   372  	require.NoError(t, err)
   373  	require.Equal(t, int64(5_0000_0000), gpb)
   374  
   375  	regP, err := neoR.GetRegisterPrice()
   376  	require.NoError(t, err)
   377  	require.Equal(t, int64(1000_0000_0000), regP)
   378  
   379  	acc0 := testchain.PrivateKey(0).PublicKey().GetScriptHash()
   380  	uncl, err := neoR.UnclaimedGas(acc0, chain.BlockHeight()+1)
   381  	require.NoError(t, err)
   382  	require.Equal(t, big.NewInt(10000), uncl)
   383  
   384  	accState, err := neoR.GetAccountState(acc0)
   385  	require.NoError(t, err)
   386  	require.Equal(t, big.NewInt(1000), &accState.Balance)
   387  	require.Equal(t, uint32(4), accState.BalanceHeight)
   388  
   389  	cands, err := neoR.GetCandidates()
   390  	require.NoError(t, err)
   391  	require.Equal(t, 0, len(cands)) // No registrations.
   392  
   393  	cands, err = neoR.GetAllCandidatesExpanded(100)
   394  	require.NoError(t, err)
   395  	require.Equal(t, 0, len(cands)) // No registrations.
   396  
   397  	iter, err := neoR.GetAllCandidates()
   398  	require.NoError(t, err)
   399  	cands, err = iter.Next(10)
   400  	require.NoError(t, err)
   401  	require.Equal(t, 0, len(cands)) // No registrations.
   402  	require.NoError(t, iter.Terminate())
   403  
   404  	act, err := actor.New(c, []actor.SignerAccount{{
   405  		Signer: transaction.Signer{
   406  			Account: testchain.CommitteeScriptHash(),
   407  			Scopes:  transaction.CalledByEntry,
   408  		},
   409  		Account: &wallet.Account{
   410  			Address: testchain.CommitteeAddress(),
   411  			Contract: &wallet.Contract{
   412  				Script: testchain.CommitteeVerificationScript(),
   413  			},
   414  		},
   415  	}})
   416  
   417  	require.NoError(t, err)
   418  
   419  	neoC := neo.New(act)
   420  
   421  	txgpb, err := neoC.SetGasPerBlockUnsigned(10 * 1_0000_0000)
   422  	require.NoError(t, err)
   423  	txregp, err := neoC.SetRegisterPriceUnsigned(1_0000)
   424  	require.NoError(t, err)
   425  
   426  	for _, tx := range []*transaction.Transaction{txgpb, txregp} {
   427  		tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
   428  	}
   429  
   430  	bl := testchain.NewBlock(t, chain, 1, 0, txgpb, txregp)
   431  	_, err = c.SubmitBlock(*bl)
   432  	require.NoError(t, err)
   433  
   434  	gpb, err = neoR.GetGasPerBlock()
   435  	require.NoError(t, err)
   436  	require.Equal(t, int64(10_0000_0000), gpb)
   437  
   438  	regP, err = neoR.GetRegisterPrice()
   439  	require.NoError(t, err)
   440  	require.Equal(t, int64(10000), regP)
   441  
   442  	act0, err := actor.NewSimple(c, wallet.NewAccountFromPrivateKey(testchain.PrivateKey(0)))
   443  	require.NoError(t, err)
   444  	neo0 := neo.New(act0)
   445  
   446  	txreg, err := neo0.RegisterCandidateTransaction(testchain.PrivateKey(0).PublicKey())
   447  	require.NoError(t, err)
   448  	bl = testchain.NewBlock(t, chain, 1, 0, txreg)
   449  	_, err = c.SubmitBlock(*bl)
   450  	require.NoError(t, err)
   451  
   452  	txvote, err := neo0.VoteTransaction(acc0, testchain.PrivateKey(0).PublicKey())
   453  	require.NoError(t, err)
   454  	bl = testchain.NewBlock(t, chain, 1, 0, txvote)
   455  	_, err = c.SubmitBlock(*bl)
   456  	require.NoError(t, err)
   457  
   458  	txunreg, err := neo0.UnregisterCandidateTransaction(testchain.PrivateKey(0).PublicKey())
   459  	require.NoError(t, err)
   460  	bl = testchain.NewBlock(t, chain, 1, 0, txunreg)
   461  	_, err = c.SubmitBlock(*bl)
   462  	require.NoError(t, err)
   463  }
   464  
   465  func TestClientNotary(t *testing.T) {
   466  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   467  
   468  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   469  	require.NoError(t, err)
   470  	t.Cleanup(c.Close)
   471  	require.NoError(t, c.Init())
   472  
   473  	notaReader := notary.NewReader(invoker.New(c, nil))
   474  
   475  	priv0 := testchain.PrivateKeyByID(0)
   476  	priv0Hash := priv0.PublicKey().GetScriptHash()
   477  	bal, err := notaReader.BalanceOf(priv0Hash)
   478  	require.NoError(t, err)
   479  	require.Equal(t, big.NewInt(10_0000_0000), bal)
   480  
   481  	expir, err := notaReader.ExpirationOf(priv0Hash)
   482  	require.NoError(t, err)
   483  	require.Equal(t, uint32(1007), expir)
   484  
   485  	maxNVBd, err := notaReader.GetMaxNotValidBeforeDelta()
   486  	require.NoError(t, err)
   487  	require.Equal(t, uint32(140), maxNVBd)
   488  
   489  	commAct, err := actor.New(c, []actor.SignerAccount{{
   490  		Signer: transaction.Signer{
   491  			Account: testchain.CommitteeScriptHash(),
   492  			Scopes:  transaction.CalledByEntry,
   493  		},
   494  		Account: &wallet.Account{
   495  			Address: testchain.CommitteeAddress(),
   496  			Contract: &wallet.Contract{
   497  				Script: testchain.CommitteeVerificationScript(),
   498  			},
   499  		},
   500  	}})
   501  	require.NoError(t, err)
   502  	notaComm := notary.New(commAct)
   503  
   504  	txNVB, err := notaComm.SetMaxNotValidBeforeDeltaUnsigned(210)
   505  	require.NoError(t, err)
   506  
   507  	txNVB.Scripts[0].InvocationScript = testchain.SignCommittee(txNVB)
   508  	bl := testchain.NewBlock(t, chain, 1, 0, txNVB)
   509  	_, err = c.SubmitBlock(*bl)
   510  	require.NoError(t, err)
   511  
   512  	maxNVBd, err = notaReader.GetMaxNotValidBeforeDelta()
   513  	require.NoError(t, err)
   514  	require.Equal(t, uint32(210), maxNVBd)
   515  
   516  	privAct, err := actor.New(c, []actor.SignerAccount{{
   517  		Signer: transaction.Signer{
   518  			Account: priv0Hash,
   519  			Scopes:  transaction.CalledByEntry,
   520  		},
   521  		Account: wallet.NewAccountFromPrivateKey(priv0),
   522  	}})
   523  	require.NoError(t, err)
   524  	notaPriv := notary.New(privAct)
   525  
   526  	txLock, err := notaPriv.LockDepositUntilTransaction(priv0Hash, 1111)
   527  	require.NoError(t, err)
   528  
   529  	bl = testchain.NewBlock(t, chain, 1, 0, txLock)
   530  	_, err = c.SubmitBlock(*bl)
   531  	require.NoError(t, err)
   532  
   533  	expir, err = notaReader.ExpirationOf(priv0Hash)
   534  	require.NoError(t, err)
   535  	require.Equal(t, uint32(1111), expir)
   536  
   537  	_, err = notaPriv.WithdrawTransaction(priv0Hash, priv0Hash)
   538  	require.Error(t, err) // Can't be withdrawn until 1111.
   539  }
   540  
   541  func TestCalculateNetworkFee_Base(t *testing.T) {
   542  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   543  	const extraFee = 10
   544  	var nonce uint32
   545  
   546  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   547  	require.NoError(t, err)
   548  	t.Cleanup(c.Close)
   549  	require.NoError(t, c.Init())
   550  
   551  	feePerByte := chain.FeePerByte()
   552  
   553  	t.Run("Simple", func(t *testing.T) {
   554  		acc0 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
   555  		check := func(t *testing.T, extraFee int64) {
   556  			tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   557  			tx.ValidUntilBlock = 25
   558  			tx.Signers = []transaction.Signer{{
   559  				Account: acc0.PrivateKey().GetScriptHash(),
   560  				Scopes:  transaction.CalledByEntry,
   561  			}}
   562  			tx.Nonce = nonce
   563  			nonce++
   564  
   565  			tx.Scripts = []transaction.Witness{
   566  				{VerificationScript: acc0.GetVerificationScript()},
   567  			}
   568  			actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
   569  			require.NoError(t, err)
   570  			tx.NetworkFee = actualCalculatedNetFee + extraFee
   571  
   572  			require.NoError(t, acc0.SignTx(testchain.Network(), tx))
   573  			cFee, _ := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
   574  			expected := int64(io.GetVarSize(tx))*feePerByte + cFee + extraFee
   575  
   576  			require.Equal(t, expected, actualCalculatedNetFee+extraFee)
   577  			err = chain.VerifyTx(tx)
   578  			if extraFee < 0 {
   579  				require.Error(t, err)
   580  			} else {
   581  				require.NoError(t, err)
   582  			}
   583  		}
   584  
   585  		t.Run("with extra fee", func(t *testing.T) {
   586  			// check that calculated network fee with extra value is enough
   587  			check(t, extraFee)
   588  		})
   589  		t.Run("without extra fee", func(t *testing.T) {
   590  			// check that calculated network fee without extra value is enough
   591  			check(t, 0)
   592  		})
   593  		t.Run("exactFee-1", func(t *testing.T) {
   594  			// check that we don't add unexpected extra GAS
   595  			check(t, -1)
   596  		})
   597  	})
   598  
   599  	t.Run("Multi", func(t *testing.T) {
   600  		acc0 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
   601  		acc1 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
   602  		err = acc1.ConvertMultisig(3, keys.PublicKeys{
   603  			testchain.PrivateKeyByID(0).PublicKey(),
   604  			testchain.PrivateKeyByID(1).PublicKey(),
   605  			testchain.PrivateKeyByID(2).PublicKey(),
   606  			testchain.PrivateKeyByID(3).PublicKey(),
   607  		})
   608  		require.NoError(t, err)
   609  		check := func(t *testing.T, extraFee int64) {
   610  			tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   611  			tx.ValidUntilBlock = 25
   612  			tx.Signers = []transaction.Signer{
   613  				{
   614  					Account: acc0.PrivateKey().GetScriptHash(),
   615  					Scopes:  transaction.CalledByEntry,
   616  				},
   617  				{
   618  					Account: hash.Hash160(acc1.Contract.Script),
   619  					Scopes:  transaction.Global,
   620  				},
   621  			}
   622  			tx.Nonce = nonce
   623  			nonce++
   624  
   625  			tx.Scripts = []transaction.Witness{
   626  				{VerificationScript: acc0.GetVerificationScript()},
   627  				{VerificationScript: acc1.GetVerificationScript()},
   628  			}
   629  			actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
   630  			require.NoError(t, err)
   631  			tx.NetworkFee = actualCalculatedNetFee + extraFee
   632  
   633  			tx.Scripts = nil
   634  			require.NoError(t, acc0.SignTx(testchain.Network(), tx))
   635  			tx.Scripts = append(tx.Scripts, transaction.Witness{
   636  				InvocationScript:   testchain.Sign(tx),
   637  				VerificationScript: acc1.Contract.Script,
   638  			})
   639  			cFee, _ := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
   640  			cFeeM, _ := fee.Calculate(chain.GetBaseExecFee(), acc1.Contract.Script)
   641  			expected := int64(io.GetVarSize(tx))*feePerByte + cFee + cFeeM + extraFee
   642  
   643  			require.Equal(t, expected, actualCalculatedNetFee+extraFee)
   644  			err = chain.VerifyTx(tx)
   645  			if extraFee < 0 {
   646  				require.Error(t, err)
   647  			} else {
   648  				require.NoError(t, err)
   649  			}
   650  		}
   651  
   652  		t.Run("with extra fee", func(t *testing.T) {
   653  			// check that calculated network fee with extra value is enough
   654  			check(t, extraFee)
   655  		})
   656  		t.Run("without extra fee", func(t *testing.T) {
   657  			// check that calculated network fee without extra value is enough
   658  			check(t, 0)
   659  		})
   660  		t.Run("exactFee-1", func(t *testing.T) {
   661  			// check that we don't add unexpected extra GAS
   662  			check(t, -1)
   663  		})
   664  	})
   665  	t.Run("Contract", func(t *testing.T) {
   666  		h, err := util.Uint160DecodeStringLE(verifyContractHash)
   667  		require.NoError(t, err)
   668  		priv := testchain.PrivateKeyByID(0)
   669  		acc0 := wallet.NewAccountFromPrivateKey(priv)
   670  		acc1 := wallet.NewAccountFromPrivateKey(priv) // contract account
   671  		acc1.Contract.Deployed = true
   672  		acc1.Contract.Script, err = base64.StdEncoding.DecodeString(verifyContractAVM)
   673  		require.NoError(t, err)
   674  
   675  		newTx := func(t *testing.T) *transaction.Transaction {
   676  			tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   677  			tx.ValidUntilBlock = chain.BlockHeight() + 10
   678  			return tx
   679  		}
   680  
   681  		t.Run("Valid", func(t *testing.T) {
   682  			check := func(t *testing.T, extraFee int64) {
   683  				tx := newTx(t)
   684  				tx.Signers = []transaction.Signer{
   685  					{
   686  						Account: acc0.PrivateKey().GetScriptHash(),
   687  						Scopes:  transaction.CalledByEntry,
   688  					},
   689  					{
   690  						Account: h,
   691  						Scopes:  transaction.Global,
   692  					},
   693  				}
   694  				// we need to fill standard verification scripts to use CalculateNetworkFee.
   695  				tx.Scripts = []transaction.Witness{
   696  					{VerificationScript: acc0.GetVerificationScript()},
   697  					{},
   698  				}
   699  				actual, err := c.CalculateNetworkFee(tx)
   700  				require.NoError(t, err)
   701  				tx.NetworkFee = actual + extraFee
   702  
   703  				tx.Scripts = nil
   704  				require.NoError(t, acc0.SignTx(testchain.Network(), tx))
   705  				tx.Scripts = append(tx.Scripts, transaction.Witness{})
   706  				err = chain.VerifyTx(tx)
   707  				if extraFee < 0 {
   708  					require.Error(t, err)
   709  				} else {
   710  					require.NoError(t, err)
   711  				}
   712  			}
   713  
   714  			t.Run("with extra fee", func(t *testing.T) {
   715  				// check that calculated network fee with extra value is enough
   716  				check(t, extraFee)
   717  			})
   718  			t.Run("without extra fee", func(t *testing.T) {
   719  				// check that calculated network fee without extra value is enough
   720  				check(t, 0)
   721  			})
   722  			t.Run("exactFee-1", func(t *testing.T) {
   723  				// check that we don't add unexpected extra GAS
   724  				check(t, -1)
   725  			})
   726  		})
   727  	})
   728  }
   729  
   730  func TestCalculateNetworkFee(t *testing.T) {
   731  	chain, _, httpSrv := initServerWithInMemoryChain(t)
   732  	const extraFee = 10
   733  
   734  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   735  	require.NoError(t, err)
   736  	t.Cleanup(c.Close)
   737  	require.NoError(t, c.Init())
   738  
   739  	h, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
   740  	require.NoError(t, err)
   741  	priv := testchain.PrivateKeyByID(0)
   742  	acc0 := wallet.NewAccountFromPrivateKey(priv)
   743  
   744  	t.Run("ContractWithArgs", func(t *testing.T) {
   745  		check := func(t *testing.T, extraFee int64) {
   746  			tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   747  			require.NoError(t, err)
   748  			tx.ValidUntilBlock = chain.BlockHeight() + 10
   749  			tx.Signers = []transaction.Signer{
   750  				{
   751  					Account: acc0.PrivateKey().GetScriptHash(),
   752  					Scopes:  transaction.CalledByEntry,
   753  				},
   754  				{
   755  					Account: h,
   756  					Scopes:  transaction.Global,
   757  				},
   758  			}
   759  
   760  			bw := io.NewBufBinWriter()
   761  			emit.Bool(bw.BinWriter, false)
   762  			emit.Int(bw.BinWriter, int64(4))
   763  			emit.String(bw.BinWriter, "good_string") // contract's `verify` return `true` with this string
   764  			require.NoError(t, bw.Err)
   765  			contractInv := bw.Bytes()
   766  			// we need to fill standard verification scripts to use CalculateNetworkFee.
   767  			tx.Scripts = []transaction.Witness{
   768  				{VerificationScript: acc0.GetVerificationScript()},
   769  				{InvocationScript: contractInv},
   770  			}
   771  			tx.NetworkFee, err = c.CalculateNetworkFee(tx)
   772  			require.NoError(t, err)
   773  			tx.NetworkFee += extraFee
   774  			tx.Scripts = nil
   775  
   776  			require.NoError(t, acc0.SignTx(testchain.Network(), tx))
   777  			tx.Scripts = append(tx.Scripts, transaction.Witness{InvocationScript: contractInv})
   778  			err = chain.VerifyTx(tx)
   779  			if extraFee < 0 {
   780  				require.Error(t, err)
   781  			} else {
   782  				require.NoError(t, err)
   783  			}
   784  		}
   785  
   786  		t.Run("with extra fee", func(t *testing.T) {
   787  			// check that calculated network fee with extra value is enough
   788  			check(t, extraFee)
   789  		})
   790  		t.Run("without extra fee", func(t *testing.T) {
   791  			// check that calculated network fee without extra value is enough
   792  			check(t, 0)
   793  		})
   794  		t.Run("exactFee-1", func(t *testing.T) {
   795  			// check that we don't add unexpected extra GAS
   796  			check(t, -1)
   797  		})
   798  	})
   799  	t.Run("extra attribute fee", func(t *testing.T) {
   800  		const conflictsFee = 100
   801  
   802  		tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   803  		tx.ValidUntilBlock = chain.BlockHeight() + 10
   804  		signer0 := transaction.Signer{
   805  			Account: acc0.ScriptHash(),
   806  			Scopes:  transaction.CalledByEntry,
   807  		}
   808  		priv1 := testchain.PrivateKeyByID(1)
   809  		acc1 := wallet.NewAccountFromPrivateKey(priv1)
   810  		signer1 := transaction.Signer{
   811  			Account: acc1.ScriptHash(),
   812  			Scopes:  transaction.CalledByEntry,
   813  		}
   814  		tx.Signers = []transaction.Signer{signer0, signer1}
   815  		tx.Attributes = []transaction.Attribute{
   816  			{
   817  				Type:  transaction.ConflictsT,
   818  				Value: &transaction.Conflicts{Hash: util.Uint256{1, 2, 3}},
   819  			},
   820  		}
   821  		tx.Scripts = []transaction.Witness{
   822  			{VerificationScript: acc0.Contract.Script},
   823  			{VerificationScript: acc1.Contract.Script},
   824  		}
   825  		oldFee, err := c.CalculateNetworkFee(tx)
   826  		require.NoError(t, err)
   827  
   828  		// Set fee per Conflicts attribute.
   829  		script, err := smartcontract.CreateCallScript(nativehashes.PolicyContract, "setAttributeFee", byte(transaction.ConflictsT), conflictsFee)
   830  		require.NoError(t, err)
   831  		txSetFee := transaction.New(script, 1_0000_0000)
   832  		txSetFee.ValidUntilBlock = chain.BlockHeight() + 1
   833  		txSetFee.Signers = []transaction.Signer{
   834  			signer0,
   835  			{
   836  				Account: testchain.CommitteeScriptHash(),
   837  				Scopes:  transaction.CalledByEntry,
   838  			},
   839  		}
   840  		txSetFee.NetworkFee = 10_0000_0000
   841  		require.NoError(t, acc0.SignTx(testchain.Network(), txSetFee))
   842  		txSetFee.Scripts = append(txSetFee.Scripts, transaction.Witness{
   843  			InvocationScript:   testchain.SignCommittee(txSetFee),
   844  			VerificationScript: testchain.CommitteeVerificationScript(),
   845  		})
   846  		require.NoError(t, chain.AddBlock(testchain.NewBlock(t, chain, 1, 0, txSetFee)))
   847  
   848  		// Calculate network fee one more time with updated Conflicts price.
   849  		newFee, err := c.CalculateNetworkFee(tx)
   850  		require.NoError(t, err)
   851  
   852  		expectedDiff := len(tx.Signers) * len(tx.GetAttributes(transaction.ConflictsT)) * conflictsFee
   853  		require.Equal(t, int64(expectedDiff), newFee-oldFee)
   854  	})
   855  }
   856  
   857  func TestNotaryActor(t *testing.T) {
   858  	_, _, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
   859  
   860  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   861  	require.NoError(t, err)
   862  	t.Cleanup(c.Close)
   863  
   864  	sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
   865  	acc := wallet.NewAccountFromPrivateKey(sender)
   866  
   867  	comm, err := c.GetCommittee()
   868  	require.NoError(t, err)
   869  
   870  	multiAcc := &wallet.Account{}
   871  	*multiAcc = *acc
   872  	require.NoError(t, multiAcc.ConvertMultisig(smartcontract.GetMajorityHonestNodeCount(len(comm)), comm))
   873  
   874  	nact, err := notary.NewActor(c, []actor.SignerAccount{{
   875  		Signer: transaction.Signer{
   876  			Account: multiAcc.Contract.ScriptHash(),
   877  			Scopes:  transaction.CalledByEntry,
   878  		},
   879  		Account: multiAcc,
   880  	}}, acc)
   881  	require.NoError(t, err)
   882  	neoW := neo.New(nact)
   883  	_, _, _, err = nact.Notarize(neoW.SetRegisterPriceTransaction(1_0000_0000))
   884  	require.NoError(t, err)
   885  }
   886  
   887  func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
   888  	var (
   889  		mainHash1, fallbackHash1, mainHash2, fallbackHash2 util.Uint256
   890  		tx1, tx2                                           *transaction.Transaction
   891  	)
   892  
   893  	_, _, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
   894  
   895  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
   896  	require.NoError(t, err)
   897  	t.Cleanup(c.Close)
   898  	t.Run("getrawnotarypool", func(t *testing.T) {
   899  		t.Run("empty pool", func(t *testing.T) {
   900  			np, err := c.GetRawNotaryPool()
   901  			require.NoError(t, err)
   902  			require.Equal(t, 0, len(np.Hashes))
   903  		})
   904  
   905  		sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
   906  		acc := wallet.NewAccountFromPrivateKey(sender)
   907  
   908  		comm, err := c.GetCommittee()
   909  		require.NoError(t, err)
   910  
   911  		multiAcc := &wallet.Account{}
   912  		*multiAcc = *acc
   913  		require.NoError(t, multiAcc.ConvertMultisig(smartcontract.GetMajorityHonestNodeCount(len(comm)), comm))
   914  
   915  		nact, err := notary.NewActor(c, []actor.SignerAccount{{
   916  			Signer: transaction.Signer{
   917  				Account: multiAcc.Contract.ScriptHash(),
   918  				Scopes:  transaction.CalledByEntry,
   919  			},
   920  			Account: multiAcc,
   921  		}}, acc)
   922  		require.NoError(t, err)
   923  		neoW := neo.New(nact)
   924  		// Send the 1st notary request
   925  		tx1, err = neoW.SetRegisterPriceTransaction(1_0000_0000)
   926  		require.NoError(t, err)
   927  		mainHash1, fallbackHash1, _, err = nact.Notarize(tx1, err)
   928  		require.NoError(t, err)
   929  
   930  		checkTxInPool := func(t *testing.T, mainHash, fallbackHash util.Uint256, res *result.RawNotaryPool) {
   931  			actFallbacks, ok := res.Hashes[mainHash]
   932  			require.Equal(t, true, ok)
   933  			require.Equal(t, 1, len(actFallbacks))
   934  			require.Equal(t, fallbackHash, actFallbacks[0])
   935  		}
   936  		t.Run("nonempty pool", func(t *testing.T) {
   937  			actNotaryPool, err := c.GetRawNotaryPool()
   938  			require.NoError(t, err)
   939  			require.Equal(t, 1, len(actNotaryPool.Hashes))
   940  			checkTxInPool(t, mainHash1, fallbackHash1, actNotaryPool)
   941  		})
   942  
   943  		// Send the 2nd notary request
   944  		tx2, err = neoW.SetRegisterPriceTransaction(2_0000_0000)
   945  		require.NoError(t, err)
   946  		mainHash2, fallbackHash2, _, err = nact.Notarize(tx2, err)
   947  		require.NoError(t, err)
   948  
   949  		t.Run("pool with 2", func(t *testing.T) {
   950  			actNotaryPool, err := c.GetRawNotaryPool()
   951  			require.NoError(t, err)
   952  			require.Equal(t, 2, len(actNotaryPool.Hashes))
   953  			checkTxInPool(t, mainHash1, fallbackHash1, actNotaryPool)
   954  			checkTxInPool(t, mainHash2, fallbackHash2, actNotaryPool)
   955  		})
   956  	})
   957  	t.Run("getrawnotarytransaction", func(t *testing.T) {
   958  		t.Run("client GetRawNotaryTransaction", func(t *testing.T) {
   959  			t.Run("unknown transaction", func(t *testing.T) {
   960  				_, err := c.GetRawNotaryTransaction(util.Uint256{0, 0, 0})
   961  				require.Error(t, err)
   962  				require.ErrorIs(t, err, neorpc.ErrUnknownTransaction)
   963  			})
   964  			_ = tx1.Size()
   965  			_ = tx2.Size()
   966  			// RPC server returns empty scripts in transaction.Witness,
   967  			// thus here the nil-value was changed to empty value.
   968  			if tx1.Scripts[1].InvocationScript == nil && tx1.Scripts[1].VerificationScript == nil {
   969  				tx1.Scripts[1] = transaction.Witness{
   970  					InvocationScript:   []byte{},
   971  					VerificationScript: []byte{},
   972  				}
   973  			}
   974  			if tx2.Scripts[1].InvocationScript == nil && tx2.Scripts[1].VerificationScript == nil {
   975  				tx2.Scripts[1] = transaction.Witness{
   976  					InvocationScript:   []byte{},
   977  					VerificationScript: []byte{},
   978  				}
   979  			}
   980  			t.Run("transactions from pool", func(t *testing.T) {
   981  				mainTx1, err := c.GetRawNotaryTransaction(mainHash1)
   982  				require.NoError(t, err)
   983  				require.Equal(t, tx1, mainTx1)
   984  				_, err = c.GetRawNotaryTransaction(fallbackHash1)
   985  				require.NoError(t, err)
   986  
   987  				mainTx2, err := c.GetRawNotaryTransaction(mainHash2)
   988  				require.NoError(t, err)
   989  				require.Equal(t, tx2, mainTx2)
   990  				_, err = c.GetRawNotaryTransaction(fallbackHash2)
   991  				require.NoError(t, err)
   992  			})
   993  		})
   994  		t.Run("client GetRawNotaryTransactionVerbose", func(t *testing.T) {
   995  			t.Run("unknown transaction", func(t *testing.T) {
   996  				_, err := c.GetRawNotaryTransactionVerbose(util.Uint256{0, 0, 0})
   997  				require.Error(t, err)
   998  				require.ErrorIs(t, err, neorpc.ErrUnknownTransaction)
   999  			})
  1000  			t.Run("transactions from pool", func(t *testing.T) {
  1001  				mainTx1, err := c.GetRawNotaryTransactionVerbose(mainHash1)
  1002  				require.NoError(t, err)
  1003  				require.Equal(t, tx1, mainTx1)
  1004  				_, err = c.GetRawNotaryTransactionVerbose(fallbackHash1)
  1005  				require.NoError(t, err)
  1006  
  1007  				mainTx2, err := c.GetRawNotaryTransactionVerbose(mainHash2)
  1008  				require.NoError(t, err)
  1009  				require.Equal(t, tx2, mainTx2)
  1010  				_, err = c.GetRawNotaryTransactionVerbose(fallbackHash2)
  1011  				require.NoError(t, err)
  1012  			})
  1013  		})
  1014  	})
  1015  }
  1016  
  1017  func TestPing(t *testing.T) {
  1018  	_, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
  1019  
  1020  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1021  	require.NoError(t, err)
  1022  	t.Cleanup(c.Close)
  1023  	require.NoError(t, c.Init())
  1024  
  1025  	require.NoError(t, c.Ping())
  1026  	rpcSrv.Shutdown()
  1027  	httpSrv.Close()
  1028  	require.Error(t, c.Ping())
  1029  }
  1030  
  1031  func TestCreateNEP17TransferTx(t *testing.T) {
  1032  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1033  
  1034  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1035  	require.NoError(t, err)
  1036  	t.Cleanup(c.Close)
  1037  	require.NoError(t, c.Init())
  1038  
  1039  	priv := testchain.PrivateKeyByID(0)
  1040  	acc := wallet.NewAccountFromPrivateKey(priv)
  1041  	addr := priv.PublicKey().GetScriptHash()
  1042  
  1043  	t.Run("default scope", func(t *testing.T) {
  1044  		act, err := actor.NewSimple(c, acc)
  1045  		require.NoError(t, err)
  1046  		gasprom := gas.New(act)
  1047  		tx, err := gasprom.TransferUnsigned(addr, util.Uint160{}, big.NewInt(1000), nil)
  1048  		require.NoError(t, err)
  1049  		require.NoError(t, acc.SignTx(testchain.Network(), tx))
  1050  		require.NoError(t, chain.VerifyTx(tx))
  1051  		ic, err := chain.GetTestVM(trigger.Application, tx, nil)
  1052  		require.NoError(t, err)
  1053  		ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
  1054  		require.NoError(t, ic.VM.Run())
  1055  	})
  1056  	t.Run("default scope, multitransfer", func(t *testing.T) {
  1057  		act, err := actor.NewSimple(c, acc)
  1058  		require.NoError(t, err)
  1059  		gazprom := gas.New(act)
  1060  		tx, err := gazprom.MultiTransferTransaction([]nep17.TransferParameters{
  1061  			{From: addr, To: util.Uint160{3, 2, 1}, Amount: big.NewInt(1000), Data: nil},
  1062  			{From: addr, To: util.Uint160{1, 2, 3}, Amount: big.NewInt(1000), Data: nil},
  1063  		})
  1064  		require.NoError(t, err)
  1065  		require.NoError(t, chain.VerifyTx(tx))
  1066  		ic, err := chain.GetTestVM(trigger.Application, tx, nil)
  1067  		require.NoError(t, err)
  1068  		ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
  1069  		require.NoError(t, ic.VM.Run())
  1070  		require.Equal(t, 2, len(ic.Notifications))
  1071  	})
  1072  	t.Run("none scope", func(t *testing.T) {
  1073  		act, err := actor.New(c, []actor.SignerAccount{{
  1074  			Signer: transaction.Signer{
  1075  				Account: addr,
  1076  				Scopes:  transaction.None,
  1077  			},
  1078  			Account: acc,
  1079  		}})
  1080  		require.NoError(t, err)
  1081  		gasprom := gas.New(act)
  1082  		_, err = gasprom.TransferUnsigned(addr, util.Uint160{}, big.NewInt(1000), nil)
  1083  		require.Error(t, err)
  1084  	})
  1085  	t.Run("customcontracts scope", func(t *testing.T) {
  1086  		act, err := actor.New(c, []actor.SignerAccount{{
  1087  			Signer: transaction.Signer{
  1088  				Account:          priv.PublicKey().GetScriptHash(),
  1089  				Scopes:           transaction.CustomContracts,
  1090  				AllowedContracts: []util.Uint160{gas.Hash},
  1091  			},
  1092  			Account: acc,
  1093  		}})
  1094  		require.NoError(t, err)
  1095  		gasprom := gas.New(act)
  1096  		tx, err := gasprom.TransferUnsigned(addr, util.Uint160{}, big.NewInt(1000), nil)
  1097  		require.NoError(t, err)
  1098  		require.NoError(t, acc.SignTx(testchain.Network(), tx))
  1099  		require.NoError(t, chain.VerifyTx(tx))
  1100  		ic, err := chain.GetTestVM(trigger.Application, tx, nil)
  1101  		require.NoError(t, err)
  1102  		ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
  1103  		require.NoError(t, ic.VM.Run())
  1104  	})
  1105  }
  1106  
  1107  func TestInvokeVerify(t *testing.T) {
  1108  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1109  
  1110  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1111  	require.NoError(t, err)
  1112  	t.Cleanup(c.Close)
  1113  	require.NoError(t, c.Init())
  1114  
  1115  	contract, err := util.Uint160DecodeStringLE(verifyContractHash)
  1116  	require.NoError(t, err)
  1117  
  1118  	t.Run("positive, with signer", func(t *testing.T) {
  1119  		res, err := c.InvokeContractVerify(contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1120  		require.NoError(t, err)
  1121  		require.Equal(t, "HALT", res.State)
  1122  		require.Equal(t, 1, len(res.Stack))
  1123  		require.True(t, res.Stack[0].Value().(bool))
  1124  	})
  1125  
  1126  	t.Run("positive, historic, by height, with signer", func(t *testing.T) {
  1127  		h := chain.BlockHeight() - 1
  1128  		res, err := c.InvokeContractVerifyAtHeight(h, contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1129  		require.NoError(t, err)
  1130  		require.Equal(t, "HALT", res.State)
  1131  		require.Equal(t, 1, len(res.Stack))
  1132  		require.True(t, res.Stack[0].Value().(bool))
  1133  	})
  1134  
  1135  	t.Run("positive, historic, by block, with signer", func(t *testing.T) {
  1136  		res, err := c.InvokeContractVerifyWithState(chain.GetHeaderHash(chain.BlockHeight()-1), contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1137  		require.NoError(t, err)
  1138  		require.Equal(t, "HALT", res.State)
  1139  		require.Equal(t, 1, len(res.Stack))
  1140  		require.True(t, res.Stack[0].Value().(bool))
  1141  	})
  1142  
  1143  	t.Run("positive, historic, by stateroot, with signer", func(t *testing.T) {
  1144  		h := chain.BlockHeight() - 1
  1145  		sr, err := chain.GetStateModule().GetStateRoot(h)
  1146  		require.NoError(t, err)
  1147  		res, err := c.InvokeContractVerifyWithState(sr.Root, contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1148  		require.NoError(t, err)
  1149  		require.Equal(t, "HALT", res.State)
  1150  		require.Equal(t, 1, len(res.Stack))
  1151  		require.True(t, res.Stack[0].Value().(bool))
  1152  	})
  1153  
  1154  	t.Run("bad, historic, by hash: contract not found", func(t *testing.T) {
  1155  		var h uint32 = 1
  1156  		_, err = c.InvokeContractVerifyAtHeight(h, contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1157  		require.Error(t, err)
  1158  		require.True(t, strings.Contains(err.Error(), core.ErrUnknownVerificationContract.Error())) // contract wasn't deployed at block #1 yet
  1159  	})
  1160  
  1161  	t.Run("bad, historic, by block: contract not found", func(t *testing.T) {
  1162  		_, err = c.InvokeContractVerifyWithState(chain.GetHeaderHash(1), contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1163  		require.Error(t, err)
  1164  		require.True(t, strings.Contains(err.Error(), core.ErrUnknownVerificationContract.Error())) // contract wasn't deployed at block #1 yet
  1165  	})
  1166  
  1167  	t.Run("bad, historic, by stateroot: contract not found", func(t *testing.T) {
  1168  		var h uint32 = 1
  1169  		sr, err := chain.GetStateModule().GetStateRoot(h)
  1170  		require.NoError(t, err)
  1171  		_, err = c.InvokeContractVerifyWithState(sr.Root, contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}})
  1172  		require.Error(t, err)
  1173  		require.True(t, strings.Contains(err.Error(), core.ErrUnknownVerificationContract.Error())) // contract wasn't deployed at block #1 yet
  1174  	})
  1175  
  1176  	t.Run("positive, with signer and witness", func(t *testing.T) {
  1177  		res, err := c.InvokeContractVerify(contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}}, transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH1), byte(opcode.RET)}})
  1178  		require.NoError(t, err)
  1179  		require.Equal(t, "HALT", res.State)
  1180  		require.Equal(t, 1, len(res.Stack))
  1181  		require.True(t, res.Stack[0].Value().(bool))
  1182  	})
  1183  
  1184  	t.Run("error, invalid witness number", func(t *testing.T) {
  1185  		_, err := c.InvokeContractVerify(contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: testchain.PrivateKeyByID(0).PublicKey().GetScriptHash()}}, transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH1), byte(opcode.RET)}}, transaction.Witness{InvocationScript: []byte{byte(opcode.RET)}})
  1186  		require.Error(t, err)
  1187  	})
  1188  
  1189  	t.Run("false", func(t *testing.T) {
  1190  		res, err := c.InvokeContractVerify(contract, []smartcontract.Parameter{}, []transaction.Signer{{Account: util.Uint160{}}})
  1191  		require.NoError(t, err)
  1192  		require.Equal(t, "HALT", res.State)
  1193  		require.Equal(t, 1, len(res.Stack))
  1194  		require.False(t, res.Stack[0].Value().(bool))
  1195  	})
  1196  }
  1197  
  1198  func TestClient_GetNativeContracts(t *testing.T) {
  1199  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1200  
  1201  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1202  	require.NoError(t, err)
  1203  	t.Cleanup(c.Close)
  1204  	require.NoError(t, c.Init())
  1205  
  1206  	cs, err := c.GetNativeContracts()
  1207  	require.NoError(t, err)
  1208  	require.Equal(t, chain.GetNatives(), cs)
  1209  }
  1210  
  1211  func TestClient_NEP11_ND(t *testing.T) {
  1212  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1213  
  1214  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1215  	require.NoError(t, err)
  1216  	t.Cleanup(c.Close)
  1217  	require.NoError(t, c.Init())
  1218  
  1219  	h, err := util.Uint160DecodeStringLE(nnsContractHash)
  1220  	require.NoError(t, err)
  1221  	priv0 := testchain.PrivateKeyByID(0)
  1222  	act, err := actor.NewSimple(c, wallet.NewAccountFromPrivateKey(priv0))
  1223  	require.NoError(t, err)
  1224  	n11 := nep11.NewNonDivisible(act, h)
  1225  	acc := priv0.GetScriptHash()
  1226  
  1227  	t.Run("Decimals", func(t *testing.T) {
  1228  		d, err := n11.Decimals()
  1229  		require.NoError(t, err)
  1230  		require.EqualValues(t, 0, d) // non-divisible
  1231  	})
  1232  	t.Run("TotalSupply", func(t *testing.T) {
  1233  		s, err := n11.TotalSupply()
  1234  		require.NoError(t, err)
  1235  		require.EqualValues(t, big.NewInt(1), s) // the only `neo.com` of acc0
  1236  	})
  1237  	t.Run("Symbol", func(t *testing.T) {
  1238  		sym, err := n11.Symbol()
  1239  		require.NoError(t, err)
  1240  		require.Equal(t, "NNS", sym)
  1241  	})
  1242  	t.Run("TokenInfo", func(t *testing.T) {
  1243  		tok, err := neptoken.Info(c, h)
  1244  		require.NoError(t, err)
  1245  		require.Equal(t, &wallet.Token{
  1246  			Name:     "NameService",
  1247  			Hash:     h,
  1248  			Decimals: 0,
  1249  			Symbol:   "NNS",
  1250  			Standard: manifest.NEP11StandardName,
  1251  		}, tok)
  1252  	})
  1253  	t.Run("BalanceOf", func(t *testing.T) {
  1254  		b, err := n11.BalanceOf(acc)
  1255  		require.NoError(t, err)
  1256  		require.EqualValues(t, big.NewInt(1), b)
  1257  	})
  1258  	t.Run("OwnerOf", func(t *testing.T) {
  1259  		b, err := n11.OwnerOf([]byte("neo.com"))
  1260  		require.NoError(t, err)
  1261  		require.EqualValues(t, acc, b)
  1262  	})
  1263  	t.Run("Tokens", func(t *testing.T) {
  1264  		iter, err := n11.Tokens()
  1265  		require.NoError(t, err)
  1266  		items, err := iter.Next(config.DefaultMaxIteratorResultItems)
  1267  		require.NoError(t, err)
  1268  		require.Equal(t, 1, len(items))
  1269  		require.Equal(t, [][]byte{[]byte("neo.com")}, items)
  1270  		require.NoError(t, iter.Terminate())
  1271  	})
  1272  	t.Run("TokensExpanded", func(t *testing.T) {
  1273  		items, err := n11.TokensExpanded(config.DefaultMaxIteratorResultItems)
  1274  		require.NoError(t, err)
  1275  		require.Equal(t, [][]byte{[]byte("neo.com")}, items)
  1276  	})
  1277  	t.Run("Properties", func(t *testing.T) {
  1278  		p, err := n11.Properties([]byte("neo.com"))
  1279  		require.NoError(t, err)
  1280  		blockRegisterDomain, err := chain.GetBlock(chain.GetHeaderHash(14)) // `neo.com` domain was registered in 14th block
  1281  		require.NoError(t, err)
  1282  		require.Equal(t, 1, len(blockRegisterDomain.Transactions))
  1283  		expected := stackitem.NewMap()
  1284  		expected.Add(stackitem.Make([]byte("name")), stackitem.Make([]byte("neo.com")))
  1285  		expected.Add(stackitem.Make([]byte("expiration")), stackitem.Make(blockRegisterDomain.Timestamp+365*24*3600*1000)) // expiration formula
  1286  		expected.Add(stackitem.Make([]byte("admin")), stackitem.Null{})
  1287  		require.EqualValues(t, expected, p)
  1288  	})
  1289  	t.Run("Transfer", func(t *testing.T) {
  1290  		_, _, err := n11.Transfer(testchain.PrivateKeyByID(1).GetScriptHash(), []byte("neo.com"), nil)
  1291  		require.NoError(t, err)
  1292  	})
  1293  }
  1294  
  1295  func TestClient_NEP11_D(t *testing.T) {
  1296  	_, _, httpSrv := initServerWithInMemoryChain(t)
  1297  
  1298  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1299  	require.NoError(t, err)
  1300  	t.Cleanup(c.Close)
  1301  	require.NoError(t, c.Init())
  1302  
  1303  	pkey0 := testchain.PrivateKeyByID(0)
  1304  	priv0 := pkey0.GetScriptHash()
  1305  	priv1 := testchain.PrivateKeyByID(1).GetScriptHash()
  1306  	token1ID, err := hex.DecodeString(nfsoToken1ID)
  1307  	require.NoError(t, err)
  1308  
  1309  	act, err := actor.NewSimple(c, wallet.NewAccountFromPrivateKey(pkey0))
  1310  	require.NoError(t, err)
  1311  	n11 := nep11.NewDivisible(act, nfsoHash)
  1312  
  1313  	t.Run("Decimals", func(t *testing.T) {
  1314  		d, err := n11.Decimals()
  1315  		require.NoError(t, err)
  1316  		require.EqualValues(t, 2, d) // Divisible.
  1317  	})
  1318  	t.Run("TotalSupply", func(t *testing.T) {
  1319  		s, err := n11.TotalSupply()
  1320  		require.NoError(t, err)
  1321  		require.EqualValues(t, big.NewInt(1), s) // the only NFSO of acc0
  1322  	})
  1323  	t.Run("Symbol", func(t *testing.T) {
  1324  		sym, err := n11.Symbol()
  1325  		require.NoError(t, err)
  1326  		require.Equal(t, "NFSO", sym)
  1327  	})
  1328  	t.Run("TokenInfo", func(t *testing.T) {
  1329  		tok, err := neptoken.Info(c, nfsoHash)
  1330  		require.NoError(t, err)
  1331  		require.Equal(t, &wallet.Token{
  1332  			Name:     "NeoFS Object NFT",
  1333  			Hash:     nfsoHash,
  1334  			Decimals: 2,
  1335  			Symbol:   "NFSO",
  1336  			Standard: manifest.NEP11StandardName,
  1337  		}, tok)
  1338  	})
  1339  	t.Run("BalanceOf", func(t *testing.T) {
  1340  		b, err := n11.BalanceOf(priv0)
  1341  		require.NoError(t, err)
  1342  		require.EqualValues(t, big.NewInt(80), b)
  1343  	})
  1344  	t.Run("BalanceOfD", func(t *testing.T) {
  1345  		b, err := n11.BalanceOfD(priv0, token1ID)
  1346  		require.NoError(t, err)
  1347  		require.EqualValues(t, big.NewInt(80), b)
  1348  	})
  1349  	t.Run("OwnerOf", func(t *testing.T) {
  1350  		iter, err := n11.OwnerOf(token1ID)
  1351  		require.NoError(t, err)
  1352  		items, err := iter.Next(config.DefaultMaxIteratorResultItems)
  1353  		require.NoError(t, err)
  1354  		require.Equal(t, 2, len(items))
  1355  		require.Equal(t, []util.Uint160{priv1, priv0}, items)
  1356  		require.NoError(t, iter.Terminate())
  1357  	})
  1358  	t.Run("OwnerOfExpanded", func(t *testing.T) {
  1359  		b, err := n11.OwnerOfExpanded(token1ID, config.DefaultMaxIteratorResultItems)
  1360  		require.NoError(t, err)
  1361  		require.Equal(t, []util.Uint160{priv1, priv0}, b)
  1362  	})
  1363  	t.Run("Properties", func(t *testing.T) {
  1364  		p, err := n11.Properties(token1ID)
  1365  		require.NoError(t, err)
  1366  		expected := stackitem.NewMap()
  1367  		expected.Add(stackitem.Make([]byte("name")), stackitem.NewBuffer([]byte("NeoFS Object "+base64.StdEncoding.EncodeToString(token1ID))))
  1368  		expected.Add(stackitem.Make([]byte("containerID")), stackitem.Make([]byte(base64.StdEncoding.EncodeToString(nfsoToken1ContainerID.BytesBE()))))
  1369  		expected.Add(stackitem.Make([]byte("objectID")), stackitem.Make([]byte(base64.StdEncoding.EncodeToString(nfsoToken1ObjectID.BytesBE()))))
  1370  		require.EqualValues(t, expected, p)
  1371  	})
  1372  	t.Run("Transfer", func(t *testing.T) {
  1373  		_, _, err := n11.TransferD(priv0, priv1, big.NewInt(20), token1ID, nil)
  1374  		require.NoError(t, err)
  1375  	})
  1376  }
  1377  
  1378  func TestClient_NNS(t *testing.T) {
  1379  	_, _, httpSrv := initServerWithInMemoryChain(t)
  1380  
  1381  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1382  	require.NoError(t, err)
  1383  	t.Cleanup(c.Close)
  1384  	require.NoError(t, c.Init())
  1385  	nnc := nns.NewReader(invoker.New(c, nil), nnsHash)
  1386  
  1387  	t.Run("IsAvailable, false", func(t *testing.T) {
  1388  		b, err := nnc.IsAvailable("neo.com")
  1389  		require.NoError(t, err)
  1390  		require.Equal(t, false, b)
  1391  	})
  1392  	t.Run("IsAvailable, true", func(t *testing.T) {
  1393  		b, err := nnc.IsAvailable("neogo.com")
  1394  		require.NoError(t, err)
  1395  		require.Equal(t, true, b)
  1396  	})
  1397  	t.Run("Resolve, good", func(t *testing.T) {
  1398  		b, err := nnc.Resolve("neo.com", nns.A)
  1399  		require.NoError(t, err)
  1400  		require.Equal(t, "1.2.3.4", b)
  1401  	})
  1402  	t.Run("Resolve, bad", func(t *testing.T) {
  1403  		_, err := nnc.Resolve("neogo.com", nns.A)
  1404  		require.Error(t, err)
  1405  	})
  1406  	t.Run("Resolve, CNAME", func(t *testing.T) {
  1407  		_, err := nnc.Resolve("neogo.com", nns.CNAME)
  1408  		require.Error(t, err)
  1409  	})
  1410  	t.Run("GetAllRecords, good", func(t *testing.T) {
  1411  		iter, err := nnc.GetAllRecords("neo.com")
  1412  		require.NoError(t, err)
  1413  		arr, err := iter.Next(config.DefaultMaxIteratorResultItems)
  1414  		require.NoError(t, err)
  1415  		require.Equal(t, 1, len(arr))
  1416  		require.Equal(t, nns.RecordState{
  1417  			Name: "neo.com",
  1418  			Type: nns.A,
  1419  			Data: "1.2.3.4",
  1420  		}, arr[0])
  1421  	})
  1422  	t.Run("GetAllRecordsExpanded, good", func(t *testing.T) {
  1423  		rss, err := nnc.GetAllRecordsExpanded("neo.com", 42)
  1424  		require.NoError(t, err)
  1425  		require.Equal(t, []nns.RecordState{
  1426  			{
  1427  				Name: "neo.com",
  1428  				Type: nns.A,
  1429  				Data: "1.2.3.4",
  1430  			},
  1431  		}, rss)
  1432  	})
  1433  	t.Run("GetAllRecords, bad", func(t *testing.T) {
  1434  		_, err := nnc.GetAllRecords("neopython.com")
  1435  		require.Error(t, err)
  1436  	})
  1437  	t.Run("GetAllRecordsExpanded, bad", func(t *testing.T) {
  1438  		_, err := nnc.GetAllRecordsExpanded("neopython.com", 7)
  1439  		require.Error(t, err)
  1440  	})
  1441  }
  1442  
  1443  func TestClient_IteratorSessions(t *testing.T) {
  1444  	_, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
  1445  
  1446  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{MaxConnsPerHost: 50})
  1447  	require.NoError(t, err)
  1448  	t.Cleanup(c.Close)
  1449  	require.NoError(t, c.Init())
  1450  
  1451  	storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
  1452  	require.NoError(t, err)
  1453  
  1454  	// storageItemsCount is the amount of storage items stored in Storage contract, it's hard-coded in the contract code.
  1455  	const storageItemsCount = 255
  1456  	expected := make([][]byte, storageItemsCount)
  1457  	for i := 0; i < storageItemsCount; i++ {
  1458  		expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes()
  1459  	}
  1460  	sort.Slice(expected, func(i, j int) bool {
  1461  		if len(expected[i]) != len(expected[j]) {
  1462  			return len(expected[i]) < len(expected[j])
  1463  		}
  1464  		return bytes.Compare(expected[i], expected[j]) < 0
  1465  	})
  1466  
  1467  	prepareSession := func(t *testing.T) (uuid.UUID, uuid.UUID) {
  1468  		res, err := c.InvokeFunction(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil)
  1469  		require.NoError(t, err)
  1470  		require.NotEmpty(t, res.Session)
  1471  		require.Equal(t, 1, len(res.Stack))
  1472  		require.Equal(t, stackitem.InteropT, res.Stack[0].Type())
  1473  		iterator, ok := res.Stack[0].Value().(result.Iterator)
  1474  		require.True(t, ok)
  1475  		require.NotEmpty(t, iterator.ID)
  1476  		return res.Session, *iterator.ID
  1477  	}
  1478  	t.Run("traverse with max constraint", func(t *testing.T) {
  1479  		sID, iID := prepareSession(t)
  1480  		check := func(t *testing.T, start, end int) {
  1481  			max := end - start
  1482  			set, err := c.TraverseIterator(sID, iID, max)
  1483  			require.NoError(t, err)
  1484  			require.Equal(t, max, len(set))
  1485  			for i := 0; i < max; i++ {
  1486  				// According to the Storage contract code.
  1487  				require.Equal(t, expected[start+i], set[i].Value().([]byte), start+i)
  1488  			}
  1489  		}
  1490  		check(t, 0, 30)
  1491  		check(t, 30, 48)
  1492  		check(t, 48, 49)
  1493  		check(t, 49, 49+config.DefaultMaxIteratorResultItems)
  1494  		check(t, 49+config.DefaultMaxIteratorResultItems, 49+2*config.DefaultMaxIteratorResultItems-1)
  1495  		check(t, 49+2*config.DefaultMaxIteratorResultItems-1, 255)
  1496  
  1497  		// Iterator ends on 255-th element, so no more elements should be returned.
  1498  		set, err := c.TraverseIterator(sID, iID, config.DefaultMaxIteratorResultItems)
  1499  		require.NoError(t, err)
  1500  		require.Equal(t, 0, len(set))
  1501  	})
  1502  
  1503  	t.Run("traverse, request more than exists", func(t *testing.T) {
  1504  		sID, iID := prepareSession(t)
  1505  		for i := 0; i < storageItemsCount/config.DefaultMaxIteratorResultItems; i++ {
  1506  			set, err := c.TraverseIterator(sID, iID, config.DefaultMaxIteratorResultItems)
  1507  			require.NoError(t, err)
  1508  			require.Equal(t, config.DefaultMaxIteratorResultItems, len(set))
  1509  		}
  1510  
  1511  		// Request more items than left untraversed.
  1512  		set, err := c.TraverseIterator(sID, iID, config.DefaultMaxIteratorResultItems)
  1513  		require.NoError(t, err)
  1514  		require.Equal(t, storageItemsCount%config.DefaultMaxIteratorResultItems, len(set))
  1515  	})
  1516  
  1517  	t.Run("traverse, no max constraint", func(t *testing.T) {
  1518  		sID, iID := prepareSession(t)
  1519  
  1520  		set, err := c.TraverseIterator(sID, iID, -1)
  1521  		require.NoError(t, err)
  1522  		require.Equal(t, config.DefaultMaxIteratorResultItems, len(set))
  1523  	})
  1524  
  1525  	t.Run("traverse, concurrent access", func(t *testing.T) {
  1526  		sID, iID := prepareSession(t)
  1527  		wg := sync.WaitGroup{}
  1528  		wg.Add(storageItemsCount)
  1529  		check := func(t *testing.T) {
  1530  			set, err := c.TraverseIterator(sID, iID, 1)
  1531  			assert.NoError(t, err)
  1532  			assert.Equal(t, 1, len(set))
  1533  			wg.Done()
  1534  		}
  1535  		for i := 0; i < storageItemsCount; i++ {
  1536  			go check(t)
  1537  		}
  1538  		wg.Wait()
  1539  	})
  1540  
  1541  	t.Run("terminate session", func(t *testing.T) {
  1542  		t.Run("manually", func(t *testing.T) {
  1543  			sID, iID := prepareSession(t)
  1544  
  1545  			// Check session is created.
  1546  			set, err := c.TraverseIterator(sID, iID, 1)
  1547  			require.NoError(t, err)
  1548  			require.Equal(t, 1, len(set))
  1549  
  1550  			ok, err := c.TerminateSession(sID)
  1551  			require.NoError(t, err)
  1552  			require.True(t, ok)
  1553  
  1554  			ok, err = c.TerminateSession(sID)
  1555  			require.Error(t, err)
  1556  			require.ErrorIs(t, err, neorpc.ErrUnknownSession)
  1557  			require.False(t, ok) // session has already been terminated.
  1558  		})
  1559  		t.Run("automatically", func(t *testing.T) {
  1560  			sID, iID := prepareSession(t)
  1561  
  1562  			// Check session is created.
  1563  			set, err := c.TraverseIterator(sID, iID, 1)
  1564  			require.NoError(t, err)
  1565  			require.Equal(t, 1, len(set))
  1566  
  1567  			require.Eventually(t, func() bool {
  1568  				rpcSrv.sessionsLock.Lock()
  1569  				defer rpcSrv.sessionsLock.Unlock()
  1570  
  1571  				_, ok := rpcSrv.sessions[sID.String()]
  1572  				return !ok
  1573  			}, time.Duration(rpcSrv.config.SessionExpirationTime)*time.Second*3,
  1574  				// Sessions list is updated once per SessionExpirationTime, thus, no need to ask for update more frequently than
  1575  				// sessions cleaning occurs.
  1576  				time.Duration(rpcSrv.config.SessionExpirationTime)*time.Second/4)
  1577  
  1578  			ok, err := c.TerminateSession(sID)
  1579  			require.Error(t, err)
  1580  			require.ErrorIs(t, err, neorpc.ErrUnknownSession)
  1581  			require.False(t, ok) // session has already been terminated.
  1582  		})
  1583  	})
  1584  }
  1585  
  1586  func TestClient_States(t *testing.T) {
  1587  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1588  
  1589  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1590  	require.NoError(t, err)
  1591  	t.Cleanup(c.Close)
  1592  	require.NoError(t, c.Init())
  1593  
  1594  	stateheight, err := c.GetStateHeight()
  1595  	assert.NoError(t, err)
  1596  	assert.Equal(t, chain.BlockHeight(), stateheight.Local)
  1597  
  1598  	stateroot, err := c.GetStateRootByHeight(stateheight.Local)
  1599  	assert.NoError(t, err)
  1600  
  1601  	t.Run("proof", func(t *testing.T) {
  1602  		policy, err := chain.GetNativeContractScriptHash(nativenames.Policy)
  1603  		assert.NoError(t, err)
  1604  		proof, err := c.GetProof(stateroot.Root, policy, []byte{19}) // storagePrice key in policy contract
  1605  		assert.NoError(t, err)
  1606  		value, err := c.VerifyProof(stateroot.Root, proof)
  1607  		assert.NoError(t, err)
  1608  		assert.Equal(t, big.NewInt(native.DefaultStoragePrice), bigint.FromBytes(value))
  1609  	})
  1610  }
  1611  
  1612  func TestClientOracle(t *testing.T) {
  1613  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1614  
  1615  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1616  	require.NoError(t, err)
  1617  	t.Cleanup(c.Close)
  1618  	require.NoError(t, c.Init())
  1619  
  1620  	oraRe := oracle.NewReader(invoker.New(c, nil))
  1621  
  1622  	var defaultOracleRequestPrice = big.NewInt(5000_0000)
  1623  	actual, err := oraRe.GetPrice()
  1624  	require.NoError(t, err)
  1625  	require.Equal(t, defaultOracleRequestPrice, actual)
  1626  
  1627  	act, err := actor.New(c, []actor.SignerAccount{{
  1628  		Signer: transaction.Signer{
  1629  			Account: testchain.CommitteeScriptHash(),
  1630  			Scopes:  transaction.CalledByEntry,
  1631  		},
  1632  		Account: &wallet.Account{
  1633  			Address: testchain.CommitteeAddress(),
  1634  			Contract: &wallet.Contract{
  1635  				Script: testchain.CommitteeVerificationScript(),
  1636  			},
  1637  		},
  1638  	}})
  1639  	require.NoError(t, err)
  1640  
  1641  	ora := oracle.New(act)
  1642  
  1643  	newPrice := big.NewInt(1_0000_0000)
  1644  	tx, err := ora.SetPriceUnsigned(newPrice)
  1645  	require.NoError(t, err)
  1646  
  1647  	tx.Scripts[0].InvocationScript = testchain.SignCommittee(tx)
  1648  	bl := testchain.NewBlock(t, chain, 1, 0, tx)
  1649  	_, err = c.SubmitBlock(*bl)
  1650  	require.NoError(t, err)
  1651  
  1652  	actual, err = ora.GetPrice()
  1653  	require.NoError(t, err)
  1654  	require.Equal(t, newPrice, actual)
  1655  }
  1656  
  1657  func TestClient_Iterator_SessionConfigVariations(t *testing.T) {
  1658  	var expected [][]byte
  1659  	storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
  1660  	require.NoError(t, err)
  1661  	// storageItemsCount is the amount of storage items stored in Storage contract, it's hard-coded in the contract code.
  1662  	const storageItemsCount = 255
  1663  
  1664  	checkSessionEnabled := func(t *testing.T, c *rpcclient.Client) {
  1665  		// We expect Iterator with designated ID to be presented on stack. It should be possible to retrieve its values via `traverseiterator` call.
  1666  		res, err := c.InvokeFunction(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil)
  1667  		require.NoError(t, err)
  1668  		require.NotEmpty(t, res.Session)
  1669  		require.Equal(t, 1, len(res.Stack))
  1670  		require.Equal(t, stackitem.InteropT, res.Stack[0].Type())
  1671  		iterator, ok := res.Stack[0].Value().(result.Iterator)
  1672  		require.True(t, ok)
  1673  		require.NotEmpty(t, iterator.ID)
  1674  		require.Empty(t, iterator.Values)
  1675  		max := 84
  1676  		actual, err := c.TraverseIterator(res.Session, *iterator.ID, max)
  1677  		require.NoError(t, err)
  1678  		require.Equal(t, max, len(actual))
  1679  		for i := 0; i < max; i++ {
  1680  			// According to the Storage contract code.
  1681  			require.Equal(t, expected[i], actual[i].Value().([]byte), i)
  1682  		}
  1683  	}
  1684  	t.Run("default sessions enabled", func(t *testing.T) {
  1685  		chain, _, httpSrv := initClearServerWithServices(t, false, false, false)
  1686  
  1687  		for _, b := range getTestBlocks(t) {
  1688  			require.NoError(t, chain.AddBlock(b))
  1689  		}
  1690  
  1691  		c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1692  		require.NoError(t, err)
  1693  		t.Cleanup(c.Close)
  1694  		require.NoError(t, c.Init())
  1695  
  1696  		// Fill in expected stackitems set during the first test.
  1697  		expected = make([][]byte, storageItemsCount)
  1698  		for i := 0; i < storageItemsCount; i++ {
  1699  			expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes()
  1700  		}
  1701  		sort.Slice(expected, func(i, j int) bool {
  1702  			if len(expected[i]) != len(expected[j]) {
  1703  				return len(expected[i]) < len(expected[j])
  1704  			}
  1705  			return bytes.Compare(expected[i], expected[j]) < 0
  1706  		})
  1707  		checkSessionEnabled(t, c)
  1708  	})
  1709  	t.Run("MPT-based sessions enables", func(t *testing.T) {
  1710  		// Prepare MPT-enabled RPC server.
  1711  		chain, orc, cfg, logger := getUnitTestChainWithCustomConfig(t, false, false, func(cfg *config.Config) {
  1712  			cfg.ApplicationConfiguration.RPC.SessionEnabled = true
  1713  			cfg.ApplicationConfiguration.RPC.SessionBackedByMPT = true
  1714  		})
  1715  		serverConfig, err := network.NewServerConfig(cfg)
  1716  		require.NoError(t, err)
  1717  		serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
  1718  		serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}
  1719  		server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
  1720  		require.NoError(t, err)
  1721  		errCh := make(chan error, 2)
  1722  		rpcSrv := New(chain, cfg.ApplicationConfiguration.RPC, server, orc, logger, errCh)
  1723  		rpcSrv.Start()
  1724  		handler := http.HandlerFunc(rpcSrv.handleHTTPRequest)
  1725  		httpSrv := httptest.NewServer(handler)
  1726  		t.Cleanup(httpSrv.Close)
  1727  		defer rpcSrv.Shutdown()
  1728  		for _, b := range getTestBlocks(t) {
  1729  			require.NoError(t, chain.AddBlock(b))
  1730  		}
  1731  
  1732  		c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1733  		require.NoError(t, err)
  1734  		t.Cleanup(c.Close)
  1735  		require.NoError(t, c.Init())
  1736  
  1737  		checkSessionEnabled(t, c)
  1738  	})
  1739  	t.Run("sessions disabled", func(t *testing.T) {
  1740  		chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
  1741  
  1742  		for _, b := range getTestBlocks(t) {
  1743  			require.NoError(t, chain.AddBlock(b))
  1744  		}
  1745  
  1746  		c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1747  		require.NoError(t, err)
  1748  		t.Cleanup(c.Close)
  1749  		require.NoError(t, c.Init())
  1750  
  1751  		// We expect unpacked iterator values to be present on stack under InteropInterface cover.
  1752  		res, err := c.InvokeFunction(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil)
  1753  		require.NoError(t, err)
  1754  		require.Empty(t, res.Session)
  1755  		require.Equal(t, 1, len(res.Stack))
  1756  		require.Equal(t, stackitem.InteropT, res.Stack[0].Type())
  1757  		iterator, ok := res.Stack[0].Value().(result.Iterator)
  1758  		require.True(t, ok)
  1759  		require.Empty(t, iterator.ID)
  1760  		require.NotEmpty(t, iterator.Values)
  1761  		require.True(t, iterator.Truncated)
  1762  		require.Equal(t, rpcSrv.config.MaxIteratorResultItems, len(iterator.Values))
  1763  		for i := 0; i < rpcSrv.config.MaxIteratorResultItems; i++ {
  1764  			// According to the Storage contract code.
  1765  			require.Equal(t, expected[i], iterator.Values[i].Value().([]byte), i)
  1766  		}
  1767  	})
  1768  }
  1769  
  1770  func TestClient_Wait(t *testing.T) {
  1771  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  1772  
  1773  	run := func(t *testing.T, ws bool) {
  1774  		acc, err := wallet.NewAccount()
  1775  		require.NoError(t, err)
  1776  
  1777  		var act *actor.Actor
  1778  		if ws {
  1779  			c, err := rpcclient.NewWS(context.Background(), "ws"+strings.TrimPrefix(httpSrv.URL, "http")+"/ws", rpcclient.WSOptions{})
  1780  			require.NoError(t, err)
  1781  			t.Cleanup(c.Close)
  1782  			require.NoError(t, c.Init())
  1783  			act, err = actor.New(c, []actor.SignerAccount{
  1784  				{
  1785  					Signer: transaction.Signer{
  1786  						Account: acc.ScriptHash(),
  1787  					},
  1788  					Account: acc,
  1789  				},
  1790  			})
  1791  			require.NoError(t, err)
  1792  		} else {
  1793  			c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  1794  			require.NoError(t, err)
  1795  			t.Cleanup(c.Close)
  1796  			require.NoError(t, c.Init())
  1797  			act, err = actor.New(c, []actor.SignerAccount{
  1798  				{
  1799  					Signer: transaction.Signer{
  1800  						Account: acc.ScriptHash(),
  1801  					},
  1802  					Account: acc,
  1803  				},
  1804  			})
  1805  			require.NoError(t, err)
  1806  		}
  1807  
  1808  		b, err := chain.GetBlock(chain.GetHeaderHash(1))
  1809  		require.NoError(t, err)
  1810  		require.True(t, len(b.Transactions) > 0)
  1811  
  1812  		check := func(t *testing.T, h util.Uint256, vub uint32, errExpected bool) {
  1813  			rcvr := make(chan struct{})
  1814  			go func() {
  1815  				aer, err := act.Wait(h, vub, nil)
  1816  				if errExpected {
  1817  					require.Error(t, err)
  1818  				} else {
  1819  					require.NoError(t, err)
  1820  					require.Equal(t, h, aer.Container)
  1821  				}
  1822  				rcvr <- struct{}{}
  1823  			}()
  1824  		waitloop:
  1825  			for {
  1826  				select {
  1827  				case <-rcvr:
  1828  					break waitloop
  1829  				case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
  1830  					t.Fatal("transaction failed to be awaited")
  1831  				}
  1832  			}
  1833  		}
  1834  
  1835  		// Wait for transaction that has been persisted and VUB block has been persisted.
  1836  		check(t, b.Transactions[0].Hash(), chain.BlockHeight()-1, false)
  1837  		// Wait for transaction that has been persisted and VUB block hasn't yet been persisted.
  1838  		check(t, b.Transactions[0].Hash(), chain.BlockHeight()+1, false)
  1839  		if !ws {
  1840  			// Wait for transaction that hasn't been persisted and VUB block has been persisted.
  1841  			// WS client waits for the next block to be accepted to ensure that transaction wasn't
  1842  			// persisted, and this test doesn't run chain, thus, don't run this test for WS client.
  1843  			check(t, util.Uint256{1, 2, 3}, chain.BlockHeight()-1, true)
  1844  		}
  1845  	}
  1846  
  1847  	t.Run("client", func(t *testing.T) {
  1848  		run(t, false)
  1849  	})
  1850  	t.Run("ws client", func(t *testing.T) {
  1851  		run(t, true)
  1852  	})
  1853  }
  1854  
  1855  func mkSubsClient(t *testing.T, rpcSrv *Server, httpSrv *httptest.Server, local bool) *rpcclient.WSClient {
  1856  	var (
  1857  		c   *rpcclient.WSClient
  1858  		err error
  1859  		icl *rpcclient.Internal
  1860  	)
  1861  	if local {
  1862  		icl, err = rpcclient.NewInternal(context.Background(), rpcSrv.RegisterLocal)
  1863  	} else {
  1864  		url := "ws" + strings.TrimPrefix(httpSrv.URL, "http") + "/ws"
  1865  		c, err = rpcclient.NewWS(context.Background(), url, rpcclient.WSOptions{})
  1866  		t.Cleanup(c.Close)
  1867  	}
  1868  	require.NoError(t, err)
  1869  	if local {
  1870  		c = &icl.WSClient
  1871  	}
  1872  	require.NoError(t, c.Init())
  1873  	return c
  1874  }
  1875  
  1876  func runWSAndLocal(t *testing.T, test func(*testing.T, bool)) {
  1877  	t.Run("ws", func(t *testing.T) {
  1878  		test(t, false)
  1879  	})
  1880  	t.Run("local", func(t *testing.T) {
  1881  		test(t, true)
  1882  	})
  1883  }
  1884  
  1885  func TestSubClientWait(t *testing.T) {
  1886  	runWSAndLocal(t, testSubClientWait)
  1887  }
  1888  
  1889  func testSubClientWait(t *testing.T, local bool) {
  1890  	chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
  1891  
  1892  	c := mkSubsClient(t, rpcSrv, httpSrv, local)
  1893  	acc, err := wallet.NewAccount()
  1894  	require.NoError(t, err)
  1895  	act, err := actor.New(c, []actor.SignerAccount{
  1896  		{
  1897  			Signer: transaction.Signer{
  1898  				Account: acc.ScriptHash(),
  1899  			},
  1900  			Account: acc,
  1901  		},
  1902  	})
  1903  	require.NoError(t, err)
  1904  
  1905  	rcvr := make(chan *state.AppExecResult)
  1906  	check := func(t *testing.T, b *block.Block, h util.Uint256, vub uint32) {
  1907  		go func() {
  1908  			aer, err := act.Wait(h, vub, nil)
  1909  			require.NoError(t, err, b.Index)
  1910  			rcvr <- aer
  1911  		}()
  1912  		go func() {
  1913  			// Wait until client is properly subscribed. The real node won't behave like this,
  1914  			// but the real node has the subsequent blocks to be added that will trigger client's
  1915  			// waitloops to finish anyway (and the test has only single block, thus, use it careful).
  1916  			require.Eventually(t, func() bool {
  1917  				rpcSrv.subsLock.Lock()
  1918  				defer rpcSrv.subsLock.Unlock()
  1919  				if len(rpcSrv.subscribers) == 1 { // single client
  1920  					for s := range rpcSrv.subscribers {
  1921  						var count int
  1922  						for _, f := range s.feeds {
  1923  							if f.event != neorpc.InvalidEventID {
  1924  								count++
  1925  							}
  1926  						}
  1927  						return count == 2 // subscription for blocks + AERs
  1928  					}
  1929  				}
  1930  				return false
  1931  			}, time.Second, 100*time.Millisecond)
  1932  			require.NoError(t, chain.AddBlock(b))
  1933  		}()
  1934  	waitloop:
  1935  		for {
  1936  			select {
  1937  			case aer := <-rcvr:
  1938  				require.Equal(t, h, aer.Container)
  1939  				require.Equal(t, trigger.Application, aer.Trigger)
  1940  				if h.StringLE() == faultedTxHashLE {
  1941  					require.Equal(t, vmstate.Fault, aer.VMState)
  1942  				} else {
  1943  					require.Equal(t, vmstate.Halt, aer.VMState)
  1944  				}
  1945  				break waitloop
  1946  			case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
  1947  				t.Fatalf("transaction from block %d failed to be awaited: deadline exceeded", b.Index)
  1948  			}
  1949  		}
  1950  		// Wait for server/client to properly unsubscribe. In real life subsequent awaiter
  1951  		// requests may be run concurrently, and it's OK, but it's important for the test
  1952  		// not to run subscription requests in parallel because block addition is bounded to
  1953  		// the number of subscribers.
  1954  		require.Eventually(t, func() bool {
  1955  			rpcSrv.subsLock.Lock()
  1956  			defer rpcSrv.subsLock.Unlock()
  1957  			if len(rpcSrv.subscribers) != 1 {
  1958  				return false
  1959  			}
  1960  			for s := range rpcSrv.subscribers {
  1961  				for _, f := range s.feeds {
  1962  					if f.event != neorpc.InvalidEventID {
  1963  						return false
  1964  					}
  1965  				}
  1966  			}
  1967  			return true
  1968  		}, time.Second, 100*time.Millisecond)
  1969  	}
  1970  
  1971  	var faultedChecked bool
  1972  	for _, b := range getTestBlocks(t) {
  1973  		if len(b.Transactions) > 0 {
  1974  			tx := b.Transactions[0]
  1975  			check(t, b, tx.Hash(), tx.ValidUntilBlock)
  1976  			if tx.Hash().StringLE() == faultedTxHashLE {
  1977  				faultedChecked = true
  1978  			}
  1979  		} else {
  1980  			require.NoError(t, chain.AddBlock(b))
  1981  		}
  1982  	}
  1983  	require.True(t, faultedChecked, "FAULTed transaction wasn't checked")
  1984  }
  1985  
  1986  func TestSubClientWaitWithLateSubscription(t *testing.T) {
  1987  	runWSAndLocal(t, testSubClientWaitWithLateSubscription)
  1988  }
  1989  
  1990  func testSubClientWaitWithLateSubscription(t *testing.T, local bool) {
  1991  	chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
  1992  
  1993  	c := mkSubsClient(t, rpcSrv, httpSrv, local)
  1994  	acc, err := wallet.NewAccount()
  1995  	require.NoError(t, err)
  1996  	act, err := actor.New(c, []actor.SignerAccount{
  1997  		{
  1998  			Signer: transaction.Signer{
  1999  				Account: acc.ScriptHash(),
  2000  			},
  2001  			Account: acc,
  2002  		},
  2003  	})
  2004  	require.NoError(t, err)
  2005  
  2006  	// Firstly, accept the block.
  2007  	blocks := getTestBlocks(t)
  2008  	b1 := blocks[0]
  2009  	tx := b1.Transactions[0]
  2010  	require.NoError(t, chain.AddBlock(b1))
  2011  
  2012  	// After that, wait and get the result immediately.
  2013  	aer, err := act.Wait(tx.Hash(), tx.ValidUntilBlock, nil)
  2014  	require.NoError(t, err)
  2015  	require.Equal(t, tx.Hash(), aer.Container)
  2016  	require.Equal(t, trigger.Application, aer.Trigger)
  2017  	require.Equal(t, vmstate.Halt, aer.VMState)
  2018  }
  2019  
  2020  func TestWSClientHandshakeError(t *testing.T) {
  2021  	_, _, httpSrv := initClearServerWithCustomConfig(t, func(cfg *config.Config) {
  2022  		cfg.ApplicationConfiguration.RPC.MaxWebSocketClients = -1
  2023  	})
  2024  
  2025  	url := "ws" + strings.TrimPrefix(httpSrv.URL, "http") + "/ws"
  2026  	_, err := rpcclient.NewWS(context.Background(), url, rpcclient.WSOptions{})
  2027  	require.ErrorContains(t, err, "websocket users limit reached")
  2028  }
  2029  
  2030  func TestSubClientWaitWithMissedEvent(t *testing.T) {
  2031  	runWSAndLocal(t, testSubClientWaitWithMissedEvent)
  2032  }
  2033  
  2034  func testSubClientWaitWithMissedEvent(t *testing.T, local bool) {
  2035  	chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
  2036  
  2037  	c := mkSubsClient(t, rpcSrv, httpSrv, local)
  2038  	acc, err := wallet.NewAccount()
  2039  	require.NoError(t, err)
  2040  	act, err := actor.New(c, []actor.SignerAccount{
  2041  		{
  2042  			Signer: transaction.Signer{
  2043  				Account: acc.ScriptHash(),
  2044  			},
  2045  			Account: acc,
  2046  		},
  2047  	})
  2048  	require.NoError(t, err)
  2049  
  2050  	blocks := getTestBlocks(t)
  2051  	b1 := blocks[0]
  2052  	tx := b1.Transactions[0]
  2053  
  2054  	rcvr := make(chan *state.AppExecResult)
  2055  	errCh := make(chan error) // Error channel for goroutine errors
  2056  
  2057  	go func() {
  2058  		aer, err := act.Wait(tx.Hash(), tx.ValidUntilBlock, nil)
  2059  		if err != nil {
  2060  			errCh <- err
  2061  			return
  2062  		}
  2063  		rcvr <- aer
  2064  	}()
  2065  
  2066  	// Wait until client is properly subscribed. The real node won't behave like this,
  2067  	// but the real node has the subsequent blocks to be added that will trigger client's
  2068  	// waitloops to finish anyway (and the test has only single block, thus, use it careful).
  2069  	require.Eventually(t, func() bool {
  2070  		rpcSrv.subsLock.Lock()
  2071  		defer rpcSrv.subsLock.Unlock()
  2072  		return len(rpcSrv.subscribers) == 1
  2073  	}, 2*time.Second, 100*time.Millisecond)
  2074  
  2075  	rpcSrv.subsLock.Lock()
  2076  	// Suppress normal event delivery.
  2077  	for s := range rpcSrv.subscribers {
  2078  		s.overflown.Store(true)
  2079  	}
  2080  	rpcSrv.subsLock.Unlock()
  2081  
  2082  	// Accept the next block, but subscriber will get no events because it's overflown.
  2083  	require.NoError(t, chain.AddBlock(b1))
  2084  
  2085  	overNotification := neorpc.Notification{
  2086  		JSONRPC: neorpc.JSONRPCVersion,
  2087  		Event:   neorpc.MissedEventID,
  2088  		Payload: make([]any, 0),
  2089  	}
  2090  	overEvent, err := json.Marshal(overNotification)
  2091  	require.NoError(t, err)
  2092  	overflowMsg, err := websocket.NewPreparedMessage(websocket.TextMessage, overEvent)
  2093  	require.NoError(t, err)
  2094  	rpcSrv.subsLock.Lock()
  2095  	// Deliver overflow message -> triggers subscriber to retry with polling waiter.
  2096  	for s := range rpcSrv.subscribers {
  2097  		s.writer <- intEvent{overflowMsg, &overNotification}
  2098  	}
  2099  	rpcSrv.subsLock.Unlock()
  2100  
  2101  	// Wait for the result.
  2102  waitloop:
  2103  	for {
  2104  		select {
  2105  		case aer := <-rcvr:
  2106  			require.Equal(t, tx.Hash(), aer.Container)
  2107  			require.Equal(t, trigger.Application, aer.Trigger)
  2108  			require.Equal(t, vmstate.Halt, aer.VMState)
  2109  			break waitloop
  2110  		case err := <-errCh:
  2111  			t.Fatalf("Error waiting for transaction: %v", err)
  2112  		case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
  2113  			t.Fatal("transaction failed to be awaited")
  2114  		}
  2115  	}
  2116  }
  2117  
  2118  // TestWSClient_SubscriptionsCompat is aimed to test both deprecated and relevant
  2119  // subscriptions API with filtered and non-filtered subscriptions from the WSClient
  2120  // user side.
  2121  func TestWSClient_SubscriptionsCompat(t *testing.T) {
  2122  	chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
  2123  
  2124  	c := mkSubsClient(t, rpcSrv, httpSrv, false)
  2125  	blocks := getTestBlocks(t)
  2126  	bCount := uint32(0)
  2127  
  2128  	getData := func(t *testing.T) (*block.Block, *block.Block, byte, util.Uint160, string, string) {
  2129  		b1 := blocks[bCount]
  2130  		primary := b1.PrimaryIndex
  2131  		tx := b1.Transactions[0]
  2132  		sender := tx.Sender()
  2133  		ntfName := "Transfer"
  2134  		st := vmstate.Halt.String()
  2135  		b2 := blocks[bCount+1]
  2136  		bCount += 2
  2137  		return b1, b2, primary, sender, ntfName, st
  2138  	}
  2139  
  2140  	checkRelevant := func(t *testing.T, filtered bool) {
  2141  		b, bNext, primary, sender, ntfName, st := getData(t)
  2142  		var (
  2143  			bID, txID, ntfID, aerID string
  2144  			blockCh                 = make(chan *block.Block)
  2145  			txCh                    = make(chan *transaction.Transaction)
  2146  			ntfCh                   = make(chan *state.ContainedNotificationEvent)
  2147  			aerCh                   = make(chan *state.AppExecResult)
  2148  			bFlt                    *neorpc.BlockFilter
  2149  			txFlt                   *neorpc.TxFilter
  2150  			ntfFlt                  *neorpc.NotificationFilter
  2151  			aerFlt                  *neorpc.ExecutionFilter
  2152  			err                     error
  2153  		)
  2154  		if filtered {
  2155  			bFlt = &neorpc.BlockFilter{Primary: &primary}
  2156  			txFlt = &neorpc.TxFilter{Sender: &sender}
  2157  			ntfFlt = &neorpc.NotificationFilter{Name: &ntfName}
  2158  			aerFlt = &neorpc.ExecutionFilter{State: &st}
  2159  		}
  2160  		bID, err = c.ReceiveBlocks(bFlt, blockCh)
  2161  		require.NoError(t, err)
  2162  		txID, err = c.ReceiveTransactions(txFlt, txCh)
  2163  		require.NoError(t, err)
  2164  		ntfID, err = c.ReceiveExecutionNotifications(ntfFlt, ntfCh)
  2165  		require.NoError(t, err)
  2166  		aerID, err = c.ReceiveExecutions(aerFlt, aerCh)
  2167  		require.NoError(t, err)
  2168  
  2169  		var (
  2170  			lock     sync.RWMutex
  2171  			received byte
  2172  			exitCh   = make(chan struct{})
  2173  		)
  2174  		go func() {
  2175  		dispatcher:
  2176  			for {
  2177  				select {
  2178  				case <-blockCh:
  2179  					lock.Lock()
  2180  					received |= 1
  2181  					lock.Unlock()
  2182  				case <-txCh:
  2183  					lock.Lock()
  2184  					received |= 1 << 1
  2185  					lock.Unlock()
  2186  				case <-ntfCh:
  2187  					lock.Lock()
  2188  					received |= 1 << 2
  2189  					lock.Unlock()
  2190  				case <-aerCh:
  2191  					lock.Lock()
  2192  					received |= 1 << 3
  2193  					lock.Unlock()
  2194  				case <-exitCh:
  2195  					break dispatcher
  2196  				}
  2197  			}
  2198  		drainLoop:
  2199  			for {
  2200  				select {
  2201  				case <-blockCh:
  2202  				case <-txCh:
  2203  				case <-ntfCh:
  2204  				case <-aerCh:
  2205  				default:
  2206  					break drainLoop
  2207  				}
  2208  			}
  2209  			close(blockCh)
  2210  			close(txCh)
  2211  			close(ntfCh)
  2212  			close(aerCh)
  2213  		}()
  2214  
  2215  		// Accept the next block and wait for events.
  2216  		require.NoError(t, chain.AddBlock(b))
  2217  		// Blockchain's events channel is not buffered, and thus, by adding one more extra block
  2218  		// we're ensuring that the previous block event receiving was successfully handled by Blockchain's
  2219  		// notificationDispatcher loop. Once we're sure in that, we may start to check the actual notifications.
  2220  		require.NoError(t, chain.AddBlock(bNext))
  2221  		assert.Eventually(t, func() bool {
  2222  			lock.RLock()
  2223  			defer lock.RUnlock()
  2224  
  2225  			return received == 1<<4-1
  2226  		}, time.Second, 100*time.Millisecond)
  2227  
  2228  		require.NoError(t, c.Unsubscribe(bID))
  2229  		require.NoError(t, c.Unsubscribe(txID))
  2230  		require.NoError(t, c.Unsubscribe(ntfID))
  2231  		require.NoError(t, c.Unsubscribe(aerID))
  2232  		exitCh <- struct{}{}
  2233  	}
  2234  	t.Run("relevant, filtered", func(t *testing.T) {
  2235  		checkRelevant(t, true)
  2236  	})
  2237  	t.Run("relevant, non-filtered", func(t *testing.T) {
  2238  		checkRelevant(t, false)
  2239  	})
  2240  }
  2241  
  2242  func TestActor_CallWithNilParam(t *testing.T) {
  2243  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  2244  
  2245  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  2246  	require.NoError(t, err)
  2247  	t.Cleanup(c.Close)
  2248  	acc, err := wallet.NewAccount()
  2249  	require.NoError(t, err)
  2250  	act, err := actor.New(c, []actor.SignerAccount{
  2251  		{
  2252  			Signer: transaction.Signer{
  2253  				Account: acc.ScriptHash(),
  2254  			},
  2255  			Account: acc,
  2256  		},
  2257  	})
  2258  	require.NoError(t, err)
  2259  
  2260  	rubles, err := chain.GetContractScriptHash(basicchain.RublesContractID)
  2261  	require.NoError(t, err)
  2262  
  2263  	// We don't have a suitable contract, thus use Rubles with simple put method,
  2264  	// it should fail at the moment of conversion Null value to ByteString (not earlier,
  2265  	// and that's the point of the test!).
  2266  	res, err := act.Call(rubles, "putValue", "123", (*util.Uint160)(nil))
  2267  	require.NoError(t, err)
  2268  
  2269  	require.True(t, strings.Contains(res.FaultException, "invalid conversion: Null/ByteString"), res.FaultException)
  2270  }
  2271  
  2272  func TestClient_FindStorage(t *testing.T) {
  2273  	_, _, httpSrv := initServerWithInMemoryChain(t)
  2274  
  2275  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  2276  	require.NoError(t, err)
  2277  	t.Cleanup(c.Close)
  2278  	require.NoError(t, c.Init())
  2279  
  2280  	h, err := util.Uint160DecodeStringLE(testContractHash)
  2281  	require.NoError(t, err)
  2282  	prefix := []byte("aa")
  2283  	expected := result.FindStorage{
  2284  		Results: []result.KeyValue{
  2285  			{
  2286  				Key:   []byte("aa"),
  2287  				Value: []byte("v1"),
  2288  			},
  2289  			{
  2290  				Key:   []byte("aa10"),
  2291  				Value: []byte("v2"),
  2292  			},
  2293  		},
  2294  		Next:      2,
  2295  		Truncated: true,
  2296  	}
  2297  
  2298  	// By hash.
  2299  	actual, err := c.FindStorageByHash(h, prefix, nil)
  2300  	require.NoError(t, err)
  2301  	require.Equal(t, expected, actual)
  2302  
  2303  	// By ID.
  2304  	actual, err = c.FindStorageByID(1, prefix, nil) // Rubles contract
  2305  	require.NoError(t, err)
  2306  	require.Equal(t, expected, actual)
  2307  
  2308  	// Non-nil start.
  2309  	start := 1
  2310  	actual, err = c.FindStorageByHash(h, prefix, &start)
  2311  	require.NoError(t, err)
  2312  	require.Equal(t, result.FindStorage{
  2313  		Results: []result.KeyValue{
  2314  			{
  2315  				Key:   []byte("aa10"),
  2316  				Value: []byte("v2"),
  2317  			},
  2318  			{
  2319  				Key:   []byte("aa50"),
  2320  				Value: []byte("v3"),
  2321  			},
  2322  		},
  2323  		Next:      3,
  2324  		Truncated: false,
  2325  	}, actual)
  2326  
  2327  	// Missing item.
  2328  	actual, err = c.FindStorageByHash(h, []byte("unknown prefix"), nil)
  2329  	require.NoError(t, err)
  2330  	require.Equal(t, result.FindStorage{
  2331  		Results:   []result.KeyValue{},
  2332  		Next:      0,
  2333  		Truncated: false,
  2334  	}, actual)
  2335  }
  2336  
  2337  func TestClient_FindStorageHistoric(t *testing.T) {
  2338  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  2339  
  2340  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  2341  	require.NoError(t, err)
  2342  	t.Cleanup(c.Close)
  2343  	require.NoError(t, c.Init())
  2344  
  2345  	root, err := util.Uint256DecodeStringLE(block20StateRootLE)
  2346  	require.NoError(t, err)
  2347  	h, err := util.Uint160DecodeStringLE(testContractHash)
  2348  	require.NoError(t, err)
  2349  	prefix := []byte("aa")
  2350  	expected := result.FindStorage{
  2351  		Results: []result.KeyValue{
  2352  			{
  2353  				Key:   []byte("aa10"),
  2354  				Value: []byte("v2"),
  2355  			},
  2356  			{
  2357  				Key:   []byte("aa50"),
  2358  				Value: []byte("v3"),
  2359  			},
  2360  		},
  2361  		Next:      2,
  2362  		Truncated: true,
  2363  	}
  2364  
  2365  	// By hash.
  2366  	actual, err := c.FindStorageByHashHistoric(root, h, prefix, nil)
  2367  	require.NoError(t, err)
  2368  	require.Equal(t, expected, actual)
  2369  
  2370  	// By ID.
  2371  	actual, err = c.FindStorageByIDHistoric(root, 1, prefix, nil) // Rubles contract
  2372  	require.NoError(t, err)
  2373  	require.Equal(t, expected, actual)
  2374  
  2375  	// Non-nil start.
  2376  	start := 1
  2377  	actual, err = c.FindStorageByHashHistoric(root, h, prefix, &start)
  2378  	require.NoError(t, err)
  2379  	require.Equal(t, result.FindStorage{
  2380  		Results: []result.KeyValue{
  2381  			{
  2382  				Key:   []byte("aa50"),
  2383  				Value: []byte("v3"),
  2384  			},
  2385  			{
  2386  				Key:   []byte("aa"), // order differs due to MPT traversal strategy.
  2387  				Value: []byte("v1"),
  2388  			},
  2389  		},
  2390  		Next:      3,
  2391  		Truncated: false,
  2392  	}, actual)
  2393  
  2394  	// Missing item.
  2395  	earlyRoot, err := chain.GetStateRoot(15) // there's no `aa10` value in Rubles contract by the moment of block #15
  2396  	require.NoError(t, err)
  2397  	actual, err = c.FindStorageByHashHistoric(earlyRoot.Root, h, prefix, nil)
  2398  	require.NoError(t, err)
  2399  	require.Equal(t, result.FindStorage{
  2400  		Results:   []result.KeyValue{},
  2401  		Next:      0,
  2402  		Truncated: false,
  2403  	}, actual)
  2404  }
  2405  
  2406  func TestClient_GetStorageHistoric(t *testing.T) {
  2407  	chain, _, httpSrv := initServerWithInMemoryChain(t)
  2408  
  2409  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  2410  	require.NoError(t, err)
  2411  	t.Cleanup(c.Close)
  2412  	require.NoError(t, c.Init())
  2413  
  2414  	root, err := util.Uint256DecodeStringLE(block20StateRootLE)
  2415  	require.NoError(t, err)
  2416  	h, err := util.Uint160DecodeStringLE(testContractHash)
  2417  	require.NoError(t, err)
  2418  	key := []byte("aa10")
  2419  	expected := []byte("v2")
  2420  
  2421  	// By hash.
  2422  	actual, err := c.GetStorageByHashHistoric(root, h, key)
  2423  	require.NoError(t, err)
  2424  	require.Equal(t, expected, actual)
  2425  
  2426  	// By ID.
  2427  	actual, err = c.GetStorageByIDHistoric(root, 1, key) // Rubles contract
  2428  	require.NoError(t, err)
  2429  	require.Equal(t, expected, actual)
  2430  
  2431  	// Missing item.
  2432  	earlyRoot, err := chain.GetStateRoot(15) // there's no `aa10` value in Rubles contract by the moment of block #15
  2433  	require.NoError(t, err)
  2434  	_, err = c.GetStorageByHashHistoric(earlyRoot.Root, h, key)
  2435  	require.ErrorIs(t, neorpc.ErrUnknownStorageItem, err)
  2436  }
  2437  
  2438  func TestClient_GetVersion_Hardforks(t *testing.T) {
  2439  	_, _, httpSrv := initServerWithInMemoryChain(t)
  2440  
  2441  	c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
  2442  	require.NoError(t, err)
  2443  	t.Cleanup(c.Close)
  2444  	require.NoError(t, c.Init())
  2445  
  2446  	v, err := c.GetVersion()
  2447  	require.NoError(t, err)
  2448  	expected := map[config.Hardfork]uint32{
  2449  		config.HFAspidochelone: 25,
  2450  	}
  2451  	require.InDeltaMapValues(t, expected, v.Protocol.Hardforks, 0)
  2452  }