Merge pull request #1558 from nspcc-dev/nep17
Replace NEP-5 with NEP-17
This commit is contained in:
commit
ad30f4d793
69 changed files with 637 additions and 633 deletions
|
@ -16,7 +16,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
defer e.Close(t)
|
||||
|
||||
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,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
|
|
@ -51,7 +51,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
|
||||
// Transfer funds to the multisig.
|
||||
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,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
@ -66,7 +66,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
txPath := path.Join(tmpDir, "multisigtx.json")
|
||||
defer os.Remove(txPath)
|
||||
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,
|
||||
"--wallet", wallet1Path, "--from", multisigAddr,
|
||||
"--to", priv.Address(), "--token", "neo", "--amount", "1",
|
||||
|
@ -93,7 +93,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
e.Chain.GoverningTokenHash().StringLE(), "transfer",
|
||||
"bytes:"+multisigHash.StringBE(),
|
||||
"bytes:"+priv.GetScriptHash().StringBE(),
|
||||
"int:1",
|
||||
"int:1", "bytes:",
|
||||
"--", strings.Join([]string{multisigHash.StringLE(), ":", "Global"}, ""))
|
||||
|
||||
e.In.WriteString("pass\r")
|
||||
|
|
|
@ -15,10 +15,10 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNEP5Balance(t *testing.T) {
|
||||
func TestNEP17Balance(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
defer e.Close(t)
|
||||
cmdbalance := []string{"neo-go", "wallet", "nep5", "balance"}
|
||||
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
|
||||
cmdbase := append(cmdbalance,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
|
@ -99,7 +99,7 @@ func TestNEP5Balance(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
func TestNEP5Transfer(t *testing.T) {
|
||||
func TestNEP17Transfer(t *testing.T) {
|
||||
w, err := wallet.NewWalletFromFile("testdata/testwallet.json")
|
||||
require.NoError(t, err)
|
||||
defer w.Close()
|
||||
|
@ -107,7 +107,7 @@ func TestNEP5Transfer(t *testing.T) {
|
|||
e := newExecutor(t, true)
|
||||
defer e.Close(t)
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "transfer",
|
||||
"neo-go", "wallet", "nep17", "transfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
@ -132,7 +132,7 @@ func TestNEP5Transfer(t *testing.T) {
|
|||
require.Equal(t, big.NewInt(1), b)
|
||||
}
|
||||
|
||||
func TestNEP5MultiTransfer(t *testing.T) {
|
||||
func TestNEP17MultiTransfer(t *testing.T) {
|
||||
privs, _ := generateKeys(t, 3)
|
||||
|
||||
e := newExecutor(t, true)
|
||||
|
@ -140,7 +140,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
|
|||
neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo")
|
||||
require.NoError(t, err)
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "multitransfer",
|
||||
"neo-go", "wallet", "nep17", "multitransfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
@ -161,7 +161,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
|
|||
require.Equal(t, big.NewInt(13), b)
|
||||
}
|
||||
|
||||
func TestNEP5ImportToken(t *testing.T) {
|
||||
func TestNEP17ImportToken(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
defer e.Close(t)
|
||||
|
||||
|
@ -174,11 +174,11 @@ func TestNEP5ImportToken(t *testing.T) {
|
|||
gasContractHash, err := e.Chain.GetNativeContractScriptHash("gas")
|
||||
require.NoError(t, err)
|
||||
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,
|
||||
"--wallet", walletPath,
|
||||
"--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,
|
||||
"--wallet", walletPath,
|
||||
"--token", neoContractHash.StringLE())
|
||||
|
@ -192,12 +192,12 @@ func TestNEP5ImportToken(t *testing.T) {
|
|||
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
|
||||
}
|
||||
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())
|
||||
checkGASInfo(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)
|
||||
checkGASInfo(t)
|
||||
_, err := e.Out.ReadString('\n')
|
||||
|
@ -210,9 +210,9 @@ func TestNEP5ImportToken(t *testing.T) {
|
|||
})
|
||||
t.Run("Remove", func(t *testing.T) {
|
||||
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())
|
||||
e.Run(t, "neo-go", "wallet", "nep5", "info",
|
||||
e.Run(t, "neo-go", "wallet", "nep17", "info",
|
||||
"--wallet", walletPath)
|
||||
checkGASInfo(t)
|
||||
_, err := e.Out.ReadString('\n')
|
|
@ -349,6 +349,7 @@ func initSmartContract(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
m := ProjectConfig{
|
||||
Name: contractName,
|
||||
SupportedStandards: []string{},
|
||||
Events: []manifest.Event{
|
||||
{
|
||||
|
@ -404,6 +405,7 @@ func contractCompile(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Name = conf.Name
|
||||
o.ContractEvents = conf.Events
|
||||
o.ContractSupportedStandards = conf.SupportedStandards
|
||||
}
|
||||
|
@ -631,6 +633,7 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
|
||||
// ProjectConfig contains project metadata.
|
||||
type ProjectConfig struct {
|
||||
Name string
|
||||
SupportedStandards []string
|
||||
Events []manifest.Event
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ func RuntimeNotify(args []interface{}) {
|
|||
manifest, err := ioutil.ReadFile(contractName + "/" + files[1].Name())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t,
|
||||
`supportedstandards: []
|
||||
`name: testContract
|
||||
supportedstandards: []
|
||||
events:
|
||||
- name: Hello world!
|
||||
parameters:
|
||||
|
|
3
cli/testdata/verify.go
vendored
3
cli/testdata/verify.go
vendored
|
@ -3,3 +3,6 @@ package testdata
|
|||
func Verify() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func OnPayment(from []byte, amount int, data interface{}) {
|
||||
}
|
||||
|
|
2
cli/testdata/verify.manifest.json
vendored
2
cli/testdata/verify.manifest.json
vendored
|
@ -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}
|
BIN
cli/testdata/verify.nef
vendored
BIN
cli/testdata/verify.nef
vendored
Binary file not shown.
|
@ -26,7 +26,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func newNEP5Commands() []cli.Command {
|
||||
func newNEP17Commands() []cli.Command {
|
||||
balanceFlags := []cli.Flag{
|
||||
walletPathFlag,
|
||||
tokenFlag,
|
||||
|
@ -69,21 +69,21 @@ func newNEP5Commands() []cli.Command {
|
|||
Name: "balance",
|
||||
Usage: "get address balance",
|
||||
UsageText: "balance --wallet <path> --rpc-endpoint <node> [--timeout <time>] [--address <address>] [--token <hash-or-name>]",
|
||||
Action: getNEP5Balance,
|
||||
Action: getNEP17Balance,
|
||||
Flags: balanceFlags,
|
||||
},
|
||||
{
|
||||
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>",
|
||||
Action: importNEP5Token,
|
||||
Action: importNEP17Token,
|
||||
Flags: importFlags,
|
||||
},
|
||||
{
|
||||
Name: "info",
|
||||
Usage: "print imported NEP5 token info",
|
||||
Usage: "print imported NEP17 token info",
|
||||
UsageText: "print --wallet <path> [--token <hash-or-name>]",
|
||||
Action: printNEP5Info,
|
||||
Action: printNEP17Info,
|
||||
Flags: []cli.Flag{
|
||||
walletPathFlag,
|
||||
cli.StringFlag{
|
||||
|
@ -94,9 +94,9 @@ func newNEP5Commands() []cli.Command {
|
|||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Usage: "remove NEP5 token from the wallet",
|
||||
Usage: "remove NEP17 token from the wallet",
|
||||
UsageText: "remove --wallet <path> --token <hash-or-name>",
|
||||
Action: removeNEP5Token,
|
||||
Action: removeNEP17Token,
|
||||
Flags: []cli.Flag{
|
||||
walletPathFlag,
|
||||
cli.StringFlag{
|
||||
|
@ -108,23 +108,23 @@ func newNEP5Commands() []cli.Command {
|
|||
},
|
||||
{
|
||||
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",
|
||||
Action: transferNEP5,
|
||||
Action: transferNEP17,
|
||||
Flags: transferFlags,
|
||||
},
|
||||
{
|
||||
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>` +
|
||||
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]]`,
|
||||
Action: multiTransferNEP5,
|
||||
Action: multiTransferNEP17,
|
||||
Flags: multiTransferFlags,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getNEP5Balance(ctx *cli.Context) error {
|
||||
func getNEP17Balance(ctx *cli.Context) error {
|
||||
var accounts []*wallet.Account
|
||||
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
|
@ -170,7 +170,7 @@ func getNEP5Balance(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid account address: %w", err), 1)
|
||||
}
|
||||
balances, err := c.GetNEP5Balances(addrHash)
|
||||
balances, err := c.GetNEP17Balances(addrHash)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ func getNEP5Balance(ctx *cli.Context) error {
|
|||
asset := balances.Balances[i].Asset
|
||||
token, err := getMatchingToken(ctx, wall, asset.StringLE())
|
||||
if err != nil {
|
||||
token, err = c.NEP5TokenInfo(asset)
|
||||
token, err = c.NEP17TokenInfo(asset)
|
||||
}
|
||||
if err == nil {
|
||||
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) {
|
||||
bs, err := c.GetNEP5Balances(addr)
|
||||
bs, err := c.GetNEP17Balances(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
get := func(i int) *wallet.Token {
|
||||
t, _ := c.NEP5TokenInfo(bs.Balances[i].Asset)
|
||||
t, _ := c.NEP17TokenInfo(bs.Balances[i].Asset)
|
||||
return t
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func importNEP5Token(ctx *cli.Context) error {
|
||||
func importNEP17Token(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -274,7 +274,7 @@ func importNEP5Token(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
tok, err := c.NEP5TokenInfo(tokenHash)
|
||||
tok, err := c.NEP17TokenInfo(tokenHash)
|
||||
if err != nil {
|
||||
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())
|
||||
}
|
||||
|
||||
func printNEP5Info(ctx *cli.Context) error {
|
||||
func printNEP17Info(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -321,7 +321,7 @@ func printNEP5Info(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func removeNEP5Token(ctx *cli.Context) error {
|
||||
func removeNEP17Token(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -345,7 +345,7 @@ func removeNEP5Token(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func multiTransferNEP5(ctx *cli.Context) error {
|
||||
func multiTransferNEP17(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -412,7 +412,7 @@ func multiTransferNEP5(ctx *cli.Context) error {
|
|||
return signAndSendTransfer(ctx, c, acc, recipients)
|
||||
}
|
||||
|
||||
func transferNEP5(ctx *cli.Context) error {
|
||||
func transferNEP17(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
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 {
|
||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||
|
||||
tx, err := c.CreateNEP5MultiTransferTx(acc, int64(gas), recipients...)
|
||||
tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients...)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
|
@ -195,9 +195,9 @@ func NewCommands() []cli.Command {
|
|||
Subcommands: newMultisigCommands(),
|
||||
},
|
||||
{
|
||||
Name: "nep5",
|
||||
Usage: "work with NEP5 contracts",
|
||||
Subcommands: newNEP5Commands(),
|
||||
Name: "nep17",
|
||||
Usage: "work with NEP17 contracts",
|
||||
Subcommands: newNEP17Commands(),
|
||||
},
|
||||
{
|
||||
Name: "candidate",
|
||||
|
@ -237,7 +237,7 @@ func claimGas(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
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 {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ func TestClaimGas(t *testing.T) {
|
|||
defer w.Close()
|
||||
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "multitransfer",
|
||||
"neo-go", "wallet", "nep17", "multitransfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
@ -258,7 +258,7 @@ func TestImportDeployed(t *testing.T) {
|
|||
|
||||
t.Run("Sign", func(t *testing.T) {
|
||||
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,
|
||||
"--wallet", validatorWallet, "--from", validatorAddr,
|
||||
"neo:"+contractAddr+":10",
|
||||
|
@ -269,7 +269,7 @@ func TestImportDeployed(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
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,
|
||||
"--wallet", walletPath, "--from", contractAddr,
|
||||
"--to", privTo.Address(), "--token", "neo", "--amount", "1")
|
||||
|
|
12
docs/rpc.md
12
docs/rpc.md
|
@ -43,8 +43,8 @@ which would yield the response:
|
|||
| `getblocksysfee` |
|
||||
| `getconnectioncount` |
|
||||
| `getcontractstate` |
|
||||
| `getnep5balances` |
|
||||
| `getnep5transfers` |
|
||||
| `getnep17balances` |
|
||||
| `getnep17transfers` |
|
||||
| `getpeers` |
|
||||
| `getrawmempool` |
|
||||
| `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.
|
||||
|
||||
#### 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
|
||||
additional parameter and then use paging to request the next batch of
|
||||
transfers.
|
||||
|
@ -119,14 +119,14 @@ Example requesting 10 events for address NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc
|
|||
within 0-1600094189 timestamps:
|
||||
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": 5, "method": "getnep5transfers", "params":
|
||||
{ "jsonrpc": "2.0", "id": 5, "method": "getnep17transfers", "params":
|
||||
["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10] }
|
||||
```
|
||||
|
||||
Get the next 10 transfers for the same account within the same time frame:
|
||||
|
||||
```json
|
||||
{ "jsonrpc": "2.0", "id": 5, "method": "getnep5transfers", "params":
|
||||
{ "jsonrpc": "2.0", "id": 5, "method": "getnep17transfers", "params":
|
||||
["NbTiM6h8r99kpRtb428XcsUk1TzKed2gTc", 0, 1600094189, 10, 1] }
|
||||
```
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
name: "Engine example"
|
||||
supportedstandards: []
|
||||
events:
|
||||
- name: Tx
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
name: "Iterator example"
|
||||
supportedstandards: []
|
||||
events:
|
||||
- name: found storage values
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
name: "Runtime example"
|
||||
supportedstandards: []
|
||||
events:
|
||||
- name: Event
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
name: "Storage example"
|
||||
supportedstandards: []
|
||||
events: []
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
name: "Timer example"
|
||||
supportedstandards: []
|
||||
events: []
|
||||
|
|
|
@ -133,14 +133,6 @@ func checkOwnerWitness() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Name returns the token name
|
||||
func Name() interface{} {
|
||||
if trigger != runtime.Application {
|
||||
return false
|
||||
}
|
||||
return token.Name
|
||||
}
|
||||
|
||||
// Decimals returns the token decimals
|
||||
func Decimals() interface{} {
|
||||
if trigger != runtime.Application {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
supportedstandards: ["NEP-5"]
|
||||
name: "My awesome token"
|
||||
supportedstandards: ["NEP-17"]
|
||||
events: []
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package nep5
|
||||
package nep17
|
||||
|
||||
import (
|
||||
"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
|
||||
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)
|
||||
if amountFrom == -1 {
|
||||
return false
|
|
@ -1,7 +1,7 @@
|
|||
package tokencontract
|
||||
|
||||
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/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/util"
|
||||
|
@ -14,14 +14,14 @@ const (
|
|||
|
||||
var (
|
||||
owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt")
|
||||
token nep5.Token
|
||||
token nep17.Token
|
||||
ctx storage.Context
|
||||
)
|
||||
|
||||
// init initializes the Token Interface and storage context for the Smart
|
||||
// Contract to operate with
|
||||
func init() {
|
||||
token = nep5.Token{
|
||||
token = nep17.Token{
|
||||
Name: "Awesome NEO Token",
|
||||
Symbol: "ANT",
|
||||
Decimals: decimals,
|
||||
|
@ -32,11 +32,6 @@ func init() {
|
|||
ctx = storage.GetContext()
|
||||
}
|
||||
|
||||
// Name returns the token name
|
||||
func Name() string {
|
||||
return token.Name
|
||||
}
|
||||
|
||||
// Symbol returns the token symbol
|
||||
func Symbol() string {
|
||||
return token.Symbol
|
||||
|
@ -58,8 +53,8 @@ func BalanceOf(holder interop.Hash160) interface{} {
|
|||
}
|
||||
|
||||
// Transfer token from one user to another
|
||||
func Transfer(from interop.Hash160, to interop.Hash160, amount int) bool {
|
||||
return token.Transfer(ctx, from, to, amount)
|
||||
func Transfer(from interop.Hash160, to interop.Hash160, amount int, data interface{}) bool {
|
||||
return token.Transfer(ctx, from, to, amount, data)
|
||||
}
|
||||
|
||||
// Mint initial supply of tokens
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
supportedstandards: ["NEP-5"]
|
||||
name: "Awesome NEO Token"
|
||||
supportedstandards: ["NEP-17"]
|
||||
events:
|
||||
- name: transfer
|
||||
- name: Transfer
|
||||
parameters:
|
||||
- name: from
|
||||
type: ByteString
|
||||
|
|
|
@ -34,6 +34,9 @@ type Options struct {
|
|||
// The name of the output for contract manifest file.
|
||||
ManifestFile string
|
||||
|
||||
// Name is contract's name to be written to manifest.
|
||||
Name string
|
||||
|
||||
// Runtime notifications.
|
||||
ContractEvents []manifest.Event
|
||||
|
||||
|
@ -207,7 +210,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
|
|||
}
|
||||
|
||||
if o.ManifestFile != "" {
|
||||
m, err := di.ConvertToManifest(o.ContractEvents, o.ContractSupportedStandards...)
|
||||
m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...)
|
||||
if err != nil {
|
||||
return b, fmt.Errorf("failed to convert debug info to manifest: %w", err)
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) {
|
|||
|
||||
// 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.
|
||||
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 == "" {
|
||||
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 {
|
||||
result.SupportedStandards = supportedStandards
|
||||
}
|
||||
|
|
|
@ -149,10 +149,11 @@ func _deploy(isUpdate bool) {}
|
|||
}
|
||||
|
||||
t.Run("convert to Manifest", func(t *testing.T) {
|
||||
actual, err := d.ConvertToManifest(nil)
|
||||
actual, err := d.ConvertToManifest("MyCTR", nil)
|
||||
require.NoError(t, err)
|
||||
// note: offsets are hard to predict, so we just take them from the output
|
||||
expected := &manifest.Manifest{
|
||||
Name: "MyCTR",
|
||||
ABI: manifest.ABI{
|
||||
Hash: hash.Hash160(buf),
|
||||
Methods: []manifest.Method{
|
||||
|
|
|
@ -101,7 +101,7 @@ func TestAppCall(t *testing.T) {
|
|||
|
||||
inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner))
|
||||
require.NoError(t, err)
|
||||
m, err := di.ConvertToManifest(nil)
|
||||
m, err := di.ConvertToManifest("Foo", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
ih := hash.Hash160(inner)
|
||||
|
|
|
@ -54,10 +54,10 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
|
|||
// Transfer funds to new validator.
|
||||
w := io.NewBufBinWriter()
|
||||
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.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)
|
||||
require.NoError(t, w.Err)
|
||||
|
||||
|
|
|
@ -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) {
|
||||
if note.Name != "transfer" && note.Name != "Transfer" {
|
||||
if note.Name != "Transfer" {
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
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 {
|
||||
|
@ -801,7 +801,7 @@ func parseUint160(addr []byte) 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)
|
||||
fromAddr := parseUint160(from)
|
||||
var id int32
|
||||
|
@ -815,7 +815,7 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
}
|
||||
id = assetContract.ID
|
||||
}
|
||||
transfer := &state.NEP5Transfer{
|
||||
transfer := &state.NEP17Transfer{
|
||||
Asset: id,
|
||||
From: fromAddr,
|
||||
To: toAddr,
|
||||
|
@ -824,7 +824,7 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
Tx: h,
|
||||
}
|
||||
if !fromAddr.Equals(util.Uint160{}) {
|
||||
balances, err := cache.GetNEP5Balances(fromAddr)
|
||||
balances, err := cache.GetNEP17Balances(fromAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -833,19 +833,19 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
bs.LastUpdatedBlock = b.Index
|
||||
balances.Trackers[id] = bs
|
||||
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 {
|
||||
return
|
||||
}
|
||||
if isBig {
|
||||
balances.NextTransferBatch++
|
||||
}
|
||||
if err := cache.PutNEP5Balances(fromAddr, balances); err != nil {
|
||||
if err := cache.PutNEP17Balances(fromAddr, balances); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if !toAddr.Equals(util.Uint160{}) {
|
||||
balances, err := cache.GetNEP5Balances(toAddr)
|
||||
balances, err := cache.GetNEP17Balances(toAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -855,27 +855,27 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
balances.Trackers[id] = bs
|
||||
|
||||
transfer.Amount = *amount
|
||||
isBig, err := cache.AppendNEP5Transfer(toAddr, balances.NextTransferBatch, transfer)
|
||||
isBig, err := cache.AppendNEP17Transfer(toAddr, balances.NextTransferBatch, transfer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if isBig {
|
||||
balances.NextTransferBatch++
|
||||
}
|
||||
if err := cache.PutNEP5Balances(toAddr, balances); err != nil {
|
||||
if err := cache.PutNEP17Balances(toAddr, balances); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ForEachNEP5Transfer executes f for each nep5 transfer in log.
|
||||
func (bc *Blockchain) ForEachNEP5Transfer(acc util.Uint160, f func(*state.NEP5Transfer) (bool, error)) error {
|
||||
balances, err := bc.dao.GetNEP5Balances(acc)
|
||||
// ForEachNEP17Transfer executes f for each nep17 transfer in log.
|
||||
func (bc *Blockchain) ForEachNEP17Transfer(acc util.Uint160, f func(*state.NEP17Transfer) (bool, error)) error {
|
||||
balances, err := bc.dao.GetNEP17Balances(acc)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
|
@ -890,9 +890,9 @@ func (bc *Blockchain) ForEachNEP5Transfer(acc util.Uint160, f func(*state.NEP5Tr
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetNEP5Balances returns NEP5 balances for the acc.
|
||||
func (bc *Blockchain) GetNEP5Balances(acc util.Uint160) *state.NEP5Balances {
|
||||
bs, err := bc.dao.GetNEP5Balances(acc)
|
||||
// GetNEP17Balances returns NEP17 balances for the acc.
|
||||
func (bc *Blockchain) GetNEP17Balances(acc util.Uint160) *state.NEP17Balances {
|
||||
bs, err := bc.dao.GetNEP17Balances(acc)
|
||||
if err != 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.
|
||||
func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
|
||||
bs, err := bc.dao.GetNEP5Balances(acc)
|
||||
bs, err := bc.dao.GetNEP17Balances(acc)
|
||||
if err != nil {
|
||||
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
|
||||
// of the last balance change for the account.
|
||||
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 {
|
||||
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.
|
||||
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.MPT = nil
|
||||
systemInterop := bc.newInteropContext(trigger.Application, d, nil, tx)
|
||||
systemInterop := bc.newInteropContext(trigger.Application, d, b, tx)
|
||||
vm := systemInterop.SpawnVM()
|
||||
vm.SetPriceGetter(getPrice)
|
||||
return vm
|
||||
|
|
|
@ -129,7 +129,7 @@ func TestAddBlockStateRoot(t *testing.T) {
|
|||
sr, err := bc.GetStateRoot(bc.BlockHeight())
|
||||
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
|
||||
addSigners(tx)
|
||||
require.NoError(t, signTx(bc, tx))
|
||||
|
@ -265,12 +265,12 @@ func TestVerifyTx(t *testing.T) {
|
|||
amount = 1_000_000_000
|
||||
}
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer",
|
||||
neoOwner, a.Contract.ScriptHash(), amount)
|
||||
neoOwner, a.Contract.ScriptHash(), amount, nil)
|
||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
||||
}
|
||||
}
|
||||
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)
|
||||
require.NoError(t, w.Err)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ type Blockchainer interface {
|
|||
GetContractScriptHash(id int32) (util.Uint160, error)
|
||||
GetEnrollments() ([]state.Validator, error)
|
||||
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
|
||||
GetHeader(hash util.Uint256) (*block.Header, error)
|
||||
CurrentHeaderHash() util.Uint256
|
||||
|
@ -42,7 +42,7 @@ type Blockchainer interface {
|
|||
GetAppExecResults(util.Uint256, trigger.Type) ([]state.AppExecResult, error)
|
||||
GetNativeContractScriptHash(string) (util.Uint160, error)
|
||||
GetNextBlockValidators() ([]*keys.PublicKey, error)
|
||||
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
||||
GetNEP17Balances(util.Uint160) *state.NEP17Balances
|
||||
GetValidators() ([]*keys.PublicKey, error)
|
||||
GetStandByCommittee() keys.PublicKeys
|
||||
GetStandByValidators() keys.PublicKeys
|
||||
|
@ -50,7 +50,7 @@ type Blockchainer interface {
|
|||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||
GetStorageItem(id int32, key []byte) *state.StorageItem
|
||||
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)
|
||||
mempool.Feer // fee interface
|
||||
GetMaxBlockSize() uint32
|
||||
|
|
|
@ -14,17 +14,17 @@ import (
|
|||
type Cached struct {
|
||||
DAO
|
||||
contracts map[util.Uint160]*state.Contract
|
||||
balances map[util.Uint160]*state.NEP5Balances
|
||||
transfers map[util.Uint160]map[uint32]*state.NEP5TransferLog
|
||||
balances map[util.Uint160]*state.NEP17Balances
|
||||
transfers map[util.Uint160]map[uint32]*state.NEP17TransferLog
|
||||
|
||||
dropNEP5Cache bool
|
||||
dropNEP17Cache bool
|
||||
}
|
||||
|
||||
// NewCached returns new Cached wrapping around given backing store.
|
||||
func NewCached(d DAO) *Cached {
|
||||
ctrs := make(map[util.Uint160]*state.Contract)
|
||||
balances := make(map[util.Uint160]*state.NEP5Balances)
|
||||
transfers := make(map[util.Uint160]map[uint32]*state.NEP5TransferLog)
|
||||
balances := make(map[util.Uint160]*state.NEP17Balances)
|
||||
transfers := make(map[util.Uint160]map[uint32]*state.NEP17TransferLog)
|
||||
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)
|
||||
}
|
||||
|
||||
// GetNEP5Balances retrieves NEP5Balances for the acc.
|
||||
func (cd *Cached) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) {
|
||||
// GetNEP17Balances retrieves NEP17Balances for the acc.
|
||||
func (cd *Cached) GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error) {
|
||||
if bs := cd.balances[acc]; bs != nil {
|
||||
return bs, nil
|
||||
}
|
||||
return cd.DAO.GetNEP5Balances(acc)
|
||||
return cd.DAO.GetNEP17Balances(acc)
|
||||
}
|
||||
|
||||
// PutNEP5Balances saves NEP5Balances for the acc.
|
||||
func (cd *Cached) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error {
|
||||
// PutNEP17Balances saves NEP17Balances for the acc.
|
||||
func (cd *Cached) PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error {
|
||||
cd.balances[acc] = bs
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNEP5TransferLog retrieves NEP5TransferLog for the acc.
|
||||
func (cd *Cached) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) {
|
||||
// GetNEP17TransferLog retrieves NEP17TransferLog for the acc.
|
||||
func (cd *Cached) GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error) {
|
||||
ts := cd.transfers[acc]
|
||||
if ts != nil && 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.
|
||||
func (cd *Cached) PutNEP5TransferLog(acc util.Uint160, index uint32, bs *state.NEP5TransferLog) error {
|
||||
// PutNEP17TransferLog saves NEP17TransferLog for the acc.
|
||||
func (cd *Cached) PutNEP17TransferLog(acc util.Uint160, index uint32, bs *state.NEP17TransferLog) error {
|
||||
ts := cd.transfers[acc]
|
||||
if ts == nil {
|
||||
ts = make(map[uint32]*state.NEP5TransferLog, 2)
|
||||
ts = make(map[uint32]*state.NEP17TransferLog, 2)
|
||||
cd.transfers[acc] = ts
|
||||
}
|
||||
ts[index] = bs
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendNEP5Transfer appends new transfer to a transfer event log.
|
||||
func (cd *Cached) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error) {
|
||||
lg, err := cd.GetNEP5TransferLog(acc, index)
|
||||
// AppendNEP17Transfer appends new transfer to a transfer event log.
|
||||
func (cd *Cached) AppendNEP17Transfer(acc util.Uint160, index uint32, tr *state.NEP17Transfer) (bool, error) {
|
||||
lg, err := cd.GetNEP17TransferLog(acc, index)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := lg.Append(tr); err != nil {
|
||||
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
|
||||
|
@ -107,8 +107,8 @@ func (cd *Cached) Persist() (int, error) {
|
|||
// usage scenario it should be good enough if cd doesn't modify object
|
||||
// caches (accounts/contracts/etc) in any way.
|
||||
if ok {
|
||||
if cd.dropNEP5Cache {
|
||||
lowerCache.balances = make(map[util.Uint160]*state.NEP5Balances)
|
||||
if cd.dropNEP17Cache {
|
||||
lowerCache.balances = make(map[util.Uint160]*state.NEP17Balances)
|
||||
}
|
||||
var simpleCache *Simple
|
||||
for simpleCache == nil {
|
||||
|
@ -125,7 +125,7 @@ func (cd *Cached) Persist() (int, error) {
|
|||
buf := io.NewBufBinWriter()
|
||||
|
||||
for acc, bs := range cd.balances {
|
||||
err := cd.DAO.putNEP5Balances(acc, bs, buf)
|
||||
err := cd.DAO.putNEP17Balances(acc, bs, buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ func (cd *Cached) Persist() (int, error) {
|
|||
}
|
||||
for acc, ts := range cd.transfers {
|
||||
for ind, lg := range ts {
|
||||
err := cd.DAO.PutNEP5TransferLog(acc, ind, lg)
|
||||
err := cd.DAO.PutNEP17TransferLog(acc, ind, lg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestCachedDaoContracts(t *testing.T) {
|
|||
_, err := dao.GetContractState(sh)
|
||||
require.NotNil(t, err)
|
||||
|
||||
m := manifest.NewManifest(hash.Hash160(script))
|
||||
m := manifest.NewManifest(hash.Hash160(script), "Test")
|
||||
|
||||
cs := &state.Contract{
|
||||
ID: 123,
|
||||
|
|
|
@ -31,7 +31,7 @@ var (
|
|||
// DAO is a data access object.
|
||||
type DAO interface {
|
||||
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
|
||||
DeleteStorageItem(id int32, 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)
|
||||
GetCurrentStateRootHeight() (uint32, error)
|
||||
GetHeaderHashes() ([]util.Uint256, error)
|
||||
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
|
||||
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
|
||||
GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error)
|
||||
GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error)
|
||||
GetAndUpdateNextContractID() (int32, error)
|
||||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||
PutStateRoot(root *state.MPTRootState) error
|
||||
|
@ -60,15 +60,15 @@ type DAO interface {
|
|||
PutAppExecResult(aer *state.AppExecResult, buf *io.BufBinWriter) error
|
||||
PutContractState(cs *state.Contract) error
|
||||
PutCurrentHeader(hashAndIndex []byte) error
|
||||
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
|
||||
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
|
||||
PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error
|
||||
PutNEP17TransferLog(acc util.Uint160, index uint32, lg *state.NEP17TransferLog) error
|
||||
PutStorageItem(id int32, key []byte, si *state.StorageItem) error
|
||||
PutVersion(v string) error
|
||||
Seek(id int32, prefix []byte, f func(k, v []byte))
|
||||
StoreAsBlock(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
|
||||
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.
|
||||
|
@ -197,12 +197,12 @@ func (dao *Simple) GetContractScriptHash(id int32) (util.Uint160, error) {
|
|||
|
||||
// -- end contracts.
|
||||
|
||||
// -- start nep5 balances.
|
||||
// -- start nep17 balances.
|
||||
|
||||
// GetNEP5Balances retrieves nep5 balances from the cache.
|
||||
func (dao *Simple) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) {
|
||||
key := storage.AppendPrefix(storage.STNEP5Balances, acc.BytesBE())
|
||||
bs := state.NewNEP5Balances()
|
||||
// GetNEP17Balances retrieves nep17 balances from the cache.
|
||||
func (dao *Simple) GetNEP17Balances(acc util.Uint160) (*state.NEP17Balances, error) {
|
||||
key := storage.AppendPrefix(storage.STNEP17Balances, acc.BytesBE())
|
||||
bs := state.NewNEP17Balances()
|
||||
err := dao.GetAndDecode(bs, key)
|
||||
if err != nil && err != storage.ErrKeyNotFound {
|
||||
return nil, err
|
||||
|
@ -210,61 +210,61 @@ func (dao *Simple) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error
|
|||
return bs, nil
|
||||
}
|
||||
|
||||
// PutNEP5Balances saves nep5 balances from the cache.
|
||||
func (dao *Simple) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error {
|
||||
return dao.putNEP5Balances(acc, bs, io.NewBufBinWriter())
|
||||
// PutNEP17Balances saves nep17 balances from the cache.
|
||||
func (dao *Simple) PutNEP17Balances(acc util.Uint160, bs *state.NEP17Balances) error {
|
||||
return dao.putNEP17Balances(acc, bs, io.NewBufBinWriter())
|
||||
}
|
||||
|
||||
func (dao *Simple) putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf *io.BufBinWriter) error {
|
||||
key := storage.AppendPrefix(storage.STNEP5Balances, acc.BytesBE())
|
||||
func (dao *Simple) putNEP17Balances(acc util.Uint160, bs *state.NEP17Balances, buf *io.BufBinWriter) error {
|
||||
key := storage.AppendPrefix(storage.STNEP17Balances, acc.BytesBE())
|
||||
return dao.putWithBuffer(bs, key, buf)
|
||||
}
|
||||
|
||||
// -- end nep5 balances.
|
||||
// -- end nep17 balances.
|
||||
|
||||
// -- 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[0] = byte(storage.STNEP5Transfers)
|
||||
key[0] = byte(storage.STNEP17Transfers)
|
||||
copy(key[1:], acc.BytesBE())
|
||||
binary.LittleEndian.PutUint32(key[util.Uint160Size:], index)
|
||||
return key
|
||||
}
|
||||
|
||||
// GetNEP5TransferLog retrieves transfer log from the cache.
|
||||
func (dao *Simple) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) {
|
||||
key := getNEP5TransferLogKey(acc, index)
|
||||
// GetNEP17TransferLog retrieves transfer log from the cache.
|
||||
func (dao *Simple) GetNEP17TransferLog(acc util.Uint160, index uint32) (*state.NEP17TransferLog, error) {
|
||||
key := getNEP17TransferLogKey(acc, index)
|
||||
value, err := dao.Store.Get(key)
|
||||
if err != nil {
|
||||
if err == storage.ErrKeyNotFound {
|
||||
return new(state.NEP5TransferLog), nil
|
||||
return new(state.NEP17TransferLog), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &state.NEP5TransferLog{Raw: value}, nil
|
||||
return &state.NEP17TransferLog{Raw: value}, nil
|
||||
}
|
||||
|
||||
// PutNEP5TransferLog saves given transfer log in the cache.
|
||||
func (dao *Simple) PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error {
|
||||
key := getNEP5TransferLogKey(acc, index)
|
||||
// PutNEP17TransferLog saves given transfer log in the cache.
|
||||
func (dao *Simple) PutNEP17TransferLog(acc util.Uint160, index uint32, lg *state.NEP17TransferLog) error {
|
||||
key := getNEP17TransferLogKey(acc, index)
|
||||
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.
|
||||
func (dao *Simple) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.NEP5Transfer) (bool, error) {
|
||||
lg, err := dao.GetNEP5TransferLog(acc, index)
|
||||
func (dao *Simple) AppendNEP17Transfer(acc util.Uint160, index uint32, tr *state.NEP17Transfer) (bool, error) {
|
||||
lg, err := dao.GetNEP17TransferLog(acc, index)
|
||||
if err != nil {
|
||||
if err != storage.ErrKeyNotFound {
|
||||
return false, err
|
||||
}
|
||||
lg = new(state.NEP5TransferLog)
|
||||
lg = new(state.NEP17TransferLog)
|
||||
}
|
||||
if err := lg.Append(tr); err != nil {
|
||||
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.
|
||||
|
|
|
@ -201,7 +201,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
|
||||
require.Equal(t, big.NewInt(5000_0000), bc.GetUtilityTokenBalance(priv0ScriptHash)) // gas bounty
|
||||
// Move some NEO to one simple account.
|
||||
txMoveNeo := newNEP5Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
|
||||
txMoveNeo := newNEP17Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
|
||||
txMoveNeo.ValidUntilBlock = validUntilBlock
|
||||
txMoveNeo.Nonce = getNextNonce()
|
||||
txMoveNeo.Signers = []transaction.Signer{{
|
||||
|
@ -212,7 +212,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
}}
|
||||
require.NoError(t, signTx(bc, txMoveNeo))
|
||||
// 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.Nonce = getNextNonce()
|
||||
txMoveGas.Signers = []transaction.Signer{{
|
||||
|
@ -244,7 +244,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// 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.ValidUntilBlock = validUntilBlock
|
||||
txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
|
||||
|
@ -270,7 +270,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
t.Logf("txInv: %s", txInv.Hash().StringLE())
|
||||
|
||||
priv1 := testchain.PrivateKeyByID(1)
|
||||
txNeo0to1 := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
|
||||
txNeo0to1 := newNEP17Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
|
||||
txNeo0to1.Nonce = getNextNonce()
|
||||
txNeo0to1.ValidUntilBlock = validUntilBlock
|
||||
txNeo0to1.Signers = []transaction.Signer{
|
||||
|
@ -295,7 +295,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
|
||||
require.NoError(t, addNetworkFee(bc, initTx, acc0))
|
||||
require.NoError(t, acc0.SignTx(initTx))
|
||||
transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000)
|
||||
transferTx := newNEP17Transfer(sh, sh, priv0.GetScriptHash(), 1000)
|
||||
transferTx.Nonce = getNextNonce()
|
||||
transferTx.ValidUntilBlock = validUntilBlock
|
||||
transferTx.Signers = []transaction.Signer{
|
||||
|
@ -313,7 +313,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
require.NoError(t, bc.AddBlock(b))
|
||||
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.ValidUntilBlock = validUntilBlock
|
||||
transferTx.Signers = []transaction.Signer{
|
||||
|
@ -332,7 +332,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
t.Logf("sendRublesTx: %v", transferTx.Hash().StringLE())
|
||||
|
||||
// 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.ValidUntilBlock = validUntilBlock
|
||||
txDeploy2.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
|
||||
|
@ -364,7 +364,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
}
|
||||
|
||||
// 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.Nonce = getNextNonce()
|
||||
txSendRaw.Signers = []transaction.Signer{{
|
||||
|
@ -380,16 +380,16 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
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()
|
||||
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)
|
||||
|
||||
script := w.Bytes()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
|
||||
script := io.NewBufBinWriter()
|
||||
m, err := di.ConvertToManifest(nil)
|
||||
m, err := di.ConvertToManifest(ctrName, nil)
|
||||
require.NoError(t, err)
|
||||
bs, err := json.Marshal(m)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -114,7 +114,7 @@ func NewContractMD(name string) *ContractMD {
|
|||
|
||||
c.Script = w.Bytes()
|
||||
c.Hash = hash.Hash160(c.Script)
|
||||
c.Manifest = *manifest.DefaultManifest(c.Hash)
|
||||
c.Manifest = *manifest.DefaultManifest(c.Hash, name)
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
script := []byte("testscript")
|
||||
m := manifest.NewManifest(hash.Hash160(script))
|
||||
m := manifest.NewManifest(hash.Hash160(script), "Test")
|
||||
contractState := &state.Contract{
|
||||
Script: script,
|
||||
Manifest: *m,
|
||||
|
|
|
@ -299,16 +299,7 @@ func runtimeLog(ic *interop.Context) error {
|
|||
// runtimeGetTime returns timestamp of the block being verified, or the latest
|
||||
// one in the blockchain if no block is given to Context.
|
||||
func runtimeGetTime(ic *interop.Context) error {
|
||||
var header *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()
|
||||
}
|
||||
header := ic.Block.Header()
|
||||
ic.VM.Estack().PushVal(header.Timestamp)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -408,10 +408,17 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
emit.String(w.BinWriter, "initial")
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
|
||||
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()
|
||||
h := hash.Hash160(script)
|
||||
m := manifest.NewManifest(h)
|
||||
m := manifest.NewManifest(h, "TestMain")
|
||||
m.ABI.Methods = []manifest.Method{
|
||||
{
|
||||
Name: "add",
|
||||
|
@ -454,7 +461,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
{
|
||||
Name: "justReturn",
|
||||
Offset: justRetOff,
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
ReturnType: smartcontract.VoidType,
|
||||
},
|
||||
{
|
||||
Name: manifest.MethodVerify,
|
||||
|
@ -482,6 +489,16 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
},
|
||||
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{
|
||||
Script: script,
|
||||
|
@ -490,7 +507,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
}
|
||||
|
||||
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.Methods.Add("add")
|
||||
perm.Methods.Add("drop")
|
||||
|
|
|
@ -62,9 +62,10 @@ func Call(ic *interop.Context) error {
|
|||
if !ic.VM.AddGas(m.Price) {
|
||||
return errors.New("gas limit exceeded")
|
||||
}
|
||||
ctx := ic.VM.Context()
|
||||
result := m.Func(ic, args)
|
||||
if m.MD.ReturnType != smartcontract.VoidType {
|
||||
ic.VM.Estack().PushVal(result)
|
||||
ctx.Estack().PushVal(result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
// GAS represents GAS native contract.
|
||||
type GAS struct {
|
||||
nep5TokenNative
|
||||
nep17TokenNative
|
||||
NEO *NEO
|
||||
}
|
||||
|
||||
|
@ -27,15 +27,15 @@ const initialGAS = 30000000
|
|||
// newGAS returns GAS native contract.
|
||||
func newGAS() *GAS {
|
||||
g := &GAS{}
|
||||
nep5 := newNEP5Native(gasName)
|
||||
nep5.symbol = "gas"
|
||||
nep5.decimals = 8
|
||||
nep5.factor = GASFactor
|
||||
nep5.onPersist = chainOnPersist(nep5.OnPersist, g.OnPersist)
|
||||
nep5.incBalance = g.increaseBalance
|
||||
nep5.ContractID = gasContractID
|
||||
nep17 := newNEP17Native(gasName)
|
||||
nep17.symbol = "gas"
|
||||
nep17.decimals = 8
|
||||
nep17.factor = GASFactor
|
||||
nep17.onPersist = chainOnPersist(nep17.OnPersist, g.OnPersist)
|
||||
nep17.incBalance = g.increaseBalance
|
||||
nep17.ContractID = gasContractID
|
||||
|
||||
g.nep5TokenNative = *nep5
|
||||
g.nep17TokenNative = *nep17
|
||||
|
||||
onp := g.Methods["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 {
|
||||
acc, err := state.NEP5BalanceStateFromBytes(si.Value)
|
||||
acc, err := state.NEP17BalanceStateFromBytes(si.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.Stor
|
|||
|
||||
// Initialize initializes GAS contract.
|
||||
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
|
||||
}
|
||||
if g.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
||||
if g.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
h, err := getStandbyValidatorsHash(ic)
|
||||
|
|
|
@ -28,7 +28,7 @@ import (
|
|||
|
||||
// NEO represents NEO native contract.
|
||||
type NEO struct {
|
||||
nep5TokenNative
|
||||
nep17TokenNative
|
||||
GAS *GAS
|
||||
|
||||
// gasPerBlock represents current value of generated gas per block.
|
||||
|
@ -93,16 +93,16 @@ func makeValidatorKey(key *keys.PublicKey) []byte {
|
|||
// newNEO returns NEO native contract.
|
||||
func newNEO() *NEO {
|
||||
n := &NEO{}
|
||||
nep5 := newNEP5Native(neoName)
|
||||
nep5.symbol = "neo"
|
||||
nep5.decimals = 0
|
||||
nep5.factor = 1
|
||||
nep5.onPersist = chainOnPersist(nep5.OnPersist, n.OnPersist)
|
||||
nep5.postPersist = chainOnPersist(nep5.postPersist, n.PostPersist)
|
||||
nep5.incBalance = n.increaseBalance
|
||||
nep5.ContractID = neoContractID
|
||||
nep17 := newNEP17Native(neoName)
|
||||
nep17.symbol = "neo"
|
||||
nep17.decimals = 0
|
||||
nep17.factor = 1
|
||||
nep17.onPersist = chainOnPersist(nep17.OnPersist, n.OnPersist)
|
||||
nep17.postPersist = chainOnPersist(nep17.postPersist, n.PostPersist)
|
||||
nep17.incBalance = n.increaseBalance
|
||||
nep17.ContractID = neoContractID
|
||||
|
||||
n.nep5TokenNative = *nep5
|
||||
n.nep17TokenNative = *nep17
|
||||
n.votesChanged.Store(true)
|
||||
n.nextValidators.Store(keys.PublicKeys(nil))
|
||||
n.validators.Store(keys.PublicKeys(nil))
|
||||
|
@ -165,11 +165,11 @@ func newNEO() *NEO {
|
|||
|
||||
// Initialize initializes NEO contract.
|
||||
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
|
||||
}
|
||||
|
||||
if n.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
||||
if n.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"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/contract"
|
||||
"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/encoding/bigint"
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
"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/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
|
@ -28,8 +30,8 @@ func makeAccountKey(h util.Uint160) []byte {
|
|||
return k
|
||||
}
|
||||
|
||||
// nep5TokenNative represents NEP-5 token contract.
|
||||
type nep5TokenNative struct {
|
||||
// nep17TokenNative represents NEP-17 token contract.
|
||||
type nep17TokenNative struct {
|
||||
interop.ContractMD
|
||||
symbol string
|
||||
decimals int64
|
||||
|
@ -42,15 +44,15 @@ type nep5TokenNative struct {
|
|||
// totalSupplyKey is the key used to store totalSupply value.
|
||||
var totalSupplyKey = []byte{11}
|
||||
|
||||
func (c *nep5TokenNative) Metadata() *interop.ContractMD {
|
||||
func (c *nep17TokenNative) Metadata() *interop.ContractMD {
|
||||
return &c.ContractMD
|
||||
}
|
||||
|
||||
var _ interop.Contract = (*nep5TokenNative)(nil)
|
||||
var _ interop.Contract = (*nep17TokenNative)(nil)
|
||||
|
||||
func newNEP5Native(name string) *nep5TokenNative {
|
||||
n := &nep5TokenNative{ContractMD: *interop.NewContractMD(name)}
|
||||
n.Manifest.SupportedStandards = []string{manifest.NEP5StandardName}
|
||||
func newNEP17Native(name string) *nep17TokenNative {
|
||||
n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name)}
|
||||
n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName}
|
||||
|
||||
desc := newDescriptor("name", smartcontract.StringType)
|
||||
md := newMethodAndPrice(nameMethod(name), 0, smartcontract.NoneFlag)
|
||||
|
@ -77,6 +79,7 @@ func newNEP5Native(name string) *nep5TokenNative {
|
|||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("to", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
)
|
||||
md = newMethodAndPrice(n.Transfer, 8000000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
|
@ -94,23 +97,23 @@ func newNEP5Native(name string) *nep5TokenNative {
|
|||
return n
|
||||
}
|
||||
|
||||
func (c *nep5TokenNative) Initialize(_ *interop.Context) error {
|
||||
func (c *nep17TokenNative) Initialize(_ *interop.Context) error {
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int {
|
||||
func (c *nep17TokenNative) getTotalSupply(d dao.DAO) *big.Int {
|
||||
si := d.GetStorageItem(c.ContractID, totalSupplyKey)
|
||||
if si == nil {
|
||||
return big.NewInt(0)
|
||||
|
@ -118,16 +121,16 @@ func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int {
|
|||
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)}
|
||||
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])
|
||||
to := toUint160(args[1])
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -138,7 +141,31 @@ func addrToStackItem(u *util.Uint160) stackitem.Item {
|
|||
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{
|
||||
ScriptHash: c.Hash,
|
||||
Name: "Transfer",
|
||||
|
@ -151,7 +178,7 @@ func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint1
|
|||
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)
|
||||
si := ic.DAO.GetStorageItem(c.ContractID, key)
|
||||
if si == nil {
|
||||
|
@ -174,7 +201,7 @@ func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160
|
|||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
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])
|
||||
bs, err := ic.DAO.GetNEP5Balances(h)
|
||||
bs, err := ic.DAO.GetNEP17Balances(h)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -219,23 +246,23 @@ func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item)
|
|||
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 {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
return errors.New("onPersist must be triggerred by system")
|
||||
}
|
|
@ -125,6 +125,13 @@ func newOracle() *Oracle {
|
|||
md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag)
|
||||
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)
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
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()) {
|
||||
return ErrNotEnoughGas
|
||||
}
|
||||
callingHash := ic.VM.GetCallingScriptHash()
|
||||
o.GAS.mint(ic, o.Hash, gas)
|
||||
si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID)
|
||||
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(),
|
||||
URL: url,
|
||||
Filter: filter,
|
||||
CallbackContract: ic.VM.GetCallingScriptHash(),
|
||||
CallbackContract: callingHash,
|
||||
CallbackMethod: cb,
|
||||
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))
|
||||
}
|
||||
|
||||
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 {
|
||||
for i := range tx.Attributes {
|
||||
if tx.Attributes[i].Type == transaction.OracleResponseT {
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"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/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/smartcontract"
|
||||
"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/vm"
|
||||
"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/stretchr/testify/require"
|
||||
)
|
||||
|
@ -80,30 +78,16 @@ func newTestNative() *testNative {
|
|||
tn.meta.AddMethod(md, desc, true)
|
||||
|
||||
desc = &manifest.Method{
|
||||
Name: "callOtherContractWithoutArgs",
|
||||
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",
|
||||
Name: "callOtherContractNoReturn",
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("contractHash", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("method", smartcontract.StringType),
|
||||
manifest.NewParameter("arg", smartcontract.ArrayType),
|
||||
},
|
||||
ReturnType: smartcontract.AnyType,
|
||||
ReturnType: smartcontract.VoidType,
|
||||
}
|
||||
md = &interop.MethodAndPrice{
|
||||
Func: tn.callOtherContractWithArg,
|
||||
Func: tn.callOtherContractNoReturn,
|
||||
Price: testSumPrice,
|
||||
RequiredFlags: smartcontract.NoneFlag}
|
||||
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))
|
||||
}
|
||||
|
||||
func (tn *testNative) callOtherContractWithoutArgs(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
vm := ic.VM
|
||||
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)
|
||||
func toUint160(item stackitem.Item) util.Uint160 {
|
||||
bs, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return stackitem.NewBigInteger(big.NewInt(-1))
|
||||
panic(err)
|
||||
}
|
||||
_ = vm.Run()
|
||||
if vm.HasFailed() {
|
||||
return stackitem.NewBigInteger(big.NewInt(-2))
|
||||
u, err := util.Uint160DecodeBytesBE(bs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return vm.Estack().Pop().Item()
|
||||
return u
|
||||
}
|
||||
|
||||
func (tn *testNative) callOtherContractWithArg(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
vm := ic.VM
|
||||
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)
|
||||
func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, retState vm.CheckReturnState) {
|
||||
cs, err := ic.DAO.GetContractState(toUint160(args[0]))
|
||||
if err != nil {
|
||||
return stackitem.NewBigInteger(big.NewInt(-1))
|
||||
panic(err)
|
||||
}
|
||||
_ = vm.Run()
|
||||
if vm.HasFailed() {
|
||||
return stackitem.NewBigInteger(big.NewInt(-2))
|
||||
bs, err := args[1].TryBytes()
|
||||
if err != nil {
|
||||
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) {
|
||||
|
@ -265,84 +249,13 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
|
|||
})
|
||||
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()
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithoutArgs", chain.contracts.Policy.Hash, "getFeePerByte")
|
||||
require.NoError(t, w.Err)
|
||||
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")
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractNoReturn",
|
||||
cs.ScriptHash(), "justReturn", []interface{}{})
|
||||
require.NoError(t, w.Err)
|
||||
script := w.Bytes()
|
||||
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, vm.HaltState, res[0].VMState)
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"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/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -76,11 +77,11 @@ func TestNEO_Vote(t *testing.T) {
|
|||
w := io.NewBufBinWriter()
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer",
|
||||
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.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.GAS.Hash, "transfer",
|
||||
neoOwner.BytesBE(), to.BytesBE(),
|
||||
int64(1_000_000_000))
|
||||
int64(1_000_000_000), nil)
|
||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
||||
require.NoError(t, w.Err)
|
||||
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)
|
||||
neoBalance[i], _ = bc.GetGoverningTokenBalance(h)
|
||||
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)
|
||||
require.NoError(t, w.Err)
|
||||
tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0)
|
||||
|
@ -303,3 +304,31 @@ func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
|
|||
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())
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func getOracleContractState(h util.Uint160) *state.Contract {
|
|||
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
|
||||
emit.Opcodes(w.BinWriter, opcode.RET)
|
||||
|
||||
m := manifest.NewManifest(h)
|
||||
m := manifest.NewManifest(h, "TestOracle")
|
||||
m.ABI.Methods = []manifest.Method{
|
||||
{
|
||||
Name: "requestURL",
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestEncodeDecodeContractState(t *testing.T) {
|
|||
script := []byte("testscript")
|
||||
|
||||
h := hash.Hash160(script)
|
||||
m := manifest.NewManifest(h)
|
||||
m := manifest.NewManifest(h, "Test")
|
||||
m.ABI.Methods = []manifest.Method{{
|
||||
Name: "main",
|
||||
Parameters: []manifest.Parameter{
|
||||
|
|
|
@ -9,21 +9,21 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// NEP5BalanceState represents balance state of a NEP5-token.
|
||||
type NEP5BalanceState struct {
|
||||
// NEP17BalanceState represents balance state of a NEP17-token.
|
||||
type NEP17BalanceState struct {
|
||||
Balance big.Int
|
||||
}
|
||||
|
||||
// NEOBalanceState represents balance state of a NEO-token.
|
||||
type NEOBalanceState struct {
|
||||
NEP5BalanceState
|
||||
NEP17BalanceState
|
||||
BalanceHeight uint32
|
||||
VoteTo *keys.PublicKey
|
||||
}
|
||||
|
||||
// NEP5BalanceStateFromBytes converts serialized NEP5BalanceState to structure.
|
||||
func NEP5BalanceStateFromBytes(b []byte) (*NEP5BalanceState, error) {
|
||||
balance := new(NEP5BalanceState)
|
||||
// NEP17BalanceStateFromBytes converts serialized NEP17BalanceState to structure.
|
||||
func NEP17BalanceStateFromBytes(b []byte) (*NEP17BalanceState, error) {
|
||||
balance := new(NEP17BalanceState)
|
||||
if len(b) == 0 {
|
||||
return balance, nil
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ func NEP5BalanceStateFromBytes(b []byte) (*NEP5BalanceState, error) {
|
|||
return balance, nil
|
||||
}
|
||||
|
||||
// Bytes returns serialized NEP5BalanceState.
|
||||
func (s *NEP5BalanceState) Bytes() []byte {
|
||||
// Bytes returns serialized NEP17BalanceState.
|
||||
func (s *NEP17BalanceState) Bytes() []byte {
|
||||
w := io.NewBufBinWriter()
|
||||
s.EncodeBinary(w.BinWriter)
|
||||
if w.Err != nil {
|
||||
|
@ -45,22 +45,22 @@ func (s *NEP5BalanceState) Bytes() []byte {
|
|||
return w.Bytes()
|
||||
}
|
||||
|
||||
func (s *NEP5BalanceState) toStackItem() stackitem.Item {
|
||||
func (s *NEP17BalanceState) toStackItem() stackitem.Item {
|
||||
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)
|
||||
}
|
||||
|
||||
// EncodeBinary implements io.Serializable interface.
|
||||
func (s *NEP5BalanceState) EncodeBinary(w *io.BinWriter) {
|
||||
func (s *NEP17BalanceState) EncodeBinary(w *io.BinWriter) {
|
||||
si := s.toStackItem()
|
||||
stackitem.EncodeBinaryStackItem(si, w)
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (s *NEP5BalanceState) DecodeBinary(r *io.BinReader) {
|
||||
func (s *NEP17BalanceState) DecodeBinary(r *io.BinReader) {
|
||||
si := stackitem.DecodeBinaryStackItem(r)
|
||||
if r.Err != nil {
|
||||
return
|
||||
|
@ -109,7 +109,7 @@ func (s *NEOBalanceState) DecodeBinary(r *io.BinReader) {
|
|||
}
|
||||
|
||||
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))))
|
||||
if s.VoteTo != nil {
|
||||
result.Append(stackitem.NewByteArray(s.VoteTo.Bytes()))
|
||||
|
|
|
@ -8,11 +8,11 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// NEP5TransferBatchSize is the maximum number of entries for NEP5TransferLog.
|
||||
const NEP5TransferBatchSize = 128
|
||||
// NEP17TransferBatchSize is the maximum number of entries for NEP17TransferLog.
|
||||
const NEP17TransferBatchSize = 128
|
||||
|
||||
// NEP5Tracker contains info about a single account in a NEP5 contract.
|
||||
type NEP5Tracker struct {
|
||||
// NEP17Tracker contains info about a single account in a NEP17 contract.
|
||||
type NEP17Tracker struct {
|
||||
// Balance is the current balance of the account.
|
||||
Balance big.Int
|
||||
// LastUpdatedBlock is a number of block when last `transfer` to or from the
|
||||
|
@ -20,14 +20,14 @@ type NEP5Tracker struct {
|
|||
LastUpdatedBlock uint32
|
||||
}
|
||||
|
||||
// NEP5TransferLog is a log of NEP5 token transfers for the specific command.
|
||||
type NEP5TransferLog struct {
|
||||
// NEP17TransferLog is a log of NEP17 token transfers for the specific command.
|
||||
type NEP17TransferLog struct {
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
// NEP5Transfer represents a single NEP5 Transfer event.
|
||||
type NEP5Transfer struct {
|
||||
// Asset is a NEP5 contract ID.
|
||||
// NEP17Transfer represents a single NEP17 Transfer event.
|
||||
type NEP17Transfer struct {
|
||||
// Asset is a NEP17 contract ID.
|
||||
Asset int32
|
||||
// Address is the address of the sender.
|
||||
From util.Uint160
|
||||
|
@ -44,29 +44,29 @@ type NEP5Transfer struct {
|
|||
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.
|
||||
type NEP5Balances struct {
|
||||
Trackers map[int32]NEP5Tracker
|
||||
type NEP17Balances struct {
|
||||
Trackers map[int32]NEP17Tracker
|
||||
// NextTransferBatch stores an index of the next transfer batch.
|
||||
NextTransferBatch uint32
|
||||
}
|
||||
|
||||
// NewNEP5Balances returns new NEP5Balances.
|
||||
func NewNEP5Balances() *NEP5Balances {
|
||||
return &NEP5Balances{
|
||||
Trackers: make(map[int32]NEP5Tracker),
|
||||
// NewNEP17Balances returns new NEP17Balances.
|
||||
func NewNEP17Balances() *NEP17Balances {
|
||||
return &NEP17Balances{
|
||||
Trackers: make(map[int32]NEP17Tracker),
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (bs *NEP5Balances) DecodeBinary(r *io.BinReader) {
|
||||
func (bs *NEP17Balances) DecodeBinary(r *io.BinReader) {
|
||||
bs.NextTransferBatch = r.ReadU32LE()
|
||||
lenBalances := r.ReadVarUint()
|
||||
m := make(map[int32]NEP5Tracker, lenBalances)
|
||||
m := make(map[int32]NEP17Tracker, lenBalances)
|
||||
for i := 0; i < int(lenBalances); i++ {
|
||||
key := int32(r.ReadU32LE())
|
||||
var tr NEP5Tracker
|
||||
var tr NEP17Tracker
|
||||
tr.DecodeBinary(r)
|
||||
m[key] = tr
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func (bs *NEP5Balances) DecodeBinary(r *io.BinReader) {
|
|||
}
|
||||
|
||||
// EncodeBinary implements io.Serializable interface.
|
||||
func (bs *NEP5Balances) EncodeBinary(w *io.BinWriter) {
|
||||
func (bs *NEP17Balances) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteU32LE(bs.NextTransferBatch)
|
||||
w.WriteVarUint(uint64(len(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.
|
||||
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
|
||||
func (lg *NEP17TransferLog) Append(tr *NEP17Transfer) error {
|
||||
w := io.NewBufBinWriter()
|
||||
// The first entry, set up counter.
|
||||
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.
|
||||
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 {
|
||||
return true, nil
|
||||
}
|
||||
transfers := make([]NEP5Transfer, lg.Size())
|
||||
transfers := make([]NEP17Transfer, lg.Size())
|
||||
r := io.NewBinReaderFromBuf(lg.Raw[1:])
|
||||
for i := 0; i < lg.Size(); i++ {
|
||||
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.
|
||||
func (lg *NEP5TransferLog) Size() int {
|
||||
func (lg *NEP17TransferLog) Size() int {
|
||||
if len(lg.Raw) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -135,19 +135,19 @@ func (lg *NEP5TransferLog) Size() int {
|
|||
}
|
||||
|
||||
// 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.WriteU32LE(t.LastUpdatedBlock)
|
||||
}
|
||||
|
||||
// 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.LastUpdatedBlock = r.ReadU32LE()
|
||||
}
|
||||
|
||||
// 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.WriteBytes(t.Tx[:])
|
||||
w.WriteBytes(t.From[:])
|
||||
|
@ -159,7 +159,7 @@ func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) {
|
|||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (t *NEP5Transfer) DecodeBinary(r *io.BinReader) {
|
||||
func (t *NEP17Transfer) DecodeBinary(r *io.BinReader) {
|
||||
t.Asset = int32(r.ReadU32LE())
|
||||
r.ReadBytes(t.Tx[:])
|
||||
r.ReadBytes(t.From[:])
|
|
@ -12,16 +12,16 @@ import (
|
|||
"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()))
|
||||
expected := []*NEP5Transfer{
|
||||
expected := []*NEP17Transfer{
|
||||
randomTransfer(r),
|
||||
randomTransfer(r),
|
||||
randomTransfer(r),
|
||||
randomTransfer(r),
|
||||
}
|
||||
|
||||
lg := new(NEP5TransferLog)
|
||||
lg := new(NEP17TransferLog)
|
||||
for _, tr := range expected {
|
||||
require.NoError(t, lg.Append(tr))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ func TestNEP5TransferLog_Append(t *testing.T) {
|
|||
require.Equal(t, len(expected), lg.Size())
|
||||
|
||||
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)
|
||||
i--
|
||||
return true, nil
|
||||
|
@ -38,17 +38,17 @@ func TestNEP5TransferLog_Append(t *testing.T) {
|
|||
require.True(t, cont)
|
||||
}
|
||||
|
||||
func TestNEP5Tracker_EncodeBinary(t *testing.T) {
|
||||
expected := &NEP5Tracker{
|
||||
func TestNEP17Tracker_EncodeBinary(t *testing.T) {
|
||||
expected := &NEP17Tracker{
|
||||
Balance: *big.NewInt(int64(rand.Uint64())),
|
||||
LastUpdatedBlock: rand.Uint32(),
|
||||
}
|
||||
|
||||
testserdes.EncodeDecodeBinary(t, expected, new(NEP5Tracker))
|
||||
testserdes.EncodeDecodeBinary(t, expected, new(NEP17Tracker))
|
||||
}
|
||||
|
||||
func TestNEP5Transfer_DecodeBinary(t *testing.T) {
|
||||
expected := &NEP5Transfer{
|
||||
func TestNEP17Transfer_DecodeBinary(t *testing.T) {
|
||||
expected := &NEP17Transfer{
|
||||
Asset: 123,
|
||||
From: util.Uint160{5, 6, 7},
|
||||
To: util.Uint160{8, 9, 10},
|
||||
|
@ -58,11 +58,11 @@ func TestNEP5Transfer_DecodeBinary(t *testing.T) {
|
|||
Tx: util.Uint256{8, 5, 3},
|
||||
}
|
||||
|
||||
testserdes.EncodeDecodeBinary(t, expected, new(NEP5Transfer))
|
||||
testserdes.EncodeDecodeBinary(t, expected, new(NEP17Transfer))
|
||||
}
|
||||
|
||||
func randomTransfer(r *rand.Rand) *NEP5Transfer {
|
||||
return &NEP5Transfer{
|
||||
func randomTransfer(r *rand.Rand) *NEP17Transfer {
|
||||
return &NEP17Transfer{
|
||||
Amount: *big.NewInt(int64(r.Uint64())),
|
||||
Block: r.Uint32(),
|
||||
Asset: int32(random.Int(10, 10000000)),
|
|
@ -16,8 +16,8 @@ const (
|
|||
STContract KeyPrefix = 0x50
|
||||
STContractID KeyPrefix = 0x51
|
||||
STStorage KeyPrefix = 0x70
|
||||
STNEP5Transfers KeyPrefix = 0x72
|
||||
STNEP5Balances KeyPrefix = 0x73
|
||||
STNEP17Transfers KeyPrefix = 0x72
|
||||
STNEP17Balances KeyPrefix = 0x73
|
||||
IXHeaderHashList KeyPrefix = 0x80
|
||||
SYSCurrentBlock KeyPrefix = 0xc0
|
||||
SYSCurrentHeader KeyPrefix = 0xc1
|
||||
|
|
|
@ -103,10 +103,10 @@ func (chain testChain) GetHeader(hash util.Uint256) (*block.Header, error) {
|
|||
func (chain testChain) GetNextBlockValidators() ([]*keys.PublicKey, error) {
|
||||
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")
|
||||
}
|
||||
func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances {
|
||||
func (chain testChain) GetNEP17Balances(util.Uint160) *state.NEP17Balances {
|
||||
panic("TODO")
|
||||
}
|
||||
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 {
|
||||
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")
|
||||
}
|
||||
func (chain testChain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) {
|
||||
|
|
|
@ -27,8 +27,8 @@ Supported methods
|
|||
getblocksysfee
|
||||
getconnectioncount
|
||||
getcontractstate
|
||||
getnep5balances
|
||||
getnep5transfers
|
||||
getnep17balances
|
||||
getnep17transfers
|
||||
getpeers
|
||||
getrawmempool
|
||||
getrawtransaction
|
||||
|
|
|
@ -29,7 +29,7 @@ func Example() {
|
|||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
resp, err := c.GetNEP5Balances(addr)
|
||||
resp, err := c.GetNEP17Balances(addr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
|
|
|
@ -23,64 +23,50 @@ type TransferTarget struct {
|
|||
Amount int64
|
||||
}
|
||||
|
||||
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
// NEP17Decimals invokes `decimals` NEP17 method on a specified contract.
|
||||
func (c *Client) NEP17Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err = getInvocationError(result)
|
||||
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)
|
||||
}
|
||||
|
||||
// NEP5Name invokes `name` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5Name(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) {
|
||||
// NEP17Symbol invokes `symbol` NEP17 method on a specified contract.
|
||||
func (c *Client) NEP17Symbol(tokenHash util.Uint160) (string, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "symbol", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = getInvocationError(result)
|
||||
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)
|
||||
}
|
||||
|
||||
// NEP5TotalSupply invokes `totalSupply` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
// NEP17TotalSupply invokes `totalSupply` NEP17 method on a specified contract.
|
||||
func (c *Client) NEP17TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "totalSupply", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err = getInvocationError(result)
|
||||
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)
|
||||
}
|
||||
|
||||
// NEP5BalanceOf invokes `balanceOf` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
|
||||
// NEP17BalanceOf invokes `balanceOf` NEP17 method on a specified contract.
|
||||
func (c *Client) NEP17BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash, "balanceOf", []smartcontract.Parameter{{
|
||||
Type: smartcontract.Hash160Type,
|
||||
Value: acc,
|
||||
|
@ -90,44 +76,44 @@ func (c *Client) NEP5BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
|
|||
}
|
||||
err = getInvocationError(result)
|
||||
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)
|
||||
}
|
||||
|
||||
// NEP5TokenInfo returns full NEP5 token info.
|
||||
func (c *Client) NEP5TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
name, err := c.NEP5Name(tokenHash)
|
||||
// NEP17TokenInfo returns full NEP17 token info.
|
||||
func (c *Client) NEP17TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
cs, err := c.GetContractStateByHash(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
symbol, err := c.NEP5Symbol(tokenHash)
|
||||
symbol, err := c.NEP17Symbol(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decimals, err := c.NEP5Decimals(tokenHash)
|
||||
decimals, err := c.NEP17Decimals(tokenHash)
|
||||
if err != nil {
|
||||
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'
|
||||
// method of a given contract (token) to move specified amount of NEP5 assets
|
||||
// CreateNEP17TransferTx creates an invocation transaction for the 'transfer'
|
||||
// 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
|
||||
// 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) {
|
||||
return c.CreateNEP5MultiTransferTx(acc, gas, TransferTarget{
|
||||
func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (*transaction.Transaction, error) {
|
||||
return c.CreateNEP17MultiTransferTx(acc, gas, TransferTarget{
|
||||
Token: token,
|
||||
Address: to,
|
||||
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.
|
||||
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)
|
||||
if err != nil {
|
||||
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()
|
||||
for i := range recipients {
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// TransferNEP5 creates an invocation transaction that invokes 'transfer' method
|
||||
// on a given token to move specified amount of NEP5 assets (in FixedN format
|
||||
// TransferNEP17 creates an invocation transaction that invokes 'transfer' method
|
||||
// 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
|
||||
// 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) {
|
||||
tx, err := c.CreateNEP5TransferTx(acc, to, token, amount, gas)
|
||||
func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
// MultiTransferNEP5 is similar to TransferNEP5, buf allows to have multiple recipients.
|
||||
func (c *Client) MultiTransferNEP5(acc *wallet.Account, gas int64, recipients ...TransferTarget) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP5MultiTransferTx(acc, gas, recipients...)
|
||||
// MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
|
||||
func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients ...TransferTarget) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients...)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
|
@ -232,22 +232,22 @@ func (c *Client) getContractState(param interface{}) (*state.Contract, error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// GetNEP5Balances is a wrapper for getnep5balances RPC.
|
||||
func (c *Client) GetNEP5Balances(address util.Uint160) (*result.NEP5Balances, error) {
|
||||
// GetNEP17Balances is a wrapper for getnep17balances RPC.
|
||||
func (c *Client) GetNEP17Balances(address util.Uint160) (*result.NEP17Balances, error) {
|
||||
params := request.NewRawParams(address.StringLE())
|
||||
resp := new(result.NEP5Balances)
|
||||
if err := c.performRequest("getnep5balances", params, resp); err != nil {
|
||||
resp := new(result.NEP17Balances)
|
||||
if err := c.performRequest("getnep17balances", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
// 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
|
||||
// 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)
|
||||
if start != nil {
|
||||
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 {
|
||||
return nil, errors.New("bad parameters")
|
||||
}
|
||||
resp := new(result.NEP5Transfers)
|
||||
if err := c.performRequest("getnep5transfers", params, resp); err != nil {
|
||||
resp := new(result.NEP17Transfers)
|
||||
if err := c.performRequest("getnep17transfers", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
|
|
@ -327,13 +327,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
}
|
||||
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{} {
|
||||
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m := manifest.NewManifest(hash.Hash160(script))
|
||||
m := manifest.NewManifest(hash.Hash160(script), "Test")
|
||||
cs := &state.Contract{
|
||||
ID: 0,
|
||||
Script: script,
|
||||
|
@ -348,13 +348,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
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{} {
|
||||
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m := manifest.NewManifest(hash.Hash160(script))
|
||||
m := manifest.NewManifest(hash.Hash160(script), "Test")
|
||||
cs := &state.Contract{
|
||||
ID: 0,
|
||||
Script: script,
|
||||
|
@ -369,13 +369,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
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{} {
|
||||
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m := manifest.NewManifest(hash.Hash160(script))
|
||||
m := manifest.NewManifest(hash.Hash160(script), "Test")
|
||||
cs := &state.Contract{
|
||||
ID: 0,
|
||||
Script: script,
|
||||
|
@ -434,7 +434,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getnep5balances": {
|
||||
"getnep17balances": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
|
@ -442,7 +442,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
if err != nil {
|
||||
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"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
|
@ -450,8 +450,8 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &result.NEP5Balances{
|
||||
Balances: []result.NEP5Balance{{
|
||||
return &result.NEP17Balances{
|
||||
Balances: []result.NEP17Balance{{
|
||||
Asset: hash,
|
||||
Amount: "50000000000",
|
||||
LastUpdated: 251604,
|
||||
|
@ -461,11 +461,11 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getnep5transfers": {
|
||||
"getnep17transfers": {
|
||||
{
|
||||
name: "positive",
|
||||
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"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
|
@ -477,9 +477,9 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &result.NEP5Transfers{
|
||||
Sent: []result.NEP5Transfer{},
|
||||
Received: []result.NEP5Transfer{
|
||||
return &result.NEP17Transfers{
|
||||
Sent: []result.NEP17Transfer{},
|
||||
Received: []result.NEP17Transfer{
|
||||
{
|
||||
Timestamp: 1555651816,
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
var start uint32
|
||||
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) {
|
||||
var start, stop uint32
|
||||
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) {
|
||||
return c.GetNEP5Balances(util.Uint160{})
|
||||
return c.GetNEP17Balances(util.Uint160{})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "getnep5transfers_unmarshalling_error",
|
||||
name: "getnep17transfers_unmarshalling_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 {
|
||||
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":
|
||||
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:
|
||||
response = resp
|
||||
}
|
||||
|
|
|
@ -4,28 +4,28 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// NEP5Balances is a result for the getnep5balances RPC call.
|
||||
type NEP5Balances struct {
|
||||
Balances []NEP5Balance `json:"balance"`
|
||||
Address string `json:"address"`
|
||||
// NEP17Balances is a result for the getnep17balances RPC call.
|
||||
type NEP17Balances struct {
|
||||
Balances []NEP17Balance `json:"balance"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// NEP5Balance represents balance for the single token contract.
|
||||
type NEP5Balance struct {
|
||||
// NEP17Balance represents balance for the single token contract.
|
||||
type NEP17Balance struct {
|
||||
Asset util.Uint160 `json:"assethash"`
|
||||
Amount string `json:"amount"`
|
||||
LastUpdated uint32 `json:"lastupdatedblock"`
|
||||
}
|
||||
|
||||
// NEP5Transfers is a result for the getnep5transfers RPC.
|
||||
type NEP5Transfers struct {
|
||||
Sent []NEP5Transfer `json:"sent"`
|
||||
Received []NEP5Transfer `json:"received"`
|
||||
Address string `json:"address"`
|
||||
// NEP17Transfers is a result for the getnep17transfers RPC.
|
||||
type NEP17Transfers struct {
|
||||
Sent []NEP17Transfer `json:"sent"`
|
||||
Received []NEP17Transfer `json:"received"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// NEP5Transfer represents single NEP5 transfer event.
|
||||
type NEP5Transfer struct {
|
||||
// NEP17Transfer represents single NEP17 transfer event.
|
||||
type NEP17Transfer struct {
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
Asset util.Uint160 `json:"assethash"`
|
||||
Address string `json:"transferaddress,omitempty"`
|
|
@ -19,7 +19,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestClient_NEP5(t *testing.T) {
|
||||
func TestClient_NEP17(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
@ -32,27 +32,22 @@ func TestClient_NEP5(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
t.Run("Decimals", func(t *testing.T) {
|
||||
d, err := c.NEP5Decimals(h)
|
||||
d, err := c.NEP17Decimals(h)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 2, d)
|
||||
})
|
||||
t.Run("TotalSupply", func(t *testing.T) {
|
||||
s, err := c.NEP5TotalSupply(h)
|
||||
s, err := c.NEP17TotalSupply(h)
|
||||
require.NoError(t, err)
|
||||
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) {
|
||||
sym, err := c.NEP5Symbol(h)
|
||||
sym, err := c.NEP17Symbol(h)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "RUB", sym)
|
||||
})
|
||||
t.Run("TokenInfo", func(t *testing.T) {
|
||||
tok, err := c.NEP5TokenInfo(h)
|
||||
tok, err := c.NEP17TokenInfo(h)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, h, tok.Hash)
|
||||
require.Equal(t, "Rubl", tok.Name)
|
||||
|
@ -61,7 +56,7 @@ func TestClient_NEP5(t *testing.T) {
|
|||
})
|
||||
t.Run("BalanceOf", func(t *testing.T) {
|
||||
acc := testchain.PrivateKeyByID(0).GetScriptHash()
|
||||
b, err := c.NEP5BalanceOf(h, acc)
|
||||
b, err := c.NEP17BalanceOf(h, acc)
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
@ -280,11 +275,11 @@ func TestCreateNEP5TransferTx(t *testing.T) {
|
|||
gasContractHash, err := c.GetNativeContractHash("gas")
|
||||
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, acc.SignTx(tx))
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
v := chain.GetTestVM(tx)
|
||||
v := chain.GetTestVM(tx, nil)
|
||||
v.LoadScriptWithFlags(tx.Script, smartcontract.All)
|
||||
require.NoError(t, v.Run())
|
||||
}
|
||||
|
|
|
@ -97,8 +97,8 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon
|
|||
"getcommittee": (*Server).getCommittee,
|
||||
"getconnectioncount": (*Server).getConnectionCount,
|
||||
"getcontractstate": (*Server).getContractState,
|
||||
"getnep5balances": (*Server).getNEP5Balances,
|
||||
"getnep5transfers": (*Server).getNEP5Transfers,
|
||||
"getnep17balances": (*Server).getNEP17Balances,
|
||||
"getnep17transfers": (*Server).getNEP17Transfers,
|
||||
"getpeers": (*Server).getPeers,
|
||||
"getproof": (*Server).getProof,
|
||||
"getrawmempool": (*Server).getRawMempool,
|
||||
|
@ -550,16 +550,16 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *resp
|
|||
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()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
||||
as := s.chain.GetNEP5Balances(u)
|
||||
bs := &result.NEP5Balances{
|
||||
as := s.chain.GetNEP17Balances(u)
|
||||
bs := &result.NEP17Balances{
|
||||
Address: address.Uint160ToString(u),
|
||||
Balances: []result.NEP5Balance{},
|
||||
Balances: []result.NEP17Balance{},
|
||||
}
|
||||
if as != nil {
|
||||
cache := make(map[int32]util.Uint160)
|
||||
|
@ -568,7 +568,7 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
bs.Balances = append(bs.Balances, result.NEP5Balance{
|
||||
bs.Balances = append(bs.Balances, result.NEP17Balance{
|
||||
Asset: h,
|
||||
Amount: bal.Balance.String(),
|
||||
LastUpdated: bal.LastUpdatedBlock,
|
||||
|
@ -628,7 +628,7 @@ func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, i
|
|||
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()
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
bs := &result.NEP5Transfers{
|
||||
bs := &result.NEP17Transfers{
|
||||
Address: address.Uint160ToString(u),
|
||||
Received: []result.NEP5Transfer{},
|
||||
Sent: []result.NEP5Transfer{},
|
||||
Received: []result.NEP17Transfer{},
|
||||
Sent: []result.NEP17Transfer{},
|
||||
}
|
||||
cache := make(map[int32]util.Uint160)
|
||||
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
|
||||
// time frame, continue looping.
|
||||
if tr.Timestamp > end {
|
||||
|
@ -668,7 +668,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
|||
return false, err
|
||||
}
|
||||
|
||||
transfer := result.NEP5Transfer{
|
||||
transfer := result.NEP17Transfer{
|
||||
Timestamp: tr.Timestamp,
|
||||
Asset: h,
|
||||
Index: tr.Block,
|
||||
|
@ -696,7 +696,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
|||
return true, 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
|
||||
}
|
||||
|
@ -1095,7 +1095,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons
|
|||
return nil, response.NewInternalServerError("can't create invocation script", err)
|
||||
}
|
||||
tx.Script = script
|
||||
return s.runScriptInVM(script, tx), nil
|
||||
return s.runScriptInVM(script, tx)
|
||||
}
|
||||
|
||||
// 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.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
|
||||
// result.
|
||||
func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *result.Invoke {
|
||||
vm := s.chain.GetTestVM(tx)
|
||||
func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) (*result.Invoke, *response.Error) {
|
||||
// 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.LoadScriptWithFlags(script, smartcontract.All)
|
||||
err := vm.Run()
|
||||
err = vm.Run()
|
||||
var faultException string
|
||||
if err != nil {
|
||||
faultException = err.Error()
|
||||
|
@ -1142,7 +1153,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu
|
|||
Stack: vm.Estack().ToArray(),
|
||||
FaultException: faultException,
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// submitBlock broadcasts a raw block over the NEO network.
|
||||
|
|
|
@ -56,8 +56,8 @@ type rpcTestCase struct {
|
|||
check func(t *testing.T, e *executor, result interface{})
|
||||
}
|
||||
|
||||
const testContractHash = "b0fda4dd46b8e5d207e86e774a4a133c6db69ee7"
|
||||
const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd77577e6194c173"
|
||||
const testContractHash = "55b692ecc09f240355e042c6c07e8f3fe57546b1"
|
||||
const deploymentTxHash = "99e40e5d169eb9a2b6faebc6fc596c050cf3f8a70ad25de8f44309bc8ccbfbfb"
|
||||
const genesisBlockHash = "a496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0"
|
||||
|
||||
const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7"
|
||||
|
@ -202,7 +202,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
},
|
||||
|
||||
"getnep5balances": {
|
||||
"getnep17balances": {
|
||||
{
|
||||
name: "no params",
|
||||
params: `[]`,
|
||||
|
@ -216,17 +216,17 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `"]`,
|
||||
result: func(e *executor) interface{} { return &result.NEP5Balances{} },
|
||||
check: checkNep5Balances,
|
||||
result: func(e *executor) interface{} { return &result.NEP17Balances{} },
|
||||
check: checkNep17Balances,
|
||||
},
|
||||
{
|
||||
name: "positive_address",
|
||||
params: `["` + address.Uint160ToString(testchain.PrivateKeyByID(0).GetScriptHash()) + `"]`,
|
||||
result: func(e *executor) interface{} { return &result.NEP5Balances{} },
|
||||
check: checkNep5Balances,
|
||||
result: func(e *executor) interface{} { return &result.NEP17Balances{} },
|
||||
check: checkNep17Balances,
|
||||
},
|
||||
},
|
||||
"getnep5transfers": {
|
||||
"getnep17transfers": {
|
||||
{
|
||||
name: "no params",
|
||||
params: `[]`,
|
||||
|
@ -275,14 +275,14 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
params: `["` + testchain.PrivateKeyByID(0).Address() + `", 0]`,
|
||||
result: func(e *executor) interface{} { return &result.NEP5Transfers{} },
|
||||
check: checkNep5Transfers,
|
||||
result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
|
||||
check: checkNep17Transfers,
|
||||
},
|
||||
{
|
||||
name: "positive_hash",
|
||||
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `", 0]`,
|
||||
result: func(e *executor) interface{} { return &result.NEP5Transfers{} },
|
||||
check: checkNep5Transfers,
|
||||
result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
|
||||
check: checkNep17Transfers,
|
||||
},
|
||||
},
|
||||
"getproof": {
|
||||
|
@ -1198,8 +1198,8 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
assert.ElementsMatch(t, expected, actual)
|
||||
})
|
||||
|
||||
t.Run("getnep5transfers", func(t *testing.T) {
|
||||
testNEP5T := func(t *testing.T, start, stop, limit, page int, sent, rcvd []int) {
|
||||
t.Run("getnep17transfers", func(t *testing.T) {
|
||||
testNEP17T := func(t *testing.T, start, stop, limit, page int, sent, rcvd []int) {
|
||||
ps := []string{`"` + testchain.PrivateKeyByID(0).Address() + `"`}
|
||||
if start != 0 {
|
||||
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))
|
||||
}
|
||||
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)
|
||||
res := checkErrGetResult(t, body, false)
|
||||
actual := new(result.NEP5Transfers)
|
||||
actual := new(result.NEP17Transfers)
|
||||
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("no res", func(t *testing.T) { testNEP5T(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 2", func(t *testing.T) { testNEP5T(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 2", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 2, []int{4, 5}, []int{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) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
|
||||
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) { testNEP17T(t, 4, 5, 2, 0, []int{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) { 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)
|
||||
}
|
||||
|
||||
func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.NEP5Balances)
|
||||
func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.NEP17Balances)
|
||||
require.True(t, ok)
|
||||
rubles, err := util.Uint160DecodeStringLE(testContractHash)
|
||||
require.NoError(t, err)
|
||||
expected := result.NEP5Balances{
|
||||
Balances: []result.NEP5Balance{
|
||||
expected := result.NEP17Balances{
|
||||
Balances: []result.NEP17Balance{
|
||||
{
|
||||
Asset: rubles,
|
||||
Amount: "877",
|
||||
|
@ -1345,7 +1345,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
|
|||
},
|
||||
{
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Amount: "80009641770",
|
||||
Amount: "80009744770",
|
||||
LastUpdated: 7,
|
||||
}},
|
||||
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)
|
||||
}
|
||||
|
||||
func checkNep5Transfers(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})
|
||||
func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
|
||||
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) {
|
||||
res, ok := acc.(*result.NEP5Transfers)
|
||||
func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
||||
res, ok := acc.(*result.NEP17Transfers)
|
||||
require.True(t, ok)
|
||||
rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
|
||||
require.NoError(t, err)
|
||||
|
@ -1410,8 +1410,8 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv
|
|||
// * to check chain events consistency
|
||||
// Technically these could be retrieved from application log, but that would almost
|
||||
// duplicate the Server method.
|
||||
expected := result.NEP5Transfers{
|
||||
Sent: []result.NEP5Transfer{
|
||||
expected := result.NEP17Transfers{
|
||||
Sent: []result.NEP17Transfer{
|
||||
{
|
||||
Timestamp: blockDeploy2.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
|
@ -1487,7 +1487,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv
|
|||
TxHash: blockCtrDeploy.Hash(),
|
||||
},
|
||||
},
|
||||
Received: []result.NEP5Transfer{
|
||||
Received: []result.NEP17Transfer{
|
||||
{
|
||||
Timestamp: blockGASBounty.Timestamp,
|
||||
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)
|
||||
|
||||
arr := make([]result.NEP5Transfer, 0, len(expected.Sent))
|
||||
arr := make([]result.NEP17Transfer, 0, len(expected.Sent))
|
||||
for i := range expected.Sent {
|
||||
for _, j := range sent {
|
||||
if i == j {
|
||||
|
|
10
pkg/rpc/server/testdata/test_contract.go
vendored
10
pkg/rpc/server/testdata/test_contract.go
vendored
|
@ -15,11 +15,11 @@ func Init() bool {
|
|||
h := runtime.GetExecutingScriptHash()
|
||||
amount := totalSupply
|
||||
storage.Put(ctx, h, amount)
|
||||
runtime.Notify("transfer", []byte{}, h, amount)
|
||||
runtime.Notify("Transfer", []byte{}, h, amount)
|
||||
return true
|
||||
}
|
||||
|
||||
func Transfer(from, to []byte, amount int) bool {
|
||||
func Transfer(from, to []byte, amount int, data interface{}) bool {
|
||||
ctx := storage.GetContext()
|
||||
if len(from) != 20 {
|
||||
runtime.Log("invalid 'from' address")
|
||||
|
@ -54,7 +54,7 @@ func Transfer(from, to []byte, amount int) bool {
|
|||
toBalance += amount
|
||||
storage.Put(ctx, to, toBalance)
|
||||
|
||||
runtime.Notify("transfer", from, to, amount)
|
||||
runtime.Notify("Transfer", from, to, amount)
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -74,10 +74,6 @@ func BalanceOf(addr []byte) int {
|
|||
return amount
|
||||
}
|
||||
|
||||
func Name() string {
|
||||
return "Rubl"
|
||||
}
|
||||
|
||||
func Symbol() string {
|
||||
return "RUB"
|
||||
}
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -20,10 +20,13 @@ const (
|
|||
// MethodVerify is a name for default verification method.
|
||||
MethodVerify = "verify"
|
||||
|
||||
// NEP5StandardName represents the name of NEP5 smartcontract standard.
|
||||
NEP5StandardName = "NEP-5"
|
||||
// MethodOnPayment is name of the method which is called when contract receives funds.
|
||||
MethodOnPayment = "onPayment"
|
||||
|
||||
// NEP10StandardName represents the name of NEP10 smartcontract standard.
|
||||
NEP10StandardName = "NEP-10"
|
||||
// NEP17StandardName represents the name of NEP17 smartcontract standard.
|
||||
NEP17StandardName = "NEP-17"
|
||||
)
|
||||
|
||||
// ABI represents a contract application binary interface.
|
||||
|
@ -35,6 +38,8 @@ type ABI struct {
|
|||
|
||||
// Manifest represens contract metadata.
|
||||
type Manifest struct {
|
||||
// Name is a contract's name.
|
||||
Name string `json:"name"`
|
||||
// ABI is a contract's ABI.
|
||||
ABI ABI `json:"abi"`
|
||||
// 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.
|
||||
func NewManifest(h util.Uint160) *Manifest {
|
||||
func NewManifest(h util.Uint160, name string) *Manifest {
|
||||
m := &Manifest{
|
||||
Name: name,
|
||||
ABI: ABI{
|
||||
Hash: h,
|
||||
Methods: []Method{},
|
||||
|
@ -67,8 +73,8 @@ func NewManifest(h util.Uint160) *Manifest {
|
|||
}
|
||||
|
||||
// DefaultManifest returns default contract manifest.
|
||||
func DefaultManifest(h util.Uint160) *Manifest {
|
||||
m := NewManifest(h)
|
||||
func DefaultManifest(h util.Uint160, name string) *Manifest {
|
||||
m := NewManifest(h, name)
|
||||
m.Permissions = []Permission{*NewPermission(PermissionWildcard)}
|
||||
return m
|
||||
}
|
||||
|
|
|
@ -13,40 +13,40 @@ import (
|
|||
// https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10
|
||||
func TestManifest_MarshalJSON(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)
|
||||
require.Equal(t, DefaultManifest(util.Uint160{}), m)
|
||||
require.Equal(t, DefaultManifest(util.Uint160{}, "Test"), m)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
|
||||
js := []byte(s)
|
||||
c := NewManifest(util.Uint160{})
|
||||
c := NewManifest(util.Uint160{}, "Test")
|
||||
require.NoError(t, json.Unmarshal(js, c))
|
||||
|
||||
data, err := json.Marshal(c)
|
||||
|
@ -58,22 +58,22 @@ func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
|
|||
|
||||
func TestManifest_CanCall(t *testing.T) {
|
||||
t.Run("safe methods", func(t *testing.T) {
|
||||
man1 := NewManifest(util.Uint160{})
|
||||
man2 := DefaultManifest(util.Uint160{})
|
||||
man1 := NewManifest(util.Uint160{}, "Test1")
|
||||
man2 := DefaultManifest(util.Uint160{}, "Test2")
|
||||
require.False(t, man1.CanCall(man2, "method1"))
|
||||
man2.SafeMethods.Add("method1")
|
||||
require.True(t, man1.CanCall(man2, "method1"))
|
||||
})
|
||||
|
||||
t.Run("wildcard permission", func(t *testing.T) {
|
||||
man1 := DefaultManifest(util.Uint160{})
|
||||
man2 := DefaultManifest(util.Uint160{})
|
||||
man1 := DefaultManifest(util.Uint160{}, "Test1")
|
||||
man2 := DefaultManifest(util.Uint160{}, "Test2")
|
||||
require.True(t, man1.CanCall(man2, "method1"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPermission_IsAllowed(t *testing.T) {
|
||||
manifest := DefaultManifest(util.Uint160{})
|
||||
manifest := DefaultManifest(util.Uint160{}, "Test")
|
||||
|
||||
t.Run("wildcard", func(t *testing.T) {
|
||||
perm := NewPermission(PermissionWildcard)
|
||||
|
@ -116,7 +116,7 @@ func TestPermission_IsAllowed(t *testing.T) {
|
|||
|
||||
func TestIsValid(t *testing.T) {
|
||||
contractHash := util.Uint160{1, 2, 3}
|
||||
m := NewManifest(contractHash)
|
||||
m := NewManifest(contractHash, "Test")
|
||||
|
||||
t.Run("valid, no groups", func(t *testing.T) {
|
||||
require.True(t, m.IsValid(contractHash))
|
||||
|
|
|
@ -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.
|
||||
func (c *Context) NextIP() int {
|
||||
return c.nextip
|
||||
|
|
|
@ -70,6 +70,8 @@ func Int(w *io.BinWriter, i int64) {
|
|||
func Array(w *io.BinWriter, es ...interface{}) {
|
||||
for i := len(es) - 1; i >= 0; i-- {
|
||||
switch e := es[i].(type) {
|
||||
case []interface{}:
|
||||
Array(w, e...)
|
||||
case int64:
|
||||
Int(w, e)
|
||||
case string:
|
||||
|
|
|
@ -143,7 +143,7 @@ func TestBytes(t *testing.T) {
|
|||
func TestEmitArray(t *testing.T) {
|
||||
t.Run("good", func(t *testing.T) {
|
||||
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)
|
||||
|
||||
res := buf.Bytes()
|
||||
|
@ -156,6 +156,10 @@ func TestEmitArray(t *testing.T) {
|
|||
assert.EqualValues(t, []byte("str"), res[7:10])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[10])
|
||||
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) {
|
||||
|
|
|
@ -13,9 +13,9 @@ func TestToken_MarshalJSON(t *testing.T) {
|
|||
h, err := util.Uint160DecodeStringLE("f8d448b227991cf07cb96a6f9c0322437f1599b9")
|
||||
require.NoError(t, err)
|
||||
|
||||
tok := NewToken(h, "NEP5 Standard", "NEP5", 8)
|
||||
require.Equal(t, "NEP5 Standard", tok.Name)
|
||||
require.Equal(t, "NEP5", tok.Symbol)
|
||||
tok := NewToken(h, "NEP17 Standard", "NEP17", 8)
|
||||
require.Equal(t, "NEP17 Standard", tok.Name)
|
||||
require.Equal(t, "NEP17", tok.Symbol)
|
||||
require.EqualValues(t, 8, tok.Decimals)
|
||||
require.Equal(t, h, tok.Hash)
|
||||
require.Equal(t, "NcqKahsZ93ZyYS5bep8G2TY1zRB7tfUPdK", tok.Address())
|
||||
|
|
Loading…
Reference in a new issue