forked from TrueCloudLab/neoneo-go
Merge pull request #1489 from nspcc-dev/rpc/invoke_with_base64
rpc, cli: use base64 script encoding for Invoke* calls; add Magic to `getversion` RPC call
This commit is contained in:
commit
8be7cd4bff
20 changed files with 254 additions and 118 deletions
|
@ -17,7 +17,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep5", "multitransfer",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
"neo:"+validatorPriv.Address()+":10",
|
||||
|
@ -26,7 +26,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "candidate", "register",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorPriv.Address())
|
||||
e.checkTxPersisted(t)
|
||||
|
@ -40,7 +40,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
t.Run("Vote", func(t *testing.T) {
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorPriv.Address(),
|
||||
"--candidate", hex.EncodeToString(validatorPriv.PublicKey().Bytes()))
|
||||
|
@ -55,7 +55,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorPriv.Address())
|
||||
e.checkTxPersisted(t)
|
||||
|
|
|
@ -40,7 +40,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "deploy",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||
"--in", nefName, "--manifest", manifestName)
|
||||
|
||||
|
@ -53,7 +53,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
h.StringLE(), "getValue")
|
||||
|
||||
res := new(result.Invoke)
|
||||
|
@ -84,7 +84,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||
h.StringLE(), "update",
|
||||
"bytes:"+hex.EncodeToString(realNef.Script),
|
||||
|
@ -94,7 +94,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
hash.Hash160(realNef.Script).StringLE(), "getValue")
|
||||
|
||||
res := new(result.Invoke)
|
||||
|
|
|
@ -53,7 +53,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
// Transfer funds to the multisig.
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep5", "multitransfer",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
"neo:"+multisigAddr+":4",
|
||||
|
@ -68,14 +68,14 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
defer os.Remove(txPath)
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep5", "transfer",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wallet1Path, "--from", multisigAddr,
|
||||
"--to", priv.Address(), "--token", "neo", "--amount", "1",
|
||||
"--out", txPath)
|
||||
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "multisig", "sign",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||
"--in", txPath, "--out", txPath)
|
||||
e.checkTxPersisted(t)
|
||||
|
@ -88,7 +88,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
t.Run("via invokefunction", func(t *testing.T) {
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wallet1Path, "--address", multisigAddr,
|
||||
"--out", txPath,
|
||||
client.NeoContractHash.StringLE(), "transfer",
|
||||
|
@ -99,7 +99,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "multisig", "sign",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||
"--in", txPath, "--out", txPath)
|
||||
e.checkTxPersisted(t)
|
||||
|
|
|
@ -109,7 +109,6 @@ func TestNEP5Transfer(t *testing.T) {
|
|||
defer e.Close(t)
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "transfer",
|
||||
"--unittest",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
|
@ -141,7 +140,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
|
|||
defer e.Close(t)
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "multitransfer",
|
||||
"--unittest", "--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--from", validatorAddr,
|
||||
"neo:" + privs[0].Address() + ":42",
|
||||
|
|
|
@ -34,10 +34,6 @@ var RPC = []cli.Flag{
|
|||
Name: "timeout, s",
|
||||
Usage: "Timeout for the operation (10 seconds by default)",
|
||||
},
|
||||
cli.BoolFlag{Name: "privnet, p"},
|
||||
cli.BoolFlag{Name: "mainnet, m"},
|
||||
cli.BoolFlag{Name: "testnet, t"},
|
||||
cli.BoolFlag{Name: "unittest", Hidden: true},
|
||||
}
|
||||
|
||||
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
||||
|
@ -73,7 +69,11 @@ func GetRPCClient(gctx context.Context, ctx *cli.Context) (*client.Client, cli.E
|
|||
if len(endpoint) == 0 {
|
||||
return nil, cli.NewExitError(errNoEndpoint, 1)
|
||||
}
|
||||
c, err := client.New(gctx, endpoint, client.Options{Network: GetNetwork(ctx)})
|
||||
c, err := client.New(gctx, endpoint, client.Options{})
|
||||
if err != nil {
|
||||
return nil, cli.NewExitError(err, 1)
|
||||
}
|
||||
err = c.Init()
|
||||
if err != nil {
|
||||
return nil, cli.NewExitError(err, 1)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,13 @@ package options
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -56,6 +59,17 @@ func TestGetTimeoutContext(t *testing.T) {
|
|||
}
|
||||
|
||||
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)
|
||||
|
@ -66,7 +80,7 @@ func TestGetRPCClient(t *testing.T) {
|
|||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||
set.String(RPCEndpointFlag, "http://localhost:50333", "")
|
||||
set.String(RPCEndpointFlag, srv.URL, "")
|
||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||
gctx, _ := GetTimeoutContext(ctx)
|
||||
_, ec := GetRPCClient(gctx, ctx)
|
||||
|
|
|
@ -487,6 +487,9 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = c.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err = c.InvokeFunction(script, operation, params, cosigners)
|
||||
if err != nil {
|
||||
|
@ -500,11 +503,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
fmt.Fprintln(ctx.App.Writer, errText+". Sending transaction...")
|
||||
}
|
||||
if out := ctx.String("out"); out != "" {
|
||||
script, err := hex.DecodeString(resp.Script)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %w", err), 1)
|
||||
}
|
||||
tx, err := c.CreateTxFromScript(script, acc, resp.GasConsumed, int64(gas), cosigners...)
|
||||
tx, err := c.CreateTxFromScript(resp.Script, acc, resp.GasConsumed, int64(gas), cosigners...)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||
}
|
||||
|
@ -518,11 +517,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
if len(resp.Script) == 0 {
|
||||
return cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
||||
}
|
||||
script, err := hex.DecodeString(resp.Script)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %w", err), 1)
|
||||
}
|
||||
txHash, err := c.SignAndPushInvocationTx(script, acc, resp.GasConsumed, gas, cosigners)
|
||||
txHash, err := c.SignAndPushInvocationTx(resp.Script, acc, resp.GasConsumed, gas, cosigners)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ func TestClaimGas(t *testing.T) {
|
|||
balanceBefore := e.Chain.GetUtilityTokenBalance(validatorHash)
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "claim",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorAddr)
|
||||
tx, end := e.checkTxPersisted(t)
|
||||
|
@ -195,7 +195,7 @@ func TestImportDeployed(t *testing.T) {
|
|||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "deploy",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||
"--in", "testdata/verify.nef", "--manifest", "testdata/verify.manifest.json")
|
||||
|
||||
|
@ -217,7 +217,7 @@ func TestImportDeployed(t *testing.T) {
|
|||
|
||||
e.In.WriteString("acc\rpass\rpass\r")
|
||||
e.Run(t, "neo-go", "wallet", "import-deployed",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", walletPath, "--wif", priv.WIF(),
|
||||
"--contract", h.StringLE())
|
||||
|
||||
|
@ -232,7 +232,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",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet, "--from", validatorAddr,
|
||||
"neo:"+contractAddr+":10",
|
||||
"gas:"+contractAddr+":10")
|
||||
|
@ -243,7 +243,7 @@ func TestImportDeployed(t *testing.T) {
|
|||
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep5", "transfer",
|
||||
"--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", walletPath, "--from", contractAddr,
|
||||
"--to", privTo.Address(), "--token", "neo", "--amount", "1")
|
||||
e.checkTxPersisted(t)
|
||||
|
|
|
@ -29,6 +29,8 @@ const (
|
|||
type Client struct {
|
||||
cli *http.Client
|
||||
endpoint *url.URL
|
||||
network netmode.Magic
|
||||
initDone bool
|
||||
ctx context.Context
|
||||
opts Options
|
||||
requestF func(*request.Raw) (*response.Raw, error)
|
||||
|
@ -46,7 +48,6 @@ type Options struct {
|
|||
CACert string
|
||||
DialTimeout time.Duration
|
||||
RequestTimeout time.Duration
|
||||
Network netmode.Magic
|
||||
}
|
||||
|
||||
// cache stores cache values for the RPC client methods
|
||||
|
@ -61,7 +62,8 @@ type calculateValidUntilBlockCache struct {
|
|||
expiresAt uint32
|
||||
}
|
||||
|
||||
// New returns a new Client ready to use.
|
||||
// New returns a new Client ready to use. You should call Init method to
|
||||
// initialize network magic the client is operating on.
|
||||
func New(ctx context.Context, endpoint string, opts Options) (*Client, error) {
|
||||
url, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
|
@ -99,6 +101,19 @@ func New(ctx context.Context, endpoint string, opts Options) (*Client, error) {
|
|||
return cl, nil
|
||||
}
|
||||
|
||||
// Init sets magic of the network client connected to. This method should be called
|
||||
// before any transaction-, header- or block-related requests in order to deserialize
|
||||
// responses properly.
|
||||
func (c *Client) Init() error {
|
||||
version, err := c.GetVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get network magic: %w", err)
|
||||
}
|
||||
c.network = version.Magic
|
||||
c.initDone = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) performRequest(method string, p request.RawParams, v interface{}) error {
|
||||
var r = request.Raw{
|
||||
JSONRPC: request.JSONRPCVersion,
|
||||
|
|
|
@ -5,14 +5,13 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
endpoint := "http://seed5.bridgeprotocol.io:10332"
|
||||
opts := client.Options{Network: netmode.MainNet}
|
||||
opts := client.Options{}
|
||||
|
||||
c, err := client.New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
|
|
|
@ -152,7 +152,8 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip
|
|||
}
|
||||
|
||||
// CreateTxFromScript creates transaction and properly sets cosigners and NetworkFee.
|
||||
// If sysFee <= 0, it is determined via result of `invokescript` RPC.
|
||||
// If sysFee <= 0, it is determined via result of `invokescript` RPC. You should
|
||||
// initialize network magic with Init before calling CreateTxFromScript.
|
||||
func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee, netFee int64,
|
||||
cosigners ...transaction.Signer) (*transaction.Transaction, error) {
|
||||
from, err := address.StringToUint160(acc.Address)
|
||||
|
@ -172,7 +173,10 @@ func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee,
|
|||
sysFee = result.GasConsumed
|
||||
}
|
||||
|
||||
tx := transaction.New(c.opts.Network, script, sysFee)
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
tx := transaction.New(c.GetNetwork(), script, sysFee)
|
||||
tx.Signers = signers
|
||||
|
||||
tx.ValidUntilBlock, err = c.CalculateValidUntilBlock()
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"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/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
|
@ -20,6 +21,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
var errNetworkNotInitialized = errors.New("RPC client network is not initialized")
|
||||
|
||||
// GetApplicationLog returns the contract log based on the specified txid.
|
||||
func (c *Client) GetApplicationLog(hash util.Uint256) (*state.AppExecResult, error) {
|
||||
var (
|
||||
|
@ -50,12 +53,14 @@ func (c *Client) GetBlockCount() (uint32, error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// GetBlockByIndex returns a block by its height.
|
||||
// GetBlockByIndex returns a block by its height. You should initialize network magic
|
||||
// with Init before calling GetBlockByIndex.
|
||||
func (c *Client) GetBlockByIndex(index uint32) (*block.Block, error) {
|
||||
return c.getBlock(request.NewRawParams(index))
|
||||
}
|
||||
|
||||
// GetBlockByHash returns a block by its hash.
|
||||
// GetBlockByHash returns a block by its hash. You should initialize network magic
|
||||
// with Init before calling GetBlockByHash.
|
||||
func (c *Client) GetBlockByHash(hash util.Uint256) (*block.Block, error) {
|
||||
return c.getBlock(request.NewRawParams(hash.StringLE()))
|
||||
}
|
||||
|
@ -66,6 +71,9 @@ func (c *Client) getBlock(params request.RawParams) (*block.Block, error) {
|
|||
err error
|
||||
b *block.Block
|
||||
)
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
if err = c.performRequest("getblock", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -74,7 +82,7 @@ func (c *Client) getBlock(params request.RawParams) (*block.Block, error) {
|
|||
return nil, err
|
||||
}
|
||||
r := io.NewBinReaderFromBuf(blockBytes)
|
||||
b = block.New(c.opts.Network)
|
||||
b = block.New(c.GetNetwork())
|
||||
b.DecodeBinary(r)
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
|
@ -83,14 +91,14 @@ func (c *Client) getBlock(params request.RawParams) (*block.Block, error) {
|
|||
}
|
||||
|
||||
// GetBlockByIndexVerbose returns a block wrapper with additional metadata by
|
||||
// its height.
|
||||
// its height. You should initialize network magic with Init before calling GetBlockByIndexVerbose.
|
||||
// NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively.
|
||||
func (c *Client) GetBlockByIndexVerbose(index uint32) (*result.Block, error) {
|
||||
return c.getBlockVerbose(request.NewRawParams(index, 1))
|
||||
}
|
||||
|
||||
// GetBlockByHashVerbose returns a block wrapper with additional metadata by
|
||||
// its hash.
|
||||
// its hash. You should initialize network magic with Init before calling GetBlockByHashVerbose.
|
||||
func (c *Client) GetBlockByHashVerbose(hash util.Uint256) (*result.Block, error) {
|
||||
return c.getBlockVerbose(request.NewRawParams(hash.StringLE(), 1))
|
||||
}
|
||||
|
@ -100,7 +108,10 @@ func (c *Client) getBlockVerbose(params request.RawParams) (*result.Block, error
|
|||
resp = &result.Block{}
|
||||
err error
|
||||
)
|
||||
resp.Network = c.opts.Network
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
resp.Network = c.GetNetwork()
|
||||
if err = c.performRequest("getblock", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -120,13 +131,17 @@ func (c *Client) GetBlockHash(index uint32) (util.Uint256, error) {
|
|||
}
|
||||
|
||||
// GetBlockHeader returns the corresponding block header information from serialized hex string
|
||||
// according to the specified script hash.
|
||||
// according to the specified script hash. You should initialize network magic
|
||||
// // with Init before calling GetBlockHeader.
|
||||
func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) {
|
||||
var (
|
||||
params = request.NewRawParams(hash.StringLE())
|
||||
resp string
|
||||
h *block.Header
|
||||
)
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
if err := c.performRequest("getblockheader", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -136,7 +151,7 @@ func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) {
|
|||
}
|
||||
r := io.NewBinReaderFromBuf(headerBytes)
|
||||
h = new(block.Header)
|
||||
h.Network = c.opts.Network
|
||||
h.Network = c.GetNetwork()
|
||||
h.DecodeBinary(r)
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
|
@ -271,13 +286,17 @@ func (c *Client) GetRawMemPool() ([]util.Uint256, error) {
|
|||
return *resp, nil
|
||||
}
|
||||
|
||||
// GetRawTransaction returns a transaction by hash.
|
||||
// GetRawTransaction returns a transaction by hash. You should initialize network magic
|
||||
// with Init before calling GetRawTransaction.
|
||||
func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, error) {
|
||||
var (
|
||||
params = request.NewRawParams(hash.StringLE())
|
||||
resp string
|
||||
err error
|
||||
)
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
if err = c.performRequest("getrawtransaction", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -285,7 +304,7 @@ func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tx, err := transaction.NewTransactionFromBytes(c.opts.Network, txBytes)
|
||||
tx, err := transaction.NewTransactionFromBytes(c.GetNetwork(), txBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -293,7 +312,8 @@ func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction,
|
|||
}
|
||||
|
||||
// GetRawTransactionVerbose returns a transaction wrapper with additional
|
||||
// metadata by transaction's hash.
|
||||
// metadata by transaction's hash. You should initialize network magic
|
||||
// with Init before calling GetRawTransactionVerbose.
|
||||
// NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively.
|
||||
func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.TransactionOutputRaw, error) {
|
||||
var (
|
||||
|
@ -301,7 +321,10 @@ func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.Transactio
|
|||
resp = &result.TransactionOutputRaw{}
|
||||
err error
|
||||
)
|
||||
resp.Network = c.opts.Network
|
||||
if !c.initDone {
|
||||
return nil, errNetworkNotInitialized
|
||||
}
|
||||
resp.Network = c.GetNetwork()
|
||||
if err = c.performRequest("getrawtransaction", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -381,7 +404,7 @@ func (c *Client) GetVersion() (*result.Version, error) {
|
|||
// InvokeScript returns the result of the given script after running it true the VM.
|
||||
// NOTE: This is a test invoke and will not affect the blockchain.
|
||||
func (c *Client) InvokeScript(script []byte, signers []transaction.Signer) (*result.Invoke, error) {
|
||||
var p = request.NewRawParams(hex.EncodeToString(script))
|
||||
var p = request.NewRawParams(script)
|
||||
return c.invokeSomething("invokescript", p, signers)
|
||||
}
|
||||
|
||||
|
@ -569,3 +592,8 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
|
|||
tx.NetworkFee += int64(size)*fee + extraFee
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNetwork returns the network magic of the RPC node client connected to.
|
||||
func (c *Client) GetNetwork() netmode.Magic {
|
||||
return c.network
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
|
@ -347,7 +348,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetFeePerByte()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c0d676574466565506572427974650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return int64(1000)
|
||||
},
|
||||
|
@ -359,7 +360,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetMaxTransactionsPerBlock()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c1a6765744d61785472616e73616374696f6e73506572426c6f636b0c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"512"}],"tx":null}}`,
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMGmdldE1heFRyYW5zYWN0aW9uc1BlckJsb2NrDBSaYaRu7Je4kwbXzoHxW0YgkdAJMkFifVtS","stack":[{"type":"Integer","value":"512"}],"tx":null}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return int64(512)
|
||||
},
|
||||
|
@ -371,7 +372,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetMaxBlockSize()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c0f6765744d6178426c6f636b53697a650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`,
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMD2dldE1heEJsb2NrU2l6ZQwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return int64(262144)
|
||||
},
|
||||
|
@ -383,7 +384,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetBlockedAccounts()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c12676574426c6f636b65644163636f756e74730c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Array","value":[]}],"tx":null}}`,
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMEmdldEJsb2NrZWRBY2NvdW50cwwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Array","value":[]}],"tx":null}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return native.BlockedAccounts{}
|
||||
},
|
||||
|
@ -631,9 +632,10 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetVersion()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`,
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"magic":42,"tcpport":20332,"wsport":20342,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return &result.Version{
|
||||
Magic: netmode.UnitTestNet,
|
||||
TCPPort: uint16(20332),
|
||||
WSPort: uint16(20342),
|
||||
Nonce: 2153672787,
|
||||
|
@ -663,7 +665,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
Account: util.Uint160{1, 2, 3},
|
||||
}})
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"01e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b5238","state":"HALT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"}}`,
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv","state":"HALT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return &result.Invoke{}
|
||||
},
|
||||
|
@ -674,9 +676,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
script, err := base64.StdEncoding.DecodeString("FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
assert.Equal(t, int64(31100000), res.GasConsumed)
|
||||
assert.Equal(t, "01e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b5238", res.Script)
|
||||
assert.Equal(t, script, res.Script)
|
||||
assert.Equal(t, []stackitem.Item{stackitem.NewByteArray(bytes)}, res.Stack)
|
||||
assert.NotNil(t, res.Transaction)
|
||||
},
|
||||
|
@ -701,7 +707,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
Account: util.Uint160{1, 2, 3},
|
||||
}})
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf","state":"FAULT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78","exception":"gas limit exceeded"}}`,
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv","state":"FAULT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78","exception":"gas limit exceeded"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return &result.Invoke{}
|
||||
},
|
||||
|
@ -712,9 +718,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
script, err := base64.StdEncoding.DecodeString("FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
assert.Equal(t, "FAULT", res.State)
|
||||
assert.Equal(t, int64(31100000), res.GasConsumed)
|
||||
assert.Equal(t, "1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf", res.Script)
|
||||
assert.Equal(t, script, res.Script)
|
||||
assert.Equal(t, []stackitem.Item{stackitem.NewByteArray(bytes)}, res.Stack)
|
||||
assert.NotNil(t, res.Transaction)
|
||||
},
|
||||
|
@ -724,7 +734,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
script, err := hex.DecodeString("00046e616d656724058e5e1b6008847cd662728549088a9ee82191")
|
||||
script, err := base64.StdEncoding.DecodeString("AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -732,16 +742,20 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
Account: util.Uint160{1, 2, 3},
|
||||
}})
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"00046e616d656724058e5e1b6008847cd662728549088a9ee82191","state":"HALT","gasconsumed":"16100000","stack":[{"type":"ByteString","value":"TkVQNSBHQVM="}],"tx":null}}`,
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR","state":"HALT","gasconsumed":"16100000","stack":[{"type":"ByteString","value":"TkVQNSBHQVM="}],"tx":null}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
bytes, err := hex.DecodeString("4e45503520474153")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
script, err := base64.StdEncoding.DecodeString("AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &result.Invoke{
|
||||
State: "HALT",
|
||||
GasConsumed: 16100000,
|
||||
Script: "00046e616d656724058e5e1b6008847cd662728549088a9ee82191",
|
||||
Script: script,
|
||||
Stack: []stackitem.Item{stackitem.NewByteArray(bytes)},
|
||||
}
|
||||
},
|
||||
|
@ -1234,12 +1248,6 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
return c.GetNextBlockValidators()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "getversion_unmarshalling_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetVersion()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invokefunction_unmarshalling_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
|
@ -1280,13 +1288,17 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
func TestRPCClients(t *testing.T) {
|
||||
t.Run("Client", func(t *testing.T) {
|
||||
testRPCClient(t, func(ctx context.Context, endpoint string, opts Options) (*Client, error) {
|
||||
return New(ctx, endpoint, opts)
|
||||
c, err := New(ctx, endpoint, opts)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
return c, nil
|
||||
})
|
||||
})
|
||||
t.Run("WSClient", func(t *testing.T) {
|
||||
testRPCClient(t, func(ctx context.Context, endpoint string, opts Options) (*Client, error) {
|
||||
wsc, err := NewWS(ctx, httpURLtoWS(endpoint), opts)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, wsc.Init())
|
||||
return &wsc.Client, nil
|
||||
})
|
||||
})
|
||||
|
@ -1301,7 +1313,7 @@ func testRPCClient(t *testing.T, newClient func(context.Context, string, Options
|
|||
defer srv.Close()
|
||||
|
||||
endpoint := srv.URL
|
||||
opts := Options{Network: netmode.UnitTestNet}
|
||||
opts := Options{}
|
||||
c, err := newClient(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1325,7 +1337,7 @@ func testRPCClient(t *testing.T, newClient func(context.Context, string, Options
|
|||
defer srv.Close()
|
||||
|
||||
endpoint := srv.URL
|
||||
opts := Options{Network: netmode.UnitTestNet}
|
||||
opts := Options{}
|
||||
c, err := newClient(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1352,12 +1364,24 @@ func initTestServer(t *testing.T, resp string) *httptest.Server {
|
|||
require.NoError(t, err)
|
||||
for {
|
||||
ws.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||
_, _, err = ws.ReadMessage()
|
||||
_, p, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
r := request.NewIn()
|
||||
err = json.Unmarshal(p, r)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
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/"}}`
|
||||
default:
|
||||
response = resp
|
||||
}
|
||||
ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
||||
err = ws.WriteMessage(1, []byte(resp))
|
||||
err = ws.WriteMessage(1, []byte(response))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
@ -1365,16 +1389,27 @@ func initTestServer(t *testing.T, resp string) *httptest.Server {
|
|||
ws.Close()
|
||||
return
|
||||
}
|
||||
requestHandler(t, w, resp)
|
||||
r := request.NewIn()
|
||||
err := r.DecodeData(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
requestHandler(t, r.Method, w, resp)
|
||||
}))
|
||||
|
||||
return srv
|
||||
}
|
||||
|
||||
func requestHandler(t *testing.T, w http.ResponseWriter, resp string) {
|
||||
func requestHandler(t *testing.T, method string, w http.ResponseWriter, resp string) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_, err := w.Write([]byte(resp))
|
||||
|
||||
var response string
|
||||
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))
|
||||
if err != nil {
|
||||
t.Fatalf("Error writing response: %s", err.Error())
|
||||
}
|
||||
|
@ -1399,10 +1434,8 @@ func TestCalculateValidUntilBlock(t *testing.T) {
|
|||
case "getnextblockvalidators":
|
||||
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}]}`
|
||||
default:
|
||||
t.Fatalf("Bad request method: %s", r.Method)
|
||||
}
|
||||
requestHandler(t, w, response)
|
||||
requestHandler(t, r.Method, w, response)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
|
@ -1412,6 +1445,7 @@ func TestCalculateValidUntilBlock(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
validUntilBlock, err := c.CalculateValidUntilBlock()
|
||||
assert.NoError(t, err)
|
||||
|
@ -1426,3 +1460,32 @@ func TestCalculateValidUntilBlock(t *testing.T) {
|
|||
assert.Equal(t, 2, getBlockCountCalled)
|
||||
assert.Equal(t, 1, getValidatorsCalled)
|
||||
}
|
||||
|
||||
func TestGetNetwork(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
// request handler already have `getversion` response wrapper
|
||||
requestHandler(t, "getversion", w, "")
|
||||
}))
|
||||
defer srv.Close()
|
||||
endpoint := srv.URL
|
||||
opts := Options{}
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// network was not initialised
|
||||
require.Equal(t, netmode.Magic(0), c.GetNetwork())
|
||||
require.Equal(t, false, c.initDone)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, c.Init())
|
||||
require.Equal(t, netmode.UnitTestNet, c.GetNetwork())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ const (
|
|||
|
||||
// NewWS returns a new WSClient ready to use (with established websocket
|
||||
// connection). You need to use websocket URL for it like `ws://1.2.3.4/ws`.
|
||||
// You should call Init method to initialize network magic the client is
|
||||
// operating on.
|
||||
func NewWS(ctx context.Context, endpoint string, opts Options) (*WSClient, error) {
|
||||
cl, err := New(ctx, endpoint, opts)
|
||||
if err != nil {
|
||||
|
@ -137,9 +139,9 @@ readloop:
|
|||
var val interface{}
|
||||
switch event {
|
||||
case response.BlockEventID:
|
||||
val = block.New(c.opts.Network)
|
||||
val = block.New(c.GetNetwork())
|
||||
case response.TransactionEventID:
|
||||
val = &transaction.Transaction{Network: c.opts.Network}
|
||||
val = &transaction.Transaction{Network: c.GetNetwork()}
|
||||
case response.NotificationEventID:
|
||||
val = new(state.NotificationEvent)
|
||||
case response.ExecutionEventID:
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
func TestWSClientClose(t *testing.T) {
|
||||
srv := initTestServer(t, "")
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
wsc.Close()
|
||||
}
|
||||
|
@ -43,8 +43,9 @@ func TestWSClientSubscription(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
srv := initTestServer(t, `{"jsonrpc": "2.0", "id": 1, "result": "55aaff00"}`)
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, wsc.Init())
|
||||
id, err := f(wsc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "55aaff00", id)
|
||||
|
@ -56,8 +57,9 @@ func TestWSClientSubscription(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
srv := initTestServer(t, `{"jsonrpc": "2.0", "id": 1, "error":{"code":-32602,"message":"Invalid Params"}}`)
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, wsc.Init())
|
||||
_, err = f(wsc)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
@ -105,8 +107,9 @@ func TestWSClientUnsubscription(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
srv := initTestServer(t, rc.response)
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, wsc.Init())
|
||||
rc.code(t, wsc)
|
||||
})
|
||||
}
|
||||
|
@ -139,8 +142,9 @@ func TestWSClientEvents(t *testing.T) {
|
|||
}
|
||||
}))
|
||||
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
wsc.network = netmode.UnitTestNet
|
||||
for range events {
|
||||
select {
|
||||
case _, ok = <-wsc.Notifications:
|
||||
|
@ -162,8 +166,9 @@ func TestWSExecutionVMStateCheck(t *testing.T) {
|
|||
// Will answer successfully if request slips through.
|
||||
srv := initTestServer(t, `{"jsonrpc": "2.0", "id": 1, "result": "55aaff00"}`)
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, wsc.Init())
|
||||
filter := "NONE"
|
||||
_, err = wsc.SubscribeForTransactionExecutions(&filter)
|
||||
require.Error(t, err)
|
||||
|
@ -326,8 +331,9 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
|||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
wsc.network = netmode.UnitTestNet
|
||||
c.clientCode(t, wsc)
|
||||
wsc.Close()
|
||||
})
|
||||
|
@ -339,11 +345,12 @@ func TestNewWS(t *testing.T) {
|
|||
defer srv.Close()
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
_, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{Network: netmode.UnitTestNet})
|
||||
c, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
})
|
||||
t.Run("bad URL", func(t *testing.T) {
|
||||
_, err := NewWS(context.TODO(), strings.Trim(srv.URL, "http://"), Options{Network: netmode.UnitTestNet})
|
||||
_, err := NewWS(context.TODO(), strings.Trim(srv.URL, "http://"), Options{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
type Invoke struct {
|
||||
State string
|
||||
GasConsumed int64
|
||||
Script string
|
||||
Script []byte
|
||||
Stack []stackitem.Item
|
||||
FaultException string
|
||||
// Transaction represents transaction bytes. Use GetTransaction method to decode it.
|
||||
|
@ -28,7 +28,7 @@ type Invoke struct {
|
|||
type invokeAux struct {
|
||||
State string `json:"state"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Script string `json:"script"`
|
||||
Script []byte `json:"script"`
|
||||
Stack json.RawMessage `json:"stack"`
|
||||
FaultException string `json:"exception,omitempty"`
|
||||
Transaction string `json:"tx,omitempty"`
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package result
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
|
||||
type (
|
||||
// Version model used for reporting server version
|
||||
// info.
|
||||
Version struct {
|
||||
TCPPort uint16 `json:"tcpport"`
|
||||
WSPort uint16 `json:"wsport,omitempty"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
UserAgent string `json:"useragent"`
|
||||
Magic netmode.Magic `json:"magic"`
|
||||
TCPPort uint16 `json:"tcpport"`
|
||||
WSPort uint16 `json:"wsport,omitempty"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
UserAgent string `json:"useragent"`
|
||||
}
|
||||
)
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
|
@ -25,8 +24,9 @@ func TestClient_NEP5(t *testing.T) {
|
|||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: netmode.UnitTestNet})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
h, err := util.Uint160DecodeStringLE(testContractHash)
|
||||
require.NoError(t, err)
|
||||
|
@ -72,8 +72,9 @@ func TestAddNetworkFee(t *testing.T) {
|
|||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
getAccounts := func(t *testing.T, n int) []*wallet.Account {
|
||||
accs := make([]*wallet.Account, n)
|
||||
|
@ -199,8 +200,9 @@ func TestSignAndPushInvocationTx(t *testing.T) {
|
|||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv := testchain.PrivateKey(0)
|
||||
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
||||
|
@ -222,8 +224,9 @@ func TestPing(t *testing.T) {
|
|||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
require.NoError(t, c.Ping())
|
||||
require.NoError(t, rpcSrv.Shutdown())
|
||||
|
@ -236,8 +239,9 @@ func TestCreateTxFromScript(t *testing.T) {
|
|||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv := testchain.PrivateKey(0)
|
||||
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
||||
|
@ -265,8 +269,9 @@ func TestCreateNEP5TransferTx(t *testing.T) {
|
|||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
||||
c, err := client.New(context.Background(), httpSrv.URL, client.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv := testchain.PrivateKeyByID(0)
|
||||
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
||||
|
|
|
@ -466,6 +466,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) {
|
|||
return nil, response.NewInternalServerError("Cannot fetch tcp port", err)
|
||||
}
|
||||
return result.Version{
|
||||
Magic: s.network,
|
||||
TCPPort: port,
|
||||
Nonce: s.coreServer.ID(),
|
||||
UserAgent: s.coreServer.UserAgent,
|
||||
|
@ -977,7 +978,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
|
|||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
||||
script, err := reqParams[0].GetBytesHex()
|
||||
script, err := reqParams[0].GetBytesBase64()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
@ -1011,7 +1012,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu
|
|||
result := &result.Invoke{
|
||||
State: vm.State().String(),
|
||||
GasConsumed: vm.GasConsumed(),
|
||||
Script: hex.EncodeToString(script),
|
||||
Script: script,
|
||||
Stack: vm.Estack().ToArray(),
|
||||
FaultException: faultException,
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd7757
|
|||
|
||||
const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7"
|
||||
const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740"
|
||||
const testVerifyContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGgRVUH4J+yMIaonBwAAABFADBQNDwMCCQACAQMHAwQFAgEADgYMCdswcWkRVUH4J+yMIaonBwAAABJAE0A="
|
||||
|
||||
var rpcTestCases = map[string][]rpcTestCase{
|
||||
"getapplicationlog": {
|
||||
|
@ -537,7 +538,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
require.True(t, ok)
|
||||
assert.NotEqual(t, "", res.Script)
|
||||
assert.NotNil(t, res.Script)
|
||||
assert.NotEqual(t, "", res.State)
|
||||
assert.NotEqual(t, 0, res.GasConsumed)
|
||||
},
|
||||
|
@ -566,7 +567,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
"invokescript": {
|
||||
{
|
||||
name: "positive",
|
||||
params: `["51c56b0d48656c6c6f2c20776f726c6421680f4e656f2e52756e74696d652e4c6f67616c7566"]`,
|
||||
params: `["UcVrDUhlbGxvLCB3b3JsZCFoD05lby5SdW50aW1lLkxvZ2FsdWY="]`,
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -578,8 +579,8 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, good witness",
|
||||
// script is hex-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
|
||||
params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`,
|
||||
// script is base64-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, testVerifyContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -591,7 +592,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, bad witness of second hash",
|
||||
params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`,
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, testVerifyContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -603,7 +604,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, no good hashes",
|
||||
params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340"]`,
|
||||
params: fmt.Sprintf(`["%s"]`, testVerifyContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
@ -615,7 +616,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
},
|
||||
{
|
||||
name: "positive, bad hashes witness",
|
||||
params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`,
|
||||
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, testVerifyContractAVM),
|
||||
result: func(e *executor) interface{} { return &result.Invoke{} },
|
||||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
|
|
Loading…
Reference in a new issue