1332 lines
51 KiB
Go
1332 lines
51 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
"github.com/nspcc-dev/neo-go/pkg/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/smartcontract/manifest"
|
|
"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 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54442fd56401107247de4e35599d1feffaf6e763972f738d2858b0a22ad06523867e4dcf921f7c1c67201000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c400f01eb6371a135527ddb205a0dae1f69d2d324837cce128bead9033091883f9ce21e6d759a40f690746592b021d397f088e3b7b417fcef73cd1bfdc2800769520c4084f7ae5d9f58a09aa56eeb2f282744a59a82d17e3be0eb1c7f54e6e8df79620e2608191bac57280a836db2ec2a776d07e43f16bc76c47d348b0fcd09d56c7c320c402b95b4e39ec35162a640795ff223e92dec95390a072eb457f6a4323052f80731517e0df029e4a457204f777f5261c6a4a88d46d4c3abdec635a6eed580d6c77f0c40b9735745b1dd795a258c31d8e6fa87d5cfc2e9b3a4890d610d33bcf833b64c58b0c5cea17f3a7128f1065ed193e636971590f193f28bdd1eeebbbc1fe6e7cee594130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb030057040000000000000002000000abec5362f11e75b6e02e407bb98d63675d14384100000000000000003e5f0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d14384101590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801fd08010c40ae6fc04fe4b6c22218ca9617c98d607d9ec9b1faf8cfdc3391bec485ae76b11adc6cc6abeb31a50b536ea8073e674d62a5566fce5e0a0ceb0718cb971c1ae3d00c40603071b725a58d052cad7afd88e99b27baab931afd5bb50d16e224335aab450170aabe251d3c0c6ad3f31dd7e9b89b209baabe5a1e2fa588bd8118f9e2a6960f0c40d72afcf39e663dba2d70fb8c36a09d1a6a6ad0d2fd38c857a8e7dc71e2b98711324e0d2ec641fe6896ba63ba80d3ea341c1aad11e082fb188ee07e215b4031b10c409afb2808b60286a56343b7ffcef28bb2ab0c595603e7323b5e5b0b9c1c10edfa5c40754d921865cb6fd71668a206b37a1eb10c0029a9fcd3a856aed07742cd3f94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb0003000000abec5362f11e75b6e02e407bb98d63675d1438410000000000000000de6e0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d143841015d0300e87648170000000c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523801fd08010c408710e7b5d8ac6cd8d09d6fb35bf2dcce5f5fb38595ddb6d04a570bc925bc2c55a73cdf5f3cb5a1feb0acc4f26c8bbca6c43df3b4a98b8c3c2c809c2f096eb25a0c40c186c102cbf72313fd94df5077fc5bbefcd32227ed2159a47a46594877fa39f330d8223b45aa24aff005bebb5b2427a50c8c4de8618e7d7b00d73d836c44942e0c40a243b5b565bd4bc2f0bb112f7624f6b3514c12413c5a95230819face3f760f03fcb96b188f98038a3f251686b53a88d69744f4e4a985e6297003a80cdb169e800c404a951e61ac99d5ee31831d111754adb711b4a9060a9524fe383a90771843cdb096382674027a87f2a15a83bd77deb2b2ab1fe8b3de6e546293ef3df9b1129e2894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
|
|
|
|
const hexTxMoveNeo = "0002000000abec5362f11e75b6e02e407bb98d63675d14384100000000000000003e5f0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d14384101590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801fd08010c40ae6fc04fe4b6c22218ca9617c98d607d9ec9b1faf8cfdc3391bec485ae76b11adc6cc6abeb31a50b536ea8073e674d62a5566fce5e0a0ceb0718cb971c1ae3d00c40603071b725a58d052cad7afd88e99b27baab931afd5bb50d16e224335aab450170aabe251d3c0c6ad3f31dd7e9b89b209baabe5a1e2fa588bd8118f9e2a6960f0c40d72afcf39e663dba2d70fb8c36a09d1a6a6ad0d2fd38c857a8e7dc71e2b98711324e0d2ec641fe6896ba63ba80d3ea341c1aad11e082fb188ee07e215b4031b10c409afb2808b60286a56343b7ffcef28bb2ab0c595603e7323b5e5b0b9c1c10edfa5c40754d921865cb6fd71668a206b37a1eb10c0029a9fcd3a856aed07742cd3f94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
|
|
|
|
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1681,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d","confirmations":6,"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensus_data":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"876350","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]},{"hash":"0xb661d5e4d9e41c3059b068f8abb6f1566a47ec800879e34c0ebd2799781a2760","size":579,"version":0,"nonce":3,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"880350","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBQxboUQOQGdOd/Cw31sP+4Z/VgJhwwUq+xTYvEedbbgLkB7uY1jZ10UOEETwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I4","scripts":[{"invocation":"DECHEOe12Kxs2NCdb7Nb8tzOX1+zhZXdttBKVwvJJbwsVac83188taH+sKzE8myLvKbEPfO0qYuMPCyAnC8JbrJaDEDBhsECy/cjE/2U31B3/Fu+/NMiJ+0hWaR6RllId/o58zDYIjtFqiSv8AW+u1skJ6UMjE3oYY59ewDXPYNsRJQuDECiQ7W1Zb1LwvC7ES92JPazUUwSQTxalSMIGfrOP3YPA/y5axiPmAOKPyUWhrU6iNaXRPTkqYXmKXADqAzbFp6ADEBKlR5hrJnV7jGDHREXVK23EbSpBgqVJP44OpB3GEPNsJY4JnQCeofyoVqDvXfesrKrH+iz3m5UYpPvPfmxEp4o","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}]}}`
|
|
|
|
const hexHeader1 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54442fd56401107247de4e35599d1feffaf6e763972f738d2858b0a22ad06523867e4dcf921f7c1c67201000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c400f01eb6371a135527ddb205a0dae1f69d2d324837cce128bead9033091883f9ce21e6d759a40f690746592b021d397f088e3b7b417fcef73cd1bfdc2800769520c4084f7ae5d9f58a09aa56eeb2f282744a59a82d17e3be0eb1c7f54e6e8df79620e2608191bac57280a836db2ec2a776d07e43f16bc76c47d348b0fcd09d56c7c320c402b95b4e39ec35162a640795ff223e92dec95390a072eb457f6a4323052f80731517e0df029e4a457204f777f5261c6a4a88d46d4c3abdec635a6eed580d6c77f0c40b9735745b1dd795a258c31d8e6fa87d5cfc2e9b3a4890d610d33bcf833b64c58b0c5cea17f3a7128f1065ed193e636971590f193f28bdd1eeebbbc1fe6e7cee594130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb00"
|
|
|
|
const header1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","size":518,"version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"confirmations":6,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d"}}`
|
|
|
|
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","confirmations":6,"blocktime":1592472500001,"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sys_fee":"0","net_fee":"876350","valid_until_block":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","scripts":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}}`
|
|
|
|
// 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 := block.New(netmode.UnitTestNet)
|
|
err = testserdes.DecodeBinary(binB, b)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
b2Hash, err := util.Uint256DecodeStringLE("45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &result.Block{
|
|
Block: *b,
|
|
BlockMetadata: result.BlockMetadata{
|
|
Size: 1681,
|
|
NextBlockHash: &b2Hash,
|
|
Confirmations: 6,
|
|
},
|
|
}
|
|
}
|
|
|
|
func getTxMoveNeo() *result.TransactionOutputRaw {
|
|
b1 := getResultBlock1()
|
|
txBin, err := hex.DecodeString(hexTxMoveNeo)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
tx, err := transaction.NewTransactionFromBytes(netmode.UnitTestNet, txBin)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &result.TransactionOutputRaw{
|
|
Transaction: *tx,
|
|
TransactionMetadata: result.TransactionMetadata{
|
|
Timestamp: b1.Timestamp,
|
|
Blockhash: b1.Block.Hash(),
|
|
Confirmations: int(b1.Confirmations),
|
|
},
|
|
}
|
|
}
|
|
|
|
// 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","trigger":"Application","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)
|
|
}
|
|
return &result.ApplicationLog{
|
|
TxHash: txHash,
|
|
Trigger: "Application",
|
|
VMState: "HALT",
|
|
GasConsumed: 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("1b4357bff5a01bdf2a6581247cf9ed1e24629176")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c.GetContractState(hash)
|
|
},
|
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","entryPoint":{"name":"Main","parameters":[{"name":"method","type":"String"},{"name":"params","type":"Array"}],"returnType":"Boolean"},"methods":[],"events":[]},"groups":[],"features":{"payable":false,"storage":true},"permissions":null,"trusts":[],"safeMethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
|
|
result: func(c *Client) interface{} {
|
|
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
m := manifest.NewManifest(hash.Hash160(script))
|
|
m.ABI.EntryPoint.Name = "Main"
|
|
m.ABI.EntryPoint.Parameters = []manifest.Parameter{
|
|
manifest.NewParameter("method", smartcontract.StringType),
|
|
manifest.NewParameter("params", smartcontract.ArrayType),
|
|
}
|
|
m.ABI.EntryPoint.ReturnType = smartcontract.BoolType
|
|
m.Features = smartcontract.HasStorage
|
|
cs := &state.Contract{
|
|
ID: 0,
|
|
Script: script,
|
|
Manifest: *m,
|
|
}
|
|
_ = cs.ScriptHash()
|
|
return cs
|
|
},
|
|
},
|
|
},
|
|
"getFeePerByte": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetFeePerByte()
|
|
},
|
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gas_consumed":"2007390","script":"10c00c0d676574466565506572427974650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"1000"}]}}`,
|
|
result: func(c *Client) interface{} {
|
|
return int64(1000)
|
|
},
|
|
},
|
|
},
|
|
"getMaxTransacctionsPerBlock": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetMaxTransactionsPerBlock()
|
|
},
|
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gas_consumed":"2007390","script":"10c00c1a6765744d61785472616e73616374696f6e73506572426c6f636b0c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"512"}]}}`,
|
|
result: func(c *Client) interface{} {
|
|
return int64(512)
|
|
},
|
|
},
|
|
},
|
|
"getMaxBlockSize": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetMaxBlockSize()
|
|
},
|
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gas_consumed":"2007390","script":"10c00c0f6765744d6178426c6f636b53697a650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"262144"}]}}`,
|
|
result: func(c *Client) interface{} {
|
|
return int64(262144)
|
|
},
|
|
},
|
|
},
|
|
"getBlockedAccounts": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetBlockedAccounts()
|
|
},
|
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gas_consumed":"2007390","script":"10c00c12676574426c6f636b65644163636f756e74730c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Array","value":[]}]}}`,
|
|
result: func(c *Client) interface{} {
|
|
return native.BlockedAccounts{}
|
|
},
|
|
},
|
|
},
|
|
"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)
|
|
}
|
|
out, err := c.GetRawTransactionVerbose(hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out.Transaction.FeePerByte() // set fee per byte
|
|
return out, nil
|
|
},
|
|
serverResponse: txMoveNeoVerbose,
|
|
result: func(c *Client) interface{} {
|
|
return getTxMoveNeo()
|
|
},
|
|
},
|
|
},
|
|
"getstorage": {
|
|
{
|
|
name: "by hash, 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.GetStorageByHash(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
|
|
},
|
|
},
|
|
{
|
|
name: "by ID, positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
key, err := hex.DecodeString("5065746572")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c.GetStorageByID(-1, 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,"ws_port":20342,"nonce":2153672787,"user_agent":"/NEO-GO:0.73.1-pre-273-ge381358/"}}`,
|
|
result: func(c *Client) interface{} {
|
|
return &result.Version{
|
|
TCPPort: uint16(20332),
|
|
WSPort: uint16(20342),
|
|
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)
|
|
}
|
|
contr, err := util.Uint160DecodeStringLE("af7c7328eee5a275a3bcaee2bf0cf662b5e739be")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c.InvokeFunction(contr, "balanceOf", []smartcontract.Parameter{
|
|
{
|
|
Type: smartcontract.Hash160Type,
|
|
Value: hash,
|
|
},
|
|
}, []transaction.Cosigner{{
|
|
Account: util.Uint160{1, 2, 3},
|
|
}})
|
|
},
|
|
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf","state":"HALT","gas_consumed":"31100000","stack":[{"type":"ByteArray","value":"JivsCEQy"}],"tx":"d101361426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf000000000000000000000000"}}`,
|
|
result: func(c *Client) interface{} {
|
|
bytes, err := hex.DecodeString("262bec084432")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &result.Invoke{
|
|
State: "HALT",
|
|
GasConsumed: 31100000,
|
|
Script: "1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf",
|
|
Stack: []smartcontract.Parameter{
|
|
{
|
|
Type: smartcontract.ByteArrayType,
|
|
Value: bytes,
|
|
},
|
|
},
|
|
}
|
|
},
|
|
},
|
|
},
|
|
"invokescript": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
script, err := hex.DecodeString("00046e616d656724058e5e1b6008847cd662728549088a9ee82191")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c.InvokeScript(script, []transaction.Cosigner{{
|
|
Account: util.Uint160{1, 2, 3},
|
|
}})
|
|
},
|
|
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"00046e616d656724058e5e1b6008847cd662728549088a9ee82191","state":"HALT","gas_consumed":"16100000","stack":[{"type":"ByteArray","value":"TkVQNSBHQVM="}],"tx":"d1011b00046e616d656724058e5e1b6008847cd662728549088a9ee82191000000000000000000000000"}}`,
|
|
result: func(c *Client) interface{} {
|
|
bytes, err := hex.DecodeString("4e45503520474153")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &result.Invoke{
|
|
State: "HALT",
|
|
GasConsumed: 16100000,
|
|
Script: "00046e616d656724058e5e1b6008847cd662728549088a9ee82191",
|
|
Stack: []smartcontract.Parameter{
|
|
{
|
|
Type: smartcontract.ByteArrayType,
|
|
Value: bytes,
|
|
},
|
|
},
|
|
}
|
|
},
|
|
},
|
|
},
|
|
"sendrawtransaction": {
|
|
{
|
|
name: "positive",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return nil, c.SendRawTransaction(transaction.New(netmode.UnitTestNet, []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: "getstoragebyhash_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.GetStorageByHash(hash, key)
|
|
},
|
|
},
|
|
{
|
|
name: "getstoragebyid_not_a_hex_response",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
key, err := hex.DecodeString("5065746572")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c.GetStorageByID(-1, 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.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{
|
|
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: "getstoragebyhash_invalid_params_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetStorageByHash(util.Uint160{}, []byte{})
|
|
},
|
|
},
|
|
{
|
|
name: "getstoragebyid_invalid_params_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetStorageByID(-1, []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(util.Uint160{}, "", []smartcontract.Parameter{}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "invokescript_invalid_params_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.InvokeScript([]byte{}, nil)
|
|
},
|
|
},
|
|
{
|
|
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: "getstoragebyhash_unmarshalling_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetStorageByHash(util.Uint160{}, []byte{})
|
|
},
|
|
},
|
|
{
|
|
name: "getstoragebyid_unmarshalling_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.GetStorageByID(-1, []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(util.Uint160{}, "", []smartcontract.Parameter{}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "invokescript_unmarshalling_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return c.InvokeScript([]byte{}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "sendrawtransaction_unmarshalling_error",
|
|
invoke: func(c *Client) (interface{}, error) {
|
|
return nil, 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{
|
|
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{Network: netmode.UnitTestNet}
|
|
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{Network: netmode.UnitTestNet}
|
|
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)
|
|
}
|