Merge pull request #2351 from nspcc-dev/nep11d-tests
*: add NEP11-D tests and refactor NEP11-related CLI and RPC client commands
This commit is contained in:
commit
32a7e97a87
17 changed files with 846 additions and 209 deletions
|
@ -40,6 +40,7 @@ const (
|
|||
testWalletAccount = "Nfyz4KcsgYepRJw1W5C2uKCi6QWKf7v6gG"
|
||||
|
||||
validatorWallet = "testdata/wallet1_solo.json"
|
||||
validatorPass = "one"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -2,12 +2,15 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
|
@ -35,6 +38,8 @@ func TestNEP11Import(t *testing.T) {
|
|||
|
||||
// deploy NFT NeoNameService contract
|
||||
nnsContractHash := deployNNSContract(t, e)
|
||||
// deploy NFT-D NeoFS Object contract
|
||||
nfsContractHash := deployNFSContract(t, e)
|
||||
neoContractHash, err := e.Chain.GetNativeContractScriptHash(nativenames.Neo)
|
||||
require.NoError(t, err)
|
||||
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
||||
|
@ -47,33 +52,38 @@ func TestNEP11Import(t *testing.T) {
|
|||
// missing token hash
|
||||
e.RunWithError(t, args...)
|
||||
|
||||
// good
|
||||
// good: non-divisible
|
||||
e.Run(t, append(args, "--token", nnsContractHash.StringLE())...)
|
||||
|
||||
// good: divisible
|
||||
e.Run(t, append(args, "--token", nfsContractHash.StringLE())...)
|
||||
|
||||
// already exists
|
||||
e.RunWithError(t, append(args, "--token", nnsContractHash.StringLE())...)
|
||||
|
||||
// not a NEP-11 token
|
||||
e.RunWithError(t, append(args, "--token", neoContractHash.StringLE())...)
|
||||
|
||||
checkInfo := func(t *testing.T, h util.Uint160, name string, symbol string, decimals int) {
|
||||
e.checkNextLine(t, "^Name:\\s*"+name)
|
||||
e.checkNextLine(t, "^Symbol:\\s*"+symbol)
|
||||
e.checkNextLine(t, "^Hash:\\s*"+h.StringLE())
|
||||
e.checkNextLine(t, "^Decimals:\\s*"+strconv.Itoa(decimals))
|
||||
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(h))
|
||||
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName))
|
||||
}
|
||||
t.Run("Info", func(t *testing.T) {
|
||||
checkNNSInfo := func(t *testing.T) {
|
||||
e.checkNextLine(t, "^Name:\\s*NameService")
|
||||
e.checkNextLine(t, "^Symbol:\\s*NNS")
|
||||
e.checkNextLine(t, "^Hash:\\s*"+nnsContractHash.StringLE())
|
||||
e.checkNextLine(t, "^Decimals:\\s*0")
|
||||
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(nnsContractHash))
|
||||
e.checkNextLine(t, "^Standard:\\s*"+string(manifest.NEP11StandardName))
|
||||
}
|
||||
t.Run("WithToken", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "info",
|
||||
"--wallet", walletPath, "--token", nnsContractHash.StringLE())
|
||||
checkNNSInfo(t)
|
||||
checkInfo(t, nnsContractHash, "NameService", "NNS", 0)
|
||||
})
|
||||
t.Run("NoToken", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "info",
|
||||
"--wallet", walletPath)
|
||||
checkNNSInfo(t)
|
||||
checkInfo(t, nnsContractHash, "NameService", "NNS", 0)
|
||||
e.checkNextLine(t, "")
|
||||
checkInfo(t, nfsContractHash, "NeoFS Object NFT", "NFSO", 2)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -83,12 +93,13 @@ func TestNEP11Import(t *testing.T) {
|
|||
"--wallet", walletPath, "--token", nnsContractHash.StringLE())
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "info",
|
||||
"--wallet", walletPath)
|
||||
checkInfo(t, nfsContractHash, "NeoFS Object NFT", "NFSO", 2)
|
||||
_, err := e.Out.ReadString('\n')
|
||||
require.Equal(t, err, io.EOF)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||
func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
|
@ -190,7 +201,7 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
|
||||
// ownerOf: missing token ID
|
||||
e.RunWithError(t, cmdOwnerOf...)
|
||||
cmdOwnerOf = append(cmdOwnerOf, "--id", string(tokenID))
|
||||
cmdOwnerOf = append(cmdOwnerOf, "--id", hex.EncodeToString(tokenID))
|
||||
|
||||
// ownerOf: good
|
||||
e.Run(t, cmdOwnerOf...)
|
||||
|
@ -209,7 +220,7 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
|
||||
// tokensOf: good
|
||||
e.Run(t, cmdTokensOf...)
|
||||
require.Equal(t, string(tokenID), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(tokenID), e.getNextLine(t))
|
||||
|
||||
// properties: no contract
|
||||
cmdProperties := []string{
|
||||
|
@ -221,12 +232,11 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
|
||||
// properties: no token ID
|
||||
e.RunWithError(t, cmdProperties...)
|
||||
cmdProperties = append(cmdProperties, "--id", string(tokenID))
|
||||
cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(tokenID))
|
||||
|
||||
// properties: ok
|
||||
e.Run(t, cmdProperties...)
|
||||
marshalledID := strings.Replace(string(tokenID), "+", "\\u002B", -1)
|
||||
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, marshalledID), e.getNextLine(t))
|
||||
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, base64.StdEncoding.EncodeToString(tokenID)), e.getNextLine(t))
|
||||
|
||||
// tokensOf: good, several tokens
|
||||
tokenID1 := mint(t)
|
||||
|
@ -236,8 +246,8 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
fst, snd = snd, fst
|
||||
}
|
||||
|
||||
require.Equal(t, string(fst), e.getNextLine(t))
|
||||
require.Equal(t, string(snd), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||
|
||||
// tokens: missing contract hash
|
||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||
|
@ -248,8 +258,8 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
|
||||
// tokens: good, several tokens
|
||||
e.Run(t, cmdTokens...)
|
||||
require.Equal(t, string(fst), e.getNextLine(t))
|
||||
require.Equal(t, string(snd), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||
|
||||
// balance check: several tokens, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
|
@ -276,7 +286,7 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
|
||||
// transfer: good
|
||||
e.In.WriteString(nftOwnerPass + "\r")
|
||||
e.Run(t, append(cmdTransfer, "--id", string(tokenID))...)
|
||||
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(tokenID))...)
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
// check balance after transfer
|
||||
|
@ -292,7 +302,7 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
"--to", verifyH.StringLE(),
|
||||
"--from", nftOwnerAddr,
|
||||
"--token", h.StringLE(),
|
||||
"--id", string(tokenID1),
|
||||
"--id", hex.EncodeToString(tokenID1),
|
||||
"--force",
|
||||
"string:some_data",
|
||||
}
|
||||
|
@ -321,10 +331,267 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
checkBalanceResult(t, nftOwnerAddr, "0")
|
||||
}
|
||||
|
||||
func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// copy wallet to temp dir in order not to overwrite the original file
|
||||
bytesRead, err := ioutil.ReadFile(validatorWallet)
|
||||
require.NoError(t, err)
|
||||
wall := filepath.Join(tmpDir, "my_wallet.json")
|
||||
err = ioutil.WriteFile(wall, bytesRead, 0755)
|
||||
require.NoError(t, err)
|
||||
|
||||
// deploy NeoFS Object contract
|
||||
h := deployNFSContract(t, e)
|
||||
|
||||
mint := func(t *testing.T, containerID, objectID util.Uint256) []byte {
|
||||
// mint 1.00 NFSO token by transferring 10 GAS to NFSO contract
|
||||
e.In.WriteString(validatorPass + "\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--to", h.StringLE(),
|
||||
"--token", "GAS",
|
||||
"--amount", "10",
|
||||
"--force",
|
||||
"--from", validatorAddr,
|
||||
"--", "[", "hash256:"+containerID.StringLE(), "hash256:"+objectID.StringLE(), "]",
|
||||
)
|
||||
txMint, _ := e.checkTxPersisted(t)
|
||||
|
||||
// get NFT ID from AER
|
||||
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(aer))
|
||||
require.Equal(t, 2, len(aer[0].Events))
|
||||
nfsoMintEvent := aer[0].Events[1]
|
||||
require.Equal(t, "Transfer", nfsoMintEvent.Name)
|
||||
tokenID, err := nfsoMintEvent.Item.Value().([]stackitem.Item)[3].TryBytes()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, tokenID)
|
||||
return tokenID
|
||||
}
|
||||
|
||||
container1ID := util.Uint256{1, 2, 3}
|
||||
object1ID := util.Uint256{4, 5, 6}
|
||||
token1ID := mint(t, container1ID, object1ID)
|
||||
|
||||
container2ID := util.Uint256{7, 8, 9}
|
||||
object2ID := util.Uint256{10, 11, 12}
|
||||
token2ID := mint(t, container2ID, object2ID)
|
||||
|
||||
// check properties
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "properties",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--token", h.StringLE(),
|
||||
"--id", hex.EncodeToString(token1ID))
|
||||
jProps := e.getNextLine(t)
|
||||
props := make(map[string]string)
|
||||
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
||||
require.Equal(t, base64.StdEncoding.EncodeToString(container1ID.BytesBE()), props["containerID"])
|
||||
require.Equal(t, base64.StdEncoding.EncodeToString(object1ID.BytesBE()), props["objectID"])
|
||||
e.checkEOF(t)
|
||||
|
||||
// check the balance
|
||||
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--address", validatorAddr}
|
||||
checkBalanceResult := func(t *testing.T, acc string, amount string, id []byte) {
|
||||
e.checkNextLine(t, "^\\s*Account\\s+"+acc)
|
||||
if id == nil {
|
||||
e.checkNextLine(t, "^\\s*NFSO:\\s+NeoFS Object NFT \\("+h.StringLE()+"\\)")
|
||||
} else {
|
||||
e.checkNextLine(t, "^\\s*NFSO:\\s+NeoFS Object NFT \\("+h.StringLE()+", "+hex.EncodeToString(id)+"\\)")
|
||||
}
|
||||
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+amount+"$")
|
||||
e.checkEOF(t)
|
||||
}
|
||||
// balance check: by symbol, token is not imported
|
||||
e.RunWithError(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
||||
|
||||
// overall NFSO balance check: by hash, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, validatorAddr, "2", nil)
|
||||
|
||||
// particular NFSO balance check: by hash, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE(), "--id", hex.EncodeToString(token2ID))...)
|
||||
checkBalanceResult(t, validatorAddr, "1", token2ID)
|
||||
|
||||
// import token
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--token", h.StringLE())
|
||||
|
||||
// overall balance check: by symbol, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", "NFSO")...)
|
||||
checkBalanceResult(t, validatorAddr, "2", nil)
|
||||
|
||||
// particular balance check: by symbol, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", "NFSO", "--id", hex.EncodeToString(token1ID))...)
|
||||
checkBalanceResult(t, validatorAddr, "1", token1ID)
|
||||
|
||||
// remove token from wallet
|
||||
e.In.WriteString("y\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep11", "remove",
|
||||
"--wallet", wall, "--token", h.StringLE())
|
||||
|
||||
// ownerOfD: missing contract hash
|
||||
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
}
|
||||
e.RunWithError(t, cmdOwnerOf...)
|
||||
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
|
||||
|
||||
// ownerOfD: missing token ID
|
||||
e.RunWithError(t, cmdOwnerOf...)
|
||||
cmdOwnerOf = append(cmdOwnerOf, "--id", hex.EncodeToString(token1ID))
|
||||
|
||||
// ownerOfD: good
|
||||
e.Run(t, cmdOwnerOf...)
|
||||
e.checkNextLine(t, validatorAddr)
|
||||
|
||||
// tokensOf: missing contract hash
|
||||
cmdTokensOf := []string{"neo-go", "wallet", "nep11", "tokensOf",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
}
|
||||
e.RunWithError(t, cmdTokensOf...)
|
||||
cmdTokensOf = append(cmdTokensOf, "--token", h.StringLE())
|
||||
|
||||
// tokensOf: missing owner address
|
||||
e.RunWithError(t, cmdTokensOf...)
|
||||
cmdTokensOf = append(cmdTokensOf, "--address", validatorAddr)
|
||||
|
||||
// tokensOf: good
|
||||
e.Run(t, cmdTokensOf...)
|
||||
require.Equal(t, hex.EncodeToString(token1ID), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(token2ID), e.getNextLine(t))
|
||||
e.checkEOF(t)
|
||||
|
||||
// properties: no contract
|
||||
cmdProperties := []string{
|
||||
"neo-go", "wallet", "nep11", "properties",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
}
|
||||
e.RunWithError(t, cmdProperties...)
|
||||
cmdProperties = append(cmdProperties, "--token", h.StringLE())
|
||||
|
||||
// properties: no token ID
|
||||
e.RunWithError(t, cmdProperties...)
|
||||
cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(token2ID))
|
||||
|
||||
// properties: ok
|
||||
e.Run(t, cmdProperties...)
|
||||
jProps = e.getNextLine(t)
|
||||
props = make(map[string]string)
|
||||
require.NoError(t, json.Unmarshal([]byte(jProps), &props))
|
||||
require.Equal(t, base64.StdEncoding.EncodeToString(container2ID.BytesBE()), props["containerID"])
|
||||
require.Equal(t, base64.StdEncoding.EncodeToString(object2ID.BytesBE()), props["objectID"])
|
||||
e.checkEOF(t)
|
||||
|
||||
// tokensOf: good, several tokens
|
||||
e.Run(t, cmdTokensOf...)
|
||||
fst, snd := token1ID, token2ID
|
||||
if bytes.Compare(token1ID, token2ID) == 1 {
|
||||
fst, snd = snd, fst
|
||||
}
|
||||
|
||||
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||
|
||||
// tokens: missing contract hash
|
||||
cmdTokens := []string{"neo-go", "wallet", "nep11", "tokens",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
}
|
||||
e.RunWithError(t, cmdTokens...)
|
||||
cmdTokens = append(cmdTokens, "--token", h.StringLE())
|
||||
|
||||
// tokens: good, several tokens
|
||||
e.Run(t, cmdTokens...)
|
||||
require.Equal(t, hex.EncodeToString(fst), e.getNextLine(t))
|
||||
require.Equal(t, hex.EncodeToString(snd), e.getNextLine(t))
|
||||
|
||||
// balance check: several tokens, ok
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, validatorAddr, "2", nil)
|
||||
|
||||
cmdTransfer := []string{
|
||||
"neo-go", "wallet", "nep11", "transfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--to", nftOwnerAddr,
|
||||
"--from", validatorAddr,
|
||||
"--force",
|
||||
}
|
||||
|
||||
// transfer: unimported token with symbol id specified
|
||||
e.In.WriteString(validatorPass + "\r")
|
||||
e.RunWithError(t, append(cmdTransfer,
|
||||
"--token", "NFSO")...)
|
||||
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
|
||||
|
||||
// transfer: no id specified
|
||||
e.In.WriteString(validatorPass + "\r")
|
||||
e.RunWithError(t, cmdTransfer...)
|
||||
|
||||
// transfer: good
|
||||
e.In.WriteString(validatorPass + "\r")
|
||||
e.Run(t, append(cmdTransfer, "--id", hex.EncodeToString(token1ID))...)
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
// check balance after transfer
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, validatorAddr, "1", nil) // only token2ID expected to be on the balance
|
||||
|
||||
// transfer: good, 1/4 of the balance, to NEP-11-Payable contract, with data
|
||||
verifyH := deployVerifyContract(t, e)
|
||||
cmdTransfer = []string{
|
||||
"neo-go", "wallet", "nep11", "transfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--to", verifyH.StringLE(),
|
||||
"--from", validatorAddr,
|
||||
"--token", h.StringLE(),
|
||||
"--id", hex.EncodeToString(token2ID),
|
||||
"--amount", "0.25",
|
||||
"--force",
|
||||
"string:some_data",
|
||||
}
|
||||
e.In.WriteString(validatorPass + "\r")
|
||||
e.Run(t, cmdTransfer...)
|
||||
tx, _ := e.checkTxPersisted(t)
|
||||
// check OnNEP11Payment event
|
||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(aer[0].Events))
|
||||
validatorHash, err := address.StringToUint160(validatorAddr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, state.NotificationEvent{
|
||||
ScriptHash: verifyH,
|
||||
Name: "OnNEP11Payment",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(validatorHash.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(25)),
|
||||
stackitem.NewByteArray(token2ID),
|
||||
stackitem.NewByteArray([]byte("some_data")),
|
||||
}),
|
||||
}, aer[0].Events[1])
|
||||
|
||||
// check balance after transfer
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, validatorAddr, "0.75", nil)
|
||||
}
|
||||
|
||||
func deployNFSContract(t *testing.T, e *executor) util.Uint160 {
|
||||
return deployContract(t, e, "../examples/nft-d/nft.go", "../examples/nft-d/nft.yml", validatorWallet, validatorAddr, validatorPass)
|
||||
}
|
||||
|
||||
func deployNFTContract(t *testing.T, e *executor) util.Uint160 {
|
||||
return deployContract(t, e, "../examples/nft-nd/nft.go", "../examples/nft-nd/nft.yml", nftOwnerWallet, nftOwnerAddr, nftOwnerPass)
|
||||
}
|
||||
|
||||
func deployNNSContract(t *testing.T, e *executor) util.Uint160 {
|
||||
return deployContract(t, e, "../examples/nft-nd-nns/", "../examples/nft-nd-nns/nns.yml", validatorWallet, validatorAddr, "one")
|
||||
return deployContract(t, e, "../examples/nft-nd-nns/", "../examples/nft-nd-nns/nns.yml", validatorWallet, validatorAddr, validatorPass)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -31,7 +32,7 @@ func newNEP11Commands() []cli.Command {
|
|||
}
|
||||
tokenID := cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "Token ID",
|
||||
Usage: "Hex-encoded token ID",
|
||||
}
|
||||
|
||||
balanceFlags := make([]cli.Flag, len(baseBalanceFlags))
|
||||
|
@ -107,7 +108,17 @@ func newNEP11Commands() []cli.Command {
|
|||
Name: "ownerOf",
|
||||
Usage: "print owner of non-divisible NEP-11 token with the specified ID",
|
||||
UsageText: "ownerOf --rpc-endpoint <node> --timeout <time> --token <hash> --id <token-id>",
|
||||
Action: printNEP11Owner,
|
||||
Action: printNEP11NDOwner,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
tokenID,
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "ownerOfD",
|
||||
Usage: "print set of owners of divisible NEP-11 token with the specified ID",
|
||||
UsageText: "ownerOfD --rpc-endpoint <node> --timeout <time> --token <hash> --id <token-id>",
|
||||
Action: printNEP11DOwner,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
tokenID,
|
||||
|
@ -196,6 +207,10 @@ func getNEP11Balance(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
tokenID := ctx.String("id")
|
||||
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid tokenID bytes: %w", err), 1)
|
||||
}
|
||||
for k, acc := range accounts {
|
||||
addrHash, err := address.StringToUint160(acc.Address)
|
||||
if err != nil {
|
||||
|
@ -208,10 +223,10 @@ func getNEP11Balance(ctx *cli.Context) error {
|
|||
fmt.Fprintf(ctx.App.Writer, "Account %s\n", acc.Address)
|
||||
|
||||
var amount int64
|
||||
if tokenID == "" {
|
||||
if len(tokenIDBytes) == 0 {
|
||||
amount, err = c.NEP11BalanceOf(token.Hash, addrHash)
|
||||
} else {
|
||||
amount, err = c.NEP11DBalanceOf(token.Hash, addrHash, tokenID)
|
||||
amount, err = c.NEP11DBalanceOf(token.Hash, addrHash, tokenIDBytes)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -220,7 +235,7 @@ func getNEP11Balance(ctx *cli.Context) error {
|
|||
|
||||
format := "%s: %s (%s)\n"
|
||||
formatArgs := []interface{}{token.Symbol, token.Name, token.Hash.StringLE()}
|
||||
if tokenID != "" {
|
||||
if len(tokenIDBytes) != 0 {
|
||||
format = "%s: %s (%s, %s)\n"
|
||||
formatArgs = append(formatArgs, tokenID)
|
||||
}
|
||||
|
@ -234,7 +249,7 @@ func transferNEP11(ctx *cli.Context) error {
|
|||
return transferNEP(ctx, manifest.NEP11StandardName)
|
||||
}
|
||||
|
||||
func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, token, to util.Uint160, tokenID string, amount *big.Int, data interface{}, cosigners []client.SignerAccount) error {
|
||||
func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, token, to util.Uint160, tokenID []byte, amount *big.Int, data interface{}, cosigners []client.SignerAccount) error {
|
||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||
sysgas := flags.Fixed8FromContext(ctx, "sysgas")
|
||||
|
||||
|
@ -279,7 +294,15 @@ func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Ac
|
|||
return nil
|
||||
}
|
||||
|
||||
func printNEP11Owner(ctx *cli.Context) error {
|
||||
func printNEP11NDOwner(ctx *cli.Context) error {
|
||||
return printNEP11Owner(ctx, false)
|
||||
}
|
||||
|
||||
func printNEP11DOwner(ctx *cli.Context) error {
|
||||
return printNEP11Owner(ctx, true)
|
||||
}
|
||||
|
||||
func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
||||
var err error
|
||||
tokenHash := ctx.Generic("token").(*flags.Address)
|
||||
if !tokenHash.IsSet {
|
||||
|
@ -290,6 +313,10 @@ func printNEP11Owner(ctx *cli.Context) error {
|
|||
if tokenID == "" {
|
||||
return cli.NewExitError(errors.New("token ID should be specified"), 1)
|
||||
}
|
||||
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid tokenID bytes: %w", err), 1)
|
||||
}
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
@ -299,12 +326,22 @@ func printNEP11Owner(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
result, err := c.NEP11NDOwnerOf(tokenHash.Uint160(), tokenID)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `ownerOf` method: %s", err.Error()), 1)
|
||||
if divisible {
|
||||
result, err := c.NEP11DOwnerOf(tokenHash.Uint160(), tokenIDBytes)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 divisible `ownerOf` method: %s", err.Error()), 1)
|
||||
}
|
||||
for _, h := range result {
|
||||
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(h))
|
||||
}
|
||||
} else {
|
||||
result, err := c.NEP11NDOwnerOf(tokenHash.Uint160(), tokenIDBytes)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 non-divisible `ownerOf` method: %s", err.Error()), 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(result))
|
||||
}
|
||||
|
||||
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(result))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -334,7 +371,7 @@ func printNEP11TokensOf(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
for i := range result {
|
||||
fmt.Fprintln(ctx.App.Writer, result[i])
|
||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result[i]))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -360,7 +397,7 @@ func printNEP11Tokens(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
for i := range result {
|
||||
fmt.Fprintln(ctx.App.Writer, result[i])
|
||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result[i]))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -376,6 +413,10 @@ func printNEP11Properties(ctx *cli.Context) error {
|
|||
if tokenID == "" {
|
||||
return cli.NewExitError(errors.New("token ID should be specified"), 1)
|
||||
}
|
||||
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid tokenID bytes: %w", err), 1)
|
||||
}
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
@ -385,7 +426,7 @@ func printNEP11Properties(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
result, err := c.NEP11Properties(tokenHash.Uint160(), tokenID)
|
||||
result, err := c.NEP11Properties(tokenHash.Uint160(), tokenIDBytes)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `properties` method: %s", err.Error()), 1)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -618,14 +619,18 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
if tokenID == "" {
|
||||
return cli.NewExitError(errors.New("token ID should be specified"), 1)
|
||||
}
|
||||
tokenIDBytes, err := hex.DecodeString(tokenID)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid token ID: %w", err), 1)
|
||||
}
|
||||
if amountArg == "" {
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, nil, data, cosignersAccounts)
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenIDBytes, nil, data, cosignersAccounts)
|
||||
}
|
||||
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||
}
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, amount, data, cosignersAccounts)
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenIDBytes, amount, data, cosignersAccounts)
|
||||
default:
|
||||
return cli.NewExitError(fmt.Errorf("unsupported token standard %s", standard), 1)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||
|
@ -30,7 +31,7 @@ const (
|
|||
balancePrefix = "b"
|
||||
// tokenOwnerPrefix contains map from [token id + owner] to token's owner.
|
||||
tokenOwnerPrefix = "t"
|
||||
// tokenPrefix contains map from token id to empty array.
|
||||
// tokenPrefix contains map from token id to its properties (serialised containerID + objectID).
|
||||
tokenPrefix = "i"
|
||||
)
|
||||
|
||||
|
@ -231,12 +232,13 @@ func Properties(id []byte) map[string]string {
|
|||
if !isTokenValid(ctx, id) {
|
||||
panic("unknown token")
|
||||
}
|
||||
t := std.Deserialize(id).(ObjectIdentifier)
|
||||
key := mkTokenKey(id)
|
||||
props := storage.Get(ctx, key).([]byte)
|
||||
t := std.Deserialize(props).(ObjectIdentifier)
|
||||
result := map[string]string{
|
||||
"name": "NFSO " + string(id),
|
||||
"fullName": "NeoFS Object",
|
||||
"containerID": string(t.ContainerID),
|
||||
"objectID": string(t.ObjectID),
|
||||
"name": "NeoFS Object " + std.Base64Encode(id), // Not a hex for contract simplicity.
|
||||
"containerID": std.Base64Encode(t.ContainerID),
|
||||
"objectID": std.Base64Encode(t.ObjectID),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -360,11 +362,11 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
|
|||
panic("invalid 'data'")
|
||||
}
|
||||
containerID := tokenInfo[0].([]byte)
|
||||
if len(containerID) != 32 {
|
||||
if len(containerID) != interop.Hash256Len {
|
||||
panic("invalid container ID")
|
||||
}
|
||||
objectID := tokenInfo[1].([]byte)
|
||||
if len(objectID) != 32 {
|
||||
if len(objectID) != interop.Hash256Len {
|
||||
panic("invalid object ID")
|
||||
}
|
||||
|
||||
|
@ -372,18 +374,19 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
|
|||
ContainerID: containerID,
|
||||
ObjectID: objectID,
|
||||
}
|
||||
id := std.Serialize(t)
|
||||
props := std.Serialize(t)
|
||||
id := crypto.Ripemd160(props)
|
||||
|
||||
var ctx = storage.GetContext()
|
||||
if isTokenValid(ctx, id) {
|
||||
panic("NFSO for the specified address is already minted")
|
||||
panic("NFSO for the specified object is already minted")
|
||||
}
|
||||
key := mkTokenKey(id)
|
||||
storage.Put(ctx, key, []byte{})
|
||||
storage.Put(ctx, key, props)
|
||||
|
||||
total := totalSupply(ctx)
|
||||
|
||||
addOwner(ctx, from, id)
|
||||
addOwner(ctx, id, from)
|
||||
addToBalance(ctx, from, id, multiplier)
|
||||
|
||||
total++
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name: "NFSO NFT"
|
||||
name: "NeoFS Object NFT"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-11"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens"]
|
||||
|
|
|
@ -273,7 +273,7 @@ func Properties(id []byte) map[string]string {
|
|||
panic("unknown token")
|
||||
}
|
||||
result := map[string]string{
|
||||
"name": "HASHY " + string(id),
|
||||
"name": "HASHY " + std.Base64Encode(id), // Not a hex for contract simplicity.
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160,
|
|||
return nil, util.Uint160{}, nil, fmt.Errorf("failed to parse configuration: %w", err)
|
||||
}
|
||||
o.Name = conf.Name
|
||||
o.SourceURL = conf.SourceURL
|
||||
o.ContractEvents = conf.Events
|
||||
o.ContractSupportedStandards = conf.SupportedStandards
|
||||
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
||||
|
@ -75,6 +76,7 @@ func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160,
|
|||
o.Permissions[i] = manifest.Permission(conf.Permissions[i])
|
||||
}
|
||||
o.SafeMethods = conf.SafeMethods
|
||||
o.Overloads = conf.Overloads
|
||||
}
|
||||
|
||||
ne, di, err := compiler.CompileWithOptions(name, r, o)
|
||||
|
|
|
@ -279,16 +279,34 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
|
||||
priv0 := testchain.PrivateKeyByID(0)
|
||||
priv0ScriptHash := priv0.GetScriptHash()
|
||||
priv1 := testchain.PrivateKeyByID(1)
|
||||
priv1ScriptHash := priv1.GetScriptHash()
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
||||
acc1 := wallet.NewAccountFromPrivateKey(priv1)
|
||||
|
||||
deployContractFromPriv0 := func(t *testing.T, path, contractName string, configPath *string, expectedID int32) (util.Uint256, util.Uint256, util.Uint160) {
|
||||
txDeploy, _ := newDeployTx(t, bc, priv0ScriptHash, path, contractName, configPath)
|
||||
txDeploy.Nonce = getNextNonce()
|
||||
txDeploy.ValidUntilBlock = validUntilBlock
|
||||
require.NoError(t, addNetworkFee(bc, txDeploy, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txDeploy))
|
||||
b := bc.newBlock(txDeploy)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #11
|
||||
checkTxHalt(t, bc, txDeploy.Hash())
|
||||
sh, err := bc.GetContractScriptHash(expectedID)
|
||||
require.NoError(t, err)
|
||||
return b.Hash(), txDeploy.Hash(), sh
|
||||
}
|
||||
|
||||
require.Equal(t, big.NewInt(5000_0000), bc.GetUtilityTokenBalance(priv0ScriptHash)) // gas bounty
|
||||
// Move some NEO to one simple account.
|
||||
|
||||
// Block #1: move 1000 GAS and neoAmount NEO to priv0.
|
||||
txMoveNeo, err := testchain.NewTransferFromOwner(bc, neoHash, priv0ScriptHash, neoAmount, getNextNonce(), validUntilBlock)
|
||||
require.NoError(t, err)
|
||||
// Move some GAS to one simple account.
|
||||
txMoveGas, err := testchain.NewTransferFromOwner(bc, gasHash, priv0ScriptHash, int64(fixedn.Fixed8FromInt64(1000)),
|
||||
getNextNonce(), validUntilBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := bc.newBlock(txMoveNeo, txMoveGas)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, txMoveGas.Hash())
|
||||
|
@ -322,25 +340,15 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
b.Header.EncodeBinary(buf.BinWriter)
|
||||
t.Logf("header: %s", hex.EncodeToString(buf.Bytes()))
|
||||
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
||||
|
||||
// Push some contract into the chain.
|
||||
// Block #2: deploy test_contract.
|
||||
cfgPath := prefix + "test_contract.yml"
|
||||
txDeploy, cHash := newDeployTx(t, bc, priv0ScriptHash, prefix+"test_contract.go", "Rubl", &cfgPath)
|
||||
txDeploy.Nonce = getNextNonce()
|
||||
txDeploy.ValidUntilBlock = validUntilBlock
|
||||
require.NoError(t, addNetworkFee(bc, txDeploy, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txDeploy))
|
||||
b = bc.newBlock(txDeploy)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, txDeploy.Hash())
|
||||
t.Logf("txDeploy: %s", txDeploy.Hash().StringLE())
|
||||
t.Logf("Block2 hash: %s", b.Hash().StringLE())
|
||||
block2H, txDeployH, cHash := deployContractFromPriv0(t, prefix+"test_contract.go", "Rubl", &cfgPath, 1)
|
||||
t.Logf("txDeploy: %s", txDeployH.StringLE())
|
||||
t.Logf("Block2 hash: %s", block2H.StringLE())
|
||||
|
||||
// Now invoke this contract.
|
||||
// Block #3: invoke `putValue` method on the test_contract.
|
||||
script := io.NewBufBinWriter()
|
||||
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "testkey", "testvalue")
|
||||
|
||||
txInv := transaction.New(script.Bytes(), 1*native.GASFactor)
|
||||
txInv.Nonce = getNextNonce()
|
||||
txInv.ValidUntilBlock = validUntilBlock
|
||||
|
@ -352,8 +360,8 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
checkTxHalt(t, bc, txInv.Hash())
|
||||
t.Logf("txInv: %s", txInv.Hash().StringLE())
|
||||
|
||||
priv1 := testchain.PrivateKeyByID(1)
|
||||
txNeo0to1 := newNEP17Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
|
||||
// Block #4: transfer 0.0000_1 NEO from priv0 to priv1.
|
||||
txNeo0to1 := newNEP17Transfer(neoHash, priv0ScriptHash, priv1ScriptHash, 1000)
|
||||
txNeo0to1.Nonce = getNextNonce()
|
||||
txNeo0to1.ValidUntilBlock = validUntilBlock
|
||||
txNeo0to1.Signers = []transaction.Signer{
|
||||
|
@ -370,6 +378,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, txNeo0to1.Hash())
|
||||
|
||||
// Block #5: initialize rubles contract and transfer 1000 rubles from the contract to priv0.
|
||||
w := io.NewBufBinWriter()
|
||||
emit.AppCall(w.BinWriter, cHash, "init", callflag.All)
|
||||
initTx := transaction.New(w.Bytes(), 1*native.GASFactor)
|
||||
|
@ -378,7 +387,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
|
||||
require.NoError(t, addNetworkFee(bc, initTx, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), initTx))
|
||||
transferTx := newNEP17Transfer(cHash, cHash, priv0.GetScriptHash(), 1000)
|
||||
transferTx := newNEP17Transfer(cHash, cHash, priv0ScriptHash, 1000)
|
||||
transferTx.Nonce = getNextNonce()
|
||||
transferTx.ValidUntilBlock = validUntilBlock
|
||||
transferTx.Signers = []transaction.Signer{
|
||||
|
@ -392,14 +401,14 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
||||
transferTx.SystemFee += 1000000
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
||||
|
||||
b = bc.newBlock(initTx, transferTx)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, initTx.Hash())
|
||||
checkTxHalt(t, bc, transferTx.Hash())
|
||||
t.Logf("recieveRublesTx: %v", transferTx.Hash().StringLE())
|
||||
|
||||
transferTx = newNEP17Transfer(cHash, priv0.GetScriptHash(), priv1.GetScriptHash(), 123)
|
||||
// Block #6: transfer 123 rubles from priv0 to priv1
|
||||
transferTx = newNEP17Transfer(cHash, priv0.GetScriptHash(), priv1ScriptHash, 123)
|
||||
transferTx.Nonce = getNextNonce()
|
||||
transferTx.ValidUntilBlock = validUntilBlock
|
||||
transferTx.Signers = []transaction.Signer{
|
||||
|
@ -413,24 +422,16 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
||||
transferTx.SystemFee += 1000000
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
||||
|
||||
b = bc.newBlock(transferTx)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, transferTx.Hash())
|
||||
t.Logf("sendRublesTx: %v", transferTx.Hash().StringLE())
|
||||
|
||||
// Push verification contract into the chain.
|
||||
// Block #7: push verification contract into the chain.
|
||||
verifyPath := filepath.Join(prefix, "verify", "verification_contract.go")
|
||||
txDeploy2, _ := newDeployTx(t, bc, priv0ScriptHash, verifyPath, "Verify", nil)
|
||||
txDeploy2.Nonce = getNextNonce()
|
||||
txDeploy2.ValidUntilBlock = validUntilBlock
|
||||
require.NoError(t, addNetworkFee(bc, txDeploy2, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txDeploy2))
|
||||
b = bc.newBlock(txDeploy2)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, txDeploy2.Hash())
|
||||
_, _, _ = deployContractFromPriv0(t, verifyPath, "Verify", nil, 2)
|
||||
|
||||
// Deposit some GAS to notary contract for priv0
|
||||
// Block #8: deposit some GAS to notary contract for priv0.
|
||||
transferTx = newNEP17Transfer(gasHash, priv0.GetScriptHash(), notaryHash, 10_0000_0000, priv0.GetScriptHash(), int64(bc.BlockHeight()+1000))
|
||||
transferTx.Nonce = getNextNonce()
|
||||
transferTx.ValidUntilBlock = validUntilBlock
|
||||
|
@ -443,68 +444,59 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, addNetworkFee(bc, transferTx, acc0))
|
||||
transferTx.SystemFee += 10_0000
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), transferTx))
|
||||
|
||||
b = bc.newBlock(transferTx)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
checkTxHalt(t, bc, transferTx.Hash())
|
||||
t.Logf("notaryDepositTxPriv0: %v", transferTx.Hash().StringLE())
|
||||
|
||||
// Designate new Notary node
|
||||
// Block #9: designate new Notary node.
|
||||
ntr, err := wallet.NewWalletFromFile(path.Join(notaryModulePath, "./testdata/notary1.json"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt))
|
||||
bc.setNodesByRole(t, true, noderoles.P2PNotary, keys.PublicKeys{ntr.Accounts[0].PrivateKey().PublicKey()})
|
||||
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PrivateKey().PublicKey().Bytes()))
|
||||
|
||||
// Push verification contract with arguments into the chain.
|
||||
// Block #10: push verification contract with arguments into the chain.
|
||||
verifyPath = filepath.Join(prefix, "verify_args", "verification_with_args_contract.go")
|
||||
txDeploy3, _ := newDeployTx(t, bc, priv0ScriptHash, verifyPath, "VerifyWithArgs", nil)
|
||||
txDeploy3.Nonce = getNextNonce()
|
||||
txDeploy3.ValidUntilBlock = validUntilBlock
|
||||
require.NoError(t, addNetworkFee(bc, txDeploy3, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txDeploy3))
|
||||
b = bc.newBlock(txDeploy3)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #10
|
||||
checkTxHalt(t, bc, txDeploy3.Hash())
|
||||
_, _, _ = deployContractFromPriv0(t, verifyPath, "VerifyWithArgs", nil, 3) // block #10
|
||||
|
||||
// Push NameService contract into the chain.
|
||||
// Block #11: push NameService contract into the chain.
|
||||
nsPath := examplesPrefix + "nft-nd-nns/"
|
||||
nsConfigPath := nsPath + "nns.yml"
|
||||
txDeploy4, _ := newDeployTx(t, bc, priv0ScriptHash, nsPath, nsPath, &nsConfigPath)
|
||||
txDeploy4.Nonce = getNextNonce()
|
||||
txDeploy4.ValidUntilBlock = validUntilBlock
|
||||
require.NoError(t, addNetworkFee(bc, txDeploy4, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txDeploy4))
|
||||
b = bc.newBlock(txDeploy4)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #11
|
||||
checkTxHalt(t, bc, txDeploy4.Hash())
|
||||
nsHash, err := bc.GetContractScriptHash(4)
|
||||
require.NoError(t, err)
|
||||
t.Logf("contract (%s): \n\tHash: %s\n", nsPath, nsHash.StringLE())
|
||||
_, _, nsHash := deployContractFromPriv0(t, nsPath, nsPath, &nsConfigPath, 4) // block #11
|
||||
|
||||
// register `neo.com` with A record type and priv0 owner via NS
|
||||
// Block #12: transfer funds to committee for futher NS record registration.
|
||||
transferFundsToCommittee(t, bc) // block #12
|
||||
|
||||
// Block #13: add `.com` root to NNS.
|
||||
res, err := invokeContractMethodGeneric(bc, -1,
|
||||
nsHash, "addRoot", true, "com") // block #13
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, stackitem.Null{})
|
||||
|
||||
// Block #14: register `neo.com` via NNS.
|
||||
res, err = invokeContractMethodGeneric(bc, -1,
|
||||
nsHash, "register", acc0, "neo.com", priv0ScriptHash) // block #14
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, stackitem.NewBool(true))
|
||||
require.Equal(t, 1, len(res.Events)) // transfer
|
||||
tokenID, err := res.Events[0].Item.Value().([]stackitem.Item)[3].TryBytes()
|
||||
require.NoError(t, err)
|
||||
t.Logf("NNS token #1 ID (hex): %s", hex.EncodeToString(tokenID))
|
||||
|
||||
// Block #15: set A record type with priv0 owner via NNS.
|
||||
res, err = invokeContractMethodGeneric(bc, -1, nsHash,
|
||||
"setRecord", acc0, "neo.com", int64(nns.A), "1.2.3.4") // block #15
|
||||
require.NoError(t, err)
|
||||
checkResult(t, res, stackitem.Null{})
|
||||
|
||||
// Invoke `test_contract.go`: put new value with the same key to check `getstate` RPC call
|
||||
// Block #16: invoke `test_contract.go`: put new value with the same key to check `getstate` RPC call
|
||||
script.Reset()
|
||||
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "testkey", "newtestvalue")
|
||||
// Invoke `test_contract.go`: put values to check `findstates` RPC call
|
||||
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "aa", "v1")
|
||||
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "aa10", "v2")
|
||||
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "aa50", "v3")
|
||||
|
||||
txInv = transaction.New(script.Bytes(), 1*native.GASFactor)
|
||||
txInv.Nonce = getNextNonce()
|
||||
txInv.ValidUntilBlock = validUntilBlock
|
||||
|
@ -512,9 +504,75 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
|||
require.NoError(t, addNetworkFee(bc, txInv, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txInv))
|
||||
b = bc.newBlock(txInv)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
require.NoError(t, bc.AddBlock(b)) // block #16
|
||||
checkTxHalt(t, bc, txInv.Hash())
|
||||
|
||||
// Block #17: deploy NeoFS Object contract (NEP11-Divisible).
|
||||
nfsPath := examplesPrefix + "nft-d/"
|
||||
nfsConfigPath := nfsPath + "nft.yml"
|
||||
_, _, nfsHash := deployContractFromPriv0(t, nfsPath, nfsPath, &nfsConfigPath, 5) // block #17
|
||||
|
||||
// Block #18: mint 1.00 NFSO token by transferring 10 GAS to NFSO contract.
|
||||
containerID := util.Uint256{1, 2, 3}
|
||||
objectID := util.Uint256{4, 5, 6}
|
||||
txGas0toNFS := newNEP17Transfer(gasHash, priv0ScriptHash, nfsHash, 10_0000_0000, containerID.BytesBE(), objectID.BytesBE())
|
||||
txGas0toNFS.SystemFee += 4000_0000
|
||||
txGas0toNFS.Nonce = getNextNonce()
|
||||
txGas0toNFS.ValidUntilBlock = validUntilBlock
|
||||
txGas0toNFS.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: priv0ScriptHash,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
}
|
||||
require.NoError(t, addNetworkFee(bc, txGas0toNFS, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txGas0toNFS))
|
||||
b = bc.newBlock(txGas0toNFS)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #18
|
||||
checkTxHalt(t, bc, txGas0toNFS.Hash())
|
||||
aer, _ := bc.GetAppExecResults(txGas0toNFS.Hash(), trigger.Application)
|
||||
require.Equal(t, 2, len(aer[0].Events)) // GAS transfer + NFSO transfer
|
||||
tokenID, err = aer[0].Events[1].Item.Value().([]stackitem.Item)[3].TryBytes()
|
||||
require.NoError(t, err)
|
||||
t.Logf("NFSO token #1 ID (hex): %s", hex.EncodeToString(tokenID))
|
||||
|
||||
// Block #19: transfer 0.25 NFSO from priv0 to priv1.
|
||||
script.Reset()
|
||||
emit.AppCall(script.BinWriter, nfsHash, "transfer", callflag.All, priv0ScriptHash, priv1ScriptHash, 25, tokenID, nil)
|
||||
emit.Opcodes(script.BinWriter, opcode.ASSERT)
|
||||
require.NoError(t, script.Err)
|
||||
txNFS0to1 := transaction.New(script.Bytes(), 1*native.GASFactor)
|
||||
txNFS0to1.Nonce = getNextNonce()
|
||||
txNFS0to1.ValidUntilBlock = validUntilBlock
|
||||
txNFS0to1.Signers = []transaction.Signer{{Account: priv0ScriptHash, Scopes: transaction.CalledByEntry}}
|
||||
require.NoError(t, addNetworkFee(bc, txNFS0to1, acc0))
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), txNFS0to1))
|
||||
b = bc.newBlock(txNFS0to1)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #19
|
||||
checkTxHalt(t, bc, txNFS0to1.Hash())
|
||||
|
||||
// Block #20: transfer 1000 GAS to priv1.
|
||||
txMoveGas, err = testchain.NewTransferFromOwner(bc, gasHash, priv1ScriptHash, int64(fixedn.Fixed8FromInt64(1000)),
|
||||
getNextNonce(), validUntilBlock)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, bc.AddBlock(bc.newBlock(txMoveGas)))
|
||||
checkTxHalt(t, bc, txMoveGas.Hash()) // block #20
|
||||
|
||||
// Block #21: transfer 0.05 NFSO from priv1 back to priv0.
|
||||
script.Reset()
|
||||
emit.AppCall(script.BinWriter, nfsHash, "transfer", callflag.All, priv1ScriptHash, priv0.GetScriptHash(), 5, tokenID, nil)
|
||||
emit.Opcodes(script.BinWriter, opcode.ASSERT)
|
||||
require.NoError(t, script.Err)
|
||||
txNFS1to0 := transaction.New(script.Bytes(), 1*native.GASFactor)
|
||||
txNFS1to0.Nonce = getNextNonce()
|
||||
txNFS1to0.ValidUntilBlock = validUntilBlock
|
||||
txNFS1to0.Signers = []transaction.Signer{{Account: priv1ScriptHash, Scopes: transaction.CalledByEntry}}
|
||||
require.NoError(t, addNetworkFee(bc, txNFS1to0, acc0))
|
||||
require.NoError(t, acc1.SignTx(testchain.Network(), txNFS1to0))
|
||||
b = bc.newBlock(txNFS1to0)
|
||||
require.NoError(t, bc.AddBlock(b)) // block #21
|
||||
checkTxHalt(t, bc, txNFS1to0.Hash())
|
||||
|
||||
// Compile contract to test `invokescript` RPC call
|
||||
invokePath := filepath.Join(prefix, "invoke", "invokescript_contract.go")
|
||||
invokeCfg := filepath.Join(prefix, "invoke", "invoke.yml")
|
||||
|
|
|
@ -280,7 +280,7 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
|
|||
var (
|
||||
stateSyncInterval = 4
|
||||
maxTraceable uint32 = 6
|
||||
stateSyncPoint = 16
|
||||
stateSyncPoint = 20
|
||||
)
|
||||
spoutCfg := func(c *config.Config) {
|
||||
c.ProtocolConfiguration.StateRootInHeader = true
|
||||
|
@ -291,10 +291,9 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
|
|||
bcSpout := newTestChainWithCustomCfg(t, spoutCfg)
|
||||
initBasicChain(t, bcSpout)
|
||||
|
||||
// make spout chain higher that latest state sync point
|
||||
// make spout chain higher that latest state sync point (add several blocks up to stateSyncPoint+2)
|
||||
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
||||
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
||||
require.Equal(t, uint32(stateSyncPoint+2), bcSpout.BlockHeight())
|
||||
require.Equal(t, stateSyncPoint+2, int(bcSpout.BlockHeight()))
|
||||
|
||||
boltCfg := func(c *config.Config) {
|
||||
spoutCfg(c)
|
||||
|
|
|
@ -110,6 +110,12 @@ func topIterableFromStack(st []stackitem.Item, resultItemType interface{}) ([]in
|
|||
result := make([]interface{}, len(iter.Values))
|
||||
for i := range iter.Values {
|
||||
switch resultItemType.(type) {
|
||||
case []byte:
|
||||
bytes, err := iter.Values[i].TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize []byte from stackitem #%d: %w", i, err)
|
||||
}
|
||||
result[i] = bytes
|
||||
case string:
|
||||
bytes, err := iter.Values[i].TryBytes()
|
||||
if err != nil {
|
||||
|
|
|
@ -51,15 +51,15 @@ func (c *Client) nepTotalSupply(tokenHash util.Uint160) (int64, error) {
|
|||
}
|
||||
|
||||
// nepBalanceOf invokes `balanceOf` NEP* method on a specified contract.
|
||||
func (c *Client) nepBalanceOf(tokenHash, acc util.Uint160, tokenID *string) (int64, error) {
|
||||
func (c *Client) nepBalanceOf(tokenHash, acc util.Uint160, tokenID []byte) (int64, error) {
|
||||
params := []smartcontract.Parameter{{
|
||||
Type: smartcontract.Hash160Type,
|
||||
Value: acc,
|
||||
}}
|
||||
if tokenID != nil {
|
||||
params = append(params, smartcontract.Parameter{
|
||||
Type: smartcontract.StringType,
|
||||
Value: *tokenID,
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: tokenID,
|
||||
})
|
||||
}
|
||||
result, err := c.InvokeFunction(tokenHash, "balanceOf", params, nil)
|
||||
|
|
|
@ -86,7 +86,7 @@ func (c *Client) CreateNEP11TransferTx(acc *wallet.Account, tokenHash util.Uint1
|
|||
}
|
||||
|
||||
// NEP11TokensOf returns an array of token IDs for the specified owner of the specified NFT token.
|
||||
func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) ([]string, error) {
|
||||
func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "tokensOf", []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.Hash160Type,
|
||||
|
@ -101,13 +101,13 @@ func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) ([]st
|
|||
return nil, err
|
||||
}
|
||||
|
||||
arr, err := topIterableFromStack(result.Stack, string(""))
|
||||
arr, err := topIterableFromStack(result.Stack, []byte{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token IDs from stack: %w", err)
|
||||
}
|
||||
ids := make([]string, len(arr))
|
||||
ids := make([][]byte, len(arr))
|
||||
for i := range ids {
|
||||
ids[i] = arr[i].(string)
|
||||
ids[i] = arr[i].([]byte)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
@ -116,10 +116,10 @@ func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) ([]st
|
|||
|
||||
// NEP11NDOwnerOf invokes `ownerOf` non-devisible NEP-11 method with the
|
||||
// specified token ID on a specified contract.
|
||||
func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID string) (util.Uint160, error) {
|
||||
func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID []byte) (util.Uint160, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "ownerOf", []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.StringType,
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: tokenID,
|
||||
},
|
||||
}, nil)
|
||||
|
@ -143,7 +143,7 @@ func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID string) (util.Ui
|
|||
// (in FixedN format using contract's number of decimals) to given account and
|
||||
// sends it to the network returning just a hash of it.
|
||||
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, amount int64, tokenID string, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tokenHash util.Uint160, amount int64, tokenID []byte, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
if !c.initDone {
|
||||
return util.Uint256{}, errNetworkNotInitialized
|
||||
}
|
||||
|
@ -161,15 +161,15 @@ func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
|||
|
||||
// NEP11DBalanceOf invokes `balanceOf` divisible NEP-11 method on a
|
||||
// specified contract.
|
||||
func (c *Client) NEP11DBalanceOf(tokenHash, owner util.Uint160, tokenID string) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, &tokenID)
|
||||
func (c *Client) NEP11DBalanceOf(tokenHash, owner util.Uint160, tokenID []byte) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, tokenID)
|
||||
}
|
||||
|
||||
// NEP11DOwnerOf returns list of the specified NEP-11 divisible token owners.
|
||||
func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID string) ([]util.Uint160, error) {
|
||||
func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "ownerOf", []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.StringType,
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: tokenID,
|
||||
},
|
||||
}, nil)
|
||||
|
@ -198,9 +198,9 @@ func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID string) ([]util.U
|
|||
|
||||
// NEP11Properties invokes `properties` optional NEP-11 method on a
|
||||
// specified contract.
|
||||
func (c *Client) NEP11Properties(tokenHash util.Uint160, tokenID string) (*stackitem.Map, error) {
|
||||
func (c *Client) NEP11Properties(tokenHash util.Uint160, tokenID []byte) (*stackitem.Map, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "properties", []smartcontract.Parameter{{
|
||||
Type: smartcontract.StringType,
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: tokenID,
|
||||
}}, nil)
|
||||
if err != nil {
|
||||
|
@ -215,7 +215,7 @@ func (c *Client) NEP11Properties(tokenHash util.Uint160, tokenID string) (*stack
|
|||
}
|
||||
|
||||
// NEP11Tokens returns list of the tokens minted by the contract.
|
||||
func (c *Client) NEP11Tokens(tokenHash util.Uint160) ([]string, error) {
|
||||
func (c *Client) NEP11Tokens(tokenHash util.Uint160) ([][]byte, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "tokens", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -225,13 +225,13 @@ func (c *Client) NEP11Tokens(tokenHash util.Uint160) ([]string, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
arr, err := topIterableFromStack(result.Stack, string(""))
|
||||
arr, err := topIterableFromStack(result.Stack, []byte{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get token IDs from stack: %w", err)
|
||||
}
|
||||
tokens := make([]string, len(arr))
|
||||
tokens := make([][]byte, len(arr))
|
||||
for i := range tokens {
|
||||
tokens[i] = arr[i].(string)
|
||||
tokens[i] = arr[i].([]byte)
|
||||
}
|
||||
return tokens, nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||
|
@ -107,7 +108,7 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
acc0 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
|
||||
check := func(t *testing.T, extraFee int64) {
|
||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
||||
tx.ValidUntilBlock = 20
|
||||
tx.ValidUntilBlock = 25
|
||||
tx.Signers = []transaction.Signer{{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
|
@ -165,7 +166,7 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
check := func(t *testing.T, extraFee int64) {
|
||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
||||
tx.ValidUntilBlock = 20
|
||||
tx.ValidUntilBlock = 25
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
|
@ -801,7 +802,7 @@ func TestClient_GetNativeContracts(t *testing.T) {
|
|||
require.Equal(t, chain.GetNatives(), cs)
|
||||
}
|
||||
|
||||
func TestClient_NEP11(t *testing.T) {
|
||||
func TestClient_NEP11_ND(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer func() { _ = rpcSrv.Shutdown() }()
|
||||
|
@ -810,7 +811,7 @@ func TestClient_NEP11(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
h, err := util.Uint160DecodeStringLE(nameServiceContractHash)
|
||||
h, err := util.Uint160DecodeStringLE(nnsContractHash)
|
||||
require.NoError(t, err)
|
||||
acc := testchain.PrivateKeyByID(0).GetScriptHash()
|
||||
|
||||
|
@ -846,12 +847,12 @@ func TestClient_NEP11(t *testing.T) {
|
|||
require.EqualValues(t, 1, b)
|
||||
})
|
||||
t.Run("OwnerOf", func(t *testing.T) {
|
||||
b, err := c.NEP11NDOwnerOf(h, "neo.com")
|
||||
b, err := c.NEP11NDOwnerOf(h, []byte("neo.com"))
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, acc, b)
|
||||
})
|
||||
t.Run("Properties", func(t *testing.T) {
|
||||
p, err := c.NEP11Properties(h, "neo.com")
|
||||
p, err := c.NEP11Properties(h, []byte("neo.com"))
|
||||
require.NoError(t, err)
|
||||
blockRegisterDomain, err := chain.GetBlock(chain.GetHeaderHash(14)) // `neo.com` domain was registered in 14th block
|
||||
require.NoError(t, err)
|
||||
|
@ -867,6 +868,73 @@ func TestClient_NEP11(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestClient_NEP11_D(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer func() { _ = rpcSrv.Shutdown() }()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv0 := testchain.PrivateKeyByID(0).GetScriptHash()
|
||||
priv1 := testchain.PrivateKeyByID(1).GetScriptHash()
|
||||
token1ID, err := hex.DecodeString(nfsoToken1ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Decimals", func(t *testing.T) {
|
||||
d, err := c.NEP11Decimals(nfsoHash)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 2, d) // Divisible.
|
||||
})
|
||||
t.Run("TotalSupply", func(t *testing.T) {
|
||||
s, err := c.NEP11TotalSupply(nfsoHash)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, s) // the only NFSO of acc0
|
||||
})
|
||||
t.Run("Symbol", func(t *testing.T) {
|
||||
sym, err := c.NEP11Symbol(nfsoHash)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "NFSO", sym)
|
||||
})
|
||||
t.Run("TokenInfo", func(t *testing.T) {
|
||||
tok, err := c.NEP11TokenInfo(nfsoHash)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &wallet.Token{
|
||||
Name: "NeoFS Object NFT",
|
||||
Hash: nfsoHash,
|
||||
Decimals: 2,
|
||||
Symbol: "NFSO",
|
||||
Standard: manifest.NEP11StandardName,
|
||||
}, tok)
|
||||
})
|
||||
t.Run("BalanceOf", func(t *testing.T) {
|
||||
b, err := c.NEP11BalanceOf(nfsoHash, priv0)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 80, b)
|
||||
})
|
||||
t.Run("OwnerOf", func(t *testing.T) {
|
||||
b, err := c.NEP11DOwnerOf(nfsoHash, token1ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []util.Uint160{priv1, priv0}, b)
|
||||
})
|
||||
t.Run("Properties", func(t *testing.T) {
|
||||
p, err := c.NEP11Properties(nfsoHash, token1ID)
|
||||
require.NoError(t, err)
|
||||
expected := stackitem.NewMap()
|
||||
expected.Add(stackitem.Make([]byte("name")), stackitem.NewBuffer([]byte("NeoFS Object "+base64.StdEncoding.EncodeToString(token1ID))))
|
||||
expected.Add(stackitem.Make([]byte("containerID")), stackitem.Make([]byte(base64.StdEncoding.EncodeToString(nfsoToken1ContainerID.BytesBE()))))
|
||||
expected.Add(stackitem.Make([]byte("objectID")), stackitem.Make([]byte(base64.StdEncoding.EncodeToString(nfsoToken1ObjectID.BytesBE()))))
|
||||
require.EqualValues(t, expected, p)
|
||||
})
|
||||
t.Run("Transfer", func(t *testing.T) {
|
||||
_, err := c.TransferNEP11D(wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0)),
|
||||
testchain.PrivateKeyByID(1).GetScriptHash(),
|
||||
nfsoHash, 20, token1ID, nil, 0, nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_NNS(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -876,34 +944,31 @@ func TestClient_NNS(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
nsHash, err := util.Uint160DecodeStringLE(nameServiceContractHash)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("NNSIsAvailable, false", func(t *testing.T) {
|
||||
b, err := c.NNSIsAvailable(nsHash, "neo.com")
|
||||
b, err := c.NNSIsAvailable(nnsHash, "neo.com")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, b)
|
||||
})
|
||||
t.Run("NNSIsAvailable, true", func(t *testing.T) {
|
||||
b, err := c.NNSIsAvailable(nsHash, "neogo.com")
|
||||
b, err := c.NNSIsAvailable(nnsHash, "neogo.com")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, b)
|
||||
})
|
||||
t.Run("NNSResolve, good", func(t *testing.T) {
|
||||
b, err := c.NNSResolve(nsHash, "neo.com", nns.A)
|
||||
b, err := c.NNSResolve(nnsHash, "neo.com", nns.A)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "1.2.3.4", b)
|
||||
})
|
||||
t.Run("NNSResolve, bad", func(t *testing.T) {
|
||||
_, err := c.NNSResolve(nsHash, "neogo.com", nns.A)
|
||||
_, err := c.NNSResolve(nnsHash, "neogo.com", nns.A)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("NNSResolve, forbidden", func(t *testing.T) {
|
||||
_, err := c.NNSResolve(nsHash, "neogo.com", nns.CNAME)
|
||||
_, err := c.NNSResolve(nnsHash, "neogo.com", nns.CNAME)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("NNSGetAllRecords, good", func(t *testing.T) {
|
||||
rss, err := c.NNSGetAllRecords(nsHash, "neo.com")
|
||||
rss, err := c.NNSGetAllRecords(nnsHash, "neo.com")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []nns.RecordState{
|
||||
{
|
||||
|
@ -914,7 +979,7 @@ func TestClient_NNS(t *testing.T) {
|
|||
}, rss)
|
||||
})
|
||||
t.Run("NNSGetAllRecords, bad", func(t *testing.T) {
|
||||
_, err := c.NNSGetAllRecords(nsHash, "neopython.com")
|
||||
_, err := c.NNSGetAllRecords(nnsHash, "neopython.com")
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func getUnitTestChain(t testing.TB, enableOracle bool, enableNotary bool) (*core
|
|||
}
|
||||
|
||||
func getTestBlocks(t *testing.T) []*block.Block {
|
||||
// File "./testdata/testblocks.acc" was generated by function core._
|
||||
// File "./testdata/testblocks.acc" was generated by function core.TestCreateBasicChain
|
||||
// ("neo-go/pkg/core/helper_test.go").
|
||||
// To generate new "./testdata/testblocks.acc", follow the steps:
|
||||
// 1. Rename the function
|
||||
|
|
|
@ -61,30 +61,27 @@ type rpcTestCase struct {
|
|||
check func(t *testing.T, e *executor, result interface{})
|
||||
}
|
||||
|
||||
const testContractHash = "5c9e40a12055c6b9e3f72271c9779958c842135d"
|
||||
const deploymentTxHash = "8de63ea12ca8a9c5233ebf8664a442c881ae1bb83708d82da7fa1da2305ecf14"
|
||||
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
|
||||
const genesisBlockHash = "a4ae00f6ac7496cac14e709fbf8b8ecb4c9831d8a6ee396056af9350fcf22671"
|
||||
const testContractHash = "1ab08f5508edafa6f28e3db3227442a9e70aac52"
|
||||
const deploymentTxHash = "017c9edb217477aeb3e0c35462361209fdb7bf104dc8e285e2385af8713926b4"
|
||||
|
||||
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
|
||||
const verifyContractAVM = "VwIAQS1RCDAhcAwU7p6iLCfjS9AUj8QQjgj3To9QSLLbMHFoE87bKGnbKJdA"
|
||||
const verifyWithArgsContractHash = "947c780f45b2a3d32e946355ee5cb57faf4decb7"
|
||||
const invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGhB+CfsjCGqJgQRQAwUDQ8DAgkAAgEDBwMEBQIBAA4GDAnbMHFpQfgn7IwhqiYEEkATQA=="
|
||||
const (
|
||||
verifyContractHash = "7deef31e5c616e157cdf02a5446f36d0a4eead52"
|
||||
verifyContractAVM = "VwIAQS1RCDBwDBTunqIsJ+NL0BSPxBCOCPdOj1BIskrZMCQE2zBxaBPOStkoJATbKGlK2SgkBNsol0A="
|
||||
verifyWithArgsContractHash = "6df009754ce475a6a5730c9e488f80e8e47bc1f1"
|
||||
nnsContractHash = "1a7530a4c6cfdd40ffed40775aa5453febab24c0"
|
||||
nnsToken1ID = "6e656f2e636f6d"
|
||||
nfsoContractHash = "aaf8913c501e25c42877e79f04cb7c2c1ab47e57"
|
||||
nfsoToken1ID = "7e244ffd6aa85fb1579d2ed22e9b761ab62e3486"
|
||||
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
|
||||
)
|
||||
|
||||
const nameServiceContractHash = "3a602b3e7cfd760850bfac44f4a9bb0ebad3e2dc"
|
||||
|
||||
var NNSHash = util.Uint160{0xdc, 0xe2, 0xd3, 0xba, 0x0e, 0xbb, 0xa9, 0xf4, 0x44, 0xac, 0xbf, 0x50, 0x08, 0x76, 0xfd, 0x7c, 0x3e, 0x2b, 0x60, 0x3a}
|
||||
|
||||
var nep11Reg = &result.NEP11Balances{
|
||||
Address: "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn",
|
||||
Balances: []result.NEP11AssetBalance{{
|
||||
Asset: NNSHash,
|
||||
Tokens: []result.NEP11TokenBalance{{
|
||||
ID: "6e656f2e636f6d",
|
||||
Amount: "1",
|
||||
LastUpdated: 14,
|
||||
}},
|
||||
}},
|
||||
}
|
||||
var (
|
||||
nnsHash, _ = util.Uint160DecodeStringLE(nnsContractHash)
|
||||
nfsoHash, _ = util.Uint160DecodeStringLE(nfsoContractHash)
|
||||
nfsoToken1ContainerID = util.Uint256{1, 2, 3}
|
||||
nfsoToken1ObjectID = util.Uint256{4, 5, 6}
|
||||
)
|
||||
|
||||
var rpcTestCases = map[string][]rpcTestCase{
|
||||
"getapplicationlog": {
|
||||
|
@ -245,12 +242,14 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `"]`,
|
||||
result: func(e *executor) interface{} { return nep11Reg },
|
||||
result: func(e *executor) interface{} { return &result.NEP11Balances{} },
|
||||
check: checkNep11Balances,
|
||||
},
|
||||
{
|
||||
name: "positive_address",
|
||||
params: `["` + address.Uint160ToString(testchain.PrivateKeyByID(0).GetScriptHash()) + `"]`,
|
||||
result: func(e *executor) interface{} { return nep11Reg },
|
||||
result: func(e *executor) interface{} { return &result.NEP11Balances{} },
|
||||
check: checkNep11Balances,
|
||||
},
|
||||
},
|
||||
"getnep11properties": {
|
||||
|
@ -266,21 +265,21 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "no token",
|
||||
params: `["` + NNSHash.StringLE() + `"]`,
|
||||
params: `["` + nnsContractHash + `"]`,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
name: "bad token",
|
||||
params: `["` + NNSHash.StringLE() + `", "abcdef"]`,
|
||||
params: `["` + nnsContractHash + `", "abcdef"]`,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
name: "positive",
|
||||
params: `["` + NNSHash.StringLE() + `", "6e656f2e636f6d"]`,
|
||||
params: `["` + nnsContractHash + `", "6e656f2e636f6d"]`,
|
||||
result: func(e *executor) interface{} {
|
||||
return &map[string]interface{}{
|
||||
"name": "neo.com",
|
||||
"expiration": "bhORxoMB",
|
||||
"expiration": "HrL+G4YB",
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -309,9 +308,8 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
params: `["` + testchain.PrivateKeyByID(0).Address() + `", 0]`,
|
||||
result: func(e *executor) interface{} {
|
||||
return &result.NEP11Transfers{Sent: []result.NEP11Transfer{}, Received: []result.NEP11Transfer{{Timestamp: 0x17c6edfe76e, Asset: util.Uint160{0xdc, 0xe2, 0xd3, 0xba, 0xe, 0xbb, 0xa9, 0xf4, 0x44, 0xac, 0xbf, 0x50, 0x8, 0x76, 0xfd, 0x7c, 0x3e, 0x2b, 0x60, 0x3a}, Address: "", ID: "6e656f2e636f6d", Amount: "1", Index: 0xe, NotifyIndex: 0x0, TxHash: util.Uint256{0x5b, 0x5a, 0x5b, 0xae, 0xf2, 0xc5, 0x63, 0x8a, 0x2e, 0xcc, 0x77, 0x27, 0xd9, 0x6b, 0xb9, 0xda, 0x3a, 0x7f, 0x30, 0xaa, 0xcf, 0xda, 0x7f, 0x8a, 0x10, 0xd3, 0x23, 0xbf, 0xd, 0x1f, 0x28, 0x69}}}, Address: "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn"}
|
||||
},
|
||||
result: func(e *executor) interface{} { return &result.NEP11Transfers{} },
|
||||
check: checkNep11Transfers,
|
||||
},
|
||||
},
|
||||
"getnep17balances": {
|
||||
|
@ -812,7 +810,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
require.True(t, ok)
|
||||
expected := result.UnclaimedGas{
|
||||
Address: testchain.MultisigScriptHash(),
|
||||
Unclaimed: *big.NewInt(8000),
|
||||
Unclaimed: *big.NewInt(10500),
|
||||
}
|
||||
assert.Equal(t, expected, *actual)
|
||||
},
|
||||
|
@ -882,16 +880,16 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, with notifications",
|
||||
params: `["` + NNSHash.StringLE() + `", "transfer", [{"type":"Hash160", "value":"0x0bcd2978634d961c24f5aea0802297ff128724d6"},{"type":"String", "value":"neo.com"},{"type":"Any", "value":null}],["0xb248508f4ef7088e10c48f14d04be3272ca29eee"]]`,
|
||||
params: `["` + nnsContractHash + `", "transfer", [{"type":"Hash160", "value":"0x0bcd2978634d961c24f5aea0802297ff128724d6"},{"type":"String", "value":"neo.com"},{"type":"Any", "value":null}],["0xb248508f4ef7088e10c48f14d04be3272ca29eee"]]`,
|
||||
result: func(e *executor) interface{} {
|
||||
script := []byte{0x0b, 0x0c, 0x07, 0x6e, 0x65, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0c, 0x14, 0xd6, 0x24, 0x87, 0x12, 0xff, 0x97, 0x22, 0x80, 0xa0, 0xae, 0xf5, 0x24, 0x1c, 0x96, 0x4d, 0x63, 0x78, 0x29, 0xcd, 0x0b, 0x13, 0xc0, 0x1f, 0x0c, 0x08, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x0c, 0x14, 0xdc, 0xe2, 0xd3, 0xba, 0x0e, 0xbb, 0xa9, 0xf4, 0x44, 0xac, 0xbf, 0x50, 0x08, 0x76, 0xfd, 0x7c, 0x3e, 0x2b, 0x60, 0x3a, 0x41, 0x62, 0x7d, 0x5b, 0x52}
|
||||
script := []byte{0x0b, 0x0c, 0x07, 0x6e, 0x65, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0c, 0x14, 0xd6, 0x24, 0x87, 0x12, 0xff, 0x97, 0x22, 0x80, 0xa0, 0xae, 0xf5, 0x24, 0x1c, 0x96, 0x4d, 0x63, 0x78, 0x29, 0xcd, 0x0b, 0x13, 0xc0, 0x1f, 0x0c, 0x08, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x0c, 0x14, 0xc0, 0x24, 0xab, 0xeb, 0x3f, 0x45, 0xa5, 0x5a, 0x77, 0x40, 0xed, 0xff, 0x40, 0xdd, 0xcf, 0xc6, 0xa4, 0x30, 0x75, 0x1a, 0x41, 0x62, 0x7d, 0x5b, 0x52}
|
||||
return &result.Invoke{
|
||||
State: "HALT",
|
||||
GasConsumed: 33767940,
|
||||
GasConsumed: 32167260,
|
||||
Script: script,
|
||||
Stack: []stackitem.Item{stackitem.Make(true)},
|
||||
Notifications: []state.NotificationEvent{{
|
||||
ScriptHash: NNSHash,
|
||||
ScriptHash: nnsHash,
|
||||
Name: "Transfer",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make([]byte{0xee, 0x9e, 0xa2, 0x2c, 0x27, 0xe3, 0x4b, 0xd0, 0x14, 0x8f, 0xc4, 0x10, 0x8e, 0x08, 0xf7, 0x4e, 0x8f, 0x50, 0x48, 0xb2}),
|
||||
|
@ -917,19 +915,19 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
chg := []storage.Operation{{
|
||||
State: "Changed",
|
||||
Key: []byte{0xfa, 0xff, 0xff, 0xff, 0xb},
|
||||
Value: []byte{0xbc, 0xf8, 0x8b, 0xa, 0x56, 0x79, 0x12},
|
||||
Value: []byte{0xe8, 0x80, 0x64, 0xcb, 0x53, 0x79, 0x12},
|
||||
}, {
|
||||
State: "Added",
|
||||
Key: []byte{0xfb, 0xff, 0xff, 0xff, 0x14, 0xd6, 0x24, 0x87, 0x12, 0xff, 0x97, 0x22, 0x80, 0xa0, 0xae, 0xf5, 0x24, 0x1c, 0x96, 0x4d, 0x63, 0x78, 0x29, 0xcd, 0xb},
|
||||
Value: []byte{0x41, 0x3, 0x21, 0x1, 0x1, 0x21, 0x1, 0x11, 0x0},
|
||||
Value: []byte{0x41, 0x3, 0x21, 0x1, 0x1, 0x21, 0x1, 0x16, 0},
|
||||
}, {
|
||||
State: "Changed",
|
||||
Key: []byte{0xfb, 0xff, 0xff, 0xff, 0x14, 0xee, 0x9e, 0xa2, 0x2c, 0x27, 0xe3, 0x4b, 0xd0, 0x14, 0x8f, 0xc4, 0x10, 0x8e, 0x8, 0xf7, 0x4e, 0x8f, 0x50, 0x48, 0xb2},
|
||||
Value: []byte{0x41, 0x3, 0x21, 0x4, 0x2f, 0xd9, 0xf5, 0x5, 0x21, 0x1, 0x11, 0x0},
|
||||
Value: []byte{0x41, 0x3, 0x21, 0x4, 0x2f, 0xd9, 0xf5, 0x5, 0x21, 0x1, 0x16, 0},
|
||||
}, {
|
||||
State: "Changed",
|
||||
Key: []byte{0xfa, 0xff, 0xff, 0xff, 0x14, 0xee, 0x9e, 0xa2, 0x2c, 0x27, 0xe3, 0x4b, 0xd0, 0x14, 0x8f, 0xc4, 0x10, 0x8e, 0x8, 0xf7, 0x4e, 0x8f, 0x50, 0x48, 0xb2},
|
||||
Value: []byte{0x41, 0x1, 0x21, 0x5, 0x4, 0xfa, 0xb2, 0x9b, 0xd},
|
||||
Value: []byte{0x41, 0x01, 0x21, 0x05, 0x9e, 0x0b, 0x0b, 0x18, 0x0b},
|
||||
}}
|
||||
// Can be returned in any order.
|
||||
assert.ElementsMatch(t, chg, res.Diagnostics.Changes)
|
||||
|
@ -937,14 +935,14 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, verbose",
|
||||
params: `["` + NNSHash.StringLE() + `", "resolve", [{"type":"String", "value":"neo.com"},{"type":"Integer","value":1}], [], true]`,
|
||||
params: `["` + nnsContractHash + `", "resolve", [{"type":"String", "value":"neo.com"},{"type":"Integer","value":1}], [], true]`,
|
||||
result: func(e *executor) interface{} {
|
||||
script := []byte{0x11, 0xc, 0x7, 0x6e, 0x65, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x12, 0xc0, 0x1f, 0xc, 0x7, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0xc, 0x14, 0xdc, 0xe2, 0xd3, 0xba, 0xe, 0xbb, 0xa9, 0xf4, 0x44, 0xac, 0xbf, 0x50, 0x8, 0x76, 0xfd, 0x7c, 0x3e, 0x2b, 0x60, 0x3a, 0x41, 0x62, 0x7d, 0x5b, 0x52}
|
||||
script := []byte{0x11, 0xc, 0x7, 0x6e, 0x65, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x12, 0xc0, 0x1f, 0xc, 0x7, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0xc, 0x14, 0xc0, 0x24, 0xab, 0xeb, 0x3f, 0x45, 0xa5, 0x5a, 0x77, 0x40, 0xed, 0xff, 0x40, 0xdd, 0xcf, 0xc6, 0xa4, 0x30, 0x75, 0x1a, 0x41, 0x62, 0x7d, 0x5b, 0x52}
|
||||
stdHash, _ := e.chain.GetNativeContractScriptHash(nativenames.StdLib)
|
||||
cryptoHash, _ := e.chain.GetNativeContractScriptHash(nativenames.CryptoLib)
|
||||
return &result.Invoke{
|
||||
State: "HALT",
|
||||
GasConsumed: 17958510,
|
||||
GasConsumed: 15928320,
|
||||
Script: script,
|
||||
Stack: []stackitem.Item{stackitem.Make("1.2.3.4")},
|
||||
Notifications: []state.NotificationEvent{},
|
||||
|
@ -954,7 +952,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
Current: hash.Hash160(script),
|
||||
Calls: []*vm.InvocationTree{
|
||||
{
|
||||
Current: NNSHash,
|
||||
Current: nnsHash,
|
||||
Calls: []*vm.InvocationTree{
|
||||
{
|
||||
Current: stdHash,
|
||||
|
@ -1834,7 +1832,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
require.NoErrorf(t, err, "could not parse response: %s", txOut)
|
||||
|
||||
assert.Equal(t, *block.Transactions[0], actual.Transaction)
|
||||
assert.Equal(t, 17, actual.Confirmations)
|
||||
assert.Equal(t, 22, actual.Confirmations)
|
||||
assert.Equal(t, TXHash, actual.Transaction.Hash())
|
||||
})
|
||||
|
||||
|
@ -1947,12 +1945,12 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
require.NoError(t, json.Unmarshal(res, actual))
|
||||
checkNep17TransfersAux(t, e, actual, sent, rcvd)
|
||||
}
|
||||
t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{10, 11, 12, 13}, []int{2, 3}) })
|
||||
t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{14, 15, 16, 17}, []int{3, 4}) })
|
||||
t.Run("no res", func(t *testing.T) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
|
||||
t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{7, 8}, []int{1}) })
|
||||
t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{10}, []int{2}) })
|
||||
t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{9, 10}, []int{2}) })
|
||||
t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{11, 12}, []int{3}) })
|
||||
t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{11, 12}, []int{2}) })
|
||||
t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{14}, []int{3}) })
|
||||
t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{13, 14}, []int{3}) })
|
||||
t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{15, 16}, []int{4}) })
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2036,6 +2034,39 @@ func doRPCCallOverHTTP(rpcCall string, url string, t *testing.T) []byte {
|
|||
return bytes.TrimSpace(body)
|
||||
}
|
||||
|
||||
func checkNep11Balances(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.NEP11Balances)
|
||||
require.True(t, ok)
|
||||
|
||||
expected := result.NEP11Balances{
|
||||
Balances: []result.NEP11AssetBalance{
|
||||
{
|
||||
Asset: nnsHash,
|
||||
Tokens: []result.NEP11TokenBalance{
|
||||
{
|
||||
ID: nnsToken1ID,
|
||||
Amount: "1",
|
||||
LastUpdated: 14,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Asset: nfsoHash,
|
||||
Tokens: []result.NEP11TokenBalance{
|
||||
{
|
||||
ID: nfsoToken1ID,
|
||||
Amount: "80",
|
||||
LastUpdated: 21,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||
}
|
||||
require.Equal(t, testchain.PrivateKeyByID(0).Address(), res.Address)
|
||||
require.ElementsMatch(t, expected.Balances, res.Balances)
|
||||
}
|
||||
|
||||
func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.NEP17Balances)
|
||||
require.True(t, ok)
|
||||
|
@ -2055,8 +2086,8 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
|||
},
|
||||
{
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Amount: "57796785740",
|
||||
LastUpdated: 16,
|
||||
Amount: "46748035310",
|
||||
LastUpdated: 19,
|
||||
}},
|
||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||
}
|
||||
|
@ -2064,8 +2095,110 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
|||
require.ElementsMatch(t, expected.Balances, res.Balances)
|
||||
}
|
||||
|
||||
func checkNep11Transfers(t *testing.T, e *executor, acc interface{}) {
|
||||
checkNep11TransfersAux(t, e, acc, []int{0}, []int{0, 1, 2})
|
||||
}
|
||||
|
||||
func checkNep11TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
||||
res, ok := acc.(*result.NEP11Transfers)
|
||||
require.True(t, ok)
|
||||
|
||||
blockReceiveNFSO, err := e.chain.GetBlock(e.chain.GetHeaderHash(21)) // transfer 0.05 NFSO from priv1 back to priv0.
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockReceiveNFSO.Transactions))
|
||||
txReceiveNFSO := blockReceiveNFSO.Transactions[0]
|
||||
|
||||
blockSendNFSO, err := e.chain.GetBlock(e.chain.GetHeaderHash(19)) // transfer 0.25 NFSO from priv0 to priv1.
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockSendNFSO.Transactions))
|
||||
txSendNFSO := blockSendNFSO.Transactions[0]
|
||||
|
||||
blockMintNFSO, err := e.chain.GetBlock(e.chain.GetHeaderHash(18)) // mint 1.00 NFSO token by transferring 10 GAS to NFSO contract.
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockMintNFSO.Transactions))
|
||||
txMintNFSO := blockMintNFSO.Transactions[0]
|
||||
|
||||
blockRegisterNSRecordA, err := e.chain.GetBlock(e.chain.GetHeaderHash(14)) // register `neo.com` with A record type and priv0 owner via NS
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockRegisterNSRecordA.Transactions))
|
||||
txRegisterNSRecordA := blockRegisterNSRecordA.Transactions[0]
|
||||
|
||||
// These are laid out here explicitly for 2 purposes:
|
||||
// * to be able to reference any particular event for paging
|
||||
// * to check chain events consistency
|
||||
// Technically these could be retrieved from application log, but that would almost
|
||||
// duplicate the Server method.
|
||||
expected := result.NEP11Transfers{
|
||||
Sent: []result.NEP11Transfer{
|
||||
{
|
||||
Timestamp: blockSendNFSO.Timestamp,
|
||||
Asset: nfsoHash,
|
||||
Address: testchain.PrivateKeyByID(1).Address(), // to priv1
|
||||
ID: nfsoToken1ID, // NFSO ID
|
||||
Amount: big.NewInt(25).String(),
|
||||
Index: 19,
|
||||
TxHash: txSendNFSO.Hash(),
|
||||
},
|
||||
},
|
||||
Received: []result.NEP11Transfer{
|
||||
{
|
||||
Timestamp: blockReceiveNFSO.Timestamp,
|
||||
Asset: nfsoHash,
|
||||
ID: nfsoToken1ID,
|
||||
Address: testchain.PrivateKeyByID(1).Address(), // from priv1
|
||||
Amount: "5",
|
||||
Index: 21,
|
||||
TxHash: txReceiveNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockMintNFSO.Timestamp,
|
||||
Asset: nfsoHash,
|
||||
ID: nfsoToken1ID,
|
||||
Address: "", // minting
|
||||
Amount: "100",
|
||||
Index: 18,
|
||||
TxHash: txMintNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockRegisterNSRecordA.Timestamp,
|
||||
Asset: nnsHash,
|
||||
ID: nnsToken1ID,
|
||||
Address: "", // minting
|
||||
Amount: "1",
|
||||
Index: 14,
|
||||
TxHash: txRegisterNSRecordA.Hash(),
|
||||
},
|
||||
},
|
||||
Address: testchain.PrivateKeyByID(0).Address(),
|
||||
}
|
||||
|
||||
require.Equal(t, expected.Address, res.Address)
|
||||
|
||||
arr := make([]result.NEP11Transfer, 0, len(expected.Sent))
|
||||
for i := range expected.Sent {
|
||||
for _, j := range sent {
|
||||
if i == j {
|
||||
arr = append(arr, expected.Sent[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
require.Equal(t, arr, res.Sent)
|
||||
|
||||
arr = arr[:0]
|
||||
for i := range expected.Received {
|
||||
for _, j := range rcvd {
|
||||
if i == j {
|
||||
arr = append(arr, expected.Received[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
require.Equal(t, arr, res.Received)
|
||||
}
|
||||
|
||||
func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
|
||||
checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, []int{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, []int{0, 1, 2, 3, 4, 5, 6, 7, 8})
|
||||
}
|
||||
|
||||
func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
||||
|
@ -2074,6 +2207,21 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
|||
rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
|
||||
require.NoError(t, err)
|
||||
|
||||
blockTransferNFSO, err := e.chain.GetBlock(e.chain.GetHeaderHash(19)) // transfer 0.25 NFSO from priv0 to priv1.
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockTransferNFSO.Transactions))
|
||||
txTransferNFSO := blockTransferNFSO.Transactions[0]
|
||||
|
||||
blockMintNFSO, err := e.chain.GetBlock(e.chain.GetHeaderHash(18)) // mint 1.00 NFSO token for priv0 by transferring 10 GAS to NFSO contract.
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockMintNFSO.Transactions))
|
||||
txMintNFSO := blockMintNFSO.Transactions[0]
|
||||
|
||||
blockDeploy5, err := e.chain.GetBlock(e.chain.GetHeaderHash(17)) // deploy NeoFS Object contract (NEP11-Divisible)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockDeploy5.Transactions))
|
||||
txDeploy5 := blockDeploy5.Transactions[0]
|
||||
|
||||
blockPutNewTestValue, err := e.chain.GetBlock(e.chain.GetHeaderHash(16)) // invoke `put` method of `test_contract.go` with `testkey`, `newtestvalue` args
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(blockPutNewTestValue.Transactions))
|
||||
|
@ -2155,6 +2303,39 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
|||
// duplicate the Server method.
|
||||
expected := result.NEP17Transfers{
|
||||
Sent: []result.NEP17Transfer{
|
||||
{
|
||||
Timestamp: blockTransferNFSO.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // burn
|
||||
Amount: big.NewInt(txTransferNFSO.SystemFee + txTransferNFSO.NetworkFee).String(),
|
||||
Index: 19,
|
||||
TxHash: blockTransferNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockMintNFSO.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: address.Uint160ToString(nfsoHash),
|
||||
Amount: "1000000000",
|
||||
Index: 18,
|
||||
NotifyIndex: 0,
|
||||
TxHash: txMintNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockMintNFSO.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // burn
|
||||
Amount: big.NewInt(txMintNFSO.SystemFee + txMintNFSO.NetworkFee).String(),
|
||||
Index: 18,
|
||||
TxHash: blockMintNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockDeploy5.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // burn
|
||||
Amount: big.NewInt(txDeploy5.SystemFee + txDeploy5.NetworkFee).String(),
|
||||
Index: 17,
|
||||
TxHash: blockDeploy5.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockPutNewTestValue.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
|
@ -2288,6 +2469,15 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
|||
},
|
||||
},
|
||||
Received: []result.NEP17Transfer{
|
||||
{
|
||||
Timestamp: blockMintNFSO.Timestamp, // GAS bounty
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "",
|
||||
Amount: "50000000",
|
||||
Index: 18,
|
||||
NotifyIndex: 0,
|
||||
TxHash: blockMintNFSO.Hash(),
|
||||
},
|
||||
{
|
||||
Timestamp: blockGASBounty2.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
Loading…
Reference in a new issue