unitTest: reworked RPC unit test
earlier we had an issue with failing test in #353 and other one #305. Reworked these test to have in-memory database. This led to multiple changes: made some functions like Hash and Persist public(otherwise it's not possible to control state of the blockchain); removed unit_tests storage package which was used mainly for leveldb in unit tests. I see these tests not really good since they look like e2e tests and as for me should be run in separate step against dockerized env or in case we want to check rpc handler we might want to rework it in order to have interface for proper unit tests. As for me this patchset at least makes as safe with not removing totally previous tests and at the same time CircleCI will be happy now.
This commit is contained in:
parent
55dfc0bbbc
commit
100fee164b
17 changed files with 394 additions and 346 deletions
|
@ -37,7 +37,7 @@ type Blockchain struct {
|
|||
|
||||
// Current index/height of the highest block.
|
||||
// Read access should always be called by BlockHeight().
|
||||
// Write access should only happen in persist().
|
||||
// Write access should only happen in Persist().
|
||||
blockHeight uint32
|
||||
|
||||
// Number of headers stored in the chain file.
|
||||
|
@ -167,7 +167,10 @@ func (bc *Blockchain) Run(ctx context.Context) {
|
|||
op(bc.headerList)
|
||||
bc.headersOpDone <- struct{}{}
|
||||
case <-persistTimer.C:
|
||||
go bc.persist(ctx)
|
||||
go func() {
|
||||
err := bc.Persist(ctx)
|
||||
log.Warnf("failed to persist blockchain: %s", err)
|
||||
}()
|
||||
persistTimer.Reset(persistInterval)
|
||||
}
|
||||
}
|
||||
|
@ -389,7 +392,8 @@ func (bc *Blockchain) persistBlock(block *Block) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (bc *Blockchain) persist(ctx context.Context) (err error) {
|
||||
//Persist starts persist loop.
|
||||
func (bc *Blockchain) Persist(ctx context.Context) (err error) {
|
||||
var (
|
||||
start = time.Now()
|
||||
persisted = 0
|
||||
|
|
|
@ -13,6 +13,9 @@ import (
|
|||
|
||||
func TestAddHeaders(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
h1 := newBlock(1).Header()
|
||||
h2 := newBlock(2).Header()
|
||||
h3 := newBlock(3).Header()
|
||||
|
@ -38,6 +41,9 @@ func TestAddHeaders(t *testing.T) {
|
|||
|
||||
func TestAddBlock(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
blocks := []*Block{
|
||||
newBlock(1),
|
||||
newBlock(2),
|
||||
|
@ -57,7 +63,7 @@ func TestAddBlock(t *testing.T) {
|
|||
|
||||
t.Log(bc.blockCache)
|
||||
|
||||
if err := bc.persist(context.Background()); err != nil {
|
||||
if err := bc.Persist(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -75,6 +81,9 @@ func TestAddBlock(t *testing.T) {
|
|||
|
||||
func TestGetHeader(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
block := newBlock(1)
|
||||
err := bc.AddBlock(block)
|
||||
assert.Nil(t, err)
|
||||
|
@ -91,6 +100,9 @@ func TestGetHeader(t *testing.T) {
|
|||
|
||||
func TestGetBlock(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
blocks := makeBlocks(100)
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
@ -111,6 +123,9 @@ func TestGetBlock(t *testing.T) {
|
|||
|
||||
func TestHasBlock(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
blocks := makeBlocks(50)
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
@ -118,7 +133,7 @@ func TestHasBlock(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
assert.Nil(t, bc.persist(context.Background()))
|
||||
assert.Nil(t, bc.Persist(context.Background()))
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
assert.True(t, bc.HasBlock(blocks[i].Hash()))
|
||||
|
@ -131,6 +146,9 @@ func TestHasBlock(t *testing.T) {
|
|||
func TestGetTransaction(t *testing.T) {
|
||||
block := getDecodedBlock(t, 2)
|
||||
bc := newTestChain(t)
|
||||
defer func() {
|
||||
require.NoError(t, bc.Close())
|
||||
}()
|
||||
|
||||
assert.Nil(t, bc.AddBlock(block))
|
||||
assert.Nil(t, bc.persistBlock(block))
|
||||
|
@ -157,5 +175,6 @@ func newTestChain(t *testing.T) *Blockchain {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go chain.Run(context.Background())
|
||||
return chain
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
MANIFEST-000025
|
|
@ -1,82 +0,0 @@
|
|||
=============== Nov 26, 2018 (CET) ===============
|
||||
23:50:38.287098 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
23:50:38.341648 db@open opening
|
||||
23:50:38.344325 version@stat F·[] S·0B[] Sc·[]
|
||||
23:50:38.387172 db@janitor F·2 G·0
|
||||
23:50:38.387311 db@open done T·45.546154ms
|
||||
23:50:42.538000 memdb@flush N·12831 S·3MiB
|
||||
23:50:42.617097 memdb@flush created L0@3 N·12831 S·2MiB "\x01\x00\x03..\xaa1\x14,v5970":"\xf0,v1"
|
||||
23:50:42.617164 version@stat F·[1] S·2MiB[2MiB] Sc·[0.25]
|
||||
23:50:42.639664 memdb@flush committed F·1 T·101.60375ms
|
||||
23:50:42.641205 journal@remove removed @1
|
||||
23:50:51.406280 memdb@flush N·16663 S·3MiB
|
||||
23:50:51.479245 memdb@flush created L0@5 N·16663 S·3MiB "\x01\x00\x01..\n\xce\xf5,v22520":"\xc1,v12833"
|
||||
23:50:51.479405 version@stat F·[2] S·5MiB[5MiB] Sc·[0.50]
|
||||
23:50:51.501823 memdb@flush committed F·1 T·95.469736ms
|
||||
23:50:51.503989 journal@remove removed @2
|
||||
23:50:52.558287 table@compaction L0·2 -> L1·0 S·5MiB Q·29522
|
||||
23:50:52.666973 table@build created L1@6 N·5499 S·2MiB "\x01\x00\x01..\n\xce\xf5,v22520":"\x01q`..\x0e\x88 ,v8859"
|
||||
23:50:52.735582 table@build created L1@7 N·5499 S·2MiB "\x01qe..\xdfvy,v25919":"\x01\xe4\x15..~e\xd4,v20183"
|
||||
23:50:52.785741 table@build created L1@8 N·3762 S·990KiB "\x01\xe4\x18..Ew@,v25246":"\xf0,v1"
|
||||
23:50:52.785895 version@stat F·[0 3] S·4MiB[0B 4MiB] Sc·[0.00 0.05]
|
||||
23:50:52.808457 table@compaction committed F+1 S-951KiB Ke·0 D·14734 T·250.047198ms
|
||||
23:50:52.810550 table@remove removed @5
|
||||
23:50:52.812603 table@remove removed @3
|
||||
23:51:55.424408 memdb@flush N·25534 S·3MiB
|
||||
23:51:55.607413 memdb@flush created L0@10 N·25534 S·3MiB "\x01\x00\x03..\xaa1\x14,v36636":"\xc1,v39129"
|
||||
23:51:55.607695 version@stat F·[1 3] S·8MiB[3MiB 4MiB] Sc·[0.25 0.05]
|
||||
23:51:55.629931 memdb@flush committed F·1 T·205.445709ms
|
||||
23:51:55.633098 journal@remove removed @4
|
||||
23:51:56.911824 table@compaction L0·1 -> L1·3 S·8MiB Q·55136
|
||||
23:51:57.016224 table@build created L1@11 N·5568 S·2MiB "\x01\x00\x01..\n\xce\xf5,v22520":"\x01r\xb9..;\xcfa,v36196"
|
||||
23:51:57.085097 table@build created L1@12 N·5559 S·2MiB "\x01r\xb9..\x8c^^,v22386":"\x01\xe6\xe0..\xcf\xf3\xdc,v34688"
|
||||
23:51:57.149174 table@build created L1@13 N·16401 S·1MiB "\x01\xe6\xe0.. \xa6\xca,v50877":"\xf0,v1"
|
||||
23:51:57.149348 version@stat F·[0 3] S·5MiB[0B 5MiB] Sc·[0.00 0.06]
|
||||
23:51:57.171727 table@compaction committed F-1 S-2MiB Ke·0 D·12766 T·259.819169ms
|
||||
23:51:57.173227 table@remove removed @10
|
||||
23:51:57.174685 table@remove removed @6
|
||||
23:51:57.176587 table@remove removed @7
|
||||
23:51:57.177884 table@remove removed @8
|
||||
=============== Dec 21, 2018 (CET) ===============
|
||||
21:48:53.302835 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
21:48:53.322817 version@stat F·[0 3] S·5MiB[0B 5MiB] Sc·[0.00 0.06]
|
||||
21:48:53.322841 db@open opening
|
||||
21:48:53.322906 journal@recovery F·1
|
||||
21:48:53.323457 journal@recovery recovering @9
|
||||
21:48:53.494374 memdb@flush created L0@14 N·24266 S·2MiB "\x01\x00\x01..\n\xce\xf5,v67975":"\xc1,v61538"
|
||||
21:48:53.500940 version@stat F·[1 3] S·8MiB[2MiB 5MiB] Sc·[0.25 0.06]
|
||||
21:48:53.541457 db@janitor F·6 G·0
|
||||
21:48:53.541547 db@open done T·218.687106ms
|
||||
=============== Dec 21, 2018 (CET) ===============
|
||||
21:49:14.115818 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
21:49:14.116034 version@stat F·[1 3] S·8MiB[2MiB 5MiB] Sc·[0.25 0.06]
|
||||
21:49:14.116045 db@open opening
|
||||
21:49:14.116086 journal@recovery F·1
|
||||
21:49:14.116495 journal@recovery recovering @15
|
||||
21:49:14.256619 memdb@flush created L0@17 N·700 S·149KiB "\x01\x00/..\x02&\xab,v79538":"\xc1,v79297"
|
||||
21:49:14.257851 version@stat F·[2 3] S·8MiB[2MiB 5MiB] Sc·[0.50 0.06]
|
||||
21:49:14.539567 db@janitor F·7 G·0
|
||||
21:49:14.539642 db@open done T·423.57991ms
|
||||
21:49:14.579206 table@compaction L0·2 -> L1·3 S·8MiB Q·79996
|
||||
=============== Dec 21, 2018 (CET) ===============
|
||||
21:54:32.133909 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
21:54:32.134127 version@stat F·[2 3] S·8MiB[2MiB 5MiB] Sc·[0.50 0.06]
|
||||
21:54:32.134137 db@open opening
|
||||
21:54:32.134181 journal@recovery F·1
|
||||
21:54:32.134631 journal@recovery recovering @18
|
||||
21:54:32.224030 memdb@flush created L0@20 N·700 S·149KiB "\x01\x00/..\x02&\xab,v80239":"\xc1,v79998"
|
||||
21:54:32.225414 version@stat F·[3 3] S·8MiB[3MiB 5MiB] Sc·[0.75 0.06]
|
||||
21:54:32.269397 db@janitor F·8 G·0
|
||||
21:54:32.269495 db@open done T·135.337131ms
|
||||
21:54:32.307525 table@compaction L0·3 -> L1·3 S·8MiB Q·80697
|
||||
=============== Dec 21, 2018 (CET) ===============
|
||||
21:57:38.775640 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||
21:57:38.775891 version@stat F·[3 3] S·8MiB[3MiB 5MiB] Sc·[0.75 0.06]
|
||||
21:57:38.775902 db@open opening
|
||||
21:57:38.775949 journal@recovery F·1
|
||||
21:57:38.776389 journal@recovery recovering @21
|
||||
21:57:38.797001 memdb@flush created L0@23 N·700 S·149KiB "\x01\x00/..\x02&\xab,v80940":"\xc1,v80699"
|
||||
21:57:38.797463 version@stat F·[4 3] S·8MiB[3MiB 5MiB] Sc·[1.00 0.06]
|
||||
21:57:38.843345 db@janitor F·9 G·0
|
||||
21:57:38.843446 db@open done T·67.525965ms
|
||||
21:57:38.843705 table@compaction L0·4 -> L1·3 S·8MiB Q·81398
|
Binary file not shown.
195
pkg/rpc/server_helper_test.go
Normal file
195
pkg/rpc/server_helper_test.go
Normal file
|
@ -0,0 +1,195 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/CityOfZion/neo-go/config"
|
||||
"github.com/CityOfZion/neo-go/pkg/core"
|
||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||
"github.com/CityOfZion/neo-go/pkg/network"
|
||||
"github.com/CityOfZion/neo-go/pkg/rpc/result"
|
||||
"github.com/CityOfZion/neo-go/pkg/rpc/wrappers"
|
||||
"github.com/CityOfZion/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// SendTXResponse struct for testing.
|
||||
type SendTXResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result bool `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// ValidateAddrResponse struct for testing.
|
||||
type ValidateAddrResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result wrappers.ValidateAddressResponse `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// GetPeersResponse struct for testing.
|
||||
type GetPeersResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result struct {
|
||||
Unconnected []int `json:"unconnected"`
|
||||
Connected []int `json:"connected"`
|
||||
Bad []int `json:"bad"`
|
||||
} `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// GetVersionResponse struct for testing.
|
||||
type GetVersionResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result result.Version `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// IntResultResponse struct for testing.
|
||||
type IntResultResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result int `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// StringResultResponse struct for testing.
|
||||
type StringResultResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result string `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// GetBlockResponse struct for testing.
|
||||
type GetBlockResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result struct {
|
||||
Version int `json:"version"`
|
||||
Previousblockhash string `json:"previousblockhash"`
|
||||
Merkleroot string `json:"merkleroot"`
|
||||
Time int `json:"time"`
|
||||
Height int `json:"height"`
|
||||
Nonce int `json:"nonce"`
|
||||
NextConsensus string `json:"next_consensus"`
|
||||
Script struct {
|
||||
Invocation string `json:"invocation"`
|
||||
Verification string `json:"verification"`
|
||||
} `json:"script"`
|
||||
Tx []struct {
|
||||
Type string `json:"type"`
|
||||
Version int `json:"version"`
|
||||
Attributes interface{} `json:"attributes"`
|
||||
Vin interface{} `json:"vin"`
|
||||
Vout interface{} `json:"vout"`
|
||||
Scripts interface{} `json:"scripts"`
|
||||
} `json:"tx"`
|
||||
Confirmations int `json:"confirmations"`
|
||||
Nextblockhash string `json:"nextblockhash"`
|
||||
Hash string `json:"hash"`
|
||||
} `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// GetAssetResponse struct for testing.
|
||||
type GetAssetResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result struct {
|
||||
AssetID string `json:"assetID"`
|
||||
AssetType int `json:"assetType"`
|
||||
Name string `json:"name"`
|
||||
Amount string `json:"amount"`
|
||||
Available string `json:"available"`
|
||||
Precision int `json:"precision"`
|
||||
Fee int `json:"fee"`
|
||||
Address string `json:"address"`
|
||||
Owner string `json:"owner"`
|
||||
Admin string `json:"admin"`
|
||||
Issuer string `json:"issuer"`
|
||||
Expiration int `json:"expiration"`
|
||||
IsFrozen bool `json:"is_frozen"`
|
||||
} `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// GetAccountStateResponse struct for testing.
|
||||
type GetAccountStateResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result struct {
|
||||
Version int `json:"version"`
|
||||
ScriptHash string `json:"script_hash"`
|
||||
Frozen bool `json:"frozen"`
|
||||
Votes []interface{} `json:"votes"`
|
||||
Balances []struct {
|
||||
Asset string `json:"asset"`
|
||||
Value string `json:"value"`
|
||||
} `json:"balances"`
|
||||
} `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
func initServerWithInMemoryChain(ctx context.Context, t *testing.T) (*core.Blockchain, http.HandlerFunc) {
|
||||
net := config.ModeUnitTestNet
|
||||
configPath := "../../config"
|
||||
cfg, err := config.Load(configPath, net)
|
||||
require.NoError(t, err, "could not load config")
|
||||
|
||||
memoryStore := storage.NewMemoryStore()
|
||||
chain, err := core.NewBlockchain(memoryStore, cfg.ProtocolConfiguration)
|
||||
require.NoError(t, err, "could not create chain")
|
||||
|
||||
go chain.Run(ctx)
|
||||
initBlocks(t, chain)
|
||||
|
||||
serverConfig := network.NewServerConfig(cfg)
|
||||
server := network.NewServer(serverConfig, chain)
|
||||
rpcServer := NewServer(chain, cfg.ApplicationConfiguration.RPCPort, server)
|
||||
handler := http.HandlerFunc(rpcServer.requestHandler)
|
||||
|
||||
return chain, handler
|
||||
}
|
||||
|
||||
func initBlocks(t *testing.T, chain *core.Blockchain) {
|
||||
blocks := makeBlocks(10)
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
require.NoError(t, chain.AddBlock(blocks[i]))
|
||||
}
|
||||
require.NoError(t, chain.Persist(context.Background()))
|
||||
}
|
||||
|
||||
func makeBlocks(n int) []*core.Block {
|
||||
blocks := make([]*core.Block, n)
|
||||
for i := 0; i < n; i++ {
|
||||
blocks[i] = newBlock(uint32(i+1), newTX(transaction.MinerType))
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
func newTX(t transaction.TXType) *transaction.Transaction {
|
||||
return &transaction.Transaction{
|
||||
Type: t,
|
||||
}
|
||||
}
|
||||
|
||||
func newBlock(index uint32, txs ...*transaction.Transaction) *core.Block {
|
||||
b := &core.Block{
|
||||
BlockBase: core.BlockBase{
|
||||
Version: 0,
|
||||
PrevHash: hash.Sha256([]byte("a")),
|
||||
MerkleRoot: hash.Sha256([]byte("b")),
|
||||
Timestamp: uint32(time.Now().UTC().Unix()),
|
||||
Index: index,
|
||||
ConsensusData: 1111,
|
||||
NextConsensus: util.Uint160{},
|
||||
Script: &transaction.Witness{
|
||||
VerificationScript: []byte{0x0},
|
||||
InvocationScript: []byte{0x1},
|
||||
},
|
||||
},
|
||||
Transactions: txs,
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -2,280 +2,193 @@ package rpc
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/CityOfZion/neo-go/config"
|
||||
"github.com/CityOfZion/neo-go/pkg/core"
|
||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||
"github.com/CityOfZion/neo-go/pkg/network"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type tc struct {
|
||||
rpcCall string
|
||||
method string
|
||||
expectedResult string
|
||||
}
|
||||
func TestRPC(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||
defer cancel()
|
||||
|
||||
var testRPCCases = []tc{
|
||||
chain, handler := initServerWithInMemoryChain(ctx, t)
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"] }`,
|
||||
method: "getassetstate_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"assetID":"0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7","assetType":1,"name":"NEOGas","amount":"100000000","available":"0","precision":8,"fee":0,"address":"0x0000000000000000000000000000000000000000","owner":"00","admin":"AWKECj9RD8rS8RPcpCgYVjk1DeYyHwxZm3","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":0,"is_frozen":false},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b"] }`,
|
||||
method: "getassetstate_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"assetID":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","assetType":0,"name":"NEO","amount":"100000000","available":"0","precision":0,"fee":0,"address":"0x0000000000000000000000000000000000000000","owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":0,"is_frozen":false},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["62c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"] }`,
|
||||
method: "getassetstate_3",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": [123] }`,
|
||||
method: "getassetstate_4",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [10] }`,
|
||||
method: "getblockhash_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"0xd69e7a1f62225a35fed91ca578f33447d93fa0fd2b2f662b957e19c38c1dab1e","id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [-2] }`,
|
||||
method: "getblockhash_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":"Internal server error"},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getblock", "params": [10] }`,
|
||||
method: "getblock",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"version":0,"previousblockhash":"0x7c5b4c8a70336bf68e8679be7c9a2a15f85c0f6d0e14389019dcc3edfab2bb4b","merkleroot":"0xc027979ad29226b7d34523b1439a64a6cf57fe3f4e823e9d3e90d43934783d26","time":1529926220,"height":10,"nonce":8313828522725096825,"next_consensus":"0xbe48d3a3f5d10013ab9ffee489706078714f1ea2","script":{"invocation":"40ac828e1c2a214e4d356fd2eccc7c7be9ef426f8e4ea67a50464e90ca4367e611c4c5247082b85a7d5ed985cfb90b9af2f1195531038f49c63fb6894b517071ea40b22b83d9457ca5c4c5bb2d8d7e95333820611d447bb171ce7b8af3b999d0a5a61c2301cdd645a33a47defd09c0f237a0afc86e9a84c2fe675d701e4015c0302240a6899296660c612736edc22f8d630927649d4ef1301868079032d80aae6cc1e21622f256497a84a71d7afeeef4c124135f611db24a0f7ab3d2a6886f15db7865","verification":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae"},"tx":[{"type":"MinerTransaction","version":0,"attributes":null,"vin":null,"vout":null,"scripts":null}],"confirmations":12338,"nextblockhash":"0x2b1c78633dae7ab81f64362e0828153079a17b018d779d0406491f84c27b086f","hash":"0xd69e7a1f62225a35fed91ca578f33447d93fa0fd2b2f662b957e19c38c1dab1e"},"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getblockcount", "params": [] }`,
|
||||
method: "getblockcount",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":12349,"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getconnectioncount", "params": [] }`,
|
||||
method: "getconnectioncount",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":0,"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getbestblockhash", "params": [] }`,
|
||||
method: "getbestblockhash",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"877f5f2084181b85ce4726ab0a86bea6cc82cdbcb6f2eb59e6b04d27fd10929c","id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getpeers", "params": [] }`,
|
||||
method: "getpeers",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"unconnected":[],"connected":[],"bad":[]},"id":1}`},
|
||||
|
||||
// Good case, valid transaction ((param[1]=1 -> verbose = 1))
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", 1] }`,
|
||||
method: "getrawtransaction_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"type":"ContractTransaction","version":0,"attributes":[{"data":"23ba2703c53263e8d6e522dc32203339dcd8eee9","usage":"Script"}],"vin":[{"txid":"0x539084697cc220916cb5b16d2805945ec9f267aa004b6688fbf15e116c846aff","vout":0}],"vout":[{"address":"AXpNr3SDfLXbPHNdqxYeHK5cYpKMHZxMZ9","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":0,"value":"10000"},{"address":"AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":1,"value":"99990000"}],"scripts":[{"invocation":"40a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c6","verification":"21031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac"}],"txid":"0xf999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a","size":283,"sys_fee":"0","net_fee":"0","blockhash":"0x6088bf9d3b55c67184f60b00d2e380228f713b4028b24c1719796dcd2006e417","confirmations":2902,"blocktime":1533756500},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]=3 -> verbose = 1. Following the C# any number different from 0 is interpreted as verbose = 1)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", 3] }`,
|
||||
method: "getrawtransaction_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"type":"ContractTransaction","version":0,"attributes":[{"data":"23ba2703c53263e8d6e522dc32203339dcd8eee9","usage":"Script"}],"vin":[{"txid":"0x539084697cc220916cb5b16d2805945ec9f267aa004b6688fbf15e116c846aff","vout":0}],"vout":[{"address":"AXpNr3SDfLXbPHNdqxYeHK5cYpKMHZxMZ9","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":0,"value":"10000"},{"address":"AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":1,"value":"99990000"}],"scripts":[{"invocation":"40a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c6","verification":"21031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac"}],"txid":"0xf999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a","size":283,"sys_fee":"0","net_fee":"0","blockhash":"0x6088bf9d3b55c67184f60b00d2e380228f713b4028b24c1719796dcd2006e417","confirmations":2902,"blocktime":1533756500},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]="dads" -> verbose = 1. Following the C# any string different from "0", "false" is interpreted as verbose = 1)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", "dads"] }`,
|
||||
method: "getrawtransaction_3",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"type":"ContractTransaction","version":0,"attributes":[{"data":"23ba2703c53263e8d6e522dc32203339dcd8eee9","usage":"Script"}],"vin":[{"txid":"0x539084697cc220916cb5b16d2805945ec9f267aa004b6688fbf15e116c846aff","vout":0}],"vout":[{"address":"AXpNr3SDfLXbPHNdqxYeHK5cYpKMHZxMZ9","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":0,"value":"10000"},{"address":"AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y","asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","n":1,"value":"99990000"}],"scripts":[{"invocation":"40a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c6","verification":"21031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac"}],"txid":"0xf999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a","size":283,"sys_fee":"0","net_fee":"0","blockhash":"0x6088bf9d3b55c67184f60b00d2e380228f713b4028b24c1719796dcd2006e417","confirmations":2902,"blocktime":1533756500},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, invalid transaction
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["45a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", 1] }`,
|
||||
method: "getrawtransaction_4",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a"] }`,
|
||||
method: "getrawtransaction_5",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"8000012023ba2703c53263e8d6e522dc32203339dcd8eee901ff6a846c115ef1fb88664b00aa67f2c95e9405286db1b56c9120c27c698490530000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50010a5d4e8000000affb37f5fdb9c6fec48d9f0eee85af82950f9b4a9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500f01b9b0986230023ba2703c53263e8d6e522dc32203339dcd8eee9014140a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c62321031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac","id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]= 0 -> verbose = 0)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", 0] }`,
|
||||
method: "getrawtransaction_6",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"8000012023ba2703c53263e8d6e522dc32203339dcd8eee901ff6a846c115ef1fb88664b00aa67f2c95e9405286db1b56c9120c27c698490530000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50010a5d4e8000000affb37f5fdb9c6fec48d9f0eee85af82950f9b4a9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500f01b9b0986230023ba2703c53263e8d6e522dc32203339dcd8eee9014140a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c62321031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac","id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]="false" -> verbose = 0)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", "false"] }`,
|
||||
method: "getrawtransaction_6_a",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"8000012023ba2703c53263e8d6e522dc32203339dcd8eee901ff6a846c115ef1fb88664b00aa67f2c95e9405286db1b56c9120c27c698490530000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50010a5d4e8000000affb37f5fdb9c6fec48d9f0eee85af82950f9b4a9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500f01b9b0986230023ba2703c53263e8d6e522dc32203339dcd8eee9014140a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c62321031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac","id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]=false -> verbose = 0)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", false] }`,
|
||||
method: "getrawtransaction_6_b",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"8000012023ba2703c53263e8d6e522dc32203339dcd8eee901ff6a846c115ef1fb88664b00aa67f2c95e9405286db1b56c9120c27c698490530000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50010a5d4e8000000affb37f5fdb9c6fec48d9f0eee85af82950f9b4a9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500f01b9b0986230023ba2703c53263e8d6e522dc32203339dcd8eee9014140a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c62321031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac","id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid transaction (param[1]="0" -> verbose = 0)
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a", "0"] }`,
|
||||
method: "getrawtransaction_6_c",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":"8000012023ba2703c53263e8d6e522dc32203339dcd8eee901ff6a846c115ef1fb88664b00aa67f2c95e9405286db1b56c9120c27c698490530000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50010a5d4e8000000affb37f5fdb9c6fec48d9f0eee85af82950f9b4a9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500f01b9b0986230023ba2703c53263e8d6e522dc32203339dcd8eee9014140a88bd1fcfba334b06da0ce1a679f80711895dade50352074e79e438e142dc95528d04a00c579398cb96c7301428669a09286ae790459e05e907c61ab8a1191c62321031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4aac","id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, param at index 0 not a string
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": [123, 0] }`,
|
||||
method: "getrawtransaction_7",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid address
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"] }`,
|
||||
method: "getaccountstate_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"version":0,"script_hash":"0xe9eed8dc39332032dc22e5d6e86332c50327ba23","frozen":false,"votes":[],"balances":[{"asset":"0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7","value":"72099.9996"},{"asset":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","value":"99989900"}]},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, invalid address
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AK2nJJpJr6o664CWJKi1QRXjqeic2zR"] }`,
|
||||
method: "getaccountstate_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, not string
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": [123] }`,
|
||||
method: "getaccountstate_3",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, empty params
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": [] }`,
|
||||
method: "getaccountstate_4",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case, valid address
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"] }`,
|
||||
method: "validateaddress_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"address":"AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i","isvalid":true},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, invalid address
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["152f1muMCNa7goXYhYAQC61hxEgGacmncB"] }`,
|
||||
method: "validateaddress_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"address":"152f1muMCNa7goXYhYAQC61hxEgGacmncB","isvalid":false},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, not string
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [1] }`,
|
||||
method: "validateaddress_3",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":{"address":1,"isvalid":false},"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, empty params
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [] }`,
|
||||
method: "validateaddress_4",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
|
||||
// Good case
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["80000190274d792072617720636f6e7472616374207472616e73616374696f6e206465736372697074696f6e01949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500a3e11100000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5004f2418010000001cc9c05cefffe6cdd7b182816a9152ec218d2ec0014140dbd3cddac5cb2bd9bf6d93701f1a6f1c9dbe2d1b480c54628bbb2a4d536158c747a6af82698edf9f8af1cac3850bcb772bd9c8e4ac38f80704751cc4e0bd0e67232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"] }`,
|
||||
method: "sendrawtransaction_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":true,"id":1}`,
|
||||
},
|
||||
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["d1001b00046e616d6567d3d8602814a429a91afdbaa3914884a1c90c733101201cc9c05cefffe6cdd7b182816a9152ec218d2ec000000141403387ef7940a5764259621e655b3c621a6aafd869a611ad64adcc364d8dd1edf84e00a7f8b11b630a377eaef02791d1c289d711c08b7ad04ff0d6c9caca22cfe6232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"] }`,
|
||||
method: "sendrawtransaction_2",
|
||||
expectedResult: `{"jsonrpc":"2.0","result":true,"id":1}`,
|
||||
},
|
||||
|
||||
// Bad case, incorrect raw transaction
|
||||
{
|
||||
rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["0274d792072617720636f6e7472616374207472616e73616374696f6e206465736372697074696f6e01949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500a3e11100000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5004f2418010000001cc9c05cefffe6cdd7b182816a9152ec218d2ec0014140dbd3cddac5cb2bd9bf6d93701f1a6f1c9dbe2d1b480c54628bbb2a4d536158c747a6af82698edf9f8af1cac3850bcb772bd9c8e4ac38f80704751cc4e0bd0e67232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"] }`,
|
||||
method: "sendrawtransaction_1",
|
||||
expectedResult: `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params"},"id":1}`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
// setup rpcServer server
|
||||
net := config.ModeUnitTestNet
|
||||
configPath := "../../config"
|
||||
cfg, err := config.Load(configPath, net)
|
||||
require.NoError(t, err, "could not load config")
|
||||
|
||||
store, err := storage.NewLevelDBStore(cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions)
|
||||
assert.Nil(t, err)
|
||||
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration)
|
||||
require.NoError(t, err, "could not create levelDB chain")
|
||||
|
||||
serverConfig := network.NewServerConfig(cfg)
|
||||
server := network.NewServer(serverConfig, chain)
|
||||
rpcServer := NewServer(chain, cfg.ApplicationConfiguration.RPCPort, server)
|
||||
|
||||
// setup handler
|
||||
handler := http.HandlerFunc(rpcServer.requestHandler)
|
||||
|
||||
testRPCCases = append(testRPCCases, tc{
|
||||
rpcCall: `{"jsonrpc": "2.0", "id": 1, "method": "getversion", "params": [] }`,
|
||||
method: "getversion",
|
||||
expectedResult: fmt.Sprintf(`{"jsonrpc":"2.0","result":{"port":20333,"nonce":%s,"useragent":"/NEO-GO:/"},"id":1}`, strconv.FormatUint(uint64(server.ID()), 10)),
|
||||
defer func() {
|
||||
require.NoError(t, chain.Close())
|
||||
}()
|
||||
t.Run("getbestblockhash", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getbestblockhash", "params": []}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res StringResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, chain.CurrentBlockHash().ReverseString(), res.Result)
|
||||
})
|
||||
|
||||
for _, tc := range testRPCCases {
|
||||
t.Run(fmt.Sprintf("method: %s, rpc call: %s", tc.method, tc.rpcCall), func(t *testing.T) {
|
||||
t.Run("getblock", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblock", "params": [1]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res GetBlockResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
block, err := chain.GetBlock(chain.GetHeaderHash(1))
|
||||
assert.NoErrorf(t, err, "could not get block")
|
||||
expectedHash := "0x" + block.Hash().ReverseString()
|
||||
assert.Equal(t, expectedHash, res.Result.Hash)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("POST", "http://0.0.0.0:20333/", strings.NewReader(tc.rpcCall))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
t.Run("getblockcount", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblockcount", "params": []}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res IntResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, chain.BlockHeight(), uint32(res.Result))
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
resp := w.Result()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoErrorf(t, err, "could not read response from the request: %s", tc.rpcCall)
|
||||
assert.JSONEq(t, tc.expectedResult, string(bytes.TrimSpace(body)))
|
||||
})
|
||||
t.Run("getblockhash", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [1]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res StringResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
block, err := chain.GetBlock(chain.GetHeaderHash(1))
|
||||
assert.NoErrorf(t, err, "could not get block")
|
||||
expectedHash := "0x" + block.Hash().ReverseString()
|
||||
assert.Equal(t, expectedHash, res.Result)
|
||||
})
|
||||
|
||||
}
|
||||
t.Run("getconnectioncount", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getconnectioncount", "params": []}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res IntResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, 0, res.Result)
|
||||
})
|
||||
|
||||
t.Run("getversion", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getversion", "params": []}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res GetVersionResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, "/NEO-GO:/", res.Result.UserAgent)
|
||||
})
|
||||
|
||||
t.Run("getpeers", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getpeers", "params": []}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res GetPeersResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, []int{}, res.Result.Bad)
|
||||
assert.Equal(t, []int{}, res.Result.Unconnected)
|
||||
assert.Equal(t, []int{}, res.Result.Connected)
|
||||
})
|
||||
|
||||
t.Run("validateaddress_positive", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res ValidateAddrResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, true, res.Result.IsValid)
|
||||
})
|
||||
|
||||
t.Run("validateaddress_negative", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [1]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res ValidateAddrResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, false, res.Result.IsValid)
|
||||
})
|
||||
|
||||
t.Run("getassetstate_positive", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res GetAssetResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, "00", res.Result.Owner)
|
||||
assert.Equal(t, "AWKECj9RD8rS8RPcpCgYVjk1DeYyHwxZm3", res.Result.Admin)
|
||||
})
|
||||
|
||||
t.Run("getassetstate_negative", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de2"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res StringResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, "Invalid assetid", res.Result)
|
||||
})
|
||||
|
||||
t.Run("getaccountstate_positive", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res GetAccountStateResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, 1, len(res.Result.Balances))
|
||||
assert.Equal(t, false, res.Result.Frozen)
|
||||
})
|
||||
|
||||
t.Run("getaccountstate_negative", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getaccountstate", "params": ["AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res StringResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, "Invalid public account address", res.Result)
|
||||
})
|
||||
|
||||
t.Run("getrawtransaction", func(t *testing.T) {
|
||||
block, _ := chain.GetBlock(chain.GetHeaderHash(0))
|
||||
TXHash := block.Transactions[1].Hash()
|
||||
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s"]}"`, TXHash.ReverseString())
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res StringResultResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, "400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res.Result)
|
||||
})
|
||||
|
||||
t.Run("sendrawtransaction_positive", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["d1001b00046e616d6567d3d8602814a429a91afdbaa3914884a1c90c733101201cc9c05cefffe6cdd7b182816a9152ec218d2ec000000141403387ef7940a5764259621e655b3c621a6aafd869a611ad64adcc364d8dd1edf84e00a7f8b11b630a377eaef02791d1c289d711c08b7ad04ff0d6c9caca22cfe6232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res SendTXResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, true, res.Result)
|
||||
})
|
||||
|
||||
t.Run("sendrawtransaction_negative", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["0274d792072617720636f6e7472616374207472616e73616374696f6e206465736372697074696f6e01949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500a3e11100000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5004f2418010000001cc9c05cefffe6cdd7b182816a9152ec218d2ec0014140dbd3cddac5cb2bd9bf6d93701f1a6f1c9dbe2d1b480c54628bbb2a4d536158c747a6af82698edf9f8af1cac3850bcb772bd9c8e4ac38f80704751cc4e0bd0e67232103cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6ac"]}`
|
||||
body := doRPCCall(rpc, handler, t)
|
||||
var res SendTXResponse
|
||||
err := json.Unmarshal(bytes.TrimSpace(body), &res)
|
||||
assert.NoErrorf(t, err, "could not parse response: %s", body)
|
||||
assert.Equal(t, false, res.Result)
|
||||
})
|
||||
}
|
||||
|
||||
func doRPCCall(rpcCall string, handler http.HandlerFunc, t *testing.T) []byte {
|
||||
req := httptest.NewRequest("POST", "http://0.0.0.0:20333/", strings.NewReader(rpcCall))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
resp := w.Result()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoErrorf(t, err, "could not read response from the request: %s", rpcCall)
|
||||
return body
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue