Merge pull request #1558 from nspcc-dev/nep17

Replace NEP-5 with NEP-17
This commit is contained in:
Roman Khimov 2020-11-24 15:09:16 +03:00 committed by GitHub
commit ad30f4d793
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 637 additions and 633 deletions

View file

@ -16,7 +16,7 @@ func TestRegisterCandidate(t *testing.T) {
defer e.Close(t) defer e.Close(t)
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
"--from", validatorAddr, "--from", validatorAddr,

View file

@ -51,7 +51,7 @@ func TestSignMultisigTx(t *testing.T) {
// Transfer funds to the multisig. // Transfer funds to the multisig.
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
"--from", validatorAddr, "--from", validatorAddr,
@ -66,7 +66,7 @@ func TestSignMultisigTx(t *testing.T) {
txPath := path.Join(tmpDir, "multisigtx.json") txPath := path.Join(tmpDir, "multisigtx.json")
defer os.Remove(txPath) defer os.Remove(txPath)
e.In.WriteString("pass\r") e.In.WriteString("pass\r")
e.Run(t, "neo-go", "wallet", "nep5", "transfer", e.Run(t, "neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", wallet1Path, "--from", multisigAddr, "--wallet", wallet1Path, "--from", multisigAddr,
"--to", priv.Address(), "--token", "neo", "--amount", "1", "--to", priv.Address(), "--token", "neo", "--amount", "1",
@ -93,7 +93,7 @@ func TestSignMultisigTx(t *testing.T) {
e.Chain.GoverningTokenHash().StringLE(), "transfer", e.Chain.GoverningTokenHash().StringLE(), "transfer",
"bytes:"+multisigHash.StringBE(), "bytes:"+multisigHash.StringBE(),
"bytes:"+priv.GetScriptHash().StringBE(), "bytes:"+priv.GetScriptHash().StringBE(),
"int:1", "int:1", "bytes:",
"--", strings.Join([]string{multisigHash.StringLE(), ":", "Global"}, "")) "--", strings.Join([]string{multisigHash.StringLE(), ":", "Global"}, ""))
e.In.WriteString("pass\r") e.In.WriteString("pass\r")

View file

@ -15,10 +15,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNEP5Balance(t *testing.T) { func TestNEP17Balance(t *testing.T) {
e := newExecutor(t, true) e := newExecutor(t, true)
defer e.Close(t) defer e.Close(t)
cmdbalance := []string{"neo-go", "wallet", "nep5", "balance"} cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
cmdbase := append(cmdbalance, cmdbase := append(cmdbalance,
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
@ -99,7 +99,7 @@ func TestNEP5Balance(t *testing.T) {
return return
} }
func TestNEP5Transfer(t *testing.T) { func TestNEP17Transfer(t *testing.T) {
w, err := wallet.NewWalletFromFile("testdata/testwallet.json") w, err := wallet.NewWalletFromFile("testdata/testwallet.json")
require.NoError(t, err) require.NoError(t, err)
defer w.Close() defer w.Close()
@ -107,7 +107,7 @@ func TestNEP5Transfer(t *testing.T) {
e := newExecutor(t, true) e := newExecutor(t, true)
defer e.Close(t) defer e.Close(t)
args := []string{ args := []string{
"neo-go", "wallet", "nep5", "transfer", "neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addr, "--rpc-endpoint", "http://" + e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
"--from", validatorAddr, "--from", validatorAddr,
@ -132,7 +132,7 @@ func TestNEP5Transfer(t *testing.T) {
require.Equal(t, big.NewInt(1), b) require.Equal(t, big.NewInt(1), b)
} }
func TestNEP5MultiTransfer(t *testing.T) { func TestNEP17MultiTransfer(t *testing.T) {
privs, _ := generateKeys(t, 3) privs, _ := generateKeys(t, 3)
e := newExecutor(t, true) e := newExecutor(t, true)
@ -140,7 +140,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo") neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo")
require.NoError(t, err) require.NoError(t, err)
args := []string{ args := []string{
"neo-go", "wallet", "nep5", "multitransfer", "neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addr, "--rpc-endpoint", "http://" + e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
"--from", validatorAddr, "--from", validatorAddr,
@ -161,7 +161,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
require.Equal(t, big.NewInt(13), b) require.Equal(t, big.NewInt(13), b)
} }
func TestNEP5ImportToken(t *testing.T) { func TestNEP17ImportToken(t *testing.T) {
e := newExecutor(t, true) e := newExecutor(t, true)
defer e.Close(t) defer e.Close(t)
@ -174,11 +174,11 @@ func TestNEP5ImportToken(t *testing.T) {
gasContractHash, err := e.Chain.GetNativeContractScriptHash("gas") gasContractHash, err := e.Chain.GetNativeContractScriptHash("gas")
require.NoError(t, err) require.NoError(t, err)
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath) e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
e.Run(t, "neo-go", "wallet", "nep5", "import", e.Run(t, "neo-go", "wallet", "nep17", "import",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath, "--wallet", walletPath,
"--token", gasContractHash.StringLE()) "--token", gasContractHash.StringLE())
e.Run(t, "neo-go", "wallet", "nep5", "import", e.Run(t, "neo-go", "wallet", "nep17", "import",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath, "--wallet", walletPath,
"--token", neoContractHash.StringLE()) "--token", neoContractHash.StringLE())
@ -192,12 +192,12 @@ func TestNEP5ImportToken(t *testing.T) {
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash)) e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
} }
t.Run("WithToken", func(t *testing.T) { t.Run("WithToken", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "nep5", "info", e.Run(t, "neo-go", "wallet", "nep17", "info",
"--wallet", walletPath, "--token", gasContractHash.StringLE()) "--wallet", walletPath, "--token", gasContractHash.StringLE())
checkGASInfo(t) checkGASInfo(t)
}) })
t.Run("NoToken", func(t *testing.T) { t.Run("NoToken", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "nep5", "info", e.Run(t, "neo-go", "wallet", "nep17", "info",
"--wallet", walletPath) "--wallet", walletPath)
checkGASInfo(t) checkGASInfo(t)
_, err := e.Out.ReadString('\n') _, err := e.Out.ReadString('\n')
@ -210,9 +210,9 @@ func TestNEP5ImportToken(t *testing.T) {
}) })
t.Run("Remove", func(t *testing.T) { t.Run("Remove", func(t *testing.T) {
e.In.WriteString("y\r") e.In.WriteString("y\r")
e.Run(t, "neo-go", "wallet", "nep5", "remove", e.Run(t, "neo-go", "wallet", "nep17", "remove",
"--wallet", walletPath, "--token", neoContractHash.StringLE()) "--wallet", walletPath, "--token", neoContractHash.StringLE())
e.Run(t, "neo-go", "wallet", "nep5", "info", e.Run(t, "neo-go", "wallet", "nep17", "info",
"--wallet", walletPath) "--wallet", walletPath)
checkGASInfo(t) checkGASInfo(t)
_, err := e.Out.ReadString('\n') _, err := e.Out.ReadString('\n')

View file

@ -349,6 +349,7 @@ func initSmartContract(ctx *cli.Context) error {
} }
m := ProjectConfig{ m := ProjectConfig{
Name: contractName,
SupportedStandards: []string{}, SupportedStandards: []string{},
Events: []manifest.Event{ Events: []manifest.Event{
{ {
@ -404,6 +405,7 @@ func contractCompile(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
o.Name = conf.Name
o.ContractEvents = conf.Events o.ContractEvents = conf.Events
o.ContractSupportedStandards = conf.SupportedStandards o.ContractSupportedStandards = conf.SupportedStandards
} }
@ -631,6 +633,7 @@ func testInvokeScript(ctx *cli.Context) error {
// ProjectConfig contains project metadata. // ProjectConfig contains project metadata.
type ProjectConfig struct { type ProjectConfig struct {
Name string
SupportedStandards []string SupportedStandards []string
Events []manifest.Event Events []manifest.Event
} }

View file

@ -58,7 +58,8 @@ func RuntimeNotify(args []interface{}) {
manifest, err := ioutil.ReadFile(contractName + "/" + files[1].Name()) manifest, err := ioutil.ReadFile(contractName + "/" + files[1].Name())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
`supportedstandards: [] `name: testContract
supportedstandards: []
events: events:
- name: Hello world! - name: Hello world!
parameters: parameters:

View file

@ -3,3 +3,6 @@ package testdata
func Verify() bool { func Verify() bool {
return true return true
} }
func OnPayment(from []byte, amount int, data interface{}) {
}

View file

@ -1 +1 @@
{"abi":{"hash":"0x8dff9f223e4622961f410c015dd37052a59892bb","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null} {"name":"verify","abi":{"hash":"0xbf214a7551e50d6fbe0bef05271719325d9fc1ef","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"},{"name":"onPayment","offset":5,"parameters":[{"name":"from","type":"ByteArray"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null}

Binary file not shown.

View file

@ -26,7 +26,7 @@ var (
} }
) )
func newNEP5Commands() []cli.Command { func newNEP17Commands() []cli.Command {
balanceFlags := []cli.Flag{ balanceFlags := []cli.Flag{
walletPathFlag, walletPathFlag,
tokenFlag, tokenFlag,
@ -69,21 +69,21 @@ func newNEP5Commands() []cli.Command {
Name: "balance", Name: "balance",
Usage: "get address balance", Usage: "get address balance",
UsageText: "balance --wallet <path> --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]", UsageText: "balance --wallet <path> --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]",
Action: getNEP5Balance, Action: getNEP17Balance,
Flags: balanceFlags, Flags: balanceFlags,
}, },
{ {
Name: "import", Name: "import",
Usage: "import NEP5 token to a wallet", Usage: "import NEP17 token to a wallet",
UsageText: "import --wallet <path> --rpc-endpoint <node> --timeout <time> --token <hash>", UsageText: "import --wallet <path> --rpc-endpoint <node> --timeout <time> --token <hash>",
Action: importNEP5Token, Action: importNEP17Token,
Flags: importFlags, Flags: importFlags,
}, },
{ {
Name: "info", Name: "info",
Usage: "print imported NEP5 token info", Usage: "print imported NEP17 token info",
UsageText: "print --wallet <path> [--token <hash-or-name>]", UsageText: "print --wallet <path> [--token <hash-or-name>]",
Action: printNEP5Info, Action: printNEP17Info,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
cli.StringFlag{ cli.StringFlag{
@ -94,9 +94,9 @@ func newNEP5Commands() []cli.Command {
}, },
{ {
Name: "remove", Name: "remove",
Usage: "remove NEP5 token from the wallet", Usage: "remove NEP17 token from the wallet",
UsageText: "remove --wallet <path> --token <hash-or-name>", UsageText: "remove --wallet <path> --token <hash-or-name>",
Action: removeNEP5Token, Action: removeNEP17Token,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
cli.StringFlag{ cli.StringFlag{
@ -108,23 +108,23 @@ func newNEP5Commands() []cli.Command {
}, },
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP5 tokens", Usage: "transfer NEP17 tokens",
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash> --amount string", UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash> --amount string",
Action: transferNEP5, Action: transferNEP17,
Flags: transferFlags, Flags: transferFlags,
}, },
{ {
Name: "multitransfer", Name: "multitransfer",
Usage: "transfer NEP5 tokens to multiple recipients", Usage: "transfer NEP17 tokens to multiple recipients",
UsageText: `multitransfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr>` + UsageText: `multitransfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr>` +
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]]`, ` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]]`,
Action: multiTransferNEP5, Action: multiTransferNEP17,
Flags: multiTransferFlags, Flags: multiTransferFlags,
}, },
} }
} }
func getNEP5Balance(ctx *cli.Context) error { func getNEP17Balance(ctx *cli.Context) error {
var accounts []*wallet.Account var accounts []*wallet.Account
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
@ -170,7 +170,7 @@ func getNEP5Balance(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("invalid account address: %w", err), 1) return cli.NewExitError(fmt.Errorf("invalid account address: %w", err), 1)
} }
balances, err := c.GetNEP5Balances(addrHash) balances, err := c.GetNEP17Balances(addrHash)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -186,7 +186,7 @@ func getNEP5Balance(ctx *cli.Context) error {
asset := balances.Balances[i].Asset asset := balances.Balances[i].Asset
token, err := getMatchingToken(ctx, wall, asset.StringLE()) token, err := getMatchingToken(ctx, wall, asset.StringLE())
if err != nil { if err != nil {
token, err = c.NEP5TokenInfo(asset) token, err = c.NEP17TokenInfo(asset)
} }
if err == nil { if err == nil {
if name != "" && !(token.Name == name || token.Symbol == name || token.Address() == name || token.Hash.StringLE() == name) { if name != "" && !(token.Name == name || token.Symbol == name || token.Address() == name || token.Hash.StringLE() == name) {
@ -215,12 +215,12 @@ func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.
} }
func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) { func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) {
bs, err := c.GetNEP5Balances(addr) bs, err := c.GetNEP17Balances(addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
get := func(i int) *wallet.Token { get := func(i int) *wallet.Token {
t, _ := c.NEP5TokenInfo(bs.Balances[i].Asset) t, _ := c.NEP17TokenInfo(bs.Balances[i].Asset)
return t return t
} }
return getMatchingTokenAux(ctx, get, len(bs.Balances), name) return getMatchingTokenAux(ctx, get, len(bs.Balances), name)
@ -247,7 +247,7 @@ func getMatchingTokenAux(ctx *cli.Context, get func(i int) *wallet.Token, n int,
return token, nil return token, nil
} }
func importNEP5Token(ctx *cli.Context) error { func importNEP17Token(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -274,7 +274,7 @@ func importNEP5Token(ctx *cli.Context) error {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
tok, err := c.NEP5TokenInfo(tokenHash) tok, err := c.NEP17TokenInfo(tokenHash)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("can't receive token info: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't receive token info: %w", err), 1)
} }
@ -296,7 +296,7 @@ func printTokenInfo(ctx *cli.Context, tok *wallet.Token) {
fmt.Fprintf(w, "Address: %s\n", tok.Address()) fmt.Fprintf(w, "Address: %s\n", tok.Address())
} }
func printNEP5Info(ctx *cli.Context) error { func printNEP17Info(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -321,7 +321,7 @@ func printNEP5Info(ctx *cli.Context) error {
return nil return nil
} }
func removeNEP5Token(ctx *cli.Context) error { func removeNEP17Token(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -345,7 +345,7 @@ func removeNEP5Token(ctx *cli.Context) error {
return nil return nil
} }
func multiTransferNEP5(ctx *cli.Context) error { func multiTransferNEP17(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -412,7 +412,7 @@ func multiTransferNEP5(ctx *cli.Context) error {
return signAndSendTransfer(ctx, c, acc, recipients) return signAndSendTransfer(ctx, c, acc, recipients)
} }
func transferNEP5(ctx *cli.Context) error { func transferNEP17(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := openWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -464,7 +464,7 @@ func transferNEP5(ctx *cli.Context) error {
func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget) error { func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget) error {
gas := flags.Fixed8FromContext(ctx, "gas") gas := flags.Fixed8FromContext(ctx, "gas")
tx, err := c.CreateNEP5MultiTransferTx(acc, int64(gas), recipients...) tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients...)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -195,9 +195,9 @@ func NewCommands() []cli.Command {
Subcommands: newMultisigCommands(), Subcommands: newMultisigCommands(),
}, },
{ {
Name: "nep5", Name: "nep17",
Usage: "work with NEP5 contracts", Usage: "work with NEP17 contracts",
Subcommands: newNEP5Commands(), Subcommands: newNEP17Commands(),
}, },
{ {
Name: "candidate", Name: "candidate",
@ -237,7 +237,7 @@ func claimGas(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
hash, err := c.TransferNEP5(acc, scriptHash, neoContractHash, 0, 0) hash, err := c.TransferNEP17(acc, scriptHash, neoContractHash, 0, 0)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -178,7 +178,7 @@ func TestClaimGas(t *testing.T) {
defer w.Close() defer w.Close()
args := []string{ args := []string{
"neo-go", "wallet", "nep5", "multitransfer", "neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addr, "--rpc-endpoint", "http://" + e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
"--from", validatorAddr, "--from", validatorAddr,
@ -258,7 +258,7 @@ func TestImportDeployed(t *testing.T) {
t.Run("Sign", func(t *testing.T) { t.Run("Sign", func(t *testing.T) {
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--from", validatorAddr, "--wallet", validatorWallet, "--from", validatorAddr,
"neo:"+contractAddr+":10", "neo:"+contractAddr+":10",
@ -269,7 +269,7 @@ func TestImportDeployed(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
e.In.WriteString("pass\r") e.In.WriteString("pass\r")
e.Run(t, "neo-go", "wallet", "nep5", "transfer", e.Run(t, "neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://"+e.RPC.Addr, "--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", walletPath, "--from", contractAddr, "--wallet", walletPath, "--from", contractAddr,
"--to", privTo.Address(), "--token", "neo", "--amount", "1") "--to", privTo.Address(), "--token", "neo", "--amount", "1")

View file

@ -43,8 +43,8 @@ which would yield the response:
| `getblocksysfee` | | `getblocksysfee` |
| `getconnectioncount` | | `getconnectioncount` |
| `getcontractstate` | | `getcontractstate` |
| `getnep5balances` | | `getnep17balances` |
| `getnep5transfers` | | `getnep17transfers` |
| `getpeers` | | `getpeers` |
| `getrawmempool` | | `getrawmempool` |
| `getrawtransaction` | | `getrawtransaction` |
@ -108,9 +108,9 @@ and we're not accepting issues related to them.
Some additional extensions are implemented as a part of this RPC server. Some additional extensions are implemented as a part of this RPC server.
#### Limits and paging for getnep5transfers #### Limits and paging for getnep17transfers
`getnep5transfers` RPC call never returns more than 1000 results for one `getnep17transfers` RPC call never returns more than 1000 results for one
request (within specified time frame). You can pass your own limit via an request (within specified time frame). You can pass your own limit via an
additional parameter and then use paging to request the next batch of additional parameter and then use paging to request the next batch of
transfers. transfers.
@ -119,14 +119,14 @@ Example requesting 10 events for address NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc
within 0-1600094189 timestamps: within 0-1600094189 timestamps:
```json ```json
{ "jsonrpc": "2.0", "id": 5, "method": "getnep5transfers", "params": { "jsonrpc": "2.0", "id": 5, "method": "getnep17transfers", "params":
["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10] } ["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10] }
``` ```
Get the next 10 transfers for the same account within the same time frame: Get the next 10 transfers for the same account within the same time frame:
```json ```json
{ "jsonrpc": "2.0", "id": 5, "method": "getnep5transfers", "params": { "jsonrpc": "2.0", "id": 5, "method": "getnep17transfers", "params":
["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10, 1] } ["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10, 1] }
``` ```

View file

@ -1,3 +1,4 @@
name: "Engine example"
supportedstandards: [] supportedstandards: []
events: events:
- name: Tx - name: Tx

View file

@ -1,3 +1,4 @@
name: "Iterator example"
supportedstandards: [] supportedstandards: []
events: events:
- name: found storage values - name: found storage values

View file

@ -1,3 +1,4 @@
name: "Runtime example"
supportedstandards: [] supportedstandards: []
events: events:
- name: Event - name: Event

View file

@ -1,2 +1,3 @@
name: "Storage example"
supportedstandards: [] supportedstandards: []
events: [] events: []

View file

@ -1,2 +1,3 @@
name: "Timer example"
supportedstandards: [] supportedstandards: []
events: [] events: []

View file

@ -133,14 +133,6 @@ func checkOwnerWitness() bool {
return false return false
} }
// Name returns the token name
func Name() interface{} {
if trigger != runtime.Application {
return false
}
return token.Name
}
// Decimals returns the token decimals // Decimals returns the token decimals
func Decimals() interface{} { func Decimals() interface{} {
if trigger != runtime.Application { if trigger != runtime.Application {

View file

@ -1,2 +1,3 @@
supportedstandards: ["NEP-5"] name: "My awesome token"
supportedstandards: ["NEP-17"]
events: [] events: []

View file

@ -1,4 +1,4 @@
package nep5 package nep17
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
@ -44,7 +44,7 @@ func (t Token) BalanceOf(ctx storage.Context, holder []byte) int {
} }
// Transfer token from one user to another // Transfer token from one user to another
func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) bool { func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int, data interface{}) bool {
amountFrom := t.CanTransfer(ctx, from, to, amount) amountFrom := t.CanTransfer(ctx, from, to, amount)
if amountFrom == -1 { if amountFrom == -1 {
return false return false

View file

@ -1,7 +1,7 @@
package tokencontract package tokencontract
import ( import (
"github.com/nspcc-dev/neo-go/examples/token/nep5" "github.com/nspcc-dev/neo-go/examples/token/nep17"
"github.com/nspcc-dev/neo-go/pkg/interop" "github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/storage" "github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util" "github.com/nspcc-dev/neo-go/pkg/interop/util"
@ -14,14 +14,14 @@ const (
var ( var (
owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt") owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt")
token nep5.Token token nep17.Token
ctx storage.Context ctx storage.Context
) )
// init initializes the Token Interface and storage context for the Smart // init initializes the Token Interface and storage context for the Smart
// Contract to operate with // Contract to operate with
func init() { func init() {
token = nep5.Token{ token = nep17.Token{
Name: "Awesome NEO Token", Name: "Awesome NEO Token",
Symbol: "ANT", Symbol: "ANT",
Decimals: decimals, Decimals: decimals,
@ -32,11 +32,6 @@ func init() {
ctx = storage.GetContext() ctx = storage.GetContext()
} }
// Name returns the token name
func Name() string {
return token.Name
}
// Symbol returns the token symbol // Symbol returns the token symbol
func Symbol() string { func Symbol() string {
return token.Symbol return token.Symbol
@ -58,8 +53,8 @@ func BalanceOf(holder interop.Hash160) interface{} {
} }
// Transfer token from one user to another // Transfer token from one user to another
func Transfer(from interop.Hash160, to interop.Hash160, amount int) bool { func Transfer(from interop.Hash160, to interop.Hash160, amount int, data interface{}) bool {
return token.Transfer(ctx, from, to, amount) return token.Transfer(ctx, from, to, amount, data)
} }
// Mint initial supply of tokens // Mint initial supply of tokens

View file

@ -1,6 +1,7 @@
supportedstandards: ["NEP-5"] name: "Awesome NEO Token"
supportedstandards: ["NEP-17"]
events: events:
- name: transfer - name: Transfer
parameters: parameters:
- name: from - name: from
type: ByteString type: ByteString

View file

@ -34,6 +34,9 @@ type Options struct {
// The name of the output for contract manifest file. // The name of the output for contract manifest file.
ManifestFile string ManifestFile string
// Name is contract's name to be written to manifest.
Name string
// Runtime notifications. // Runtime notifications.
ContractEvents []manifest.Event ContractEvents []manifest.Event
@ -207,7 +210,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
} }
if o.ManifestFile != "" { if o.ManifestFile != "" {
m, err := di.ConvertToManifest(o.ContractEvents, o.ContractSupportedStandards...) m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...)
if err != nil { if err != nil {
return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) return b, fmt.Errorf("failed to convert debug info to manifest: %w", err)
} }

View file

@ -409,7 +409,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) {
// ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // ConvertToManifest converts contract to the manifest.Manifest struct for debugger.
// Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038. // Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038.
func (di *DebugInfo) ConvertToManifest(events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) {
if di.MainPkg == "" { if di.MainPkg == "" {
return nil, errors.New("no Main method was found") return nil, errors.New("no Main method was found")
} }
@ -424,7 +424,7 @@ func (di *DebugInfo) ConvertToManifest(events []manifest.Event, supportedStandar
} }
} }
result := manifest.NewManifest(di.Hash) result := manifest.NewManifest(di.Hash, name)
if supportedStandards != nil { if supportedStandards != nil {
result.SupportedStandards = supportedStandards result.SupportedStandards = supportedStandards
} }

View file

@ -149,10 +149,11 @@ func _deploy(isUpdate bool) {}
} }
t.Run("convert to Manifest", func(t *testing.T) { t.Run("convert to Manifest", func(t *testing.T) {
actual, err := d.ConvertToManifest(nil) actual, err := d.ConvertToManifest("MyCTR", nil)
require.NoError(t, err) require.NoError(t, err)
// note: offsets are hard to predict, so we just take them from the output // note: offsets are hard to predict, so we just take them from the output
expected := &manifest.Manifest{ expected := &manifest.Manifest{
Name: "MyCTR",
ABI: manifest.ABI{ ABI: manifest.ABI{
Hash: hash.Hash160(buf), Hash: hash.Hash160(buf),
Methods: []manifest.Method{ Methods: []manifest.Method{

View file

@ -101,7 +101,7 @@ func TestAppCall(t *testing.T) {
inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner))
require.NoError(t, err) require.NoError(t, err)
m, err := di.ConvertToManifest(nil) m, err := di.ConvertToManifest("Foo", nil)
require.NoError(t, err) require.NoError(t, err)
ih := hash.Hash160(inner) ih := hash.Hash160(inner)

View file

@ -54,10 +54,10 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
// Transfer funds to new validator. // Transfer funds to new validator.
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "transfer",
acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply)) acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.UtilityTokenHash(), "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, bc.UtilityTokenHash(), "transfer",
acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000)) acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)

View file

@ -758,7 +758,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.C
} }
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) { func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) {
if note.Name != "transfer" && note.Name != "Transfer" { if note.Name != "Transfer" {
return return
} }
arr, ok := note.Item.Value().([]stackitem.Item) arr, ok := note.Item.Value().([]stackitem.Item)
@ -791,7 +791,7 @@ func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.C
} }
amount = bigint.FromBytes(bs) amount = bigint.FromBytes(bs)
} }
bc.processNEP5Transfer(d, h, b, note.ScriptHash, from, to, amount) bc.processNEP17Transfer(d, h, b, note.ScriptHash, from, to, amount)
} }
func parseUint160(addr []byte) util.Uint160 { func parseUint160(addr []byte) util.Uint160 {
@ -801,7 +801,7 @@ func parseUint160(addr []byte) util.Uint160 {
return util.Uint160{} return util.Uint160{}
} }
func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *block.Block, sc util.Uint160, from, to []byte, amount *big.Int) { func (bc *Blockchain) processNEP17Transfer(cache *dao.Cached, h util.Uint256, b *block.Block, sc util.Uint160, from, to []byte, amount *big.Int) {
toAddr := parseUint160(to) toAddr := parseUint160(to)
fromAddr := parseUint160(from) fromAddr := parseUint160(from)
var id int32 var id int32
@ -815,7 +815,7 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
} }
id = assetContract.ID id = assetContract.ID
} }
transfer := &state.NEP5Transfer{ transfer := &state.NEP17Transfer{
Asset: id, Asset: id,
From: fromAddr, From: fromAddr,
To: toAddr, To: toAddr,
@ -824,7 +824,7 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
Tx: h, Tx: h,
} }
if !fromAddr.Equals(util.Uint160{}) { if !fromAddr.Equals(util.Uint160{}) {
balances, err := cache.GetNEP5Balances(fromAddr) balances, err := cache.GetNEP17Balances(fromAddr)
if err != nil { if err != nil {
return return
} }
@ -833,19 +833,19 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
bs.LastUpdatedBlock = b.Index bs.LastUpdatedBlock = b.Index
balances.Trackers[id] = bs balances.Trackers[id] = bs
transfer.Amount = *new(big.Int).Sub(&transfer.Amount, amount) transfer.Amount = *new(big.Int).Sub(&transfer.Amount, amount)
isBig, err := cache.AppendNEP5Transfer(fromAddr, balances.NextTransferBatch, transfer) isBig, err := cache.AppendNEP17Transfer(fromAddr, balances.NextTransferBatch, transfer)
if err != nil { if err != nil {
return return
} }
if isBig { if isBig {
balances.NextTransferBatch++ balances.NextTransferBatch++
} }
if err := cache.PutNEP5Balances(fromAddr, balances); err != nil { if err := cache.PutNEP17Balances(fromAddr, balances); err != nil {
return return
} }
} }
if !toAddr.Equals(util.Uint160{}) { if !toAddr.Equals(util.Uint160{}) {
balances, err := cache.GetNEP5Balances(toAddr) balances, err := cache.GetNEP17Balances(toAddr)
if err != nil { if err != nil {
return return
} }
@ -855,27 +855,27 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
balances.Trackers[id] = bs balances.Trackers[id] = bs
transfer.Amount = *amount transfer.Amount = *amount
isBig, err := cache.AppendNEP5Transfer(toAddr, balances.NextTransferBatch, transfer) isBig, err := cache.AppendNEP17Transfer(toAddr, balances.NextTransferBatch, transfer)
if err != nil { if err != nil {
return return
} }
if isBig { if isBig {
balances.NextTransferBatch++ balances.NextTransferBatch++
} }
if err := cache.PutNEP5Balances(toAddr, balances); err != nil { if err := cache.PutNEP17Balances(toAddr, balances); err != nil {
return return
} }
} }
} }
// ForEachNEP5Transfer executes f for each nep5 transfer in log. // ForEachNEP17Transfer executes f for each nep17 transfer in log.
func (bc *Blockchain) ForEachNEP5Transfer(acc util.Uint160, f func(*state.NEP5Transfer) (bool, error)) error { func (bc *Blockchain) ForEachNEP17Transfer(acc util.Uint160, f func(*state.NEP17Transfer) (bool, error)) error {
balances, err := bc.dao.GetNEP5Balances(acc) balances, err := bc.dao.GetNEP17Balances(acc)
if err != nil { if err != nil {
return nil return nil
} }
for i := int(balances.NextTransferBatch); i >= 0; i-- { for i := int(balances.NextTransferBatch); i >= 0; i-- {
lg, err := bc.dao.GetNEP5TransferLog(acc, uint32(i)) lg, err := bc.dao.GetNEP17TransferLog(acc, uint32(i))
if err != nil { if err != nil {
return nil return nil
} }
@ -890,9 +890,9 @@ func (bc *Blockchain) ForEachNEP5Transfer(acc util.Uint160, f func(*state.NEP5Tr
return nil return nil
} }
// GetNEP5Balances returns NEP5 balances for the acc. // GetNEP17Balances returns NEP17 balances for the acc.
func (bc *Blockchain) GetNEP5Balances(acc util.Uint160) *state.NEP5Balances { func (bc *Blockchain) GetNEP17Balances(acc util.Uint160) *state.NEP17Balances {
bs, err := bc.dao.GetNEP5Balances(acc) bs, err := bc.dao.GetNEP17Balances(acc)
if err != nil { if err != nil {
return nil return nil
} }
@ -901,7 +901,7 @@ func (bc *Blockchain) GetNEP5Balances(acc util.Uint160) *state.NEP5Balances {
// GetUtilityTokenBalance returns utility token (GAS) balance for the acc. // GetUtilityTokenBalance returns utility token (GAS) balance for the acc.
func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) *big.Int { func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
bs, err := bc.dao.GetNEP5Balances(acc) bs, err := bc.dao.GetNEP17Balances(acc)
if err != nil { if err != nil {
return big.NewInt(0) return big.NewInt(0)
} }
@ -912,7 +912,7 @@ func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
// GetGoverningTokenBalance returns governing token (NEO) balance and the height // GetGoverningTokenBalance returns governing token (NEO) balance and the height
// of the last balance change for the account. // of the last balance change for the account.
func (bc *Blockchain) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32) { func (bc *Blockchain) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32) {
bs, err := bc.dao.GetNEP5Balances(acc) bs, err := bc.dao.GetNEP17Balances(acc)
if err != nil { if err != nil {
return big.NewInt(0), 0 return big.NewInt(0), 0
} }
@ -1557,10 +1557,10 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
} }
// GetTestVM returns a VM and a Store setup for a test run of some sort of code. // GetTestVM returns a VM and a Store setup for a test run of some sort of code.
func (bc *Blockchain) GetTestVM(tx *transaction.Transaction) *vm.VM { func (bc *Blockchain) GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM {
d := bc.dao.GetWrapped().(*dao.Simple) d := bc.dao.GetWrapped().(*dao.Simple)
d.MPT = nil d.MPT = nil
systemInterop := bc.newInteropContext(trigger.Application, d, nil, tx) systemInterop := bc.newInteropContext(trigger.Application, d, b, tx)
vm := systemInterop.SpawnVM() vm := systemInterop.SpawnVM()
vm.SetPriceGetter(getPrice) vm.SetPriceGetter(getPrice)
return vm return vm

View file

@ -129,7 +129,7 @@ func TestAddBlockStateRoot(t *testing.T) {
sr, err := bc.GetStateRoot(bc.BlockHeight()) sr, err := bc.GetStateRoot(bc.BlockHeight())
require.NoError(t, err) require.NoError(t, err)
tx := newNEP5Transfer(bc.contracts.NEO.Hash, neoOwner, util.Uint160{}, 1) tx := newNEP17Transfer(bc.contracts.NEO.Hash, neoOwner, util.Uint160{}, 1)
tx.ValidUntilBlock = bc.BlockHeight() + 1 tx.ValidUntilBlock = bc.BlockHeight() + 1
addSigners(tx) addSigners(tx)
require.NoError(t, signTx(bc, tx)) require.NoError(t, signTx(bc, tx))
@ -265,12 +265,12 @@ func TestVerifyTx(t *testing.T) {
amount = 1_000_000_000 amount = 1_000_000_000
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer",
neoOwner, a.Contract.ScriptHash(), amount) neoOwner, a.Contract.ScriptHash(), amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
} }
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer",
neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000)) neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)

View file

@ -32,7 +32,7 @@ type Blockchainer interface {
GetContractScriptHash(id int32) (util.Uint160, error) GetContractScriptHash(id int32) (util.Uint160, error)
GetEnrollments() ([]state.Validator, error) GetEnrollments() ([]state.Validator, error)
GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32)
ForEachNEP5Transfer(util.Uint160, func(*state.NEP5Transfer) (bool, error)) error ForEachNEP17Transfer(util.Uint160, func(*state.NEP17Transfer) (bool, error)) error
GetHeaderHash(int) util.Uint256 GetHeaderHash(int) util.Uint256
GetHeader(hash util.Uint256) (*block.Header, error) GetHeader(hash util.Uint256) (*block.Header, error)
CurrentHeaderHash() util.Uint256 CurrentHeaderHash() util.Uint256
@ -42,7 +42,7 @@ type Blockchainer interface {
GetAppExecResults(util.Uint256, trigger.Type) ([]state.AppExecResult, error) GetAppExecResults(util.Uint256, trigger.Type) ([]state.AppExecResult, error)
GetNativeContractScriptHash(string) (util.Uint160, error) GetNativeContractScriptHash(string) (util.Uint160, error)
GetNextBlockValidators() ([]*keys.PublicKey, error) GetNextBlockValidators() ([]*keys.PublicKey, error)
GetNEP5Balances(util.Uint160) *state.NEP5Balances GetNEP17Balances(util.Uint160) *state.NEP17Balances
GetValidators() ([]*keys.PublicKey, error) GetValidators() ([]*keys.PublicKey, error)
GetStandByCommittee() keys.PublicKeys GetStandByCommittee() keys.PublicKeys
GetStandByValidators() keys.PublicKeys GetStandByValidators() keys.PublicKeys
@ -50,7 +50,7 @@ type Blockchainer interface {
GetStateRoot(height uint32) (*state.MPTRootState, error) GetStateRoot(height uint32) (*state.MPTRootState, error)
GetStorageItem(id int32, key []byte) *state.StorageItem GetStorageItem(id int32, key []byte) *state.StorageItem
GetStorageItems(id int32) (map[string]*state.StorageItem, error) GetStorageItems(id int32) (map[string]*state.StorageItem, error)
GetTestVM(tx *transaction.Transaction) *vm.VM GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error) GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
mempool.Feer // fee interface mempool.Feer // fee interface
GetMaxBlockSize() uint32 GetMaxBlockSize() uint32

View file

@ -14,17 +14,17 @@ import (
type Cached struct { type Cached struct {
DAO DAO
contracts map[util.Uint160]*state.Contract contracts map[util.Uint160]*state.Contract
balances map[util.Uint160]*state.NEP5Balances balances map[util.Uint160]*state.NEP17Balances
transfers map[util.Uint160]map[uint32]*state.NEP5TransferLog transfers map[util.Uint160]map[uint32]*state.NEP17TransferLog
dropNEP5Cache bool dropNEP17Cache bool
} }
// NewCached returns new Cached wrapping around given backing store. // NewCached returns new Cached wrapping around given backing store.
func NewCached(d DAO) *Cached { func NewCached(d DAO) *Cached {
ctrs := make(map[util.Uint160]*state.Contract) ctrs := make(map[util.Uint160]*state.Contract)
balances := make(map[util.Uint160]*state.NEP5Balances) balances := make(map[util.Uint160]*state.NEP17Balances)
transfers := make(map[util.Uint160]map[uint32]*state.NEP5TransferLog) transfers := make(map[util.Uint160]map[uint32]*state.NEP17TransferLog)
return &Cached{d.GetWrapped(), ctrs, balances, transfers, false} return &Cached{d.GetWrapped(), ctrs, balances, transfers, false}
} }
@ -52,50 +52,50 @@ func (cd *Cached) DeleteContractState(hash util.Uint160) error {
return cd.DAO.DeleteContractState(hash) return cd.DAO.DeleteContractState(hash)
} }
// GetNEP5Balances retrieves NEP5Balances for the acc. // GetNEP17Balances retrieves NEP17Balances for the acc.
func (cd *Cached) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) { func (cd *Cached) GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error) {
if bs := cd.balances[acc]; bs != nil { if bs := cd.balances[acc]; bs != nil {
return bs, nil return bs, nil
} }
return cd.DAO.GetNEP5Balances(acc) return cd.DAO.GetNEP17Balances(acc)
} }
// PutNEP5Balances saves NEP5Balances for the acc. // PutNEP17Balances saves NEP17Balances for the acc.
func (cd *Cached) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error { func (cd *Cached) PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error {
cd.balances[acc] = bs cd.balances[acc] = bs
return nil return nil
} }
// GetNEP5TransferLog retrieves NEP5TransferLog for the acc. // GetNEP17TransferLog retrieves NEP17TransferLog for the acc.
func (cd *Cached) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) { func (cd *Cached) GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error) {
ts := cd.transfers[acc] ts := cd.transfers[acc]
if ts != nil && ts[index] != nil { if ts != nil && ts[index] != nil {
return ts[index], nil return ts[index], nil
} }
return cd.DAO.GetNEP5TransferLog(acc, index) return cd.DAO.GetNEP17TransferLog(acc, index)
} }
// PutNEP5TransferLog saves NEP5TransferLog for the acc. // PutNEP17TransferLog saves NEP17TransferLog for the acc.
func (cd *Cached) PutNEP5TransferLog(acc util.Uint160, index uint32, bs *state.NEP5TransferLog) error { func (cd *Cached) PutNEP17TransferLog(acc util.Uint160, index uint32, bs *state.NEP17TransferLog) error {
ts := cd.transfers[acc] ts := cd.transfers[acc]
if ts == nil { if ts == nil {
ts = make(map[uint32]*state.NEP5TransferLog, 2) ts = make(map[uint32]*state.NEP17TransferLog, 2)
cd.transfers[acc] = ts cd.transfers[acc] = ts
} }
ts[index] = bs ts[index] = bs
return nil return nil
} }
// AppendNEP5Transfer appends new transfer to a transfer event log. // AppendNEP17Transfer appends new transfer to a transfer event log.
func (cd *Cached) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error) { func (cd *Cached) AppendNEP17Transfer(acc util.Uint160, index uint32, tr *state.NEP17Transfer) (bool, error) {
lg, err := cd.GetNEP5TransferLog(acc, index) lg, err := cd.GetNEP17TransferLog(acc, index)
if err != nil { if err != nil {
return false, err return false, err
} }
if err := lg.Append(tr); err != nil { if err := lg.Append(tr); err != nil {
return false, err return false, err
} }
return lg.Size() >= state.NEP5TransferBatchSize, cd.PutNEP5TransferLog(acc, index, lg) return lg.Size() >= state.NEP17TransferBatchSize, cd.PutNEP17TransferLog(acc, index, lg)
} }
// Persist flushes all the changes made into the (supposedly) persistent // Persist flushes all the changes made into the (supposedly) persistent
@ -107,8 +107,8 @@ func (cd *Cached) Persist() (int, error) {
// usage scenario it should be good enough if cd doesn't modify object // usage scenario it should be good enough if cd doesn't modify object
// caches (accounts/contracts/etc) in any way. // caches (accounts/contracts/etc) in any way.
if ok { if ok {
if cd.dropNEP5Cache { if cd.dropNEP17Cache {
lowerCache.balances = make(map[util.Uint160]*state.NEP5Balances) lowerCache.balances = make(map[util.Uint160]*state.NEP17Balances)
} }
var simpleCache *Simple var simpleCache *Simple
for simpleCache == nil { for simpleCache == nil {
@ -125,7 +125,7 @@ func (cd *Cached) Persist() (int, error) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
for acc, bs := range cd.balances { for acc, bs := range cd.balances {
err := cd.DAO.putNEP5Balances(acc, bs, buf) err := cd.DAO.putNEP17Balances(acc, bs, buf)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -133,7 +133,7 @@ func (cd *Cached) Persist() (int, error) {
} }
for acc, ts := range cd.transfers { for acc, ts := range cd.transfers {
for ind, lg := range ts { for ind, lg := range ts {
err := cd.DAO.PutNEP5TransferLog(acc, ind, lg) err := cd.DAO.PutNEP17TransferLog(acc, ind, lg)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -23,7 +23,7 @@ func TestCachedDaoContracts(t *testing.T) {
_, err := dao.GetContractState(sh) _, err := dao.GetContractState(sh)
require.NotNil(t, err) require.NotNil(t, err)
m := manifest.NewManifest(hash.Hash160(script)) m := manifest.NewManifest(hash.Hash160(script), "Test")
cs := &state.Contract{ cs := &state.Contract{
ID: 123, ID: 123,

View file

@ -31,7 +31,7 @@ var (
// DAO is a data access object. // DAO is a data access object.
type DAO interface { type DAO interface {
AppendAppExecResult(aer *state.AppExecResult, buf *io.BufBinWriter) error AppendAppExecResult(aer *state.AppExecResult, buf *io.BufBinWriter) error
AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error) AppendNEP17Transfer(acc util.Uint160, index uint32, tr *state.NEP17Transfer) (bool, error)
DeleteContractState(hash util.Uint160) error DeleteContractState(hash util.Uint160) error
DeleteStorageItem(id int32, key []byte) error DeleteStorageItem(id int32, key []byte) error
GetAndDecode(entity io.Serializable, key []byte) error GetAndDecode(entity io.Serializable, key []byte) error
@ -44,8 +44,8 @@ type DAO interface {
GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error) GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error)
GetCurrentStateRootHeight() (uint32, error) GetCurrentStateRootHeight() (uint32, error)
GetHeaderHashes() ([]util.Uint256, error) GetHeaderHashes() ([]util.Uint256, error)
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error)
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error)
GetAndUpdateNextContractID() (int32, error) GetAndUpdateNextContractID() (int32, error)
GetStateRoot(height uint32) (*state.MPTRootState, error) GetStateRoot(height uint32) (*state.MPTRootState, error)
PutStateRoot(root *state.MPTRootState) error PutStateRoot(root *state.MPTRootState) error
@ -60,15 +60,15 @@ type DAO interface {
PutAppExecResult(aer *state.AppExecResult, buf *io.BufBinWriter) error PutAppExecResult(aer *state.AppExecResult, buf *io.BufBinWriter) error
PutContractState(cs *state.Contract) error PutContractState(cs *state.Contract) error
PutCurrentHeader(hashAndIndex []byte) error PutCurrentHeader(hashAndIndex []byte) error
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error PutNEP17TransferLog(acc util.Uint160, index uint32, lg *state.NEP17TransferLog) error
PutStorageItem(id int32, key []byte, si *state.StorageItem) error PutStorageItem(id int32, key []byte, si *state.StorageItem) error
PutVersion(v string) error PutVersion(v string) error
Seek(id int32, prefix []byte, f func(k, v []byte)) Seek(id int32, prefix []byte, f func(k, v []byte))
StoreAsBlock(block *block.Block, buf *io.BufBinWriter) error StoreAsBlock(block *block.Block, buf *io.BufBinWriter) error
StoreAsCurrentBlock(block *block.Block, buf *io.BufBinWriter) error StoreAsCurrentBlock(block *block.Block, buf *io.BufBinWriter) error
StoreAsTransaction(tx *transaction.Transaction, index uint32, buf *io.BufBinWriter) error StoreAsTransaction(tx *transaction.Transaction, index uint32, buf *io.BufBinWriter) error
putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf *io.BufBinWriter) error putNEP17Balances(acc util.Uint160, bs *state.NEP17Balances, buf *io.BufBinWriter) error
} }
// Simple is memCached wrapper around DB, simple DAO implementation. // Simple is memCached wrapper around DB, simple DAO implementation.
@ -197,12 +197,12 @@ func (dao *Simple) GetContractScriptHash(id int32) (util.Uint160, error) {
// -- end contracts. // -- end contracts.
// -- start nep5 balances. // -- start nep17 balances.
// GetNEP5Balances retrieves nep5 balances from the cache. // GetNEP17Balances retrieves nep17 balances from the cache.
func (dao *Simple) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) { func (dao *Simple) GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error) {
key := storage.AppendPrefix(storage.STNEP5Balances, acc.BytesBE()) key := storage.AppendPrefix(storage.STNEP17Balances, acc.BytesBE())
bs := state.NewNEP5Balances() bs := state.NewNEP17Balances()
err := dao.GetAndDecode(bs, key) err := dao.GetAndDecode(bs, key)
if err != nil && err != storage.ErrKeyNotFound { if err != nil && err != storage.ErrKeyNotFound {
return nil, err return nil, err
@ -210,61 +210,61 @@ func (dao *Simple) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error
return bs, nil return bs, nil
} }
// PutNEP5Balances saves nep5 balances from the cache. // PutNEP17Balances saves nep17 balances from the cache.
func (dao *Simple) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error { func (dao *Simple) PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error {
return dao.putNEP5Balances(acc, bs, io.NewBufBinWriter()) return dao.putNEP17Balances(acc, bs, io.NewBufBinWriter())
} }
func (dao *Simple) putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf *io.BufBinWriter) error { func (dao *Simple) putNEP17Balances(acc util.Uint160, bs *state.NEP17Balances, buf *io.BufBinWriter) error {
key := storage.AppendPrefix(storage.STNEP5Balances, acc.BytesBE()) key := storage.AppendPrefix(storage.STNEP17Balances, acc.BytesBE())
return dao.putWithBuffer(bs, key, buf) return dao.putWithBuffer(bs, key, buf)
} }
// -- end nep5 balances. // -- end nep17 balances.
// -- start transfer log. // -- start transfer log.
func getNEP5TransferLogKey(acc util.Uint160, index uint32) []byte { func getNEP17TransferLogKey(acc util.Uint160, index uint32) []byte {
key := make([]byte, 1+util.Uint160Size+4) key := make([]byte, 1+util.Uint160Size+4)
key[0] = byte(storage.STNEP5Transfers) key[0] = byte(storage.STNEP17Transfers)
copy(key[1:], acc.BytesBE()) copy(key[1:], acc.BytesBE())
binary.LittleEndian.PutUint32(key[util.Uint160Size:], index) binary.LittleEndian.PutUint32(key[util.Uint160Size:], index)
return key return key
} }
// GetNEP5TransferLog retrieves transfer log from the cache. // GetNEP17TransferLog retrieves transfer log from the cache.
func (dao *Simple) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) { func (dao *Simple) GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error) {
key := getNEP5TransferLogKey(acc, index) key := getNEP17TransferLogKey(acc, index)
value, err := dao.Store.Get(key) value, err := dao.Store.Get(key)
if err != nil { if err != nil {
if err == storage.ErrKeyNotFound { if err == storage.ErrKeyNotFound {
return new(state.NEP5TransferLog), nil return new(state.NEP17TransferLog), nil
} }
return nil, err return nil, err
} }
return &state.NEP5TransferLog{Raw: value}, nil return &state.NEP17TransferLog{Raw: value}, nil
} }
// PutNEP5TransferLog saves given transfer log in the cache. // PutNEP17TransferLog saves given transfer log in the cache.
func (dao *Simple) PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error { func (dao *Simple) PutNEP17TransferLog(acc util.Uint160, index uint32, lg *state.NEP17TransferLog) error {
key := getNEP5TransferLogKey(acc, index) key := getNEP17TransferLogKey(acc, index)
return dao.Store.Put(key, lg.Raw) return dao.Store.Put(key, lg.Raw)
} }
// AppendNEP5Transfer appends a single NEP5 transfer to a log. // AppendNEP17Transfer appends a single NEP17 transfer to a log.
// First return value signalizes that log size has exceeded batch size. // First return value signalizes that log size has exceeded batch size.
func (dao *Simple) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error) { func (dao *Simple) AppendNEP17Transfer(acc util.Uint160, index uint32, tr *state.NEP17Transfer) (bool, error) {
lg, err := dao.GetNEP5TransferLog(acc, index) lg, err := dao.GetNEP17TransferLog(acc, index)
if err != nil { if err != nil {
if err != storage.ErrKeyNotFound { if err != storage.ErrKeyNotFound {
return false, err return false, err
} }
lg = new(state.NEP5TransferLog) lg = new(state.NEP17TransferLog)
} }
if err := lg.Append(tr); err != nil { if err := lg.Append(tr); err != nil {
return false, err return false, err
} }
return lg.Size() >= state.NEP5TransferBatchSize, dao.PutNEP5TransferLog(acc, index, lg) return lg.Size() >= state.NEP17TransferBatchSize, dao.PutNEP17TransferLog(acc, index, lg)
} }
// -- end transfer log. // -- end transfer log.

View file

@ -201,7 +201,7 @@ func TestCreateBasicChain(t *testing.T) {
require.Equal(t, big.NewInt(5000_0000), bc.GetUtilityTokenBalance(priv0ScriptHash)) // gas bounty require.Equal(t, big.NewInt(5000_0000), bc.GetUtilityTokenBalance(priv0ScriptHash)) // gas bounty
// Move some NEO to one simple account. // Move some NEO to one simple account.
txMoveNeo := newNEP5Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount) txMoveNeo := newNEP17Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
txMoveNeo.ValidUntilBlock = validUntilBlock txMoveNeo.ValidUntilBlock = validUntilBlock
txMoveNeo.Nonce = getNextNonce() txMoveNeo.Nonce = getNextNonce()
txMoveNeo.Signers = []transaction.Signer{{ txMoveNeo.Signers = []transaction.Signer{{
@ -212,7 +212,7 @@ func TestCreateBasicChain(t *testing.T) {
}} }}
require.NoError(t, signTx(bc, txMoveNeo)) require.NoError(t, signTx(bc, txMoveNeo))
// Move some GAS to one simple account. // Move some GAS to one simple account.
txMoveGas := newNEP5Transfer(gasHash, neoOwner, priv0ScriptHash, int64(util.Fixed8FromInt64(1000))) txMoveGas := newNEP17Transfer(gasHash, neoOwner, priv0ScriptHash, int64(util.Fixed8FromInt64(1000)))
txMoveGas.ValidUntilBlock = validUntilBlock txMoveGas.ValidUntilBlock = validUntilBlock
txMoveGas.Nonce = getNextNonce() txMoveGas.Nonce = getNextNonce()
txMoveGas.Signers = []transaction.Signer{{ txMoveGas.Signers = []transaction.Signer{{
@ -244,7 +244,7 @@ func TestCreateBasicChain(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Push some contract into the chain. // Push some contract into the chain.
txDeploy, avm := newDeployTx(t, prefix+"test_contract.go") txDeploy, avm := newDeployTx(t, prefix+"test_contract.go", "Rubl")
txDeploy.Nonce = getNextNonce() txDeploy.Nonce = getNextNonce()
txDeploy.ValidUntilBlock = validUntilBlock txDeploy.ValidUntilBlock = validUntilBlock
txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}} txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
@ -270,7 +270,7 @@ func TestCreateBasicChain(t *testing.T) {
t.Logf("txInv: %s", txInv.Hash().StringLE()) t.Logf("txInv: %s", txInv.Hash().StringLE())
priv1 := testchain.PrivateKeyByID(1) priv1 := testchain.PrivateKeyByID(1)
txNeo0to1 := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000) txNeo0to1 := newNEP17Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
txNeo0to1.Nonce = getNextNonce() txNeo0to1.Nonce = getNextNonce()
txNeo0to1.ValidUntilBlock = validUntilBlock txNeo0to1.ValidUntilBlock = validUntilBlock
txNeo0to1.Signers = []transaction.Signer{ txNeo0to1.Signers = []transaction.Signer{
@ -295,7 +295,7 @@ func TestCreateBasicChain(t *testing.T) {
initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}} initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, initTx, acc0)) require.NoError(t, addNetworkFee(bc, initTx, acc0))
require.NoError(t, acc0.SignTx(initTx)) require.NoError(t, acc0.SignTx(initTx))
transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000) transferTx := newNEP17Transfer(sh, sh, priv0.GetScriptHash(), 1000)
transferTx.Nonce = getNextNonce() transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock transferTx.ValidUntilBlock = validUntilBlock
transferTx.Signers = []transaction.Signer{ transferTx.Signers = []transaction.Signer{
@ -313,7 +313,7 @@ func TestCreateBasicChain(t *testing.T) {
require.NoError(t, bc.AddBlock(b)) require.NoError(t, bc.AddBlock(b))
t.Logf("recieveRublesTx: %v", transferTx.Hash().StringLE()) t.Logf("recieveRublesTx: %v", transferTx.Hash().StringLE())
transferTx = newNEP5Transfer(sh, priv0.GetScriptHash(), priv1.GetScriptHash(), 123) transferTx = newNEP17Transfer(sh, priv0.GetScriptHash(), priv1.GetScriptHash(), 123)
transferTx.Nonce = getNextNonce() transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock transferTx.ValidUntilBlock = validUntilBlock
transferTx.Signers = []transaction.Signer{ transferTx.Signers = []transaction.Signer{
@ -332,7 +332,7 @@ func TestCreateBasicChain(t *testing.T) {
t.Logf("sendRublesTx: %v", transferTx.Hash().StringLE()) t.Logf("sendRublesTx: %v", transferTx.Hash().StringLE())
// Push verification contract into the chain. // Push verification contract into the chain.
txDeploy2, _ := newDeployTx(t, prefix+"verification_contract.go") txDeploy2, _ := newDeployTx(t, prefix+"verification_contract.go", "Verify")
txDeploy2.Nonce = getNextNonce() txDeploy2.Nonce = getNextNonce()
txDeploy2.ValidUntilBlock = validUntilBlock txDeploy2.ValidUntilBlock = validUntilBlock
txDeploy2.Signers = []transaction.Signer{{Account: priv0ScriptHash}} txDeploy2.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
@ -364,7 +364,7 @@ func TestCreateBasicChain(t *testing.T) {
} }
// Prepare some transaction for future submission. // Prepare some transaction for future submission.
txSendRaw := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), int64(util.Fixed8FromInt64(1000))) txSendRaw := newNEP17Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), int64(util.Fixed8FromInt64(1000)))
txSendRaw.ValidUntilBlock = validUntilBlock txSendRaw.ValidUntilBlock = validUntilBlock
txSendRaw.Nonce = getNextNonce() txSendRaw.Nonce = getNextNonce()
txSendRaw.Signers = []transaction.Signer{{ txSendRaw.Signers = []transaction.Signer{{
@ -380,16 +380,16 @@ func TestCreateBasicChain(t *testing.T) {
t.Logf("sendrawtransaction: %s", hex.EncodeToString(bw.Bytes())) t.Logf("sendrawtransaction: %s", hex.EncodeToString(bw.Bytes()))
} }
func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction { func newNEP17Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount) emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
script := w.Bytes() script := w.Bytes()
return transaction.New(testchain.Network(), script, 10000000) return transaction.New(testchain.Network(), script, 10000000)
} }
func newDeployTx(t *testing.T, name string) (*transaction.Transaction, []byte) { func newDeployTx(t *testing.T, name, ctrName string) (*transaction.Transaction, []byte) {
c, err := ioutil.ReadFile(name) c, err := ioutil.ReadFile(name)
require.NoError(t, err) require.NoError(t, err)
avm, di, err := compiler.CompileWithDebugInfo(name, bytes.NewReader(c)) avm, di, err := compiler.CompileWithDebugInfo(name, bytes.NewReader(c))
@ -398,7 +398,7 @@ func newDeployTx(t *testing.T, name string) (*transaction.Transaction, []byte) {
t.Logf("contractScript: %x", avm) t.Logf("contractScript: %x", avm)
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
m, err := di.ConvertToManifest(nil) m, err := di.ConvertToManifest(ctrName, nil)
require.NoError(t, err) require.NoError(t, err)
bs, err := json.Marshal(m) bs, err := json.Marshal(m)
require.NoError(t, err) require.NoError(t, err)

View file

@ -114,7 +114,7 @@ func NewContractMD(name string) *ContractMD {
c.Script = w.Bytes() c.Script = w.Bytes()
c.Hash = hash.Hash160(c.Script) c.Hash = hash.Hash160(c.Script)
c.Manifest = *manifest.DefaultManifest(c.Hash) c.Manifest = *manifest.DefaultManifest(c.Hash, name)
return c return c
} }

View file

@ -294,7 +294,7 @@ func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop
func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) { func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) {
script := []byte("testscript") script := []byte("testscript")
m := manifest.NewManifest(hash.Hash160(script)) m := manifest.NewManifest(hash.Hash160(script), "Test")
contractState := &state.Contract{ contractState := &state.Contract{
Script: script, Script: script,
Manifest: *m, Manifest: *m,

View file

@ -299,16 +299,7 @@ func runtimeLog(ic *interop.Context) error {
// runtimeGetTime returns timestamp of the block being verified, or the latest // runtimeGetTime returns timestamp of the block being verified, or the latest
// one in the blockchain if no block is given to Context. // one in the blockchain if no block is given to Context.
func runtimeGetTime(ic *interop.Context) error { func runtimeGetTime(ic *interop.Context) error {
var header *block.Header header := ic.Block.Header()
if ic.Block == nil {
var err error
header, err = ic.Chain.GetHeader(ic.Chain.CurrentBlockHash())
if err != nil {
return err
}
} else {
header = ic.Block.Header()
}
ic.VM.Estack().PushVal(header.Timestamp) ic.VM.Estack().PushVal(header.Timestamp)
return nil return nil
} }

View file

@ -408,10 +408,17 @@ func getTestContractState() (*state.Contract, *state.Contract) {
emit.String(w.BinWriter, "initial") emit.String(w.BinWriter, "initial")
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
emit.Syscall(w.BinWriter, interopnames.SystemStorageGet) emit.Syscall(w.BinWriter, interopnames.SystemStorageGet)
emit.Opcodes(w.BinWriter, opcode.RET)
onPaymentOff := w.Len()
emit.Int(w.BinWriter, 3)
emit.Opcodes(w.BinWriter, opcode.PACK)
emit.String(w.BinWriter, "LastPayment")
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify)
emit.Opcodes(w.BinWriter, opcode.RET)
script := w.Bytes() script := w.Bytes()
h := hash.Hash160(script) h := hash.Hash160(script)
m := manifest.NewManifest(h) m := manifest.NewManifest(h, "TestMain")
m.ABI.Methods = []manifest.Method{ m.ABI.Methods = []manifest.Method{
{ {
Name: "add", Name: "add",
@ -454,7 +461,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
{ {
Name: "justReturn", Name: "justReturn",
Offset: justRetOff, Offset: justRetOff,
ReturnType: smartcontract.IntegerType, ReturnType: smartcontract.VoidType,
}, },
{ {
Name: manifest.MethodVerify, Name: manifest.MethodVerify,
@ -482,6 +489,16 @@ func getTestContractState() (*state.Contract, *state.Contract) {
}, },
ReturnType: smartcontract.VoidType, ReturnType: smartcontract.VoidType,
}, },
{
Name: "onPayment",
Offset: onPaymentOff,
Parameters: []manifest.Parameter{
manifest.NewParameter("from", smartcontract.Hash160Type),
manifest.NewParameter("amount", smartcontract.IntegerType),
manifest.NewParameter("data", smartcontract.AnyType),
},
ReturnType: smartcontract.VoidType,
},
} }
cs := &state.Contract{ cs := &state.Contract{
Script: script, Script: script,
@ -490,7 +507,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
} }
currScript := []byte{byte(opcode.RET)} currScript := []byte{byte(opcode.RET)}
m = manifest.NewManifest(hash.Hash160(currScript)) m = manifest.NewManifest(hash.Hash160(currScript), "TestAux")
perm := manifest.NewPermission(manifest.PermissionHash, h) perm := manifest.NewPermission(manifest.PermissionHash, h)
perm.Methods.Add("add") perm.Methods.Add("add")
perm.Methods.Add("drop") perm.Methods.Add("drop")

View file

@ -62,9 +62,10 @@ func Call(ic *interop.Context) error {
if !ic.VM.AddGas(m.Price) { if !ic.VM.AddGas(m.Price) {
return errors.New("gas limit exceeded") return errors.New("gas limit exceeded")
} }
ctx := ic.VM.Context()
result := m.Func(ic, args) result := m.Func(ic, args)
if m.MD.ReturnType != smartcontract.VoidType { if m.MD.ReturnType != smartcontract.VoidType {
ic.VM.Estack().PushVal(result) ctx.Estack().PushVal(result)
} }
return nil return nil
} }

View file

@ -13,7 +13,7 @@ import (
// GAS represents GAS native contract. // GAS represents GAS native contract.
type GAS struct { type GAS struct {
nep5TokenNative nep17TokenNative
NEO *NEO NEO *NEO
} }
@ -27,15 +27,15 @@ const initialGAS = 30000000
// newGAS returns GAS native contract. // newGAS returns GAS native contract.
func newGAS() *GAS { func newGAS() *GAS {
g := &GAS{} g := &GAS{}
nep5 := newNEP5Native(gasName) nep17 := newNEP17Native(gasName)
nep5.symbol = "gas" nep17.symbol = "gas"
nep5.decimals = 8 nep17.decimals = 8
nep5.factor = GASFactor nep17.factor = GASFactor
nep5.onPersist = chainOnPersist(nep5.OnPersist, g.OnPersist) nep17.onPersist = chainOnPersist(nep17.OnPersist, g.OnPersist)
nep5.incBalance = g.increaseBalance nep17.incBalance = g.increaseBalance
nep5.ContractID = gasContractID nep17.ContractID = gasContractID
g.nep5TokenNative = *nep5 g.nep17TokenNative = *nep17
onp := g.Methods["onPersist"] onp := g.Methods["onPersist"]
onp.Func = getOnPersistWrapper(g.onPersist) onp.Func = getOnPersistWrapper(g.onPersist)
@ -45,7 +45,7 @@ func newGAS() *GAS {
} }
func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.StorageItem, amount *big.Int) error { func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.StorageItem, amount *big.Int) error {
acc, err := state.NEP5BalanceStateFromBytes(si.Value) acc, err := state.NEP17BalanceStateFromBytes(si.Value)
if err != nil { if err != nil {
return err return err
} }
@ -65,10 +65,10 @@ func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.Stor
// Initialize initializes GAS contract. // Initialize initializes GAS contract.
func (g *GAS) Initialize(ic *interop.Context) error { func (g *GAS) Initialize(ic *interop.Context) error {
if err := g.nep5TokenNative.Initialize(ic); err != nil { if err := g.nep17TokenNative.Initialize(ic); err != nil {
return err return err
} }
if g.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { if g.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
return errors.New("already initialized") return errors.New("already initialized")
} }
h, err := getStandbyValidatorsHash(ic) h, err := getStandbyValidatorsHash(ic)

View file

@ -28,7 +28,7 @@ import (
// NEO represents NEO native contract. // NEO represents NEO native contract.
type NEO struct { type NEO struct {
nep5TokenNative nep17TokenNative
GAS *GAS GAS *GAS
// gasPerBlock represents current value of generated gas per block. // gasPerBlock represents current value of generated gas per block.
@ -93,16 +93,16 @@ func makeValidatorKey(key *keys.PublicKey) []byte {
// newNEO returns NEO native contract. // newNEO returns NEO native contract.
func newNEO() *NEO { func newNEO() *NEO {
n := &NEO{} n := &NEO{}
nep5 := newNEP5Native(neoName) nep17 := newNEP17Native(neoName)
nep5.symbol = "neo" nep17.symbol = "neo"
nep5.decimals = 0 nep17.decimals = 0
nep5.factor = 1 nep17.factor = 1
nep5.onPersist = chainOnPersist(nep5.OnPersist, n.OnPersist) nep17.onPersist = chainOnPersist(nep17.OnPersist, n.OnPersist)
nep5.postPersist = chainOnPersist(nep5.postPersist, n.PostPersist) nep17.postPersist = chainOnPersist(nep17.postPersist, n.PostPersist)
nep5.incBalance = n.increaseBalance nep17.incBalance = n.increaseBalance
nep5.ContractID = neoContractID nep17.ContractID = neoContractID
n.nep5TokenNative = *nep5 n.nep17TokenNative = *nep17
n.votesChanged.Store(true) n.votesChanged.Store(true)
n.nextValidators.Store(keys.PublicKeys(nil)) n.nextValidators.Store(keys.PublicKeys(nil))
n.validators.Store(keys.PublicKeys(nil)) n.validators.Store(keys.PublicKeys(nil))
@ -165,11 +165,11 @@ func newNEO() *NEO {
// Initialize initializes NEO contract. // Initialize initializes NEO contract.
func (n *NEO) Initialize(ic *interop.Context) error { func (n *NEO) Initialize(ic *interop.Context) error {
if err := n.nep5TokenNative.Initialize(ic); err != nil { if err := n.nep17TokenNative.Initialize(ic); err != nil {
return err return err
} }
if n.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { if n.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
return errors.New("already initialized") return errors.New("already initialized")
} }

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
@ -14,6 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -28,8 +30,8 @@ func makeAccountKey(h util.Uint160) []byte {
return k return k
} }
// nep5TokenNative represents NEP-5 token contract. // nep17TokenNative represents NEP-17 token contract.
type nep5TokenNative struct { type nep17TokenNative struct {
interop.ContractMD interop.ContractMD
symbol string symbol string
decimals int64 decimals int64
@ -42,15 +44,15 @@ type nep5TokenNative struct {
// totalSupplyKey is the key used to store totalSupply value. // totalSupplyKey is the key used to store totalSupply value.
var totalSupplyKey = []byte{11} var totalSupplyKey = []byte{11}
func (c *nep5TokenNative) Metadata() *interop.ContractMD { func (c *nep17TokenNative) Metadata() *interop.ContractMD {
return &c.ContractMD return &c.ContractMD
} }
var _ interop.Contract = (*nep5TokenNative)(nil) var _ interop.Contract = (*nep17TokenNative)(nil)
func newNEP5Native(name string) *nep5TokenNative { func newNEP17Native(name string) *nep17TokenNative {
n := &nep5TokenNative{ContractMD: *interop.NewContractMD(name)} n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name)}
n.Manifest.SupportedStandards = []string{manifest.NEP5StandardName} n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName}
desc := newDescriptor("name", smartcontract.StringType) desc := newDescriptor("name", smartcontract.StringType)
md := newMethodAndPrice(nameMethod(name), 0, smartcontract.NoneFlag) md := newMethodAndPrice(nameMethod(name), 0, smartcontract.NoneFlag)
@ -77,6 +79,7 @@ func newNEP5Native(name string) *nep5TokenNative {
manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("from", smartcontract.Hash160Type),
manifest.NewParameter("to", smartcontract.Hash160Type), manifest.NewParameter("to", smartcontract.Hash160Type),
manifest.NewParameter("amount", smartcontract.IntegerType), manifest.NewParameter("amount", smartcontract.IntegerType),
manifest.NewParameter("data", smartcontract.AnyType),
) )
md = newMethodAndPrice(n.Transfer, 8000000, smartcontract.AllowModifyStates) md = newMethodAndPrice(n.Transfer, 8000000, smartcontract.AllowModifyStates)
n.AddMethod(md, desc, false) n.AddMethod(md, desc, false)
@ -94,23 +97,23 @@ func newNEP5Native(name string) *nep5TokenNative {
return n return n
} }
func (c *nep5TokenNative) Initialize(_ *interop.Context) error { func (c *nep17TokenNative) Initialize(_ *interop.Context) error {
return nil return nil
} }
func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item { func (c *nep17TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewByteArray([]byte(c.symbol)) return stackitem.NewByteArray([]byte(c.symbol))
} }
func (c *nep5TokenNative) Decimals(_ *interop.Context, _ []stackitem.Item) stackitem.Item { func (c *nep17TokenNative) Decimals(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBigInteger(big.NewInt(c.decimals)) return stackitem.NewBigInteger(big.NewInt(c.decimals))
} }
func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) stackitem.Item { func (c *nep17TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBigInteger(c.getTotalSupply(ic.DAO)) return stackitem.NewBigInteger(c.getTotalSupply(ic.DAO))
} }
func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int { func (c *nep17TokenNative) getTotalSupply(d dao.DAO) *big.Int {
si := d.GetStorageItem(c.ContractID, totalSupplyKey) si := d.GetStorageItem(c.ContractID, totalSupplyKey)
if si == nil { if si == nil {
return big.NewInt(0) return big.NewInt(0)
@ -118,16 +121,16 @@ func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int {
return bigint.FromBytes(si.Value) return bigint.FromBytes(si.Value)
} }
func (c *nep5TokenNative) saveTotalSupply(d dao.DAO, supply *big.Int) error { func (c *nep17TokenNative) saveTotalSupply(d dao.DAO, supply *big.Int) error {
si := &state.StorageItem{Value: bigint.ToBytes(supply)} si := &state.StorageItem{Value: bigint.ToBytes(supply)}
return d.PutStorageItem(c.ContractID, totalSupplyKey, si) return d.PutStorageItem(c.ContractID, totalSupplyKey, si)
} }
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (c *nep17TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item {
from := toUint160(args[0]) from := toUint160(args[0])
to := toUint160(args[1]) to := toUint160(args[1])
amount := toBigInt(args[2]) amount := toBigInt(args[2])
err := c.TransferInternal(ic, from, to, amount) err := c.TransferInternal(ic, from, to, amount, args[3])
return stackitem.NewBool(err == nil) return stackitem.NewBool(err == nil)
} }
@ -138,7 +141,31 @@ func addrToStackItem(u *util.Uint160) stackitem.Item {
return stackitem.NewByteArray(u.BytesBE()) return stackitem.NewByteArray(u.BytesBE())
} }
func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) { func (c *nep17TokenNative) postTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int, data stackitem.Item) {
c.emitTransfer(ic, from, to, amount)
if to == nil {
return
}
cs, err := ic.DAO.GetContractState(*to)
if err != nil {
return
}
fromArg := stackitem.Item(stackitem.Null{})
if from != nil {
fromArg = stackitem.NewByteArray((*from).BytesBE())
}
args := []stackitem.Item{
fromArg,
stackitem.NewBigInteger(amount),
data,
}
if err := contract.CallExInternal(ic, cs, manifest.MethodOnPayment, args, smartcontract.All, vm.EnsureIsEmpty); err != nil {
panic(err)
}
}
func (c *nep17TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) {
ne := state.NotificationEvent{ ne := state.NotificationEvent{
ScriptHash: c.Hash, ScriptHash: c.Hash,
Name: "Transfer", Name: "Transfer",
@ -151,7 +178,7 @@ func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint1
ic.Notifications = append(ic.Notifications, ne) ic.Notifications = append(ic.Notifications, ne)
} }
func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160, amount *big.Int) error { func (c *nep17TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160, amount *big.Int) error {
key := makeAccountKey(acc) key := makeAccountKey(acc)
si := ic.DAO.GetStorageItem(c.ContractID, key) si := ic.DAO.GetStorageItem(c.ContractID, key)
if si == nil { if si == nil {
@ -174,7 +201,7 @@ func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160
} }
// TransferInternal transfers NEO between accounts. // TransferInternal transfers NEO between accounts.
func (c *nep5TokenNative) TransferInternal(ic *interop.Context, from, to util.Uint160, amount *big.Int) error { func (c *nep17TokenNative) TransferInternal(ic *interop.Context, from, to util.Uint160, amount *big.Int, data stackitem.Item) error {
if amount.Sign() == -1 { if amount.Sign() == -1 {
return errors.New("negative amount") return errors.New("negative amount")
} }
@ -205,13 +232,13 @@ func (c *nep5TokenNative) TransferInternal(ic *interop.Context, from, to util.Ui
} }
} }
c.emitTransfer(ic, &from, &to, amount) c.postTransfer(ic, &from, &to, amount, data)
return nil return nil
} }
func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (c *nep17TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) stackitem.Item {
h := toUint160(args[0]) h := toUint160(args[0])
bs, err := ic.DAO.GetNEP5Balances(h) bs, err := ic.DAO.GetNEP17Balances(h)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -219,23 +246,23 @@ func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item)
return stackitem.NewBigInteger(&balance) return stackitem.NewBigInteger(&balance)
} }
func (c *nep5TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) { func (c *nep17TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) {
if amount.Sign() == 0 { if amount.Sign() == 0 {
return return
} }
c.addTokens(ic, h, amount) c.addTokens(ic, h, amount)
c.emitTransfer(ic, nil, &h, amount) c.postTransfer(ic, nil, &h, amount, stackitem.Null{})
} }
func (c *nep5TokenNative) burn(ic *interop.Context, h util.Uint160, amount *big.Int) { func (c *nep17TokenNative) burn(ic *interop.Context, h util.Uint160, amount *big.Int) {
if amount.Sign() == 0 { if amount.Sign() == 0 {
return return
} }
c.addTokens(ic, h, new(big.Int).Neg(amount)) c.addTokens(ic, h, new(big.Int).Neg(amount))
c.emitTransfer(ic, &h, nil, amount) c.postTransfer(ic, &h, nil, amount, stackitem.Null{})
} }
func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount *big.Int) { func (c *nep17TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount *big.Int) {
if amount.Sign() == 0 { if amount.Sign() == 0 {
return return
} }
@ -260,7 +287,7 @@ func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount
} }
} }
func (c *nep5TokenNative) OnPersist(ic *interop.Context) error { func (c *nep17TokenNative) OnPersist(ic *interop.Context) error {
if ic.Trigger != trigger.OnPersist { if ic.Trigger != trigger.OnPersist {
return errors.New("onPersist must be triggerred by system") return errors.New("onPersist must be triggerred by system")
} }

View file

@ -125,6 +125,13 @@ func newOracle() *Oracle {
md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag) md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag)
o.AddMethod(md, desc, false) o.AddMethod(md, desc, false)
desc = newDescriptor("onPayment", smartcontract.VoidType,
manifest.NewParameter("from", smartcontract.Hash160Type),
manifest.NewParameter("amount", smartcontract.IntegerType),
manifest.NewParameter("data", smartcontract.AnyType))
md = newMethodAndPrice(o.onPayment, 0, smartcontract.NoneFlag)
o.AddMethod(md, desc, false)
pp := chainOnPersist(postPersistBase, o.PostPersist) pp := chainOnPersist(postPersistBase, o.PostPersist)
desc = newDescriptor("postPersist", smartcontract.VoidType) desc = newDescriptor("postPersist", smartcontract.VoidType)
md = newMethodAndPrice(getOnPersistWrapper(pp), 0, smartcontract.AllowModifyStates) md = newMethodAndPrice(getOnPersistWrapper(pp), 0, smartcontract.AllowModifyStates)
@ -299,6 +306,7 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string
if !ic.VM.AddGas(gas.Int64()) { if !ic.VM.AddGas(gas.Int64()) {
return ErrNotEnoughGas return ErrNotEnoughGas
} }
callingHash := ic.VM.GetCallingScriptHash()
o.GAS.mint(ic, o.Hash, gas) o.GAS.mint(ic, o.Hash, gas)
si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID) si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID)
id := binary.LittleEndian.Uint64(si.Value) + 1 id := binary.LittleEndian.Uint64(si.Value) + 1
@ -344,7 +352,7 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string
GasForResponse: gas.Uint64(), GasForResponse: gas.Uint64(),
URL: url, URL: url,
Filter: filter, Filter: filter,
CallbackContract: ic.VM.GetCallingScriptHash(), CallbackContract: callingHash,
CallbackMethod: cb, CallbackMethod: cb,
UserData: data, UserData: data,
} }
@ -402,6 +410,14 @@ func (o *Oracle) verify(ic *interop.Context, _ []stackitem.Item) stackitem.Item
return stackitem.NewBool(ic.Tx.HasAttribute(transaction.OracleResponseT)) return stackitem.NewBool(ic.Tx.HasAttribute(transaction.OracleResponseT))
} }
func (o *Oracle) onPayment(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
// FIXME when calling native transfer directly, context is not provided.
if h := ic.VM.GetCallingScriptHash(); h != o.Hash && h != o.GAS.Hash {
panic("only GAS can be accepted")
}
return stackitem.Null{}
}
func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 { func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 {
for i := range tx.Attributes { for i := range tx.Attributes {
if tx.Attributes[i].Type == transaction.OracleResponseT { if tx.Attributes[i].Type == transaction.OracleResponseT {

View file

@ -12,7 +12,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -20,7 +19,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -80,30 +78,16 @@ func newTestNative() *testNative {
tn.meta.AddMethod(md, desc, true) tn.meta.AddMethod(md, desc, true)
desc = &manifest.Method{ desc = &manifest.Method{
Name: "callOtherContractWithoutArgs", Name: "callOtherContractNoReturn",
Parameters: []manifest.Parameter{
manifest.NewParameter("contractHash", smartcontract.Hash160Type),
manifest.NewParameter("method", smartcontract.StringType),
},
ReturnType: smartcontract.AnyType,
}
md = &interop.MethodAndPrice{
Func: tn.callOtherContractWithoutArgs,
Price: testSumPrice,
RequiredFlags: smartcontract.NoneFlag}
tn.meta.AddMethod(md, desc, true)
desc = &manifest.Method{
Name: "callOtherContractWithArg",
Parameters: []manifest.Parameter{ Parameters: []manifest.Parameter{
manifest.NewParameter("contractHash", smartcontract.Hash160Type), manifest.NewParameter("contractHash", smartcontract.Hash160Type),
manifest.NewParameter("method", smartcontract.StringType), manifest.NewParameter("method", smartcontract.StringType),
manifest.NewParameter("arg", smartcontract.ArrayType), manifest.NewParameter("arg", smartcontract.ArrayType),
}, },
ReturnType: smartcontract.AnyType, ReturnType: smartcontract.VoidType,
} }
md = &interop.MethodAndPrice{ md = &interop.MethodAndPrice{
Func: tn.callOtherContractWithArg, Func: tn.callOtherContractNoReturn,
Price: testSumPrice, Price: testSumPrice,
RequiredFlags: smartcontract.NoneFlag} RequiredFlags: smartcontract.NoneFlag}
tn.meta.AddMethod(md, desc, true) tn.meta.AddMethod(md, desc, true)
@ -127,36 +111,36 @@ func (tn *testNative) sum(_ *interop.Context, args []stackitem.Item) stackitem.I
return stackitem.NewBigInteger(s1.Add(s1, s2)) return stackitem.NewBigInteger(s1.Add(s1, s2))
} }
func (tn *testNative) callOtherContractWithoutArgs(ic *interop.Context, args []stackitem.Item) stackitem.Item { func toUint160(item stackitem.Item) util.Uint160 {
vm := ic.VM bs, err := item.TryBytes()
vm.Estack().PushVal(stackitem.NewArray([]stackitem.Item{})) // no args
vm.Estack().PushVal(args[1]) // method
vm.Estack().PushVal(args[0]) // contract hash
err := contract.Call(ic)
if err != nil { if err != nil {
return stackitem.NewBigInteger(big.NewInt(-1)) panic(err)
} }
_ = vm.Run() u, err := util.Uint160DecodeBytesBE(bs)
if vm.HasFailed() { if err != nil {
return stackitem.NewBigInteger(big.NewInt(-2)) panic(err)
} }
return vm.Estack().Pop().Item() return u
} }
func (tn *testNative) callOtherContractWithArg(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, retState vm.CheckReturnState) {
vm := ic.VM cs, err := ic.DAO.GetContractState(toUint160(args[0]))
vm.Estack().PushVal(stackitem.NewArray([]stackitem.Item{args[2]})) // arg
vm.Estack().PushVal(args[1]) // method
vm.Estack().PushVal(args[0]) // contract hash
err := contract.Call(ic)
if err != nil { if err != nil {
return stackitem.NewBigInteger(big.NewInt(-1)) panic(err)
} }
_ = vm.Run() bs, err := args[1].TryBytes()
if vm.HasFailed() { if err != nil {
return stackitem.NewBigInteger(big.NewInt(-2)) panic(err)
} }
return vm.Estack().Pop().Item() err = contract.CallExInternal(ic, cs, string(bs), args[2].Value().([]stackitem.Item), smartcontract.All, retState)
if err != nil {
panic(err)
}
}
func (tn *testNative) callOtherContractNoReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item {
tn.call(ic, args, vm.EnsureIsEmpty)
return stackitem.Null{}
} }
func TestNativeContract_Invoke(t *testing.T) { func TestNativeContract_Invoke(t *testing.T) {
@ -265,84 +249,13 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
t.Run("native Policy, getFeePerByte", func(t *testing.T) { cs, _ := getTestContractState()
require.NoError(t, chain.dao.PutContractState(cs))
t.Run("non-native, no return", func(t *testing.T) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithoutArgs", chain.contracts.Policy.Hash, "getFeePerByte") emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractNoReturn",
require.NoError(t, w.Err) cs.ScriptHash(), "justReturn", []interface{}{})
script := w.Bytes()
tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*4+10000)
validUntil := chain.blockHeight + 1
tx.ValidUntilBlock = validUntil
addSigners(tx)
require.NoError(t, signTx(chain, tx))
b := chain.newBlock(tx)
require.NoError(t, chain.AddBlock(b))
res, err := chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, 1, len(res))
// we expect it to be FeePerByte from Policy contract
require.Equal(t, vm.HaltState, res[0].VMState)
require.Equal(t, 1, len(res[0].Stack))
require.Equal(t, big.NewInt(1000), res[0].Stack[0].Value())
})
t.Run("native Policy, setFeePerByte", func(t *testing.T) {
w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithArg", chain.contracts.Policy.Hash, "setFeePerByte", int64(500))
require.NoError(t, w.Err)
script := w.Bytes()
tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*5+18000)
validUntil := chain.blockHeight + 1
tx.ValidUntilBlock = validUntil
addSigners(tx)
// to pass policy.checkValidators
tx.Signers[0].Scopes = transaction.Global
require.NoError(t, signTx(chain, tx))
b := chain.newBlock(tx)
require.NoError(t, chain.AddBlock(b))
require.NoError(t, chain.persist())
res, err := chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, 1, len(res))
// we expect it to be `true` which means that native policy value was successfully updated
require.Equal(t, vm.HaltState, res[0].VMState)
require.Equal(t, 1, len(res[0].Stack))
require.Equal(t, true, res[0].Stack[0].Value())
require.NoError(t, chain.persist())
// check that feePerByte was updated
n := chain.contracts.Policy.GetFeePerByteInternal(chain.dao)
require.Equal(t, 500, int(n))
})
t.Run("non-native contract", func(t *testing.T) {
// put some other contract into chain (this contract just pushes `5` on stack)
avm := []byte{byte(opcode.PUSH5), byte(opcode.RET)}
contractHash := hash.Hash160(avm)
m := manifest.NewManifest(contractHash)
m.ABI.Methods = []manifest.Method{
{
Name: "five",
Offset: 0,
Parameters: []manifest.Parameter{},
ReturnType: smartcontract.IntegerType,
},
}
err = chain.dao.PutContractState(&state.Contract{
Script: avm,
Manifest: *m,
})
require.NoError(t, err)
w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithoutArgs", contractHash, "five")
require.NoError(t, w.Err) require.NoError(t, w.Err)
script := w.Bytes() script := w.Bytes()
tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*4+10000) tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*4+10000)
@ -359,7 +272,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
require.Equal(t, 1, len(res)) require.Equal(t, 1, len(res))
require.Equal(t, vm.HaltState, res[0].VMState) require.Equal(t, vm.HaltState, res[0].VMState)
require.Equal(t, 1, len(res[0].Stack)) require.Equal(t, 1, len(res[0].Stack))
require.Equal(t, int64(5), res[0].Stack[0].Value().(*big.Int).Int64()) require.Equal(t, stackitem.Null{}, res[0].Stack[0]) // simple call is done with EnsureNotEmpty
}) })
} }

View file

@ -16,6 +16,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -76,11 +77,11 @@ func TestNEO_Vote(t *testing.T) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer",
neoOwner.BytesBE(), to.BytesBE(), neoOwner.BytesBE(), to.BytesBE(),
big.NewInt(int64(sz-i)*1000000).Int64()) big.NewInt(int64(sz-i)*1000000).Int64(), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.GAS.Hash, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.GAS.Hash, "transfer",
neoOwner.BytesBE(), to.BytesBE(), neoOwner.BytesBE(), to.BytesBE(),
int64(1_000_000_000)) int64(1_000_000_000), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)
tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 1000_000_000) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 1000_000_000)
@ -141,7 +142,7 @@ func TestNEO_Vote(t *testing.T) {
gasBalance[i] = bc.GetUtilityTokenBalance(h) gasBalance[i] = bc.GetUtilityTokenBalance(h)
neoBalance[i], _ = bc.GetGoverningTokenBalance(h) neoBalance[i], _ = bc.GetGoverningTokenBalance(h)
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer",
h.BytesBE(), h.BytesBE(), int64(1)) h.BytesBE(), h.BytesBE(), int64(1), nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
require.NoError(t, w.Err) require.NoError(t, w.Err)
tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0)
@ -303,3 +304,31 @@ func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
checkBalances() checkBalances()
} }
} }
func TestNEO_TransferOnPayment(t *testing.T) {
bc := newTestChain(t)
defer bc.Close()
cs, _ := getTestContractState()
require.NoError(t, bc.dao.PutContractState(cs))
const amount = 2
tx := newNEP17Transfer(bc.contracts.NEO.Hash, neoOwner, cs.ScriptHash(), amount)
tx.SystemFee += 1_000_000
tx.NetworkFee = 10_000_000
tx.ValidUntilBlock = bc.BlockHeight() + 1
addSigners(tx)
require.NoError(t, signTx(bc, tx))
require.NoError(t, bc.AddBlock(bc.newBlock(tx)))
aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, vm.HaltState, aer[0].VMState)
require.Len(t, aer[0].Events, 3) // transfer + auto GAS claim + onPayment
e := aer[0].Events[2]
require.Equal(t, "LastPayment", e.Name)
arr := e.Item.Value().([]stackitem.Item)
require.Equal(t, neoOwner.BytesBE(), arr[0].Value())
require.Equal(t, big.NewInt(amount), arr[1].Value())
}

View file

@ -50,7 +50,7 @@ func getOracleContractState(h util.Uint160) *state.Contract {
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
m := manifest.NewManifest(h) m := manifest.NewManifest(h, "TestOracle")
m.ABI.Methods = []manifest.Method{ m.ABI.Methods = []manifest.Method{
{ {
Name: "requestURL", Name: "requestURL",

View file

@ -14,7 +14,7 @@ func TestEncodeDecodeContractState(t *testing.T) {
script := []byte("testscript") script := []byte("testscript")
h := hash.Hash160(script) h := hash.Hash160(script)
m := manifest.NewManifest(h) m := manifest.NewManifest(h, "Test")
m.ABI.Methods = []manifest.Method{{ m.ABI.Methods = []manifest.Method{{
Name: "main", Name: "main",
Parameters: []manifest.Parameter{ Parameters: []manifest.Parameter{

View file

@ -9,21 +9,21 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// NEP5BalanceState represents balance state of a NEP5-token. // NEP17BalanceState represents balance state of a NEP17-token.
type NEP5BalanceState struct { type NEP17BalanceState struct {
Balance big.Int Balance big.Int
} }
// NEOBalanceState represents balance state of a NEO-token. // NEOBalanceState represents balance state of a NEO-token.
type NEOBalanceState struct { type NEOBalanceState struct {
NEP5BalanceState NEP17BalanceState
BalanceHeight uint32 BalanceHeight uint32
VoteTo *keys.PublicKey VoteTo *keys.PublicKey
} }
// NEP5BalanceStateFromBytes converts serialized NEP5BalanceState to structure. // NEP17BalanceStateFromBytes converts serialized NEP17BalanceState to structure.
func NEP5BalanceStateFromBytes(b []byte) (*NEP5BalanceState, error) { func NEP17BalanceStateFromBytes(b []byte) (*NEP17BalanceState, error) {
balance := new(NEP5BalanceState) balance := new(NEP17BalanceState)
if len(b) == 0 { if len(b) == 0 {
return balance, nil return balance, nil
} }
@ -35,8 +35,8 @@ func NEP5BalanceStateFromBytes(b []byte) (*NEP5BalanceState, error) {
return balance, nil return balance, nil
} }
// Bytes returns serialized NEP5BalanceState. // Bytes returns serialized NEP17BalanceState.
func (s *NEP5BalanceState) Bytes() []byte { func (s *NEP17BalanceState) Bytes() []byte {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
s.EncodeBinary(w.BinWriter) s.EncodeBinary(w.BinWriter)
if w.Err != nil { if w.Err != nil {
@ -45,22 +45,22 @@ func (s *NEP5BalanceState) Bytes() []byte {
return w.Bytes() return w.Bytes()
} }
func (s *NEP5BalanceState) toStackItem() stackitem.Item { func (s *NEP17BalanceState) toStackItem() stackitem.Item {
return stackitem.NewStruct([]stackitem.Item{stackitem.NewBigInteger(&s.Balance)}) return stackitem.NewStruct([]stackitem.Item{stackitem.NewBigInteger(&s.Balance)})
} }
func (s *NEP5BalanceState) fromStackItem(item stackitem.Item) { func (s *NEP17BalanceState) fromStackItem(item stackitem.Item) {
s.Balance = *item.(*stackitem.Struct).Value().([]stackitem.Item)[0].Value().(*big.Int) s.Balance = *item.(*stackitem.Struct).Value().([]stackitem.Item)[0].Value().(*big.Int)
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (s *NEP5BalanceState) EncodeBinary(w *io.BinWriter) { func (s *NEP17BalanceState) EncodeBinary(w *io.BinWriter) {
si := s.toStackItem() si := s.toStackItem()
stackitem.EncodeBinaryStackItem(si, w) stackitem.EncodeBinaryStackItem(si, w)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (s *NEP5BalanceState) DecodeBinary(r *io.BinReader) { func (s *NEP17BalanceState) DecodeBinary(r *io.BinReader) {
si := stackitem.DecodeBinaryStackItem(r) si := stackitem.DecodeBinaryStackItem(r)
if r.Err != nil { if r.Err != nil {
return return
@ -109,7 +109,7 @@ func (s *NEOBalanceState) DecodeBinary(r *io.BinReader) {
} }
func (s *NEOBalanceState) toStackItem() stackitem.Item { func (s *NEOBalanceState) toStackItem() stackitem.Item {
result := s.NEP5BalanceState.toStackItem().(*stackitem.Struct) result := s.NEP17BalanceState.toStackItem().(*stackitem.Struct)
result.Append(stackitem.NewBigInteger(big.NewInt(int64(s.BalanceHeight)))) result.Append(stackitem.NewBigInteger(big.NewInt(int64(s.BalanceHeight))))
if s.VoteTo != nil { if s.VoteTo != nil {
result.Append(stackitem.NewByteArray(s.VoteTo.Bytes())) result.Append(stackitem.NewByteArray(s.VoteTo.Bytes()))

View file

@ -8,11 +8,11 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
) )
// NEP5TransferBatchSize is the maximum number of entries for NEP5TransferLog. // NEP17TransferBatchSize is the maximum number of entries for NEP17TransferLog.
const NEP5TransferBatchSize = 128 const NEP17TransferBatchSize = 128
// NEP5Tracker contains info about a single account in a NEP5 contract. // NEP17Tracker contains info about a single account in a NEP17 contract.
type NEP5Tracker struct { type NEP17Tracker struct {
// Balance is the current balance of the account. // Balance is the current balance of the account.
Balance big.Int Balance big.Int
// LastUpdatedBlock is a number of block when last `transfer` to or from the // LastUpdatedBlock is a number of block when last `transfer` to or from the
@ -20,14 +20,14 @@ type NEP5Tracker struct {
LastUpdatedBlock uint32 LastUpdatedBlock uint32
} }
// NEP5TransferLog is a log of NEP5 token transfers for the specific command. // NEP17TransferLog is a log of NEP17 token transfers for the specific command.
type NEP5TransferLog struct { type NEP17TransferLog struct {
Raw []byte Raw []byte
} }
// NEP5Transfer represents a single NEP5 Transfer event. // NEP17Transfer represents a single NEP17 Transfer event.
type NEP5Transfer struct { type NEP17Transfer struct {
// Asset is a NEP5 contract ID. // Asset is a NEP17 contract ID.
Asset int32 Asset int32
// Address is the address of the sender. // Address is the address of the sender.
From util.Uint160 From util.Uint160
@ -44,29 +44,29 @@ type NEP5Transfer struct {
Tx util.Uint256 Tx util.Uint256
} }
// NEP5Balances is a map of the NEP5 contract IDs // NEP17Balances is a map of the NEP17 contract IDs
// to the corresponding structures. // to the corresponding structures.
type NEP5Balances struct { type NEP17Balances struct {
Trackers map[int32]NEP5Tracker Trackers map[int32]NEP17Tracker
// NextTransferBatch stores an index of the next transfer batch. // NextTransferBatch stores an index of the next transfer batch.
NextTransferBatch uint32 NextTransferBatch uint32
} }
// NewNEP5Balances returns new NEP5Balances. // NewNEP17Balances returns new NEP17Balances.
func NewNEP5Balances() *NEP5Balances { func NewNEP17Balances() *NEP17Balances {
return &NEP5Balances{ return &NEP17Balances{
Trackers: make(map[int32]NEP5Tracker), Trackers: make(map[int32]NEP17Tracker),
} }
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (bs *NEP5Balances) DecodeBinary(r *io.BinReader) { func (bs *NEP17Balances) DecodeBinary(r *io.BinReader) {
bs.NextTransferBatch = r.ReadU32LE() bs.NextTransferBatch = r.ReadU32LE()
lenBalances := r.ReadVarUint() lenBalances := r.ReadVarUint()
m := make(map[int32]NEP5Tracker, lenBalances) m := make(map[int32]NEP17Tracker, lenBalances)
for i := 0; i < int(lenBalances); i++ { for i := 0; i < int(lenBalances); i++ {
key := int32(r.ReadU32LE()) key := int32(r.ReadU32LE())
var tr NEP5Tracker var tr NEP17Tracker
tr.DecodeBinary(r) tr.DecodeBinary(r)
m[key] = tr m[key] = tr
} }
@ -74,7 +74,7 @@ func (bs *NEP5Balances) DecodeBinary(r *io.BinReader) {
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (bs *NEP5Balances) EncodeBinary(w *io.BinWriter) { func (bs *NEP17Balances) EncodeBinary(w *io.BinWriter) {
w.WriteU32LE(bs.NextTransferBatch) w.WriteU32LE(bs.NextTransferBatch)
w.WriteVarUint(uint64(len(bs.Trackers))) w.WriteVarUint(uint64(len(bs.Trackers)))
for k, v := range bs.Trackers { for k, v := range bs.Trackers {
@ -84,7 +84,7 @@ func (bs *NEP5Balances) EncodeBinary(w *io.BinWriter) {
} }
// Append appends single transfer to a log. // Append appends single transfer to a log.
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error { func (lg *NEP17TransferLog) Append(tr *NEP17Transfer) error {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
// The first entry, set up counter. // The first entry, set up counter.
if len(lg.Raw) == 0 { if len(lg.Raw) == 0 {
@ -102,11 +102,11 @@ func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
} }
// ForEach iterates over transfer log returning on first error. // ForEach iterates over transfer log returning on first error.
func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) (bool, error)) (bool, error) { func (lg *NEP17TransferLog) ForEach(f func(*NEP17Transfer) (bool, error)) (bool, error) {
if lg == nil || len(lg.Raw) == 0 { if lg == nil || len(lg.Raw) == 0 {
return true, nil return true, nil
} }
transfers := make([]NEP5Transfer, lg.Size()) transfers := make([]NEP17Transfer, lg.Size())
r := io.NewBinReaderFromBuf(lg.Raw[1:]) r := io.NewBinReaderFromBuf(lg.Raw[1:])
for i := 0; i < lg.Size(); i++ { for i := 0; i < lg.Size(); i++ {
transfers[i].DecodeBinary(r) transfers[i].DecodeBinary(r)
@ -127,7 +127,7 @@ func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) (bool, error)) (bool, e
} }
// Size returns an amount of transfer written in log. // Size returns an amount of transfer written in log.
func (lg *NEP5TransferLog) Size() int { func (lg *NEP17TransferLog) Size() int {
if len(lg.Raw) == 0 { if len(lg.Raw) == 0 {
return 0 return 0
} }
@ -135,19 +135,19 @@ func (lg *NEP5TransferLog) Size() int {
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (t *NEP5Tracker) EncodeBinary(w *io.BinWriter) { func (t *NEP17Tracker) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(bigint.ToBytes(&t.Balance)) w.WriteVarBytes(bigint.ToBytes(&t.Balance))
w.WriteU32LE(t.LastUpdatedBlock) w.WriteU32LE(t.LastUpdatedBlock)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (t *NEP5Tracker) DecodeBinary(r *io.BinReader) { func (t *NEP17Tracker) DecodeBinary(r *io.BinReader) {
t.Balance = *bigint.FromBytes(r.ReadVarBytes()) t.Balance = *bigint.FromBytes(r.ReadVarBytes())
t.LastUpdatedBlock = r.ReadU32LE() t.LastUpdatedBlock = r.ReadU32LE()
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) { func (t *NEP17Transfer) EncodeBinary(w *io.BinWriter) {
w.WriteU32LE(uint32(t.Asset)) w.WriteU32LE(uint32(t.Asset))
w.WriteBytes(t.Tx[:]) w.WriteBytes(t.Tx[:])
w.WriteBytes(t.From[:]) w.WriteBytes(t.From[:])
@ -159,7 +159,7 @@ func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) {
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (t *NEP5Transfer) DecodeBinary(r *io.BinReader) { func (t *NEP17Transfer) DecodeBinary(r *io.BinReader) {
t.Asset = int32(r.ReadU32LE()) t.Asset = int32(r.ReadU32LE())
r.ReadBytes(t.Tx[:]) r.ReadBytes(t.Tx[:])
r.ReadBytes(t.From[:]) r.ReadBytes(t.From[:])

View file

@ -12,16 +12,16 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNEP5TransferLog_Append(t *testing.T) { func TestNEP17TransferLog_Append(t *testing.T) {
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
expected := []*NEP5Transfer{ expected := []*NEP17Transfer{
randomTransfer(r), randomTransfer(r),
randomTransfer(r), randomTransfer(r),
randomTransfer(r), randomTransfer(r),
randomTransfer(r), randomTransfer(r),
} }
lg := new(NEP5TransferLog) lg := new(NEP17TransferLog)
for _, tr := range expected { for _, tr := range expected {
require.NoError(t, lg.Append(tr)) require.NoError(t, lg.Append(tr))
} }
@ -29,7 +29,7 @@ func TestNEP5TransferLog_Append(t *testing.T) {
require.Equal(t, len(expected), lg.Size()) require.Equal(t, len(expected), lg.Size())
i := len(expected) - 1 i := len(expected) - 1
cont, err := lg.ForEach(func(tr *NEP5Transfer) (bool, error) { cont, err := lg.ForEach(func(tr *NEP17Transfer) (bool, error) {
require.Equal(t, expected[i], tr) require.Equal(t, expected[i], tr)
i-- i--
return true, nil return true, nil
@ -38,17 +38,17 @@ func TestNEP5TransferLog_Append(t *testing.T) {
require.True(t, cont) require.True(t, cont)
} }
func TestNEP5Tracker_EncodeBinary(t *testing.T) { func TestNEP17Tracker_EncodeBinary(t *testing.T) {
expected := &NEP5Tracker{ expected := &NEP17Tracker{
Balance: *big.NewInt(int64(rand.Uint64())), Balance: *big.NewInt(int64(rand.Uint64())),
LastUpdatedBlock: rand.Uint32(), LastUpdatedBlock: rand.Uint32(),
} }
testserdes.EncodeDecodeBinary(t, expected, new(NEP5Tracker)) testserdes.EncodeDecodeBinary(t, expected, new(NEP17Tracker))
} }
func TestNEP5Transfer_DecodeBinary(t *testing.T) { func TestNEP17Transfer_DecodeBinary(t *testing.T) {
expected := &NEP5Transfer{ expected := &NEP17Transfer{
Asset: 123, Asset: 123,
From: util.Uint160{5, 6, 7}, From: util.Uint160{5, 6, 7},
To: util.Uint160{8, 9, 10}, To: util.Uint160{8, 9, 10},
@ -58,11 +58,11 @@ func TestNEP5Transfer_DecodeBinary(t *testing.T) {
Tx: util.Uint256{8, 5, 3}, Tx: util.Uint256{8, 5, 3},
} }
testserdes.EncodeDecodeBinary(t, expected, new(NEP5Transfer)) testserdes.EncodeDecodeBinary(t, expected, new(NEP17Transfer))
} }
func randomTransfer(r *rand.Rand) *NEP5Transfer { func randomTransfer(r *rand.Rand) *NEP17Transfer {
return &NEP5Transfer{ return &NEP17Transfer{
Amount: *big.NewInt(int64(r.Uint64())), Amount: *big.NewInt(int64(r.Uint64())),
Block: r.Uint32(), Block: r.Uint32(),
Asset: int32(random.Int(10, 10000000)), Asset: int32(random.Int(10, 10000000)),

View file

@ -16,8 +16,8 @@ const (
STContract KeyPrefix = 0x50 STContract KeyPrefix = 0x50
STContractID KeyPrefix = 0x51 STContractID KeyPrefix = 0x51
STStorage KeyPrefix = 0x70 STStorage KeyPrefix = 0x70
STNEP5Transfers KeyPrefix = 0x72 STNEP17Transfers KeyPrefix = 0x72
STNEP5Balances KeyPrefix = 0x73 STNEP17Balances KeyPrefix = 0x73
IXHeaderHashList KeyPrefix = 0x80 IXHeaderHashList KeyPrefix = 0x80
SYSCurrentBlock KeyPrefix = 0xc0 SYSCurrentBlock KeyPrefix = 0xc0
SYSCurrentHeader KeyPrefix = 0xc1 SYSCurrentHeader KeyPrefix = 0xc1

View file

@ -103,10 +103,10 @@ func (chain testChain) GetHeader(hash util.Uint256) (*block.Header, error) {
func (chain testChain) GetNextBlockValidators() ([]*keys.PublicKey, error) { func (chain testChain) GetNextBlockValidators() ([]*keys.PublicKey, error) {
panic("TODO") panic("TODO")
} }
func (chain testChain) ForEachNEP5Transfer(util.Uint160, func(*state.NEP5Transfer) (bool, error)) error { func (chain testChain) ForEachNEP17Transfer(util.Uint160, func(*state.NEP17Transfer) (bool, error)) error {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances { func (chain testChain) GetNEP17Balances(util.Uint160) *state.NEP17Balances {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetValidators() ([]*keys.PublicKey, error) { func (chain testChain) GetValidators() ([]*keys.PublicKey, error) {
@ -130,7 +130,7 @@ func (chain testChain) GetStateRoot(height uint32) (*state.MPTRootState, error)
func (chain testChain) GetStorageItem(id int32, key []byte) *state.StorageItem { func (chain testChain) GetStorageItem(id int32, key []byte) *state.StorageItem {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM { func (chain testChain) GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) { func (chain testChain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) {

View file

@ -27,8 +27,8 @@ Supported methods
getblocksysfee getblocksysfee
getconnectioncount getconnectioncount
getcontractstate getcontractstate
getnep5balances getnep17balances
getnep5transfers getnep17transfers
getpeers getpeers
getrawmempool getrawmempool
getrawtransaction getrawtransaction

View file

@ -29,7 +29,7 @@ func Example() {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
resp, err := c.GetNEP5Balances(addr) resp, err := c.GetNEP17Balances(addr)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

View file

@ -23,64 +23,50 @@ type TransferTarget struct {
Amount int64 Amount int64
} }
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract. // NEP17Decimals invokes `decimals` NEP17 method on a specified contract.
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) { func (c *Client) NEP17Decimals(tokenHash util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} }
err = getInvocationError(result) err = getInvocationError(result)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to get NEP5 decimals: %w", err) return 0, fmt.Errorf("failed to get NEP17 decimals: %w", err)
} }
return topIntFromStack(result.Stack) return topIntFromStack(result.Stack)
} }
// NEP5Name invokes `name` NEP5 method on a specified contract. // NEP17Symbol invokes `symbol` NEP17 method on a specified contract.
func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) { func (c *Client) NEP17Symbol(tokenHash util.Uint160) (string, error) {
result, err := c.InvokeFunction(tokenHash, "name", []smartcontract.Parameter{}, nil)
if err != nil {
return "", err
}
err = getInvocationError(result)
if err != nil {
return "", fmt.Errorf("failed to get NEP5 name: %w", err)
}
return topStringFromStack(result.Stack)
}
// NEP5Symbol invokes `symbol` NEP5 method on a specified contract.
func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) {
result, err := c.InvokeFunction(tokenHash, "symbol", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "symbol", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return "", err return "", err
} }
err = getInvocationError(result) err = getInvocationError(result)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get NEP5 symbol: %w", err) return "", fmt.Errorf("failed to get NEP17 symbol: %w", err)
} }
return topStringFromStack(result.Stack) return topStringFromStack(result.Stack)
} }
// NEP5TotalSupply invokes `totalSupply` NEP5 method on a specified contract. // NEP17TotalSupply invokes `totalSupply` NEP17 method on a specified contract.
func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) { func (c *Client) NEP17TotalSupply(tokenHash util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash, "totalSupply", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "totalSupply", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} }
err = getInvocationError(result) err = getInvocationError(result)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to get NEP5 total supply: %w", err) return 0, fmt.Errorf("failed to get NEP17 total supply: %w", err)
} }
return topIntFromStack(result.Stack) return topIntFromStack(result.Stack)
} }
// NEP5BalanceOf invokes `balanceOf` NEP5 method on a specified contract. // NEP17BalanceOf invokes `balanceOf` NEP17 method on a specified contract.
func (c *Client) NEP5BalanceOf(tokenHash, acc util.Uint160) (int64, error) { func (c *Client) NEP17BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash, "balanceOf", []smartcontract.Parameter{{ result, err := c.InvokeFunction(tokenHash, "balanceOf", []smartcontract.Parameter{{
Type: smartcontract.Hash160Type, Type: smartcontract.Hash160Type,
Value: acc, Value: acc,
@ -90,44 +76,44 @@ func (c *Client) NEP5BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
} }
err = getInvocationError(result) err = getInvocationError(result)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to get NEP5 balance: %w", err) return 0, fmt.Errorf("failed to get NEP17 balance: %w", err)
} }
return topIntFromStack(result.Stack) return topIntFromStack(result.Stack)
} }
// NEP5TokenInfo returns full NEP5 token info. // NEP17TokenInfo returns full NEP17 token info.
func (c *Client) NEP5TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) { func (c *Client) NEP17TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
name, err := c.NEP5Name(tokenHash) cs, err := c.GetContractStateByHash(tokenHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
symbol, err := c.NEP5Symbol(tokenHash) symbol, err := c.NEP17Symbol(tokenHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
decimals, err := c.NEP5Decimals(tokenHash) decimals, err := c.NEP17Decimals(tokenHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return wallet.NewToken(tokenHash, name, symbol, decimals), nil return wallet.NewToken(tokenHash, cs.Manifest.Name, symbol, decimals), nil
} }
// CreateNEP5TransferTx creates an invocation transaction for the 'transfer' // CreateNEP17TransferTx creates an invocation transaction for the 'transfer'
// method of a given contract (token) to move specified amount of NEP5 assets // method of a given contract (token) to move specified amount of NEP17 assets
// (in FixedN format using contract's number of decimals) to given account and // (in FixedN format using contract's number of decimals) to given account and
// returns it. The returned transaction is not signed. // returns it. The returned transaction is not signed.
func (c *Client) CreateNEP5TransferTx(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (*transaction.Transaction, error) { func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (*transaction.Transaction, error) {
return c.CreateNEP5MultiTransferTx(acc, gas, TransferTarget{ return c.CreateNEP17MultiTransferTx(acc, gas, TransferTarget{
Token: token, Token: token,
Address: to, Address: to,
Amount: amount, Amount: amount,
}) })
} }
// CreateNEP5MultiTransferTx creates an invocation transaction for performing NEP5 transfers // CreateNEP17MultiTransferTx creates an invocation transaction for performing NEP17 transfers
// from a single sender to multiple recipients. // from a single sender to multiple recipients.
func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recipients ...TransferTarget) (*transaction.Transaction, error) { func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64, recipients ...TransferTarget) (*transaction.Transaction, error) {
from, err := address.StringToUint160(acc.Address) from, err := address.StringToUint160(acc.Address)
if err != nil { if err != nil {
return nil, fmt.Errorf("bad account address: %w", err) return nil, fmt.Errorf("bad account address: %w", err)
@ -135,7 +121,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
for i := range recipients { for i := range recipients {
emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from, emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from,
recipients[i].Address, recipients[i].Amount) recipients[i].Address, recipients[i].Amount, nil)
emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
} }
return c.CreateTxFromScript(w.Bytes(), acc, -1, gas, transaction.Signer{ return c.CreateTxFromScript(w.Bytes(), acc, -1, gas, transaction.Signer{
@ -185,12 +171,12 @@ func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee,
return tx, nil return tx, nil
} }
// TransferNEP5 creates an invocation transaction that invokes 'transfer' method // TransferNEP17 creates an invocation transaction that invokes 'transfer' method
// on a given token to move specified amount of NEP5 assets (in FixedN format // on a given token to move specified amount of NEP17 assets (in FixedN format
// using contract's number of decimals) to given account and sends it to the // using contract's number of decimals) to given account and sends it to the
// network returning just a hash of it. // network returning just a hash of it.
func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (util.Uint256, error) { func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (util.Uint256, error) {
tx, err := c.CreateNEP5TransferTx(acc, to, token, amount, gas) tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas)
if err != nil { if err != nil {
return util.Uint256{}, err return util.Uint256{}, err
} }
@ -202,9 +188,9 @@ func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token util.U
return c.SendRawTransaction(tx) return c.SendRawTransaction(tx)
} }
// MultiTransferNEP5 is similar to TransferNEP5, buf allows to have multiple recipients. // MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
func (c *Client) MultiTransferNEP5(acc *wallet.Account, gas int64, recipients ...TransferTarget) (util.Uint256, error) { func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients ...TransferTarget) (util.Uint256, error) {
tx, err := c.CreateNEP5MultiTransferTx(acc, gas, recipients...) tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients...)
if err != nil { if err != nil {
return util.Uint256{}, err return util.Uint256{}, err
} }

View file

@ -232,22 +232,22 @@ func (c *Client) getContractState(param interface{}) (*state.Contract, error) {
return resp, nil return resp, nil
} }
// GetNEP5Balances is a wrapper for getnep5balances RPC. // GetNEP17Balances is a wrapper for getnep17balances RPC.
func (c *Client) GetNEP5Balances(address util.Uint160) (*result.NEP5Balances, error) { func (c *Client) GetNEP17Balances(address util.Uint160) (*result.NEP17Balances, error) {
params := request.NewRawParams(address.StringLE()) params := request.NewRawParams(address.StringLE())
resp := new(result.NEP5Balances) resp := new(result.NEP17Balances)
if err := c.performRequest("getnep5balances", params, resp); err != nil { if err := c.performRequest("getnep17balances", params, resp); err != nil {
return nil, err return nil, err
} }
return resp, nil return resp, nil
} }
// GetNEP5Transfers is a wrapper for getnep5transfers RPC. Address parameter // GetNEP17Transfers is a wrapper for getnep17transfers RPC. Address parameter
// is mandatory, while all the others are optional. Start and stop parameters // is mandatory, while all the others are optional. Start and stop parameters
// are supported since neo-go 0.77.0 and limit and page since neo-go 0.78.0. // are supported since neo-go 0.77.0 and limit and page since neo-go 0.78.0.
// These parameters are positional in the JSON-RPC call, you can't specify limit // These parameters are positional in the JSON-RPC call, you can't specify limit
// and not specify start/stop for example. // and not specify start/stop for example.
func (c *Client) GetNEP5Transfers(address string, start, stop *uint32, limit, page *int) (*result.NEP5Transfers, error) { func (c *Client) GetNEP17Transfers(address string, start, stop *uint32, limit, page *int) (*result.NEP17Transfers, error) {
params := request.NewRawParams(address) params := request.NewRawParams(address)
if start != nil { if start != nil {
params.Values = append(params.Values, *start) params.Values = append(params.Values, *start)
@ -267,8 +267,8 @@ func (c *Client) GetNEP5Transfers(address string, start, stop *uint32, limit, pa
} else if stop != nil || limit != nil || page != nil { } else if stop != nil || limit != nil || page != nil {
return nil, errors.New("bad parameters") return nil, errors.New("bad parameters")
} }
resp := new(result.NEP5Transfers) resp := new(result.NEP17Transfers)
if err := c.performRequest("getnep5transfers", params, resp); err != nil { if err := c.performRequest("getnep17transfers", params, resp); err != nil {
return nil, err return nil, err
} }
return resp, nil return resp, nil

View file

@ -327,13 +327,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
} }
return c.GetContractStateByHash(hash) return c.GetContractStateByHash(hash)
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
panic(err) panic(err)
} }
m := manifest.NewManifest(hash.Hash160(script)) m := manifest.NewManifest(hash.Hash160(script), "Test")
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Script: script, Script: script,
@ -348,13 +348,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15") return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15")
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
panic(err) panic(err)
} }
m := manifest.NewManifest(hash.Hash160(script)) m := manifest.NewManifest(hash.Hash160(script), "Test")
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Script: script, Script: script,
@ -369,13 +369,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByID(0) return c.GetContractStateByID(0)
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
panic(err) panic(err)
} }
m := manifest.NewManifest(hash.Hash160(script)) m := manifest.NewManifest(hash.Hash160(script), "Test")
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Script: script, Script: script,
@ -434,7 +434,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
}, },
}, },
}, },
"getnep5balances": { "getnep17balances": {
{ {
name: "positive", name: "positive",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
@ -442,7 +442,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
if err != nil { if err != nil {
panic(err) panic(err)
} }
return c.GetNEP5Balances(hash) return c.GetNEP17Balances(hash)
}, },
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"balance":[{"assethash":"a48b6e1291ba24211ad11bb90ae2a10bf1fcd5a8","amount":"50000000000","lastupdatedblock":251604}],"address":"AY6eqWjsUFCzsVELG7yG72XDukKvC34p2w"}}`, serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"balance":[{"assethash":"a48b6e1291ba24211ad11bb90ae2a10bf1fcd5a8","amount":"50000000000","lastupdatedblock":251604}],"address":"AY6eqWjsUFCzsVELG7yG72XDukKvC34p2w"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
@ -450,8 +450,8 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
if err != nil { if err != nil {
panic(err) panic(err)
} }
return &result.NEP5Balances{ return &result.NEP17Balances{
Balances: []result.NEP5Balance{{ Balances: []result.NEP17Balance{{
Asset: hash, Asset: hash,
Amount: "50000000000", Amount: "50000000000",
LastUpdated: 251604, LastUpdated: 251604,
@ -461,11 +461,11 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
}, },
}, },
}, },
"getnep5transfers": { "getnep17transfers": {
{ {
name: "positive", name: "positive",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF", nil, nil, nil, nil) return c.GetNEP17Transfers("AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF", nil, nil, nil, nil)
}, },
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sent":[],"received":[{"timestamp":1555651816,"assethash":"600c4f5200db36177e3e8a09e9f18e2fc7d12a0f","transferaddress":"AYwgBNMepiv5ocGcyNT4mA8zPLTQ8pDBis","amount":"1000000","blockindex":436036,"transfernotifyindex":0,"txhash":"df7683ece554ecfb85cf41492c5f143215dd43ef9ec61181a28f922da06aba58"}],"address":"AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF"}}`, serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sent":[],"received":[{"timestamp":1555651816,"assethash":"600c4f5200db36177e3e8a09e9f18e2fc7d12a0f","transferaddress":"AYwgBNMepiv5ocGcyNT4mA8zPLTQ8pDBis","amount":"1000000","blockindex":436036,"transfernotifyindex":0,"txhash":"df7683ece554ecfb85cf41492c5f143215dd43ef9ec61181a28f922da06aba58"}],"address":"AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
@ -477,9 +477,9 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
if err != nil { if err != nil {
panic(err) panic(err)
} }
return &result.NEP5Transfers{ return &result.NEP17Transfers{
Sent: []result.NEP5Transfer{}, Sent: []result.NEP17Transfer{},
Received: []result.NEP5Transfer{ Received: []result.NEP17Transfer{
{ {
Timestamp: 1555651816, Timestamp: 1555651816,
Asset: assetHash, Asset: assetHash,
@ -1040,38 +1040,38 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
}, },
}, },
{ {
name: "getnep5balances_invalid_params_error", name: "getnep17balances_invalid_params_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Balances(util.Uint160{}) return c.GetNEP17Balances(util.Uint160{})
}, },
}, },
{ {
name: "getnep5transfers_invalid_params_error", name: "getnep17transfers_invalid_params_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("", nil, nil, nil, nil) return c.GetNEP17Transfers("", nil, nil, nil, nil)
}, },
}, },
{ {
name: "getnep5transfers_invalid_params_error 2", name: "getnep17transfers_invalid_params_error 2",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
var stop uint32 var stop uint32
return c.GetNEP5Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", nil, &stop, nil, nil) return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", nil, &stop, nil, nil)
}, },
}, },
{ {
name: "getnep5transfers_invalid_params_error 3", name: "getnep17transfers_invalid_params_error 3",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
var start uint32 var start uint32
var limit int var limit int
return c.GetNEP5Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, nil, &limit, nil) return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, nil, &limit, nil)
}, },
}, },
{ {
name: "getnep5transfers_invalid_params_error 4", name: "getnep17transfers_invalid_params_error 4",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
var start, stop uint32 var start, stop uint32
var page int var page int
return c.GetNEP5Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, &stop, nil, &page) return c.GetNEP17Transfers("NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", &start, &stop, nil, &page)
}, },
}, },
{ {
@ -1227,15 +1227,15 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
}, },
}, },
{ {
name: "getnep5balances_unmarshalling_error", name: "getnep17balances_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Balances(util.Uint160{}) return c.GetNEP17Balances(util.Uint160{})
}, },
}, },
{ {
name: "getnep5transfers_unmarshalling_error", name: "getnep17transfers_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("", nil, nil, nil, nil) return c.GetNEP17Transfers("", nil, nil, nil, nil)
}, },
}, },
{ {
@ -1463,9 +1463,9 @@ func wrapInitResponse(r *request.In, resp string) string {
} }
switch name { switch name {
case "neo": case "neo":
response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}` response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"name":"NEO","abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}`
case "gas": case "gas":
response = `{"id":1,"jsonrpc":"2.0","result":{"id":-2,"script":"DANHQVNBa2d4Cw==","manifest":{"abi":{"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf"],"extra":null},"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"}}` response = `{"id":1,"jsonrpc":"2.0","result":{"id":-2,"script":"DANHQVNBa2d4Cw==","manifest":{"name":"GAS","abi":{"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf"],"extra":null},"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"}}`
default: default:
response = resp response = resp
} }

View file

@ -4,28 +4,28 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
) )
// NEP5Balances is a result for the getnep5balances RPC call. // NEP17Balances is a result for the getnep17balances RPC call.
type NEP5Balances struct { type NEP17Balances struct {
Balances []NEP5Balance `json:"balance"` Balances []NEP17Balance `json:"balance"`
Address string `json:"address"` Address string `json:"address"`
} }
// NEP5Balance represents balance for the single token contract. // NEP17Balance represents balance for the single token contract.
type NEP5Balance struct { type NEP17Balance struct {
Asset util.Uint160 `json:"assethash"` Asset util.Uint160 `json:"assethash"`
Amount string `json:"amount"` Amount string `json:"amount"`
LastUpdated uint32 `json:"lastupdatedblock"` LastUpdated uint32 `json:"lastupdatedblock"`
} }
// NEP5Transfers is a result for the getnep5transfers RPC. // NEP17Transfers is a result for the getnep17transfers RPC.
type NEP5Transfers struct { type NEP17Transfers struct {
Sent []NEP5Transfer `json:"sent"` Sent []NEP17Transfer `json:"sent"`
Received []NEP5Transfer `json:"received"` Received []NEP17Transfer `json:"received"`
Address string `json:"address"` Address string `json:"address"`
} }
// NEP5Transfer represents single NEP5 transfer event. // NEP17Transfer represents single NEP17 transfer event.
type NEP5Transfer struct { type NEP17Transfer struct {
Timestamp uint64 `json:"timestamp"` Timestamp uint64 `json:"timestamp"`
Asset util.Uint160 `json:"assethash"` Asset util.Uint160 `json:"assethash"`
Address string `json:"transferaddress,omitempty"` Address string `json:"transferaddress,omitempty"`

View file

@ -19,7 +19,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestClient_NEP5(t *testing.T) { func TestClient_NEP17(t *testing.T) {
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t) chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
defer chain.Close() defer chain.Close()
defer rpcSrv.Shutdown() defer rpcSrv.Shutdown()
@ -32,27 +32,22 @@ func TestClient_NEP5(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Run("Decimals", func(t *testing.T) { t.Run("Decimals", func(t *testing.T) {
d, err := c.NEP5Decimals(h) d, err := c.NEP17Decimals(h)
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, 2, d) require.EqualValues(t, 2, d)
}) })
t.Run("TotalSupply", func(t *testing.T) { t.Run("TotalSupply", func(t *testing.T) {
s, err := c.NEP5TotalSupply(h) s, err := c.NEP17TotalSupply(h)
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, 1_000_000, s) require.EqualValues(t, 1_000_000, s)
}) })
t.Run("Name", func(t *testing.T) {
name, err := c.NEP5Name(h)
require.NoError(t, err)
require.Equal(t, "Rubl", name)
})
t.Run("Symbol", func(t *testing.T) { t.Run("Symbol", func(t *testing.T) {
sym, err := c.NEP5Symbol(h) sym, err := c.NEP17Symbol(h)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "RUB", sym) require.Equal(t, "RUB", sym)
}) })
t.Run("TokenInfo", func(t *testing.T) { t.Run("TokenInfo", func(t *testing.T) {
tok, err := c.NEP5TokenInfo(h) tok, err := c.NEP17TokenInfo(h)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, h, tok.Hash) require.Equal(t, h, tok.Hash)
require.Equal(t, "Rubl", tok.Name) require.Equal(t, "Rubl", tok.Name)
@ -61,7 +56,7 @@ func TestClient_NEP5(t *testing.T) {
}) })
t.Run("BalanceOf", func(t *testing.T) { t.Run("BalanceOf", func(t *testing.T) {
acc := testchain.PrivateKeyByID(0).GetScriptHash() acc := testchain.PrivateKeyByID(0).GetScriptHash()
b, err := c.NEP5BalanceOf(h, acc) b, err := c.NEP17BalanceOf(h, acc)
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, 877, b) require.EqualValues(t, 877, b)
}) })
@ -264,7 +259,7 @@ func TestCreateTxFromScript(t *testing.T) {
}) })
} }
func TestCreateNEP5TransferTx(t *testing.T) { func TestCreateNEP17TransferTx(t *testing.T) {
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t) chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
defer chain.Close() defer chain.Close()
defer rpcSrv.Shutdown() defer rpcSrv.Shutdown()
@ -280,11 +275,11 @@ func TestCreateNEP5TransferTx(t *testing.T) {
gasContractHash, err := c.GetNativeContractHash("gas") gasContractHash, err := c.GetNativeContractHash("gas")
require.NoError(t, err) require.NoError(t, err)
tx, err := c.CreateNEP5TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0) tx, err := c.CreateNEP17TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, acc.SignTx(tx)) require.NoError(t, acc.SignTx(tx))
require.NoError(t, chain.VerifyTx(tx)) require.NoError(t, chain.VerifyTx(tx))
v := chain.GetTestVM(tx) v := chain.GetTestVM(tx, nil)
v.LoadScriptWithFlags(tx.Script, smartcontract.All) v.LoadScriptWithFlags(tx.Script, smartcontract.All)
require.NoError(t, v.Run()) require.NoError(t, v.Run())
} }

View file

@ -97,8 +97,8 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon
"getcommittee": (*Server).getCommittee, "getcommittee": (*Server).getCommittee,
"getconnectioncount": (*Server).getConnectionCount, "getconnectioncount": (*Server).getConnectionCount,
"getcontractstate": (*Server).getContractState, "getcontractstate": (*Server).getContractState,
"getnep5balances": (*Server).getNEP5Balances, "getnep17balances": (*Server).getNEP17Balances,
"getnep5transfers": (*Server).getNEP5Transfers, "getnep17transfers": (*Server).getNEP17Transfers,
"getpeers": (*Server).getPeers, "getpeers": (*Server).getPeers,
"getproof": (*Server).getProof, "getproof": (*Server).getProof,
"getrawmempool": (*Server).getRawMempool, "getrawmempool": (*Server).getRawMempool,
@ -550,16 +550,16 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *resp
return result.NewApplicationLog(hash, appExecResults, trig), nil return result.NewApplicationLog(hash, appExecResults, trig), nil
} }
func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Error) { func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Error) {
u, err := ps.Value(0).GetUint160FromAddressOrHex() u, err := ps.Value(0).GetUint160FromAddressOrHex()
if err != nil { if err != nil {
return nil, response.ErrInvalidParams return nil, response.ErrInvalidParams
} }
as := s.chain.GetNEP5Balances(u) as := s.chain.GetNEP17Balances(u)
bs := &result.NEP5Balances{ bs := &result.NEP17Balances{
Address: address.Uint160ToString(u), Address: address.Uint160ToString(u),
Balances: []result.NEP5Balance{}, Balances: []result.NEP17Balance{},
} }
if as != nil { if as != nil {
cache := make(map[int32]util.Uint160) cache := make(map[int32]util.Uint160)
@ -568,7 +568,7 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro
if err != nil { if err != nil {
continue continue
} }
bs.Balances = append(bs.Balances, result.NEP5Balance{ bs.Balances = append(bs.Balances, result.NEP17Balance{
Asset: h, Asset: h,
Amount: bal.Balance.String(), Amount: bal.Balance.String(),
LastUpdated: bal.LastUpdatedBlock, LastUpdated: bal.LastUpdatedBlock,
@ -628,7 +628,7 @@ func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, i
return start, end, limit, page, nil return start, end, limit, page, nil
} }
func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Error) { func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.Error) {
u, err := ps.Value(0).GetUint160FromAddressOrHex() u, err := ps.Value(0).GetUint160FromAddressOrHex()
if err != nil { if err != nil {
return nil, response.ErrInvalidParams return nil, response.ErrInvalidParams
@ -639,14 +639,14 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
return nil, response.NewInvalidParamsError(err.Error(), err) return nil, response.NewInvalidParamsError(err.Error(), err)
} }
bs := &result.NEP5Transfers{ bs := &result.NEP17Transfers{
Address: address.Uint160ToString(u), Address: address.Uint160ToString(u),
Received: []result.NEP5Transfer{}, Received: []result.NEP17Transfer{},
Sent: []result.NEP5Transfer{}, Sent: []result.NEP17Transfer{},
} }
cache := make(map[int32]util.Uint160) cache := make(map[int32]util.Uint160)
var resCount, frameCount int var resCount, frameCount int
err = s.chain.ForEachNEP5Transfer(u, func(tr *state.NEP5Transfer) (bool, error) { err = s.chain.ForEachNEP17Transfer(u, func(tr *state.NEP17Transfer) (bool, error) {
// Iterating from newest to oldest, not yet reached required // Iterating from newest to oldest, not yet reached required
// time frame, continue looping. // time frame, continue looping.
if tr.Timestamp > end { if tr.Timestamp > end {
@ -668,7 +668,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
return false, err return false, err
} }
transfer := result.NEP5Transfer{ transfer := result.NEP17Transfer{
Timestamp: tr.Timestamp, Timestamp: tr.Timestamp,
Asset: h, Asset: h,
Index: tr.Block, Index: tr.Block,
@ -696,7 +696,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
return true, nil return true, nil
}) })
if err != nil { if err != nil {
return nil, response.NewInternalServerError("invalid NEP5 transfer log", err) return nil, response.NewInternalServerError("invalid NEP17 transfer log", err)
} }
return bs, nil return bs, nil
} }
@ -1095,7 +1095,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons
return nil, response.NewInternalServerError("can't create invocation script", err) return nil, response.NewInternalServerError("can't create invocation script", err)
} }
tx.Script = script tx.Script = script
return s.runScriptInVM(script, tx), nil return s.runScriptInVM(script, tx)
} }
// invokescript implements the `invokescript` RPC call. // invokescript implements the `invokescript` RPC call.
@ -1121,16 +1121,27 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}} tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
} }
tx.Script = script tx.Script = script
return s.runScriptInVM(script, tx), nil return s.runScriptInVM(script, tx)
} }
// runScriptInVM runs given script in a new test VM and returns the invocation // runScriptInVM runs given script in a new test VM and returns the invocation
// result. // result.
func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *result.Invoke { func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) (*result.Invoke, *response.Error) {
vm := s.chain.GetTestVM(tx) // When transfering funds, script execution does no auto GAS claim,
// because it depends on persisting tx height.
// This is why we provide block here.
b := block.New(s.network, s.stateRootEnabled)
b.Index = s.chain.BlockHeight() + 1
hdr, err := s.chain.GetHeader(s.chain.GetHeaderHash(int(s.chain.BlockHeight())))
if err != nil {
return nil, response.NewInternalServerError("can't get last block", err)
}
b.Timestamp = hdr.Timestamp + uint64(s.chain.GetConfig().SecondsPerBlock*int(time.Second/time.Millisecond))
vm := s.chain.GetTestVM(tx, b)
vm.GasLimit = int64(s.config.MaxGasInvoke) vm.GasLimit = int64(s.config.MaxGasInvoke)
vm.LoadScriptWithFlags(script, smartcontract.All) vm.LoadScriptWithFlags(script, smartcontract.All)
err := vm.Run() err = vm.Run()
var faultException string var faultException string
if err != nil { if err != nil {
faultException = err.Error() faultException = err.Error()
@ -1142,7 +1153,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu
Stack: vm.Estack().ToArray(), Stack: vm.Estack().ToArray(),
FaultException: faultException, FaultException: faultException,
} }
return result return result, nil
} }
// submitBlock broadcasts a raw block over the NEO network. // submitBlock broadcasts a raw block over the NEO network.

View file

@ -56,8 +56,8 @@ type rpcTestCase struct {
check func(t *testing.T, e *executor, result interface{}) check func(t *testing.T, e *executor, result interface{})
} }
const testContractHash = "b0fda4dd46b8e5d207e86e774a4a133c6db69ee7" const testContractHash = "55b692ecc09f240355e042c6c07e8f3fe57546b1"
const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd77577e6194c173" const deploymentTxHash = "99e40e5d169eb9a2b6faebc6fc596c050cf3f8a70ad25de8f44309bc8ccbfbfb"
const genesisBlockHash = "a496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0" const genesisBlockHash = "a496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0"
const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7" const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7"
@ -202,7 +202,7 @@ var rpcTestCases = map[string][]rpcTestCase{
}, },
}, },
"getnep5balances": { "getnep17balances": {
{ {
name: "no params", name: "no params",
params: `[]`, params: `[]`,
@ -216,17 +216,17 @@ var rpcTestCases = map[string][]rpcTestCase{
{ {
name: "positive", name: "positive",
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `"]`, params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `"]`,
result: func(e *executor) interface{} { return &result.NEP5Balances{} }, result: func(e *executor) interface{} { return &result.NEP17Balances{} },
check: checkNep5Balances, check: checkNep17Balances,
}, },
{ {
name: "positive_address", name: "positive_address",
params: `["` + address.Uint160ToString(testchain.PrivateKeyByID(0).GetScriptHash()) + `"]`, params: `["` + address.Uint160ToString(testchain.PrivateKeyByID(0).GetScriptHash()) + `"]`,
result: func(e *executor) interface{} { return &result.NEP5Balances{} }, result: func(e *executor) interface{} { return &result.NEP17Balances{} },
check: checkNep5Balances, check: checkNep17Balances,
}, },
}, },
"getnep5transfers": { "getnep17transfers": {
{ {
name: "no params", name: "no params",
params: `[]`, params: `[]`,
@ -275,14 +275,14 @@ var rpcTestCases = map[string][]rpcTestCase{
{ {
name: "positive", name: "positive",
params: `["` + testchain.PrivateKeyByID(0).Address() + `", 0]`, params: `["` + testchain.PrivateKeyByID(0).Address() + `", 0]`,
result: func(e *executor) interface{} { return &result.NEP5Transfers{} }, result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
check: checkNep5Transfers, check: checkNep17Transfers,
}, },
{ {
name: "positive_hash", name: "positive_hash",
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `", 0]`, params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `", 0]`,
result: func(e *executor) interface{} { return &result.NEP5Transfers{} }, result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
check: checkNep5Transfers, check: checkNep17Transfers,
}, },
}, },
"getproof": { "getproof": {
@ -1198,8 +1198,8 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
assert.ElementsMatch(t, expected, actual) assert.ElementsMatch(t, expected, actual)
}) })
t.Run("getnep5transfers", func(t *testing.T) { t.Run("getnep17transfers", func(t *testing.T) {
testNEP5T := func(t *testing.T, start, stop, limit, page int, sent, rcvd []int) { testNEP17T := func(t *testing.T, start, stop, limit, page int, sent, rcvd []int) {
ps := []string{`"` + testchain.PrivateKeyByID(0).Address() + `"`} ps := []string{`"` + testchain.PrivateKeyByID(0).Address() + `"`}
if start != 0 { if start != 0 {
h, err := e.chain.GetHeader(e.chain.GetHeaderHash(start)) h, err := e.chain.GetHeader(e.chain.GetHeaderHash(start))
@ -1228,19 +1228,19 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
ps = append(ps, strconv.FormatInt(int64(page), 10)) ps = append(ps, strconv.FormatInt(int64(page), 10))
} }
p := strings.Join(ps, ", ") p := strings.Join(ps, ", ")
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getnep5transfers", "params": [%s]}`, p) rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getnep17transfers", "params": [%s]}`, p)
body := doRPCCall(rpc, httpSrv.URL, t) body := doRPCCall(rpc, httpSrv.URL, t)
res := checkErrGetResult(t, body, false) res := checkErrGetResult(t, body, false)
actual := new(result.NEP5Transfers) actual := new(result.NEP17Transfers)
require.NoError(t, json.Unmarshal(res, actual)) require.NoError(t, json.Unmarshal(res, actual))
checkNep5TransfersAux(t, e, actual, sent, rcvd) checkNep17TransfersAux(t, e, actual, sent, rcvd)
} }
t.Run("time frame only", func(t *testing.T) { testNEP5T(t, 4, 5, 0, 0, []int{3, 4, 5, 6}, []int{1, 2}) }) t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{3, 4, 5, 6}, []int{1, 2}) })
t.Run("no res", func(t *testing.T) { testNEP5T(t, 100, 100, 0, 0, []int{}, []int{}) }) t.Run("no res", func(t *testing.T) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
t.Run("limit", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 0, []int{0, 1}, []int{0}) }) t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{0, 1}, []int{0}) })
t.Run("limit 2", func(t *testing.T) { testNEP5T(t, 4, 5, 2, 0, []int{3}, []int{1}) }) t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{3}, []int{1}) })
t.Run("limit with page", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 1, []int{2, 3}, []int{1}) }) t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{2, 3}, []int{1}) })
t.Run("limit with page 2", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 2, []int{4, 5}, []int{2}) }) t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{4, 5}, []int{2}) })
}) })
} }
@ -1326,13 +1326,13 @@ func doRPCCallOverHTTP(rpcCall string, url string, t *testing.T) []byte {
return bytes.TrimSpace(body) return bytes.TrimSpace(body)
} }
func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
res, ok := acc.(*result.NEP5Balances) res, ok := acc.(*result.NEP17Balances)
require.True(t, ok) require.True(t, ok)
rubles, err := util.Uint160DecodeStringLE(testContractHash) rubles, err := util.Uint160DecodeStringLE(testContractHash)
require.NoError(t, err) require.NoError(t, err)
expected := result.NEP5Balances{ expected := result.NEP17Balances{
Balances: []result.NEP5Balance{ Balances: []result.NEP17Balance{
{ {
Asset: rubles, Asset: rubles,
Amount: "877", Amount: "877",
@ -1345,7 +1345,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
}, },
{ {
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
Amount: "80009641770", Amount: "80009744770",
LastUpdated: 7, LastUpdated: 7,
}}, }},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
@ -1354,12 +1354,12 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
require.ElementsMatch(t, expected.Balances, res.Balances) require.ElementsMatch(t, expected.Balances, res.Balances)
} }
func checkNep5Transfers(t *testing.T, e *executor, acc interface{}) { func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
checkNep5TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3, 4, 5, 6}) checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3, 4, 5, 6})
} }
func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) { func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
res, ok := acc.(*result.NEP5Transfers) res, ok := acc.(*result.NEP17Transfers)
require.True(t, ok) require.True(t, ok)
rublesHash, err := util.Uint160DecodeStringLE(testContractHash) rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
require.NoError(t, err) require.NoError(t, err)
@ -1410,8 +1410,8 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv
// * to check chain events consistency // * to check chain events consistency
// Technically these could be retrieved from application log, but that would almost // Technically these could be retrieved from application log, but that would almost
// duplicate the Server method. // duplicate the Server method.
expected := result.NEP5Transfers{ expected := result.NEP17Transfers{
Sent: []result.NEP5Transfer{ Sent: []result.NEP17Transfer{
{ {
Timestamp: blockDeploy2.Timestamp, Timestamp: blockDeploy2.Timestamp,
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
@ -1487,7 +1487,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv
TxHash: blockCtrDeploy.Hash(), TxHash: blockCtrDeploy.Hash(),
}, },
}, },
Received: []result.NEP5Transfer{ Received: []result.NEP17Transfer{
{ {
Timestamp: blockGASBounty.Timestamp, Timestamp: blockGASBounty.Timestamp,
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
@ -1547,7 +1547,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv
require.Equal(t, expected.Address, res.Address) require.Equal(t, expected.Address, res.Address)
arr := make([]result.NEP5Transfer, 0, len(expected.Sent)) arr := make([]result.NEP17Transfer, 0, len(expected.Sent))
for i := range expected.Sent { for i := range expected.Sent {
for _, j := range sent { for _, j := range sent {
if i == j { if i == j {

View file

@ -15,11 +15,11 @@ func Init() bool {
h := runtime.GetExecutingScriptHash() h := runtime.GetExecutingScriptHash()
amount := totalSupply amount := totalSupply
storage.Put(ctx, h, amount) storage.Put(ctx, h, amount)
runtime.Notify("transfer", []byte{}, h, amount) runtime.Notify("Transfer", []byte{}, h, amount)
return true return true
} }
func Transfer(from, to []byte, amount int) bool { func Transfer(from, to []byte, amount int, data interface{}) bool {
ctx := storage.GetContext() ctx := storage.GetContext()
if len(from) != 20 { if len(from) != 20 {
runtime.Log("invalid 'from' address") runtime.Log("invalid 'from' address")
@ -54,7 +54,7 @@ func Transfer(from, to []byte, amount int) bool {
toBalance += amount toBalance += amount
storage.Put(ctx, to, toBalance) storage.Put(ctx, to, toBalance)
runtime.Notify("transfer", from, to, amount) runtime.Notify("Transfer", from, to, amount)
return true return true
} }
@ -74,10 +74,6 @@ func BalanceOf(addr []byte) int {
return amount return amount
} }
func Name() string {
return "Rubl"
}
func Symbol() string { func Symbol() string {
return "RUB" return "RUB"
} }

Binary file not shown.

View file

@ -20,10 +20,13 @@ const (
// MethodVerify is a name for default verification method. // MethodVerify is a name for default verification method.
MethodVerify = "verify" MethodVerify = "verify"
// NEP5StandardName represents the name of NEP5 smartcontract standard. // MethodOnPayment is name of the method which is called when contract receives funds.
NEP5StandardName = "NEP-5" MethodOnPayment = "onPayment"
// NEP10StandardName represents the name of NEP10 smartcontract standard. // NEP10StandardName represents the name of NEP10 smartcontract standard.
NEP10StandardName = "NEP-10" NEP10StandardName = "NEP-10"
// NEP17StandardName represents the name of NEP17 smartcontract standard.
NEP17StandardName = "NEP-17"
) )
// ABI represents a contract application binary interface. // ABI represents a contract application binary interface.
@ -35,6 +38,8 @@ type ABI struct {
// Manifest represens contract metadata. // Manifest represens contract metadata.
type Manifest struct { type Manifest struct {
// Name is a contract's name.
Name string `json:"name"`
// ABI is a contract's ABI. // ABI is a contract's ABI.
ABI ABI `json:"abi"` ABI ABI `json:"abi"`
// Groups is a set of groups to which a contract belongs. // Groups is a set of groups to which a contract belongs.
@ -51,8 +56,9 @@ type Manifest struct {
} }
// NewManifest returns new manifest with necessary fields initialized. // NewManifest returns new manifest with necessary fields initialized.
func NewManifest(h util.Uint160) *Manifest { func NewManifest(h util.Uint160, name string) *Manifest {
m := &Manifest{ m := &Manifest{
Name: name,
ABI: ABI{ ABI: ABI{
Hash: h, Hash: h,
Methods: []Method{}, Methods: []Method{},
@ -67,8 +73,8 @@ func NewManifest(h util.Uint160) *Manifest {
} }
// DefaultManifest returns default contract manifest. // DefaultManifest returns default contract manifest.
func DefaultManifest(h util.Uint160) *Manifest { func DefaultManifest(h util.Uint160, name string) *Manifest {
m := NewManifest(h) m := NewManifest(h, name)
m.Permissions = []Permission{*NewPermission(PermissionWildcard)} m.Permissions = []Permission{*NewPermission(PermissionWildcard)}
return m return m
} }

View file

@ -13,40 +13,40 @@ import (
// https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10 // https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10
func TestManifest_MarshalJSON(t *testing.T) { func TestManifest_MarshalJSON(t *testing.T) {
t.Run("default", func(t *testing.T) { t.Run("default", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
m := testUnmarshalMarshalManifest(t, s) m := testUnmarshalMarshalManifest(t, s)
require.Equal(t, DefaultManifest(util.Uint160{}), m) require.Equal(t, DefaultManifest(util.Uint160{}, "Test"), m)
}) })
t.Run("permissions", func(t *testing.T) { t.Run("permissions", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}` s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s) testUnmarshalMarshalManifest(t, s)
}) })
t.Run("safe methods", func(t *testing.T) { t.Run("safe methods", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}` s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}`
testUnmarshalMarshalManifest(t, s) testUnmarshalMarshalManifest(t, s)
}) })
t.Run("trust", func(t *testing.T) { t.Run("trust", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}` s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s) testUnmarshalMarshalManifest(t, s)
}) })
t.Run("groups", func(t *testing.T) { t.Run("groups", func(t *testing.T) {
s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s) testUnmarshalMarshalManifest(t, s)
}) })
t.Run("extra", func(t *testing.T) { t.Run("extra", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}` s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}`
testUnmarshalMarshalManifest(t, s) testUnmarshalMarshalManifest(t, s)
}) })
} }
func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest { func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
js := []byte(s) js := []byte(s)
c := NewManifest(util.Uint160{}) c := NewManifest(util.Uint160{}, "Test")
require.NoError(t, json.Unmarshal(js, c)) require.NoError(t, json.Unmarshal(js, c))
data, err := json.Marshal(c) data, err := json.Marshal(c)
@ -58,22 +58,22 @@ func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
func TestManifest_CanCall(t *testing.T) { func TestManifest_CanCall(t *testing.T) {
t.Run("safe methods", func(t *testing.T) { t.Run("safe methods", func(t *testing.T) {
man1 := NewManifest(util.Uint160{}) man1 := NewManifest(util.Uint160{}, "Test1")
man2 := DefaultManifest(util.Uint160{}) man2 := DefaultManifest(util.Uint160{}, "Test2")
require.False(t, man1.CanCall(man2, "method1")) require.False(t, man1.CanCall(man2, "method1"))
man2.SafeMethods.Add("method1") man2.SafeMethods.Add("method1")
require.True(t, man1.CanCall(man2, "method1")) require.True(t, man1.CanCall(man2, "method1"))
}) })
t.Run("wildcard permission", func(t *testing.T) { t.Run("wildcard permission", func(t *testing.T) {
man1 := DefaultManifest(util.Uint160{}) man1 := DefaultManifest(util.Uint160{}, "Test1")
man2 := DefaultManifest(util.Uint160{}) man2 := DefaultManifest(util.Uint160{}, "Test2")
require.True(t, man1.CanCall(man2, "method1")) require.True(t, man1.CanCall(man2, "method1"))
}) })
} }
func TestPermission_IsAllowed(t *testing.T) { func TestPermission_IsAllowed(t *testing.T) {
manifest := DefaultManifest(util.Uint160{}) manifest := DefaultManifest(util.Uint160{}, "Test")
t.Run("wildcard", func(t *testing.T) { t.Run("wildcard", func(t *testing.T) {
perm := NewPermission(PermissionWildcard) perm := NewPermission(PermissionWildcard)
@ -116,7 +116,7 @@ func TestPermission_IsAllowed(t *testing.T) {
func TestIsValid(t *testing.T) { func TestIsValid(t *testing.T) {
contractHash := util.Uint160{1, 2, 3} contractHash := util.Uint160{1, 2, 3}
m := NewManifest(contractHash) m := NewManifest(contractHash, "Test")
t.Run("valid, no groups", func(t *testing.T) { t.Run("valid, no groups", func(t *testing.T) {
require.True(t, m.IsValid(contractHash)) require.True(t, m.IsValid(contractHash))

View file

@ -72,6 +72,11 @@ func NewContext(b []byte) *Context {
} }
} }
// Estack returns the evaluation stack of c.
func (c *Context) Estack() *Stack {
return c.estack
}
// NextIP returns next instruction pointer. // NextIP returns next instruction pointer.
func (c *Context) NextIP() int { func (c *Context) NextIP() int {
return c.nextip return c.nextip

View file

@ -70,6 +70,8 @@ func Int(w *io.BinWriter, i int64) {
func Array(w *io.BinWriter, es ...interface{}) { func Array(w *io.BinWriter, es ...interface{}) {
for i := len(es) - 1; i >= 0; i-- { for i := len(es) - 1; i >= 0; i-- {
switch e := es[i].(type) { switch e := es[i].(type) {
case []interface{}:
Array(w, e...)
case int64: case int64:
Int(w, e) Int(w, e)
case string: case string:

View file

@ -143,7 +143,7 @@ func TestBytes(t *testing.T) {
func TestEmitArray(t *testing.T) { func TestEmitArray(t *testing.T) {
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
Array(buf.BinWriter, nil, int64(1), "str", true, []byte{0xCA, 0xFE}) Array(buf.BinWriter, []interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE})
require.NoError(t, buf.Err) require.NoError(t, buf.Err)
res := buf.Bytes() res := buf.Bytes()
@ -156,6 +156,10 @@ func TestEmitArray(t *testing.T) {
assert.EqualValues(t, []byte("str"), res[7:10]) assert.EqualValues(t, []byte("str"), res[7:10])
assert.EqualValues(t, opcode.PUSH1, res[10]) assert.EqualValues(t, opcode.PUSH1, res[10])
assert.EqualValues(t, opcode.PUSHNULL, res[11]) assert.EqualValues(t, opcode.PUSHNULL, res[11])
assert.EqualValues(t, opcode.PUSH2, res[12])
assert.EqualValues(t, opcode.PUSH1, res[13])
assert.EqualValues(t, opcode.PUSH2, res[14])
assert.EqualValues(t, opcode.PACK, res[15])
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {

View file

@ -13,9 +13,9 @@ func TestToken_MarshalJSON(t *testing.T) {
h, err := util.Uint160DecodeStringLE("f8d448b227991cf07cb96a6f9c0322437f1599b9") h, err := util.Uint160DecodeStringLE("f8d448b227991cf07cb96a6f9c0322437f1599b9")
require.NoError(t, err) require.NoError(t, err)
tok := NewToken(h, "NEP5 Standard", "NEP5", 8) tok := NewToken(h, "NEP17 Standard", "NEP17", 8)
require.Equal(t, "NEP5 Standard", tok.Name) require.Equal(t, "NEP17 Standard", tok.Name)
require.Equal(t, "NEP5", tok.Symbol) require.Equal(t, "NEP17", tok.Symbol)
require.EqualValues(t, 8, tok.Decimals) require.EqualValues(t, 8, tok.Decimals)
require.Equal(t, h, tok.Hash) require.Equal(t, h, tok.Hash)
require.Equal(t, "NcqKahsZ93ZyYS5bep8G2TY1zRB7tfUPdK", tok.Address()) require.Equal(t, "NcqKahsZ93ZyYS5bep8G2TY1zRB7tfUPdK", tok.Address())