Merge pull request #1426 from nspcc-dev/rpc/getcontractstate_by_id_or_name
rpc: allow to `getcontractstate` by id or name
This commit is contained in:
commit
679846c1a1
20 changed files with 347 additions and 117 deletions
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -91,7 +90,7 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", wallet1Path, "--address", multisigAddr,
|
"--wallet", wallet1Path, "--address", multisigAddr,
|
||||||
"--out", txPath,
|
"--out", txPath,
|
||||||
client.NeoContractHash.StringLE(), "transfer",
|
e.Chain.GoverningTokenHash().StringLE(), "transfer",
|
||||||
"bytes:"+multisigHash.StringBE(),
|
"bytes:"+multisigHash.StringBE(),
|
||||||
"bytes:"+priv.GetScriptHash().StringBE(),
|
"bytes:"+priv.GetScriptHash().StringBE(),
|
||||||
"int:1",
|
"int:1",
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -138,6 +137,8 @@ func TestNEP5MultiTransfer(t *testing.T) {
|
||||||
|
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
defer e.Close(t)
|
defer e.Close(t)
|
||||||
|
neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo")
|
||||||
|
require.NoError(t, err)
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep5", "multitransfer",
|
"neo-go", "wallet", "nep5", "multitransfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
@ -145,7 +146,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
|
||||||
"--from", validatorAddr,
|
"--from", validatorAddr,
|
||||||
"neo:" + privs[0].Address() + ":42",
|
"neo:" + privs[0].Address() + ":42",
|
||||||
"GAS:" + privs[1].Address() + ":7",
|
"GAS:" + privs[1].Address() + ":7",
|
||||||
client.NeoContractHash.StringLE() + ":" + privs[2].Address() + ":13",
|
neoContractHash.StringLE() + ":" + privs[2].Address() + ":13",
|
||||||
}
|
}
|
||||||
|
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
|
@ -168,27 +169,31 @@ func TestNEP5ImportToken(t *testing.T) {
|
||||||
walletPath := path.Join(tmpDir, "walletForImport.json")
|
walletPath := path.Join(tmpDir, "walletForImport.json")
|
||||||
defer os.Remove(walletPath)
|
defer os.Remove(walletPath)
|
||||||
|
|
||||||
|
neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo")
|
||||||
|
require.NoError(t, err)
|
||||||
|
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", "init", "--wallet", walletPath)
|
||||||
e.Run(t, "neo-go", "wallet", "nep5", "import",
|
e.Run(t, "neo-go", "wallet", "nep5", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", client.GasContractHash.StringLE())
|
"--token", gasContractHash.StringLE())
|
||||||
e.Run(t, "neo-go", "wallet", "nep5", "import",
|
e.Run(t, "neo-go", "wallet", "nep5", "import",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--token", client.NeoContractHash.StringLE())
|
"--token", neoContractHash.StringLE())
|
||||||
|
|
||||||
t.Run("Info", func(t *testing.T) {
|
t.Run("Info", func(t *testing.T) {
|
||||||
checkGASInfo := func(t *testing.T) {
|
checkGASInfo := func(t *testing.T) {
|
||||||
e.checkNextLine(t, "^Name:\\s*GAS")
|
e.checkNextLine(t, "^Name:\\s*GAS")
|
||||||
e.checkNextLine(t, "^Symbol:\\s*gas")
|
e.checkNextLine(t, "^Symbol:\\s*gas")
|
||||||
e.checkNextLine(t, "^Hash:\\s*"+client.GasContractHash.StringLE())
|
e.checkNextLine(t, "^Hash:\\s*"+gasContractHash.StringLE())
|
||||||
e.checkNextLine(t, "^Decimals:\\s*8")
|
e.checkNextLine(t, "^Decimals:\\s*8")
|
||||||
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(client.GasContractHash))
|
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash))
|
||||||
}
|
}
|
||||||
t.Run("WithToken", func(t *testing.T) {
|
t.Run("WithToken", func(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "nep5", "info",
|
e.Run(t, "neo-go", "wallet", "nep5", "info",
|
||||||
"--wallet", walletPath, "--token", client.GasContractHash.StringLE())
|
"--wallet", walletPath, "--token", gasContractHash.StringLE())
|
||||||
checkGASInfo(t)
|
checkGASInfo(t)
|
||||||
})
|
})
|
||||||
t.Run("NoToken", func(t *testing.T) {
|
t.Run("NoToken", func(t *testing.T) {
|
||||||
|
@ -199,14 +204,14 @@ func TestNEP5ImportToken(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.checkNextLine(t, "^Name:\\s*NEO")
|
e.checkNextLine(t, "^Name:\\s*NEO")
|
||||||
e.checkNextLine(t, "^Symbol:\\s*neo")
|
e.checkNextLine(t, "^Symbol:\\s*neo")
|
||||||
e.checkNextLine(t, "^Hash:\\s*"+client.NeoContractHash.StringLE())
|
e.checkNextLine(t, "^Hash:\\s*"+neoContractHash.StringLE())
|
||||||
e.checkNextLine(t, "^Decimals:\\s*0")
|
e.checkNextLine(t, "^Decimals:\\s*0")
|
||||||
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(client.NeoContractHash))
|
e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(neoContractHash))
|
||||||
})
|
})
|
||||||
t.Run("Remove", func(t *testing.T) {
|
t.Run("Remove", func(t *testing.T) {
|
||||||
e.In.WriteString("y\r")
|
e.In.WriteString("y\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep5", "remove",
|
e.Run(t, "neo-go", "wallet", "nep5", "remove",
|
||||||
"--wallet", walletPath, "--token", client.NeoContractHash.StringLE())
|
"--wallet", walletPath, "--token", neoContractHash.StringLE())
|
||||||
e.Run(t, "neo-go", "wallet", "nep5", "info",
|
e.Run(t, "neo-go", "wallet", "nep5", "info",
|
||||||
"--wallet", walletPath)
|
"--wallet", walletPath)
|
||||||
checkGASInfo(t)
|
checkGASInfo(t)
|
||||||
|
|
|
@ -2,8 +2,6 @@ package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -57,34 +55,3 @@ func TestGetTimeoutContext(t *testing.T) {
|
||||||
require.True(t, start.Before(dl) && dl.Before(end.Add(time.Nanosecond*20)))
|
require.True(t, start.Before(dl) && dl.Before(end.Add(time.Nanosecond*20)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRPCClient(t *testing.T) {
|
|
||||||
// need test server for proper client.Init() handling
|
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
||||||
response := `{"id":1,"jsonrpc":"2.0","result":{"magic":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
|
||||||
|
|
||||||
_, err := w.Write([]byte(response))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error writing response: %s", err.Error())
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
defer srv.Close()
|
|
||||||
t.Run("no endpoint", func(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
|
||||||
gctx, _ := GetTimeoutContext(ctx)
|
|
||||||
_, ec := GetRPCClient(gctx, ctx)
|
|
||||||
require.Equal(t, 1, ec.ExitCode())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
|
||||||
set.String(RPCEndpointFlag, srv.URL, "")
|
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
|
||||||
gctx, _ := GetTimeoutContext(ctx)
|
|
||||||
_, ec := GetRPCClient(gctx, ctx)
|
|
||||||
require.Nil(t, ec)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
32
cli/options_test.go
Normal file
32
cli/options_test.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetRPCClient(t *testing.T) {
|
||||||
|
e := newExecutor(t, true)
|
||||||
|
defer e.Close(t)
|
||||||
|
|
||||||
|
t.Run("no endpoint", func(t *testing.T) {
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
gctx, _ := options.GetTimeoutContext(ctx)
|
||||||
|
_, ec := options.GetRPCClient(gctx, ctx)
|
||||||
|
require.Equal(t, 1, ec.ExitCode())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
set.String(options.RPCEndpointFlag, "http://"+e.RPC.Addr, "")
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
gctx, _ := options.GetTimeoutContext(ctx)
|
||||||
|
_, ec := options.GetRPCClient(gctx, ctx)
|
||||||
|
require.Nil(t, ec)
|
||||||
|
})
|
||||||
|
}
|
|
@ -80,7 +80,7 @@ func signMultisig(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
res, err := c.SendRawTransaction(tx)
|
res, err := c.SendRawTransaction(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,11 +15,6 @@ import (
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
neoToken = wallet.NewToken(client.NeoContractHash, "NEO", "neo", 0)
|
|
||||||
gasToken = wallet.NewToken(client.GasContractHash, "GAS", "gas", 8)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tokenFlag = cli.StringFlag{
|
tokenFlag = cli.StringFlag{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
|
@ -161,7 +156,11 @@ func getNEP5Balance(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
err = c.Init()
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to init RPC client: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := ctx.String("token")
|
name := ctx.String("token")
|
||||||
|
@ -210,12 +209,6 @@ func getNEP5Balance(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.Token, error) {
|
func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.Token, error) {
|
||||||
switch strings.ToLower(name) {
|
|
||||||
case "neo", client.NeoContractHash.StringLE():
|
|
||||||
return neoToken, nil
|
|
||||||
case "gas", client.GasContractHash.StringLE():
|
|
||||||
return gasToken, nil
|
|
||||||
}
|
|
||||||
return getMatchingTokenAux(ctx, func(i int) *wallet.Token {
|
return getMatchingTokenAux(ctx, func(i int) *wallet.Token {
|
||||||
return w.Extra.Tokens[i]
|
return w.Extra.Tokens[i]
|
||||||
}, len(w.Extra.Tokens), name)
|
}, len(w.Extra.Tokens), name)
|
||||||
|
@ -278,7 +271,7 @@ func importNEP5Token(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tok, err := c.NEP5TokenInfo(tokenHash)
|
tok, err := c.NEP5TokenInfo(tokenHash)
|
||||||
|
@ -371,7 +364,11 @@ func multiTransferNEP5(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
err = c.Init()
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to init RPC client: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.NArg() == 0 {
|
if ctx.NArg() == 0 {
|
||||||
|
@ -434,7 +431,11 @@ func transferNEP5(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
err = c.Init()
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to init RPC client: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
toFlag := ctx.Generic("to").(*flags.Address)
|
toFlag := ctx.Generic("to").(*flags.Address)
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
@ -96,12 +95,16 @@ func handleCandidate(ctx *cli.Context, method string) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||||
|
neoContractHash, err := c.GetNativeContractHash("neo")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes())
|
emit.AppCallWithOperationAndArgs(w.BinWriter, neoContractHash, method, acc.PrivateKey().PublicKey().Bytes())
|
||||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
||||||
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
|
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
|
||||||
Account: acc.Contract.ScriptHash(),
|
Account: acc.Contract.ScriptHash(),
|
||||||
|
@ -149,7 +152,7 @@ func handleVote(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pubArg interface{}
|
var pubArg interface{}
|
||||||
|
@ -158,8 +161,12 @@ func handleVote(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||||
|
neoContractHash, err := c.GetNativeContractHash("neo")
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, "vote", addr.BytesBE(), pubArg)
|
emit.AppCallWithOperationAndArgs(w.BinWriter, neoContractHash, "vote", addr.BytesBE(), pubArg)
|
||||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
|
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
@ -231,10 +230,14 @@ func claimGas(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, err := c.TransferNEP5(acc, scriptHash, client.NeoContractHash, 0, 0)
|
neoContractHash, err := c.GetNativeContractHash("neo")
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
hash, err := c.TransferNEP5(acc, scriptHash, neoContractHash, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -423,10 +426,10 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs, err := c.GetContractState(h)
|
cs, err := c.GetContractStateByHash(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't fetch contract info: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't fetch contract info: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,13 +70,20 @@ key in the server which doesn't fit the model of our node-client interactions.
|
||||||
Lacking this signature the transaction is almost useless, so there is no point
|
Lacking this signature the transaction is almost useless, so there is no point
|
||||||
in returning it.
|
in returning it.
|
||||||
|
|
||||||
Both methods also don't currently support arrays in function parameters.
|
It's possible to use `invokefunction` not only with contract scripthash, but also
|
||||||
|
with contract name (for native contracts) or contract ID (for all contracts). This
|
||||||
|
feature is not supported by the C# node.
|
||||||
|
|
||||||
##### `getunclaimedgas`
|
##### `getunclaimedgas`
|
||||||
|
|
||||||
It's possible to call this method for any address with neo-go, unlike with C#
|
It's possible to call this method for any address with neo-go, unlike with C#
|
||||||
node where it only works for addresses from opened wallet.
|
node where it only works for addresses from opened wallet.
|
||||||
|
|
||||||
|
##### `getcontractstate`
|
||||||
|
|
||||||
|
It's possible to get non-native contract state by its ID, unlike with C# node where
|
||||||
|
it only works for native contracts.
|
||||||
|
|
||||||
### Unsupported methods
|
### Unsupported methods
|
||||||
|
|
||||||
Methods listed down below are not going to be supported for various reasons
|
Methods listed down below are not going to be supported for various reasons
|
||||||
|
|
|
@ -1073,6 +1073,15 @@ func (bc *Blockchain) GetContractScriptHash(id int32) (util.Uint160, error) {
|
||||||
return bc.dao.GetContractScriptHash(id)
|
return bc.dao.GetContractScriptHash(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNativeContractScriptHash returns native contract script hash by its name.
|
||||||
|
func (bc *Blockchain) GetNativeContractScriptHash(name string) (util.Uint160, error) {
|
||||||
|
c := bc.contracts.ByName(name)
|
||||||
|
if c != nil {
|
||||||
|
return c.Metadata().Hash, nil
|
||||||
|
}
|
||||||
|
return util.Uint160{}, errors.New("Unknown native contract")
|
||||||
|
}
|
||||||
|
|
||||||
// GetConfig returns the config stored in the blockchain.
|
// GetConfig returns the config stored in the blockchain.
|
||||||
func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
|
func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
|
||||||
return bc.config
|
return bc.config
|
||||||
|
|
|
@ -39,6 +39,7 @@ type Blockchainer interface {
|
||||||
HasBlock(util.Uint256) bool
|
HasBlock(util.Uint256) bool
|
||||||
HasTransaction(util.Uint256) bool
|
HasTransaction(util.Uint256) bool
|
||||||
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||||
|
GetNativeContractScriptHash(string) (util.Uint160, error)
|
||||||
GetNextBlockValidators() ([]*keys.PublicKey, error)
|
GetNextBlockValidators() ([]*keys.PublicKey, error)
|
||||||
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
GetNEP5Balances(util.Uint160) *state.NEP5Balances
|
||||||
GetValidators() ([]*keys.PublicKey, error)
|
GetValidators() ([]*keys.PublicKey, error)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
@ -35,6 +36,17 @@ func (cs *Contracts) ByHash(h util.Uint160) interop.Contract {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByName returns native contract with the specified name.
|
||||||
|
func (cs *Contracts) ByName(name string) interop.Contract {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
for _, ctr := range cs.Contracts {
|
||||||
|
if strings.ToLower(ctr.Metadata().Name) == name {
|
||||||
|
return ctr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewContracts returns new set of native contracts with new GAS, NEO and Policy
|
// NewContracts returns new set of native contracts with new GAS, NEO and Policy
|
||||||
// contracts.
|
// contracts.
|
||||||
func NewContracts() *Contracts {
|
func NewContracts() *Contracts {
|
||||||
|
|
|
@ -89,6 +89,9 @@ func (chain testChain) GetContractState(hash util.Uint160) *state.Contract {
|
||||||
func (chain testChain) GetContractScriptHash(id int32) (util.Uint160, error) {
|
func (chain testChain) GetContractScriptHash(id int32) (util.Uint160, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
func (chain testChain) GetNativeContractScriptHash(name string) (util.Uint160, error) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
func (chain testChain) GetHeaderHash(int) util.Uint256 {
|
func (chain testChain) GetHeaderHash(int) util.Uint256 {
|
||||||
return util.Uint256{}
|
return util.Uint256{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -53,6 +54,7 @@ type Options struct {
|
||||||
// cache stores cache values for the RPC client methods
|
// cache stores cache values for the RPC client methods
|
||||||
type cache struct {
|
type cache struct {
|
||||||
calculateValidUntilBlock calculateValidUntilBlockCache
|
calculateValidUntilBlock calculateValidUntilBlockCache
|
||||||
|
nativeHashes map[string]util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateValidUntilBlockCache stores cached number of validators and
|
// calculateValidUntilBlockCache stores cached number of validators and
|
||||||
|
@ -95,21 +97,34 @@ func New(ctx context.Context, endpoint string, opts Options) (*Client, error) {
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cli: httpClient,
|
cli: httpClient,
|
||||||
endpoint: url,
|
endpoint: url,
|
||||||
|
cache: cache{
|
||||||
|
nativeHashes: make(map[string]util.Uint160),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cl.opts = opts
|
cl.opts = opts
|
||||||
cl.requestF = cl.makeHTTPRequest
|
cl.requestF = cl.makeHTTPRequest
|
||||||
return cl, nil
|
return cl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init sets magic of the network client connected to. This method should be called
|
// Init sets magic of the network client connected to and native NEO and GAS
|
||||||
// before any transaction-, header- or block-related requests in order to deserialize
|
// contracts scripthashes. This method should be called before any transaction-,
|
||||||
// responses properly.
|
// header- or block-related requests in order to deserialize responses properly.
|
||||||
func (c *Client) Init() error {
|
func (c *Client) Init() error {
|
||||||
version, err := c.GetVersion()
|
version, err := c.GetVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get network magic: %w", err)
|
return fmt.Errorf("failed to get network magic: %w", err)
|
||||||
}
|
}
|
||||||
c.network = version.Magic
|
c.network = version.Magic
|
||||||
|
neoContractHash, err := c.GetContractStateByAddressOrName("neo")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get NEO contract scripthash: %w", err)
|
||||||
|
}
|
||||||
|
c.cache.nativeHashes["neo"] = neoContractHash.ScriptHash()
|
||||||
|
gasContractHash, err := c.GetContractStateByAddressOrName("gas")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get GAS contract scripthash: %w", err)
|
||||||
|
}
|
||||||
|
c.cache.nativeHashes["gas"] = gasContractHash.ScriptHash()
|
||||||
c.initDone = true
|
c.initDone = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,6 @@ type TransferTarget struct {
|
||||||
Amount int64
|
Amount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// NeoContractHash is a hash of the NEO native contract.
|
|
||||||
NeoContractHash, _ = util.Uint160DecodeStringBE("25059ecb4878d3a875f91c51ceded330d4575fde")
|
|
||||||
// GasContractHash is a hash of the GAS native contract.
|
|
||||||
GasContractHash, _ = util.Uint160DecodeStringBE("bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e66")
|
|
||||||
)
|
|
||||||
|
|
||||||
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
||||||
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
|
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
|
||||||
result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil)
|
result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
|
@ -208,10 +209,25 @@ func (c *Client) GetCommittee() (keys.PublicKeys, error) {
|
||||||
return *resp, nil
|
return *resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractState queries contract information, according to the contract script hash.
|
// GetContractStateByHash queries contract information, according to the contract script hash.
|
||||||
func (c *Client) GetContractState(hash util.Uint160) (*state.Contract, error) {
|
func (c *Client) GetContractStateByHash(hash util.Uint160) (*state.Contract, error) {
|
||||||
|
return c.getContractState(hash.StringLE())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContractStateByAddressOrName queries contract information, according to the contract address or name.
|
||||||
|
func (c *Client) GetContractStateByAddressOrName(addressOrName string) (*state.Contract, error) {
|
||||||
|
return c.getContractState(addressOrName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContractStateByID queries contract information, according to the contract ID.
|
||||||
|
func (c *Client) GetContractStateByID(id int32) (*state.Contract, error) {
|
||||||
|
return c.getContractState(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getContractState is an internal representation of GetContractStateBy* methods.
|
||||||
|
func (c *Client) getContractState(param interface{}) (*state.Contract, error) {
|
||||||
var (
|
var (
|
||||||
params = request.NewRawParams(hash.StringLE())
|
params = request.NewRawParams(param)
|
||||||
resp = &state.Contract{}
|
resp = &state.Contract{}
|
||||||
)
|
)
|
||||||
if err := c.performRequest("getcontractstate", params, resp); err != nil {
|
if err := c.performRequest("getcontractstate", params, resp); err != nil {
|
||||||
|
@ -597,3 +613,18 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
|
||||||
func (c *Client) GetNetwork() netmode.Magic {
|
func (c *Client) GetNetwork() netmode.Magic {
|
||||||
return c.network
|
return c.network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNativeContractHash returns native contract hash by its name. It is not case-sensitive.
|
||||||
|
func (c *Client) GetNativeContractHash(name string) (util.Uint160, error) {
|
||||||
|
lowercasedName := strings.ToLower(name)
|
||||||
|
hash, ok := c.cache.nativeHashes[lowercasedName]
|
||||||
|
if ok {
|
||||||
|
return hash, nil
|
||||||
|
}
|
||||||
|
cs, err := c.GetContractStateByAddressOrName(name)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint160{}, err
|
||||||
|
}
|
||||||
|
c.cache.nativeHashes[lowercasedName] = cs.ScriptHash()
|
||||||
|
return cs.ScriptHash(), nil
|
||||||
|
}
|
||||||
|
|
|
@ -315,13 +315,57 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
},
|
},
|
||||||
"getcontractstate": {
|
"getcontractstate": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive, by hash",
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
hash, err := util.Uint160DecodeStringLE("1b4357bff5a01bdf2a6581247cf9ed1e24629176")
|
hash, err := util.Uint160DecodeStringLE("1b4357bff5a01bdf2a6581247cf9ed1e24629176")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return c.GetContractState(hash)
|
return c.GetContractStateByHash(hash)
|
||||||
|
},
|
||||||
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"features":{"payable":false,"storage":true},"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.Features = smartcontract.HasStorage
|
||||||
|
cs := &state.Contract{
|
||||||
|
ID: 0,
|
||||||
|
Script: script,
|
||||||
|
Manifest: *m,
|
||||||
|
}
|
||||||
|
_ = cs.ScriptHash()
|
||||||
|
return cs
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, by address",
|
||||||
|
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":[],"features":{"payable":false,"storage":true},"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.Features = smartcontract.HasStorage
|
||||||
|
cs := &state.Contract{
|
||||||
|
ID: 0,
|
||||||
|
Script: script,
|
||||||
|
Manifest: *m,
|
||||||
|
}
|
||||||
|
_ = cs.ScriptHash()
|
||||||
|
return cs
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, by id",
|
||||||
|
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":[],"features":{"payable":false,"storage":true},"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"features":{"payable":false,"storage":true},"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
|
||||||
result: func(c *Client) interface{} {
|
result: func(c *Client) interface{} {
|
||||||
|
@ -645,7 +689,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
},
|
},
|
||||||
"invokefunction": {
|
"invokefunction": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive, by scripthash",
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
hash, err := util.Uint160DecodeStringLE("91b83e96f2a7c4fdf0c1688441ec61986c7cae26")
|
hash, err := util.Uint160DecodeStringLE("91b83e96f2a7c4fdf0c1688441ec61986c7cae26")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -991,7 +1035,7 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
||||||
{
|
{
|
||||||
name: "getcontractstate_invalid_params_error",
|
name: "getcontractstate_invalid_params_error",
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
return c.GetContractState(util.Uint160{})
|
return c.GetContractStateByHash(util.Uint160{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1178,7 +1222,7 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
||||||
{
|
{
|
||||||
name: "getcontractstate_unmarshalling_error",
|
name: "getcontractstate_unmarshalling_error",
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
return c.GetContractState(util.Uint160{})
|
return c.GetContractStateByHash(util.Uint160{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1372,13 +1416,7 @@ func initTestServer(t *testing.T, resp string) *httptest.Server {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||||
}
|
}
|
||||||
var response string
|
response := wrapInitResponse(r, resp)
|
||||||
switch r.Method {
|
|
||||||
case "getversion":
|
|
||||||
response = `{"id":1,"jsonrpc":"2.0","result":{"magic":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
|
||||||
default:
|
|
||||||
response = resp
|
|
||||||
}
|
|
||||||
ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
||||||
err = ws.WriteMessage(1, []byte(response))
|
err = ws.WriteMessage(1, []byte(response))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1393,27 +1431,49 @@ func initTestServer(t *testing.T, resp string) *httptest.Server {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||||
}
|
}
|
||||||
requestHandler(t, r.Method, w, resp)
|
requestHandler(t, r, w, resp)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return srv
|
return srv
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestHandler(t *testing.T, method string, w http.ResponseWriter, resp string) {
|
func requestHandler(t *testing.T, r *request.In, w http.ResponseWriter, resp string) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
var response string
|
response := wrapInitResponse(r, resp)
|
||||||
switch method {
|
|
||||||
case "getversion":
|
|
||||||
response = `{"id":1,"jsonrpc":"2.0","result":{"magic":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
|
||||||
default:
|
|
||||||
response = resp
|
|
||||||
}
|
|
||||||
_, err := w.Write([]byte(response))
|
_, err := w.Write([]byte(response))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error writing response: %s", err.Error())
|
t.Fatalf("Error writing response: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapInitResponse(r *request.In, resp string) string {
|
||||||
|
var response string
|
||||||
|
switch r.Method {
|
||||||
|
case "getversion":
|
||||||
|
response = `{"id":1,"jsonrpc":"2.0","result":{"magic":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`
|
||||||
|
case "getcontractstate":
|
||||||
|
p, err := r.Params()
|
||||||
|
if err != nil {
|
||||||
|
response = resp
|
||||||
|
}
|
||||||
|
name, err := p.ValueWithType(0, request.StringT).GetString()
|
||||||
|
if err != nil {
|
||||||
|
response = resp
|
||||||
|
}
|
||||||
|
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":[],"features":{"payable":false,"storage":false},"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":[],"features":{"payable":false,"storage":false},"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf"],"extra":null},"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"}}`
|
||||||
|
default:
|
||||||
|
response = resp
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
response = resp
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
func TestCalculateValidUntilBlock(t *testing.T) {
|
func TestCalculateValidUntilBlock(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
getBlockCountCalled int
|
getBlockCountCalled int
|
||||||
|
@ -1434,7 +1494,7 @@ func TestCalculateValidUntilBlock(t *testing.T) {
|
||||||
getValidatorsCalled++
|
getValidatorsCalled++
|
||||||
response = `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}`
|
response = `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}`
|
||||||
}
|
}
|
||||||
requestHandler(t, r.Method, w, response)
|
requestHandler(t, r, w, response)
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
|
@ -1462,8 +1522,13 @@ func TestCalculateValidUntilBlock(t *testing.T) {
|
||||||
|
|
||||||
func TestGetNetwork(t *testing.T) {
|
func TestGetNetwork(t *testing.T) {
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
r := request.NewIn()
|
||||||
|
err := r.DecodeData(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||||
|
}
|
||||||
// request handler already have `getversion` response wrapper
|
// request handler already have `getversion` response wrapper
|
||||||
requestHandler(t, "getversion", w, "")
|
requestHandler(t, r, w, "")
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
endpoint := srv.URL
|
endpoint := srv.URL
|
||||||
|
|
|
@ -277,7 +277,10 @@ func TestCreateNEP5TransferTx(t *testing.T) {
|
||||||
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tx, err := c.CreateNEP5TransferTx(acc, util.Uint160{}, client.GasContractHash, 1000, 0)
|
gasContractHash, err := c.GetNativeContractHash("gas")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tx, err := c.CreateNEP5TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, acc.SignTx(tx))
|
require.NoError(t, acc.SignTx(tx))
|
||||||
require.NoError(t, chain.VerifyTx(tx))
|
require.NoError(t, chain.VerifyTx(tx))
|
||||||
|
|
|
@ -765,6 +765,42 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getContractScriptHashFromParam returns the contract script hash by hex contract hash, address, id or native contract name.
|
||||||
|
func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.Error) {
|
||||||
|
var result util.Uint160
|
||||||
|
if param == nil {
|
||||||
|
return result, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
switch param.Type {
|
||||||
|
case request.StringT:
|
||||||
|
var err error
|
||||||
|
result, err = param.GetUint160FromAddressOrHex()
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
name, err := param.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return result, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
result, err = s.chain.GetNativeContractScriptHash(name)
|
||||||
|
if err != nil {
|
||||||
|
return result, response.NewRPCError("Unknown contract: querying by name is supported for native contracts only", "", nil)
|
||||||
|
}
|
||||||
|
case request.NumberT:
|
||||||
|
id, err := param.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return result, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
result, err = s.chain.GetContractScriptHash(int32(id))
|
||||||
|
if err != nil {
|
||||||
|
return result, response.NewRPCError("Unknown contract", "", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return result, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
|
func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
|
||||||
id, rErr := s.contractIDFromParam(ps.Value(0))
|
id, rErr := s.contractIDFromParam(ps.Value(0))
|
||||||
if rErr == response.ErrUnknown {
|
if rErr == response.ErrUnknown {
|
||||||
|
@ -828,11 +864,12 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response
|
||||||
return height, nil
|
return height, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getContractState returns contract state (contract information, according to the contract script hash).
|
// getContractState returns contract state (contract information, according to the contract script hash,
|
||||||
|
// contract id or native contract name).
|
||||||
func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
scriptHash, err := reqParams.ValueWithType(0, request.StringT).GetUint160FromHex()
|
scriptHash, err := s.contractScriptHashFromParam(reqParams.Value(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, err
|
||||||
}
|
}
|
||||||
cs := s.chain.GetContractState(scriptHash)
|
cs := s.chain.GetContractState(scriptHash)
|
||||||
if cs == nil {
|
if cs == nil {
|
||||||
|
@ -947,9 +984,9 @@ func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) {
|
||||||
|
|
||||||
// invokeFunction implements the `invokeFunction` RPC call.
|
// invokeFunction implements the `invokeFunction` RPC call.
|
||||||
func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
scriptHash, err := reqParams.ValueWithType(0, request.StringT).GetUint160FromHex()
|
scriptHash, responseErr := s.contractScriptHashFromParam(reqParams.Value(0))
|
||||||
if err != nil {
|
if responseErr != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, responseErr
|
||||||
}
|
}
|
||||||
tx := &transaction.Transaction{}
|
tx := &transaction.Transaction{}
|
||||||
checkWitnessHashesIndex := len(reqParams)
|
checkWitnessHashesIndex := len(reqParams)
|
||||||
|
|
|
@ -96,7 +96,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
},
|
},
|
||||||
"getcontractstate": {
|
"getcontractstate": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive, by hash",
|
||||||
params: fmt.Sprintf(`["%s"]`, testContractHash),
|
params: fmt.Sprintf(`["%s"]`, testContractHash),
|
||||||
result: func(e *executor) interface{} { return &state.Contract{} },
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
||||||
check: func(t *testing.T, e *executor, cs interface{}) {
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
||||||
|
@ -106,10 +106,50 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "negative",
|
name: "positive, by id",
|
||||||
|
params: `[0]`,
|
||||||
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
||||||
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
||||||
|
res, ok := cs.(*state.Contract)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Equal(t, int32(0), res.ID)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, native by id",
|
||||||
|
params: `[-3]`,
|
||||||
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
||||||
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
||||||
|
res, ok := cs.(*state.Contract)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Equal(t, int32(-3), res.ID)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, native by name",
|
||||||
|
params: `["Policy"]`,
|
||||||
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
||||||
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
||||||
|
res, ok := cs.(*state.Contract)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Equal(t, int32(-3), res.ID)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative, bad hash",
|
||||||
params: `["6d1eeca891ee93de2b7a77eb91c26f3b3c04d6c3"]`,
|
params: `["6d1eeca891ee93de2b7a77eb91c26f3b3c04d6c3"]`,
|
||||||
fail: true,
|
fail: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "negative, bad ID",
|
||||||
|
params: `[-8]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative, bad native name",
|
||||||
|
params: `["unknown_native"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "no params",
|
name: "no params",
|
||||||
params: `[]`,
|
params: `[]`,
|
||||||
|
|
Loading…
Reference in a new issue