Merge pull request #1558 from nspcc-dev/nep17

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

View file

@ -16,7 +16,7 @@ func TestRegisterCandidate(t *testing.T) {
defer e.Close(t)
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,

View file

@ -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")

View file

@ -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')

View file

@ -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
}

View file

@ -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:

View file

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

View file

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

Binary file not shown.

View file

@ -26,7 +26,7 @@ var (
}
)
func newNEP5Commands() []cli.Command {
func newNEP17Commands() []cli.Command {
balanceFlags := []cli.Flag{
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)
}

View file

@ -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)
}

View file

@ -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")

View file

@ -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] }
```

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 {

View file

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

View file

@ -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

View file

@ -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

View file

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

View file

@ -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)
}

View file

@ -409,7 +409,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) {
// ConvertToManifest converts contract to the manifest.Manifest struct for debugger.
// 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
}

View file

@ -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{

View file

@ -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)

View file

@ -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)

View file

@ -758,7 +758,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.C
}
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) {
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

View file

@ -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)

View file

@ -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

View file

@ -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
}

View file

@ -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,

View file

@ -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.

View file

@ -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)

View file

@ -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
}

View file

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

View file

@ -299,16 +299,7 @@ func runtimeLog(ic *interop.Context) error {
// runtimeGetTime returns timestamp of the block being verified, or the latest
// 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
}

View file

@ -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")

View file

@ -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
}

View file

@ -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)

View file

@ -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")
}

View file

@ -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")
}

View file

@ -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 {

View file

@ -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
})
}

View file

@ -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())
}

View file

@ -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",

View file

@ -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{

View file

@ -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()))

View file

@ -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[:])

View file

@ -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)),

View file

@ -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

View file

@ -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) {

View file

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

View file

@ -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)

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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"`
// 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"`
// 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"`

View file

@ -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())
}

View file

@ -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.

View file

@ -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 {

View file

@ -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"
}

Binary file not shown.

View file

@ -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
}

View file

@ -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))

View file

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

View file

@ -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:

View file

@ -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) {

View file

@ -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())