neoneo-go/pkg/rpc/client/rpc_test.go
2020-06-05 19:20:16 +03:00

1236 lines
54 KiB
Go

package client
import (
"context"
"encoding/hex"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/gorilla/websocket"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type rpcClientTestCase struct {
name string
invoke func(c *Client) (interface{}, error)
serverResponse string
result func(c *Client) interface{}
check func(t *testing.T, c *Client, result interface{})
}
const hexB1 = "0000000028de4a34063483263ea9899827792bfdc4acf6b533e7294dbb4838b820e9a40b5a448a04e699901d0ed78a62d11e2d0754f152dce78e08c8227d95bdf1df932a3eefd85e0000000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c40585acaabe5810f6a4a42bb44d946494887b4d9286ca3ccbe626f240d60080fccb602d7c4eda9d1aeeb6958adbd604aa227cd7e9238e5ea1925bf57af4c8726270c40785af1caba4069090bbcf6cf2a4eae8dcf9d706f719c8681c6c8599d21052ea1e982f1c35ea8241580c67d5ac33426135ef44575636dafdc3fa769f1d7f09fd20c400222d67892af0cb6561faf5107013f11d24432ae0100b9313799c9fd5c8db0ca8da95e31500fdaea820b06a9bd822b42b8e6b7803182619f9da3b6402e48bd250c40d614157118af153bbb89642280b4bf55fc4873d3bfd7cef3f30946598caa227b566d6c9a116f23ef3c0b383ae1a756cb3a2e724936d22830fef486f3946ae76294130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb03005704000000000000d10102000000abec5362f11e75b6e02e407bb98d63675d1438410000000000000000f66a0d0000000000b0040000590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b52380001abec5362f11e75b6e02e407bb98d63675d14384101000001fd08010c4076ef230b83bf1964ed734fc264df284de8eedbdf0e6403389c812146d34535863142e50aa61f4c6a6a9140441a180aba10166a62a1030458ef9725144f4bc5670c40c122b669c1e3d4346bebe959ffc3c9551533f00ad3b42a512dce6b90fa62f5779f211f576d80c3883ebe3d50b854d472c91c2632ed9c2da7d932b5f6d37fdaa40c4089accd1ef5b0a489acd360c9da7bdd1ad52550b4384d5bb76052debc136680be18d00f4c9c3ac3d9c3e4914c01e6b70f2cc0efc625c5b55ebd656f0f1bb650bb0c407d8de81ebfea87a1bbf366ff472eccdaa6e82a1988d8832318f2f66c7fd2e61f91c4a856d2778215b4d45703728da8a487aa71e53740b603d17d8af7d1a3f7b694130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bbd10103000000abec5362f11e75b6e02e407bb98d63675d1438410000000000000000967a0d0000000000b00400005d0300e87648170000000c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52380001abec5362f11e75b6e02e407bb98d63675d14384101000001fd08010c40cfb0f8c01f320069f8f826cc5e3a9538e4eee4d228f1f2c53028be61c2df99b4341005ff8f50bde0e4827c7b0828eab59faca6eb2315fd11cd802daf88354fc90c4022deeaf06116faad8d9665dbb504a0049bb9f5b57713c85bfd894e12d3d46a73617199ff0854e3d5dde0dece92d8f1fd496b78c71727cfc03819f1d109ef827e0c406f68afac9da6dc56172ae57f56c5f1f3767d12d1a0aee2fecae80133b8e725578639b2ab15f230ce528ed4c85dfcfa4b231d5ff4ecc48555e68adf45e2e475500c4042a504fae6914f86b1318a3e278e8ca18e92db7fa432f05364824ea96a95899a0b3c0b07a910a3782b17fc46bc2a6b31259d1d046fcc508d7873e90ec67cc70794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
const hexTxMoveNeo = "d10102000000abec5362f11e75b6e02e407bb98d63675d1438410000000000000000f66a0d0000000000b0040000590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b52380001abec5362f11e75b6e02e407bb98d63675d14384101000001fd08010c4076ef230b83bf1964ed734fc264df284de8eedbdf0e6403389c812146d34535863142e50aa61f4c6a6a9140441a180aba10166a62a1030458ef9725144f4bc5670c40c122b669c1e3d4346bebe959ffc3c9551533f00ad3b42a512dce6b90fa62f5779f211f576d80c3883ebe3d50b854d472c91c2632ed9c2da7d932b5f6d37fdaa40c4089accd1ef5b0a489acd360c9da7bdd1ad52550b4384d5bb76052debc136680be18d00f4c9c3ac3d9c3e4914c01e6b70f2cc0efc625c5b55ebd656f0f1bb650bb0c407d8de81ebfea87a1bbf366ff472eccdaa6e82a1988d8832318f2f66c7fd2e61f91c4a856d2778215b4d45703728da8a487aa71e53740b603d17d8af7d1a3f7b694130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1687,"nextblockhash":"0x96a0856f49798732e6eae4026a5f3e919b96250d847bcb3560d03bbad895c740","confirmations":4,"hash":"0xf7c3cecbe8fb15560c3113dd03911e52858a233b32cdc761ca03bc0721553424","version":0,"previousblockhash":"0x0ba4e920b83848bb4d29e733b5f6acc4fd2b79279889a93e26833406344ade28","merkleroot":"0x2a93dff1bd957d22c8088ee7dc52f154072d1ed1628ad70e1d9099e6048a445a","time":1591275326,"index":1,"nextconsensus":"AXSvJVzydxXuL9da4GVwK25zdesCrVKkHL","witnesses":[{"invocation":"0c40585acaabe5810f6a4a42bb44d946494887b4d9286ca3ccbe626f240d60080fccb602d7c4eda9d1aeeb6958adbd604aa227cd7e9238e5ea1925bf57af4c8726270c40785af1caba4069090bbcf6cf2a4eae8dcf9d706f719c8681c6c8599d21052ea1e982f1c35ea8241580c67d5ac33426135ef44575636dafdc3fa769f1d7f09fd20c400222d67892af0cb6561faf5107013f11d24432ae0100b9313799c9fd5c8db0ca8da95e31500fdaea820b06a9bd822b42b8e6b7803182619f9da3b6402e48bd250c40d614157118af153bbb89642280b4bf55fc4873d3bfd7cef3f30946598caa227b566d6c9a116f23ef3c0b383ae1a756cb3a2e724936d22830fef486f3946ae762","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"txid":"0xf93ae1dbd2167e9b4a06431741297b351ac6a8ea3ae8892785c49f690a40b2c0","size":578,"type":"InvocationTransaction","version":1,"nonce":2,"sender":"AXSvJVzydxXuL9da4GVwK25zdesCrVKkHL","sys_fee":"0","net_fee":"0.0087935","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":1}],"vin":[],"vout":[],"scripts":[{"invocation":"0c4076ef230b83bf1964ed734fc264df284de8eedbdf0e6403389c812146d34535863142e50aa61f4c6a6a9140441a180aba10166a62a1030458ef9725144f4bc5670c40c122b669c1e3d4346bebe959ffc3c9551533f00ad3b42a512dce6b90fa62f5779f211f576d80c3883ebe3d50b854d472c91c2632ed9c2da7d932b5f6d37fdaa40c4089accd1ef5b0a489acd360c9da7bdd1ad52550b4384d5bb76052debc136680be18d00f4c9c3ac3d9c3e4914c01e6b70f2cc0efc625c5b55ebd656f0f1bb650bb0c407d8de81ebfea87a1bbf366ff472eccdaa6e82a1988d8832318f2f66c7fd2e61f91c4a856d2778215b4d45703728da8a487aa71e53740b603d17d8af7d1a3f7b6","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"}],"script":"0218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b5238"},{"txid":"0xe2caf7a9ce32a0daad81fd76f67aa64ffbe7cedf0fdeb8c57c466b6f5833bf0b","size":582,"type":"InvocationTransaction","version":1,"nonce":3,"sender":"AXSvJVzydxXuL9da4GVwK25zdesCrVKkHL","sys_fee":"0","net_fee":"0.0088335","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":1}],"vin":[],"vout":[],"scripts":[{"invocation":"0c40cfb0f8c01f320069f8f826cc5e3a9538e4eee4d228f1f2c53028be61c2df99b4341005ff8f50bde0e4827c7b0828eab59faca6eb2315fd11cd802daf88354fc90c4022deeaf06116faad8d9665dbb504a0049bb9f5b57713c85bfd894e12d3d46a73617199ff0854e3d5dde0dece92d8f1fd496b78c71727cfc03819f1d109ef827e0c406f68afac9da6dc56172ae57f56c5f1f3767d12d1a0aee2fecae80133b8e725578639b2ab15f230ce528ed4c85dfcfa4b231d5ff4ecc48555e68adf45e2e475500c4042a504fae6914f86b1318a3e278e8ca18e92db7fa432f05364824ea96a95899a0b3c0b07a910a3782b17fc46bc2a6b31259d1d046fcc508d7873e90ec67cc707","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"}],"script":"0300e87648170000000c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5238"}]}}`
const hexHeader1 = "0000000028de4a34063483263ea9899827792bfdc4acf6b533e7294dbb4838b820e9a40b5a448a04e699901d0ed78a62d11e2d0754f152dce78e08c8227d95bdf1df932a3eefd85e0000000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c40585acaabe5810f6a4a42bb44d946494887b4d9286ca3ccbe626f240d60080fccb602d7c4eda9d1aeeb6958adbd604aa227cd7e9238e5ea1925bf57af4c8726270c40785af1caba4069090bbcf6cf2a4eae8dcf9d706f719c8681c6c8599d21052ea1e982f1c35ea8241580c67d5ac33426135ef44575636dafdc3fa769f1d7f09fd20c400222d67892af0cb6561faf5107013f11d24432ae0100b9313799c9fd5c8db0ca8da95e31500fdaea820b06a9bd822b42b8e6b7803182619f9da3b6402e48bd250c40d614157118af153bbb89642280b4bf55fc4873d3bfd7cef3f30946598caa227b566d6c9a116f23ef3c0b383ae1a756cb3a2e724936d22830fef486f3946ae76294130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb00"
const header1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"hash":"0xf7c3cecbe8fb15560c3113dd03911e52858a233b32cdc761ca03bc0721553424","size":518,"version":0,"previousblockhash":"0x0ba4e920b83848bb4d29e733b5f6acc4fd2b79279889a93e26833406344ade28","merkleroot":"0x2a93dff1bd957d22c8088ee7dc52f154072d1ed1628ad70e1d9099e6048a445a","time":1591275326,"index":1,"nextconsensus":"AXSvJVzydxXuL9da4GVwK25zdesCrVKkHL","witnesses":[{"invocation":"0c40585acaabe5810f6a4a42bb44d946494887b4d9286ca3ccbe626f240d60080fccb602d7c4eda9d1aeeb6958adbd604aa227cd7e9238e5ea1925bf57af4c8726270c40785af1caba4069090bbcf6cf2a4eae8dcf9d706f719c8681c6c8599d21052ea1e982f1c35ea8241580c67d5ac33426135ef44575636dafdc3fa769f1d7f09fd20c400222d67892af0cb6561faf5107013f11d24432ae0100b9313799c9fd5c8db0ca8da95e31500fdaea820b06a9bd822b42b8e6b7803182619f9da3b6402e48bd250c40d614157118af153bbb89642280b4bf55fc4873d3bfd7cef3f30946598caa227b566d6c9a116f23ef3c0b383ae1a756cb3a2e724936d22830fef486f3946ae762","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"}],"confirmations":6,"nextblockhash":"0x96a0856f49798732e6eae4026a5f3e919b96250d847bcb3560d03bbad895c740"}}`
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0xf7c3cecbe8fb15560c3113dd03911e52858a233b32cdc761ca03bc0721553424","confirmations":6,"blocktime":1591275326,"txid":"0xf93ae1dbd2167e9b4a06431741297b351ac6a8ea3ae8892785c49f690a40b2c0","size":578,"type":"InvocationTransaction","version":1,"nonce":2,"sender":"AXSvJVzydxXuL9da4GVwK25zdesCrVKkHL","sys_fee":"0","net_fee":"0.0087935","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":1}],"vin":[],"vout":[],"scripts":[{"invocation":"0c4076ef230b83bf1964ed734fc264df284de8eedbdf0e6403389c812146d34535863142e50aa61f4c6a6a9140441a180aba10166a62a1030458ef9725144f4bc5670c40c122b669c1e3d4346bebe959ffc3c9551533f00ad3b42a512dce6b90fa62f5779f211f576d80c3883ebe3d50b854d472c91c2632ed9c2da7d932b5f6d37fdaa40c4089accd1ef5b0a489acd360c9da7bdd1ad52550b4384d5bb76052debc136680be18d00f4c9c3ac3d9c3e4914c01e6b70f2cc0efc625c5b55ebd656f0f1bb650bb0c407d8de81ebfea87a1bbf366ff472eccdaa6e82a1988d8832318f2f66c7fd2e61f91c4a856d2778215b4d45703728da8a487aa71e53740b603d17d8af7d1a3f7b6","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"}],"script":"0218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b5238"}}`
// getResultBlock1 returns data for block number 1 which is used by several tests.
func getResultBlock1() *result.Block {
binB, err := hex.DecodeString(hexB1)
if err != nil {
panic(err)
}
b := new(block.Block)
err = testserdes.DecodeBinary(binB, b)
if err != nil {
panic(err)
}
b2Hash, err := util.Uint256DecodeStringLE("96a0856f49798732e6eae4026a5f3e919b96250d847bcb3560d03bbad895c740")
if err != nil {
panic(err)
}
return &result.Block{
Block: b,
BlockMetadata: result.BlockMetadata{
Size: 1687,
NextBlockHash: &b2Hash,
Confirmations: 4,
},
}
}
func getTxMoveNeo() *result.TransactionOutputRaw {
b1 := getResultBlock1()
txBin, err := hex.DecodeString(hexTxMoveNeo)
if err != nil {
panic(err)
}
tx := new(transaction.Transaction)
err = testserdes.DecodeBinary(txBin, tx)
if err != nil {
panic(err)
}
return &result.TransactionOutputRaw{
Transaction: tx,
TransactionMetadata: result.TransactionMetadata{
Timestamp: b1.Timestamp,
Blockhash: b1.Block.Hash(),
Confirmations: 6,
},
}
}
// rpcClientTestCases contains `serverResponse` json data fetched from examples
// published in official C# JSON-RPC API v2.10.3 reference
// (see https://docs.neo.org/docs/en-us/reference/rpc/latest-version/api.html)
var rpcClientTestCases = map[string][]rpcClientTestCase{
"getapplicationlog": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetApplicationLog(util.Uint256{})
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"txid":"0x17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521","executions":[{"trigger":"Application","contract":"0xb9fa3b421eb749d5dd585fe1c1133b311a14bcb1","vmstate":"HALT","gas_consumed":"1","stack":[{"type":"Integer","value":1}],"notifications":[]}]}}`,
result: func(c *Client) interface{} {
txHash, err := util.Uint256DecodeStringLE("17145a039fca704fcdbeb46e6b210af98a1a9e5b9768e46ffc38f71c79ac2521")
if err != nil {
panic(err)
}
scriptHash, err := util.Uint160DecodeStringLE("b9fa3b421eb749d5dd585fe1c1133b311a14bcb1")
if err != nil {
panic(err)
}
return &result.ApplicationLog{
TxHash: txHash,
Executions: []result.Execution{
{
Trigger: "Application",
ScriptHash: scriptHash,
VMState: "HALT",
GasConsumed: util.Fixed8FromInt64(1),
Stack: []smartcontract.Parameter{{Type: smartcontract.IntegerType, Value: int64(1)}},
Events: []result.NotificationEvent{},
},
},
}
},
},
},
"getbestblockhash": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetBestBlockHash()
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"0x773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"}`,
result: func(c *Client) interface{} {
result, err := util.Uint256DecodeStringLE("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e")
if err != nil {
panic(err)
}
return result
},
},
},
"getblock": {
{
name: "byIndex_positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndex(1)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"` + hexB1 + `"}`,
result: func(c *Client) interface{} {
b := getResultBlock1()
return b.Block
},
},
{
name: "byIndex_verbose_positive",
invoke: func(c *Client) (i interface{}, err error) {
return c.GetBlockByIndexVerbose(1)
},
serverResponse: b1Verbose,
result: func(c *Client) interface{} {
return getResultBlock1()
},
},
{
name: "byHash_positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("d151651e86680a7ecbc87babf3346a42e7bc9974414ce192c9c22ac4f2e9d043")
if err != nil {
panic(err)
}
return c.GetBlockByHash(hash)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"` + hexB1 + `"}`,
result: func(c *Client) interface{} {
b := getResultBlock1()
return b.Block
},
},
{
name: "byHash_verbose_positive",
invoke: func(c *Client) (i interface{}, err error) {
hash, err := util.Uint256DecodeStringLE("86fe1061140b2ea791b0739fb9732abc6e5e47de4927228a1ac41de3d93eb7cb")
if err != nil {
panic(err)
}
return c.GetBlockByHashVerbose(hash)
},
serverResponse: b1Verbose,
result: func(c *Client) interface{} {
return getResultBlock1()
},
},
},
"getblockcount": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockCount()
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":991991}`,
result: func(c *Client) interface{} {
return uint32(991991)
},
},
},
"getblockhash": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHash(1)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"}`,
result: func(c *Client) interface{} {
hash, err := util.Uint256DecodeStringLE("4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2")
if err != nil {
panic(err)
}
return hash
},
},
},
"getblockheader": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("68e4bd688b852e807eef13a0ff7da7b02223e359a35153667e88f9cb4a3b0801")
if err != nil {
panic(err)
}
return c.GetBlockHeader(hash)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"` + hexHeader1 + `"}`,
result: func(c *Client) interface{} {
b := getResultBlock1()
return b.Header()
},
},
{
name: "verbose_positive",
invoke: func(c *Client) (i interface{}, err error) {
hash, err := util.Uint256DecodeStringLE("cbb73ed9e31dc41a8a222749de475e6ebc2a73b99f73b091a72e0b146110fe86")
if err != nil {
panic(err)
}
return c.GetBlockHeaderVerbose(hash)
},
serverResponse: header1Verbose,
result: func(c *Client) interface{} {
b := getResultBlock1()
return &result.Header{
Hash: b.Hash(),
Size: 518,
Version: b.Version,
NextBlockHash: b.NextBlockHash,
PrevBlockHash: b.PrevHash,
MerkleRoot: b.MerkleRoot,
Timestamp: b.Timestamp,
Index: b.Index,
NextConsensus: address.Uint160ToString(b.NextConsensus),
Witnesses: []transaction.Witness{b.Script},
Confirmations: 6,
}
},
},
},
"getblocksysfee": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockSysFee(1)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"195500"}`,
result: func(c *Client) interface{} {
return util.Fixed8FromInt64(195500)
},
},
},
"getconnectioncount": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetConnectionCount()
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":10}`,
result: func(c *Client) interface{} {
return 10
},
},
},
"getcontractstate": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint160DecodeStringLE("dc675afc61a7c0f7b3d2682bf6e1d8ed865a0e5f")
if err != nil {
panic(err)
}
return c.GetContractState(hash)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"version":0,"hash":"0xdc675afc61a7c0f7b3d2682bf6e1d8ed865a0e5f","script":"5fc56b6c766b00527ac46c766b51527ac46107576f6f6c6f6e676c766b52527ac403574e476c766b53527ac4006c766b54527ac4210354ae498221046c666efebbaee9bd0eb4823469c98e748494a92a71f346b1a6616c766b55527ac46c766b00c3066465706c6f79876c766b56527ac46c766b56c36416006c766b55c36165f2026c766b57527ac462d8016c766b55c36165d801616c766b00c30b746f74616c537570706c79876c766b58527ac46c766b58c36440006168164e656f2e53746f726167652e476574436f6e7465787406737570706c79617c680f4e656f2e53746f726167652e4765746c766b57527ac46270016c766b00c3046e616d65876c766b59527ac46c766b59c36412006c766b52c36c766b57527ac46247016c766b00c30673796d626f6c876c766b5a527ac46c766b5ac36412006c766b53c36c766b57527ac4621c016c766b00c308646563696d616c73876c766b5b527ac46c766b5bc36412006c766b54c36c766b57527ac462ef006c766b00c30962616c616e63654f66876c766b5c527ac46c766b5cc36440006168164e656f2e53746f726167652e476574436f6e746578746c766b51c351c3617c680f4e656f2e53746f726167652e4765746c766b57527ac46293006c766b51c300c36168184e656f2e52756e74696d652e436865636b5769746e657373009c6c766b5d527ac46c766b5dc3640e00006c766b57527ac46255006c766b00c3087472616e73666572876c766b5e527ac46c766b5ec3642c006c766b51c300c36c766b51c351c36c766b51c352c36165d40361527265c9016c766b57527ac4620e00006c766b57527ac46203006c766b57c3616c756653c56b6c766b00527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746165700351936c766b51527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c361651103615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e7465787406737570706c79617c680f4e656f2e53746f726167652e4765746165f40251936c766b52527ac46168164e656f2e53746f726167652e476574436f6e7465787406737570706c796c766b52c361659302615272680f4e656f2e53746f726167652e50757461616c756653c56b6c766b00527ac461516c766b51527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c361654002615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e7465787406737570706c796c766b51c361650202615272680f4e656f2e53746f726167652e50757461516c766b52527ac46203006c766b52c3616c756659c56b6c766b00527ac46c766b51527ac46c766b52527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b53527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b51c3617c680f4e656f2e53746f726167652e4765746c766b54527ac46c766b53c3616576016c766b52c3946c766b55527ac46c766b54c3616560016c766b52c3936c766b56527ac46c766b55c300a2640d006c766b52c300a2620400006c766b57527ac46c766b57c364ec00616168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b55c36165d800615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e746578746c766b51c36c766b56c361659c00615272680f4e656f2e53746f726167652e5075746155c57600135472616e73666572205375636365737366756cc476516c766b00c3c476526c766b51c3c476536c766b52c3c476546168184e656f2e426c6f636b636861696e2e476574486569676874c46168124e656f2e52756e74696d652e4e6f7469667961516c766b58527ac4620e00006c766b58527ac46203006c766b58c3616c756653c56b6c766b00527ac4616c766b00c36c766b51527ac46c766b51c36c766b52527ac46203006c766b52c3616c756653c56b6c766b00527ac461516c766b00c36a527a527ac46c766b51c36c766b52527ac46203006c766b52c3616c7566","parameters":["ByteArray"],"returntype":"ByteArray","name":"Woolong","code_version":"0.9.2","author":"lllwvlvwlll","email":"lllwvlvwlll@gmail.com","description":"GO NEO!!!","properties":{"storage":true,"dynamic_invoke":false}}}`,
result: func(c *Client) interface{} {
hash, err := util.Uint160DecodeStringLE("dc675afc61a7c0f7b3d2682bf6e1d8ed865a0e5f")
if err != nil {
panic(err)
}
script, err := hex.DecodeString("5fc56b6c766b00527ac46c766b51527ac46107576f6f6c6f6e676c766b52527ac403574e476c766b53527ac4006c766b54527ac4210354ae498221046c666efebbaee9bd0eb4823469c98e748494a92a71f346b1a6616c766b55527ac46c766b00c3066465706c6f79876c766b56527ac46c766b56c36416006c766b55c36165f2026c766b57527ac462d8016c766b55c36165d801616c766b00c30b746f74616c537570706c79876c766b58527ac46c766b58c36440006168164e656f2e53746f726167652e476574436f6e7465787406737570706c79617c680f4e656f2e53746f726167652e4765746c766b57527ac46270016c766b00c3046e616d65876c766b59527ac46c766b59c36412006c766b52c36c766b57527ac46247016c766b00c30673796d626f6c876c766b5a527ac46c766b5ac36412006c766b53c36c766b57527ac4621c016c766b00c308646563696d616c73876c766b5b527ac46c766b5bc36412006c766b54c36c766b57527ac462ef006c766b00c30962616c616e63654f66876c766b5c527ac46c766b5cc36440006168164e656f2e53746f726167652e476574436f6e746578746c766b51c351c3617c680f4e656f2e53746f726167652e4765746c766b57527ac46293006c766b51c300c36168184e656f2e52756e74696d652e436865636b5769746e657373009c6c766b5d527ac46c766b5dc3640e00006c766b57527ac46255006c766b00c3087472616e73666572876c766b5e527ac46c766b5ec3642c006c766b51c300c36c766b51c351c36c766b51c352c36165d40361527265c9016c766b57527ac4620e00006c766b57527ac46203006c766b57c3616c756653c56b6c766b00527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746165700351936c766b51527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c361651103615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e7465787406737570706c79617c680f4e656f2e53746f726167652e4765746165f40251936c766b52527ac46168164e656f2e53746f726167652e476574436f6e7465787406737570706c796c766b52c361659302615272680f4e656f2e53746f726167652e50757461616c756653c56b6c766b00527ac461516c766b51527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c361654002615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e7465787406737570706c796c766b51c361650202615272680f4e656f2e53746f726167652e50757461516c766b52527ac46203006c766b52c3616c756659c56b6c766b00527ac46c766b51527ac46c766b52527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b53527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b51c3617c680f4e656f2e53746f726167652e4765746c766b54527ac46c766b53c3616576016c766b52c3946c766b55527ac46c766b54c3616560016c766b52c3936c766b56527ac46c766b55c300a2640d006c766b52c300a2620400006c766b57527ac46c766b57c364ec00616168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b55c36165d800615272680f4e656f2e53746f726167652e507574616168164e656f2e53746f726167652e476574436f6e746578746c766b51c36c766b56c361659c00615272680f4e656f2e53746f726167652e5075746155c57600135472616e73666572205375636365737366756cc476516c766b00c3c476526c766b51c3c476536c766b52c3c476546168184e656f2e426c6f636b636861696e2e476574486569676874c46168124e656f2e52756e74696d652e4e6f7469667961516c766b58527ac4620e00006c766b58527ac46203006c766b58c3616c756653c56b6c766b00527ac4616c766b00c36c766b51527ac46c766b51c36c766b52527ac46203006c766b52c3616c756653c56b6c766b00527ac461516c766b00c36a527a527ac46c766b51c36c766b52527ac46203006c766b52c3616c7566")
if err != nil {
panic(err)
}
return &result.ContractState{
Version: 0,
ScriptHash: hash,
Script: script,
ParamList: []smartcontract.ParamType{smartcontract.ByteArrayType},
ReturnType: smartcontract.ByteArrayType,
Name: "Woolong",
CodeVersion: "0.9.2",
Author: "lllwvlvwlll",
Email: "lllwvlvwlll@gmail.com",
Description: "GO NEO!!!",
Properties: result.Properties{
HasStorage: true,
HasDynamicInvoke: false,
IsPayable: false,
},
}
},
},
},
"getnep5balances": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint160DecodeStringLE("1aada0032aba1ef6d1f07bbd8bec1d85f5380fb3")
if err != nil {
panic(err)
}
return c.GetNEP5Balances(hash)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"balance":[{"asset_hash":"a48b6e1291ba24211ad11bb90ae2a10bf1fcd5a8","amount":"50000000000","last_updated_block":251604}],"address":"AY6eqWjsUFCzsVELG7yG72XDukKvC34p2w"}}`,
result: func(c *Client) interface{} {
hash, err := util.Uint160DecodeStringLE("a48b6e1291ba24211ad11bb90ae2a10bf1fcd5a8")
if err != nil {
panic(err)
}
return &result.NEP5Balances{
Balances: []result.NEP5Balance{{
Asset: hash,
Amount: "50000000000",
LastUpdated: 251604,
}},
Address: "AY6eqWjsUFCzsVELG7yG72XDukKvC34p2w",
}
},
},
},
"getnep5transfers": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF")
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sent":[],"received":[{"timestamp":1555651816,"asset_hash":"600c4f5200db36177e3e8a09e9f18e2fc7d12a0f","transfer_address":"AYwgBNMepiv5ocGcyNT4mA8zPLTQ8pDBis","amount":"1000000","block_index":436036,"transfer_notify_index":0,"tx_hash":"df7683ece554ecfb85cf41492c5f143215dd43ef9ec61181a28f922da06aba58"}],"address":"AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF"}}`,
result: func(c *Client) interface{} {
assetHash, err := util.Uint160DecodeStringLE("600c4f5200db36177e3e8a09e9f18e2fc7d12a0f")
if err != nil {
panic(err)
}
txHash, err := util.Uint256DecodeStringLE("df7683ece554ecfb85cf41492c5f143215dd43ef9ec61181a28f922da06aba58")
if err != nil {
panic(err)
}
return &result.NEP5Transfers{
Sent: []result.NEP5Transfer{},
Received: []result.NEP5Transfer{
{
Timestamp: 1555651816,
Asset: assetHash,
Address: "AYwgBNMepiv5ocGcyNT4mA8zPLTQ8pDBis",
Amount: "1000000",
Index: 436036,
NotifyIndex: 0,
TxHash: txHash,
},
},
Address: "AbHgdBaWEnHkCiLtDZXjhvhaAK2cwFh5pF",
}
},
},
},
"getpeers": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetPeers()
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"unconnected":[{"address":"172.200.0.1","port":"20333"}],"connected":[{"address":"127.0.0.1","port":"20335"}],"bad":[{"address":"172.200.0.254","port":"20332"}]}}`,
result: func(c *Client) interface{} {
return &result.GetPeers{
Unconnected: result.Peers{
{
Address: "172.200.0.1",
Port: "20333",
},
},
Connected: result.Peers{
{
Address: "127.0.0.1",
Port: "20335",
},
},
Bad: result.Peers{
{
Address: "172.200.0.254",
Port: "20332",
},
},
}
},
},
},
"getrawmempool": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawMemPool()
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":["0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"]}`,
result: func(c *Client) interface{} {
hash, err := util.Uint256DecodeStringLE("9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e")
if err != nil {
panic(err)
}
return []util.Uint256{hash}
},
},
},
"getrawtransaction": {
{
name: "positive",
invoke: func(c *Client) (i interface{}, err error) {
hash, err := util.Uint256DecodeStringLE("ca23bd5df3249836849309ca2afe972bfd288b0a7ae61302c8fd545daa8bffd6")
if err != nil {
panic(err)
}
return c.GetRawTransaction(hash)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"` + hexTxMoveNeo + `"}`,
result: func(c *Client) interface{} {
tx := getTxMoveNeo()
return tx.Transaction
},
},
{
name: "verbose_positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("8185b0db7ed77190b93ac8bd44896822cd8f3cfcf702b3f50131e0efd200ef96")
if err != nil {
panic(err)
}
return c.GetRawTransactionVerbose(hash)
},
serverResponse: txMoveNeoVerbose,
result: func(c *Client) interface{} {
return getTxMoveNeo()
},
},
},
"getstorage": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint160DecodeStringLE("03febccf81ac85e3d795bc5cbd4e84e907812aa3")
if err != nil {
panic(err)
}
key, err := hex.DecodeString("5065746572")
if err != nil {
panic(err)
}
return c.GetStorage(hash, key)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"4c696e"}`,
result: func(c *Client) interface{} {
value, err := hex.DecodeString("4c696e")
if err != nil {
panic(err)
}
return value
},
},
},
"gettransactionheight": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2")
if err != nil {
panic(err)
}
return c.GetTransactionHeight(hash)
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":1}`,
result: func(c *Client) interface{} {
return uint32(1)
},
},
},
"getunclaimedgas": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetUnclaimedGas("AGofsxAUDwt52KjaB664GYsqVAkULYvKNt")
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"897299680935"}`,
result: func(c *Client) interface{} {
return util.Fixed8(897299680935)
},
},
},
"getvalidators": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetValidators()
},
serverResponse: `{"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}]}`,
result: func(c *Client) interface{} { return []result.Validator{} },
check: func(t *testing.T, c *Client, uns interface{}) {
res, ok := uns.([]result.Validator)
require.True(t, ok)
assert.Equal(t, 4, len(res))
},
},
},
"getversion": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.GetVersion()
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"tcp_port":20332,"nonce":2153672787,"useragent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`,
result: func(c *Client) interface{} {
return &result.Version{
Port: uint16(20332),
Nonce: 2153672787,
UserAgent: "/NEO-GO:0.73.1-pre-273-ge381358/",
}
},
},
},
"invokefunction": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint160DecodeStringLE("91b83e96f2a7c4fdf0c1688441ec61986c7cae26")
if err != nil {
panic(err)
}
return c.InvokeFunction("af7c7328eee5a275a3bcaee2bf0cf662b5e739be", "balanceOf", []smartcontract.Parameter{
{
Type: smartcontract.Hash160Type,
Value: hash,
},
})
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf","state":"HALT","gas_consumed":"0.311","stack":[{"type":"ByteArray","value":"262bec084432"}],"tx":"d101361426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf000000000000000000000000"}}`,
result: func(c *Client) interface{} {
bytes, err := hex.DecodeString("262bec084432")
if err != nil {
panic(err)
}
return &result.Invoke{
State: "HALT",
GasConsumed: "0.311",
Script: "1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf",
Stack: []smartcontract.Parameter{
{
Type: smartcontract.ByteArrayType,
Value: bytes,
},
},
}
},
},
},
"invokescript": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191")
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"00046e616d656724058e5e1b6008847cd662728549088a9ee82191","state":"HALT","gas_consumed":"0.161","stack":[{"type":"ByteArray","value":"4e45503520474153"}],"tx":"d1011b00046e616d656724058e5e1b6008847cd662728549088a9ee82191000000000000000000000000"}}`,
result: func(c *Client) interface{} {
bytes, err := hex.DecodeString("4e45503520474153")
if err != nil {
panic(err)
}
return &result.Invoke{
State: "HALT",
GasConsumed: "0.161",
Script: "00046e616d656724058e5e1b6008847cd662728549088a9ee82191",
Stack: []smartcontract.Parameter{
{
Type: smartcontract.ByteArrayType,
Value: bytes,
},
},
}
},
},
},
"sendrawtransaction": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.NewInvocationTX([]byte{byte(opcode.PUSH1)}, 0))
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":true}`,
result: func(c *Client) interface{} {
// no error expected
return nil
},
},
},
"submitblock": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,
})
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":true}`,
result: func(c *Client) interface{} {
// no error expected
return nil
},
},
},
"validateaddress": {
{
name: "positive",
invoke: func(c *Client) (interface{}, error) {
return nil, c.ValidateAddress("AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i")
},
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"address":"AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i","isvalid":true}}`,
result: func(c *Client) interface{} {
// no error expected
return nil
},
},
},
}
type rpcClientErrorCase struct {
name string
invoke func(c *Client) (interface{}, error)
}
var rpcClientErrorCases = map[string][]rpcClientErrorCase{
`{"jsonrpc":"2.0","id":1,"result":"not-a-hex-string"}`: {
{
name: "getblock_not_a_hex_response",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndex(1)
},
},
{
name: "getblockheader_not_a_hex_response",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c")
if err != nil {
panic(err)
}
return c.GetBlockHeader(hash)
},
},
{
name: "getrawtransaction_not_a_hex_response",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c")
if err != nil {
panic(err)
}
return c.GetRawTransaction(hash)
},
},
{
name: "getstorage_not_a_hex_response",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint160DecodeStringLE("03febccf81ac85e3d795bc5cbd4e84e907812aa3")
if err != nil {
panic(err)
}
key, err := hex.DecodeString("5065746572")
if err != nil {
panic(err)
}
return c.GetStorage(hash, key)
},
},
},
`{"jsonrpc":"2.0","id":1,"result":"01"}`: {
{
name: "getblock_decodebin_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndex(1)
},
},
{
name: "getheader_decodebin_err",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c")
if err != nil {
panic(err)
}
return c.GetBlockHeader(hash)
},
},
{
name: "getrawtransaction_decodebin_err",
invoke: func(c *Client) (interface{}, error) {
hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c")
if err != nil {
panic(err)
}
return c.GetRawTransaction(hash)
},
},
},
`{"jsonrpc":"2.0","id":1,"result":false}`: {
{
name: "sendrawtransaction_bad_server_answer",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.NewInvocationTX([]byte{byte(opcode.PUSH1)}, 0))
},
},
{
name: "submitblock_bad_server_answer",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,
})
},
},
{
name: "validateaddress_bad_server_answer",
invoke: func(c *Client) (interface{}, error) {
return nil, c.ValidateAddress("AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i")
},
},
},
`{"id":1,"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"}}`: {
{
name: "getapplicationlog_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetApplicationLog(util.Uint256{})
},
},
{
name: "getbestblockhash_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBestBlockHash()
},
},
{
name: "getblock_byindex_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndex(1)
},
},
{
name: "getblock_byindex_verbose_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndexVerbose(1)
},
},
{
name: "getblock_byhash_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByHash(util.Uint256{})
},
},
{
name: "getblock_byhash_verbose_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByHashVerbose(util.Uint256{})
},
},
{
name: "getblockhash_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHash(0)
},
},
{
name: "getblockheader_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHeader(util.Uint256{})
},
},
{
name: "getblockheader_verbose_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHeaderVerbose(util.Uint256{})
},
},
{
name: "getblocksysfee_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockSysFee(1)
},
},
{
name: "getconnectioncount_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetConnectionCount()
},
},
{
name: "getcontractstate_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetContractState(util.Uint160{})
},
},
{
name: "getnep5balances_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Balances(util.Uint160{})
},
},
{
name: "getnep5transfers_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("")
},
},
{
name: "getrawtransaction_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawTransaction(util.Uint256{})
},
},
{
name: "getrawtransaction_verbose_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawTransactionVerbose(util.Uint256{})
},
},
{
name: "getstorage_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetStorage(util.Uint160{}, []byte{})
},
},
{
name: "gettransactionheight_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetTransactionHeight(util.Uint256{})
},
},
{
name: "getunclaimedgas_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetUnclaimedGas("")
},
},
{
name: "invokefunction_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.InvokeFunction("", "", []smartcontract.Parameter{})
},
},
{
name: "invokescript_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("")
},
},
{
name: "sendrawtransaction_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(&transaction.Transaction{})
},
},
{
name: "submitblock_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{})
},
},
{
name: "validateaddress_invalid_params_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.ValidateAddress("")
},
},
},
`{}`: {
{
name: "getapplicationlog_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetApplicationLog(util.Uint256{})
},
},
{
name: "getbestblockhash_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBestBlockHash()
},
},
{
name: "getblock_byindex_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndex(1)
},
},
{
name: "getblock_byindex_verbose_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByIndexVerbose(1)
},
},
{
name: "getblock_byhash_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByHash(util.Uint256{})
},
},
{
name: "getblock_byhash_verbose_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockByHashVerbose(util.Uint256{})
},
},
{
name: "getblockcount_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockCount()
},
},
{
name: "getblockhash_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHash(1)
},
},
{
name: "getblockheader_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHeader(util.Uint256{})
},
},
{
name: "getblockheader_verbose_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockHeaderVerbose(util.Uint256{})
},
},
{
name: "getblocksysfee_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetBlockSysFee(1)
},
},
{
name: "getconnectioncount_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetConnectionCount()
},
},
{
name: "getcontractstate_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetContractState(util.Uint160{})
},
},
{
name: "getnep5balances_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Balances(util.Uint160{})
},
},
{
name: "getnep5transfers_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetNEP5Transfers("")
},
},
{
name: "getpeers_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetPeers()
},
},
{
name: "getrawmempool_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawMemPool()
},
},
{
name: "getrawtransaction_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawTransaction(util.Uint256{})
},
},
{
name: "getrawtransaction_verbose_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetRawTransactionVerbose(util.Uint256{})
},
},
{
name: "getstorage_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetStorage(util.Uint160{}, []byte{})
},
},
{
name: "gettransactionheight_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetTransactionHeight(util.Uint256{})
},
},
{
name: "getunclaimedgas_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetUnclaimedGas("")
},
},
{
name: "getvalidators_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetValidators()
},
},
{
name: "getversion_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.GetVersion()
},
},
{
name: "invokefunction_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.InvokeFunction("", "", []smartcontract.Parameter{})
},
},
{
name: "invokescript_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("")
},
},
{
name: "sendrawtransaction_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SendRawTransaction(transaction.NewInvocationTX([]byte{byte(opcode.PUSH1)}, 0))
},
},
{
name: "submitblock_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.SubmitBlock(block.Block{
Base: block.Base{},
Transactions: nil,
Trimmed: false,
})
},
},
{
name: "validateaddress_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) {
return nil, c.ValidateAddress("")
},
},
},
}
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)
})
})
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)
return &wsc.Client, nil
})
})
}
func testRPCClient(t *testing.T, newClient func(context.Context, string, Options) (*Client, error)) {
for method, testBatch := range rpcClientTestCases {
t.Run(method, func(t *testing.T) {
for _, testCase := range testBatch {
t.Run(testCase.name, func(t *testing.T) {
srv := initTestServer(t, testCase.serverResponse)
defer srv.Close()
endpoint := srv.URL
opts := Options{}
c, err := newClient(context.TODO(), endpoint, opts)
if err != nil {
t.Fatal(err)
}
actual, err := testCase.invoke(c)
assert.NoError(t, err)
expected := testCase.result(c)
if testCase.check == nil {
assert.Equal(t, expected, actual)
} else {
testCase.check(t, c, actual)
}
})
}
})
}
for serverResponse, testBatch := range rpcClientErrorCases {
srv := initTestServer(t, serverResponse)
defer srv.Close()
endpoint := srv.URL
opts := Options{}
c, err := newClient(context.TODO(), endpoint, opts)
if err != nil {
t.Fatal(err)
}
for _, testCase := range testBatch {
t.Run(testCase.name, func(t *testing.T) {
_, err := testCase.invoke(c)
assert.Error(t, err)
})
}
}
}
func httpURLtoWS(url string) string {
return "ws" + strings.TrimPrefix(url, "http") + "/ws"
}
func initTestServer(t *testing.T, resp string) *httptest.Server {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/ws" && req.Method == "GET" {
var upgrader = websocket.Upgrader{}
ws, err := upgrader.Upgrade(w, req, nil)
require.NoError(t, err)
for {
ws.SetReadDeadline(time.Now().Add(2 * time.Second))
_, _, err = ws.ReadMessage()
if err != nil {
break
}
ws.SetWriteDeadline(time.Now().Add(2 * time.Second))
err = ws.WriteMessage(1, []byte(resp))
if err != nil {
break
}
}
ws.Close()
return
}
requestHandler(t, w, resp)
}))
return srv
}
func requestHandler(t *testing.T, w http.ResponseWriter, resp string) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_, err := w.Write([]byte(resp))
if err != nil {
t.Fatalf("Error writing response: %s", err.Error())
}
}
func TestCalculateValidUntilBlock(t *testing.T) {
var (
getBlockCountCalled int
getValidatorsCalled int
)
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)
}
var response string
switch r.Method {
case "getblockcount":
getBlockCountCalled++
response = `{"jsonrpc":"2.0","id":1,"result":50}`
case "getvalidators":
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)
}))
defer srv.Close()
endpoint := srv.URL
opts := Options{}
c, err := New(context.TODO(), endpoint, opts)
if err != nil {
t.Fatal(err)
}
validUntilBlock, err := c.CalculateValidUntilBlock()
assert.NoError(t, err)
assert.Equal(t, uint32(54), validUntilBlock)
assert.Equal(t, 1, getBlockCountCalled)
assert.Equal(t, 1, getValidatorsCalled)
// check, whether caching is working
validUntilBlock, err = c.CalculateValidUntilBlock()
assert.NoError(t, err)
assert.Equal(t, uint32(54), validUntilBlock)
assert.Equal(t, 2, getBlockCountCalled)
assert.Equal(t, 1, getValidatorsCalled)
}