Merge pull request #1216 from nspcc-dev/neo3/rpc/sendrawtransaction

rpc: adjust `sendrawtransaction` and `submitblock` RPC calls
This commit is contained in:
Roman Khimov 2020-07-22 22:13:21 +03:00 committed by GitHub
commit c4cde44543
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 48 deletions

View file

@ -89,9 +89,12 @@ func signMultisig(ctx *cli.Context) error {
if err != nil {
return err
}
if err := c.SendRawTransaction(tx); err != nil {
res, err := c.SendRawTransaction(tx)
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
return nil
}
fmt.Println(tx.Hash().StringLE())

View file

@ -384,9 +384,12 @@ func transferNEP5(ctx *cli.Context) error {
}
} else {
_ = acc.SignTx(tx)
if err := c.SendRawTransaction(tx); err != nil {
res, err := c.SendRawTransaction(tx)
if err != nil {
return cli.NewExitError(err, 1)
}
fmt.Println(res.StringLE())
return nil
}
fmt.Println(tx.Hash().StringLE())

View file

@ -159,11 +159,7 @@ func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token util.U
return util.Uint256{}, fmt.Errorf("can't sign tx: %v", err)
}
if err := c.SendRawTransaction(tx); err != nil {
return util.Uint256{}, err
}
return tx.Hash(), nil
return c.SendRawTransaction(tx)
}
func topIntFromStack(st []smartcontract.Parameter) (int64, error) {

View file

@ -2,6 +2,7 @@ package client
import (
"encoding/hex"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block"
@ -385,40 +386,34 @@ func (c *Client) invokeSomething(method string, p request.RawParams, cosigners [
// The given hex string needs to be signed with a keypair.
// When the result of the response object is true, the TX has successfully
// been broadcasted to the network.
func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) error {
func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) (util.Uint256, error) {
var (
params = request.NewRawParams(hex.EncodeToString(rawTX.Bytes()))
resp bool
resp = new(result.RelayResult)
)
if err := c.performRequest("sendrawtransaction", params, &resp); err != nil {
return err
if err := c.performRequest("sendrawtransaction", params, resp); err != nil {
return util.Uint256{}, err
}
if !resp {
return errors.New("sendrawtransaction returned false")
}
return nil
return resp.Hash, nil
}
// SubmitBlock broadcasts a raw block over the NEO network.
func (c *Client) SubmitBlock(b block.Block) error {
func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) {
var (
params request.RawParams
resp bool
resp = new(result.RelayResult)
)
buf := io.NewBufBinWriter()
b.EncodeBinary(buf.BinWriter)
if err := buf.Err; err != nil {
return err
return util.Uint256{}, err
}
params = request.NewRawParams(hex.EncodeToString(buf.Bytes()))
if err := c.performRequest("submitblock", params, &resp); err != nil {
return err
if err := c.performRequest("submitblock", params, resp); err != nil {
return util.Uint256{}, err
}
if !resp {
return errors.New("submitblock returned false")
}
return nil
return resp.Hash, nil
}
// SignAndPushInvocationTx signs and pushes given script as an invocation
@ -453,11 +448,13 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys
return txHash, errors.Wrap(err, "failed to sign tx")
}
txHash = tx.Hash()
err = c.SendRawTransaction(tx)
actualHash, err := c.SendRawTransaction(tx)
if err != nil {
return txHash, errors.Wrap(err, "failed sendning tx")
}
if !actualHash.Equals(txHash) {
return actualHash, fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", txHash.StringLE(), actualHash.StringLE())
}
return txHash, nil
}

View file

@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"math/big"
"net/http"
"net/http/httptest"
@ -699,12 +700,15 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
return c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":true}`,
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"hash":"0x72159b0cf1221110daad6e1df6ef4ff03012173b63c86910bd7134deb659c875"}}`,
result: func(c *Client) interface{} {
// no error expected
return nil
h, err := util.Uint256DecodeStringLE("72159b0cf1221110daad6e1df6ef4ff03012173b63c86910bd7134deb659c875")
if err != nil {
panic(fmt.Errorf("can't decode `sendrawtransaction` result hash: %v", err))
}
return h
},
},
},
@ -712,16 +716,19 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
return c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,
})
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":true}`,
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"hash":"0x1bdea8f80eb5bd97fade38d5e7fb93b02c9d3e01394e9f4324218132293f7ea6"}}`,
result: func(c *Client) interface{} {
// no error expected
return nil
h, err := util.Uint256DecodeStringLE("1bdea8f80eb5bd97fade38d5e7fb93b02c9d3e01394e9f4324218132293f7ea6")
if err != nil {
panic(fmt.Errorf("can't decode `submitblock` result hash: %v", err))
}
return h
},
},
},
@ -830,13 +837,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
{
name: "sendrawtransaction_bad_server_answer",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
return c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
},
},
{
name: "submitblock_bad_server_answer",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
return c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,
@ -986,13 +993,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
{
name: "sendrawtransaction_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(&transaction.Transaction{})
return c.SendRawTransaction(&transaction.Transaction{})
},
},
{
name: "submitblock_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{})
return c.SubmitBlock(block.Block{})
},
},
{
@ -1168,13 +1175,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
{
name: "sendrawtransaction_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
return c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0))
},
},
{
name: "submitblock_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
return c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,

View file

@ -0,0 +1,8 @@
package result
import "github.com/nspcc-dev/neo-go/pkg/util"
// RelayResult ia a result of `sendrawtransaction` or `submitblock` RPC calls.
type RelayResult struct {
Hash util.Uint256 `json:"hash"`
}

View file

@ -902,7 +902,9 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.E
return nil, response.ErrValidationFailed
}
}
return true, nil
return &result.RelayResult{
Hash: b.Hash(),
}, nil
}
func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) {
@ -921,7 +923,9 @@ func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *res
relayReason := s.coreServer.RelayTxn(tx)
switch relayReason {
case network.RelaySucceed:
results = true
results = result.RelayResult{
Hash: tx.Hash(),
}
case network.RelayAlreadyExists:
resultsErr = response.ErrAlreadyExists
case network.RelayOutOfMemory:

View file

@ -590,9 +590,13 @@ var rpcTestCases = map[string][]rpcTestCase{
{
name: "positive",
params: `["000a000000aa8acf859d4fe402b34e673f2156821796a488eb80969800000000009269130000000000b00400000001aa8acf859d4fe402b34e673f2156821796a488eb015d0300e87648170000000c1478ba4c24009fe510e136c9995a2e05215e1be4dc0c14aa8acf859d4fe402b34e673f2156821796a488eb13c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c4040719393aa590d962cb5a48e16360ac75a6c358c9699e9f1a853afede4d601b6783e28f5ec74542aaf59519e76830ba9d267656db324461fdb08d1d51521e103290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"]`,
result: func(e *executor) interface{} {
v := true
return &v
result: func(e *executor) interface{} { return &result.RelayResult{} },
check: func(t *testing.T, e *executor, inv interface{}) {
res, ok := inv.(*result.RelayResult)
require.True(t, ok)
expectedHash, err := util.Uint256DecodeStringLE("72159b0cf1221110daad6e1df6ef4ff03012173b63c86910bd7134deb659c875")
require.NoError(t, err)
assert.Equal(t, expectedHash, res.Hash)
},
},
{
@ -756,9 +760,9 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
b := newBlock(t, chain, 1, 0, newTx())
body := doRPCCall(fmt.Sprintf(rpc, encodeBlock(t, b)), httpSrv.URL, t)
data := checkErrGetResult(t, body, false)
var res bool
require.NoError(t, json.Unmarshal(data, &res))
require.True(t, res)
var res = new(result.RelayResult)
require.NoError(t, json.Unmarshal(data, res))
require.Equal(t, b.Hash(), res.Hash)
})
})