diff --git a/cli/server/server.go b/cli/server/server.go index 2e8227ea4..62d45f6d1 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -7,7 +7,6 @@ import ( "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/CityOfZion/neo-go/pkg/rpc" "github.com/pkg/errors" @@ -53,7 +52,7 @@ func startServer(ctx *cli.Context) error { signal.Notify(interruptChan, os.Interrupt) serverConfig := network.NewServerConfig(cfg) - chain, err := newBlockchain(cfg) + chain, err := core.NewBlockchainLevelDB(cfg) if err != nil { err = fmt.Errorf("could not initialize blockchain: %s", err) return cli.NewExitError(err, 1) @@ -98,19 +97,6 @@ Main: return nil } -func newBlockchain(cfg config.Config) (*core.Blockchain, error) { - // Hardcoded for now. - store, err := storage.NewLevelDBStore( - cfg.ApplicationConfiguration.DataDirectoryPath, - nil, - ) - if err != nil { - return nil, err - } - - return core.NewBlockchain(store, cfg.ProtocolConfiguration) -} - func logo() string { return ` _ ____________ __________ diff --git a/config/config.go b/config/config.go index 73082c89c..874de3238 100644 --- a/config/config.go +++ b/config/config.go @@ -14,9 +14,10 @@ const ( userAgentFormat = "/NEO-GO:%s/" // Valid NetMode constants. - ModeMainNet NetMode = 0x00746e41 // 7630401 - ModeTestNet NetMode = 0x74746e41 // 1953787457 - ModePrivNet NetMode = 56753 // docker privnet + ModeMainNet NetMode = 0x00746e41 // 7630401 + ModeTestNet NetMode = 0x74746e41 // 1953787457 + ModePrivNet NetMode = 56753 // docker privnet + ModeUnitTestNet NetMode = 0 ) var ( @@ -78,6 +79,8 @@ func (n NetMode) String() string { return "testnet" case ModeMainNet: return "mainnet" + case ModeUnitTestNet: + return "unit_testnet" default: return "net unknown" } diff --git a/config/protocol.unit_testnet.yml b/config/protocol.unit_testnet.yml new file mode 100644 index 000000000..baefd1690 --- /dev/null +++ b/config/protocol.unit_testnet.yml @@ -0,0 +1,26 @@ +ProtocolConfiguration: + Magic: 56753 + AddressVersion: 23 + StandbyValidators: + - 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2 + - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e + - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 + - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + SeedList: + - 127.0.0.1:20334 + - 127.0.0.1:20335 + - 127.0.0.1:20336 + SystemFee: + EnrollmentTransaction: 1000 + IssueTransaction: 500 + PublishTransaction: 500 + RegisterTransaction: 10000 + +ApplicationConfiguration: + DataDirectoryPath: "./chains/unit_testnet" + RPCPort: 20332 + NodePort: 20333 + Relay: true + DialTimeout: 3 + ProtoTickInterval: 2 + MaxPeers: 50 diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index 987001fff..f927e4e0d 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -139,7 +139,7 @@ func (a *AssetState) EncodeBinary(w io.Writer) error { return binary.Write(w, binary.LittleEndian, a.IsFrozen) } -// Get the asset name based on its type. +// GetName returns the asset name based on its type. func (a *AssetState) GetName() string { if a.AssetType == transaction.GoverningToken { diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 83e8c5c41..404879110 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -9,6 +9,7 @@ import ( "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/util" @@ -79,6 +80,19 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration) (*Blockcha return bc, nil } +// GetBlockchainLevelDB returns blockchain based on configuration +func NewBlockchainLevelDB(cfg config.Config) (*Blockchain, error) { + store, err := storage.NewLevelDBStore( + cfg.ApplicationConfiguration.DataDirectoryPath, + nil, + ) + if err != nil { + return nil, err + } + + return NewBlockchain(store, cfg.ProtocolConfiguration) +} + func (bc *Blockchain) init() error { genesisBlock, err := createGenesisBlock(bc.config) if err != nil { diff --git a/pkg/core/cache.go b/pkg/core/cache.go index 6efa4893e..ce0f4a3d7 100644 --- a/pkg/core/cache.go +++ b/pkg/core/cache.go @@ -51,7 +51,7 @@ func (c *Cache) has(h util.Uint256) bool { return ok } -// Hash returns whether the cach contains the given hash. +// Has returns whether the cach contains the given hash. func (c *Cache) Has(h util.Uint256) bool { c.lock.Lock() defer c.lock.Unlock() diff --git a/pkg/core/unspent_coin_state.go b/pkg/core/unspent_coin_state.go index 21019117a..a47758489 100644 --- a/pkg/core/unspent_coin_state.go +++ b/pkg/core/unspent_coin_state.go @@ -52,9 +52,9 @@ func NewUnspentCoinState(n int) *UnspentCoinState { } // commit writes all unspent coin states to the given Batch. -func (s UnspentCoins) commit(b storage.Batch) error { +func (u UnspentCoins) commit(b storage.Batch) error { buf := new(bytes.Buffer) - for hash, state := range s { + for hash, state := range u { if err := state.EncodeBinary(buf); err != nil { return err } @@ -78,7 +78,7 @@ func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { return nil } -// DecodBinary decodes UnspentCoinState from the given io.Reader. +// DecodeBinary decodes UnspentCoinState from the given io.Reader. func (s *UnspentCoinState) DecodeBinary(r io.Reader) error { lenStates := util.ReadVarUint(r) s.states = make([]CoinState, lenStates) diff --git a/pkg/rpc/chains/unit_testnet/000011.ldb b/pkg/rpc/chains/unit_testnet/000011.ldb new file mode 100644 index 000000000..f565db8ac Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000011.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000012.ldb b/pkg/rpc/chains/unit_testnet/000012.ldb new file mode 100644 index 000000000..af43f28a3 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000012.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000013.ldb b/pkg/rpc/chains/unit_testnet/000013.ldb new file mode 100644 index 000000000..579b7110a Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000013.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000014.ldb b/pkg/rpc/chains/unit_testnet/000014.ldb new file mode 100644 index 000000000..ac132afb9 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000014.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000017.ldb b/pkg/rpc/chains/unit_testnet/000017.ldb new file mode 100644 index 000000000..ca2bbbda1 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000017.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000020.ldb b/pkg/rpc/chains/unit_testnet/000020.ldb new file mode 100644 index 000000000..514153918 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000020.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000023.ldb b/pkg/rpc/chains/unit_testnet/000023.ldb new file mode 100644 index 000000000..acbcb7708 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000023.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/000024.log b/pkg/rpc/chains/unit_testnet/000024.log new file mode 100644 index 000000000..0da494651 Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000024.log differ diff --git a/pkg/rpc/chains/unit_testnet/000026.ldb b/pkg/rpc/chains/unit_testnet/000026.ldb new file mode 100644 index 000000000..6f7dfb64e Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/000026.ldb differ diff --git a/pkg/rpc/chains/unit_testnet/CURRENT b/pkg/rpc/chains/unit_testnet/CURRENT new file mode 100644 index 000000000..f62209062 --- /dev/null +++ b/pkg/rpc/chains/unit_testnet/CURRENT @@ -0,0 +1 @@ +MANIFEST-000025 diff --git a/pkg/rpc/chains/unit_testnet/LOCK b/pkg/rpc/chains/unit_testnet/LOCK new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/rpc/chains/unit_testnet/LOG b/pkg/rpc/chains/unit_testnet/LOG new file mode 100644 index 000000000..368ceb5bf --- /dev/null +++ b/pkg/rpc/chains/unit_testnet/LOG @@ -0,0 +1,82 @@ +=============== 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 diff --git a/pkg/rpc/chains/unit_testnet/MANIFEST-000025 b/pkg/rpc/chains/unit_testnet/MANIFEST-000025 new file mode 100644 index 000000000..ed6d6440d Binary files /dev/null and b/pkg/rpc/chains/unit_testnet/MANIFEST-000025 differ diff --git a/pkg/rpc/server_test.go b/pkg/rpc/server_test.go new file mode 100644 index 000000000..343593956 --- /dev/null +++ b/pkg/rpc/server_test.go @@ -0,0 +1,121 @@ +package rpc + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" + + "github.com/CityOfZion/neo-go/pkg/core" + + "github.com/CityOfZion/neo-go/config" + "github.com/CityOfZion/neo-go/pkg/network" + "github.com/stretchr/testify/assert" +) + +func TestHandler(t *testing.T) { + + // setup rpcServer server + net := config.ModeUnitTestNet + + configPath := "../../config" + + cfg, err := config.Load(configPath, net) + if err != nil { + t.Errorf("could not load configuration file") + } + + chain, err := core.NewBlockchainLevelDB(cfg) + if err != nil { + t.Errorf("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) + + testCases := []struct { + rpcCall string + method string + expectedResult string + }{ + {`{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"] }`, + "getassetstate_1", + `{"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}`}, + + {`{ "jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b"] }`, + "getassetstate_2", + `{"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}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": ["62c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"] }`, + "getassetstate_3", + `{"jsonrpc":"2.0","result":"Invalid assetid","id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": [123] }`, + "getassetstate_4", + `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params","data":"Param need to be a string"},"id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [10] }`, + "getblockhash_1", + `{"jsonrpc":"2.0","result":"0xd69e7a1f62225a35fed91ca578f33447d93fa0fd2b2f662b957e19c38c1dab1e","id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [-2] }`, + "getblockhash_2", + `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params","data":"Param at index 0 should be greater than or equal to 0 and less then or equal to current block height, got: -2"},"id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getblock", "params": [10] }`, + "getblock", + `{"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":0,"version":0,"attributes":null,"vin":null,"vout":null,"scripts":null}],"confirmations":12338,"nextblockhash":"0x2b1c78633dae7ab81f64362e0828153079a17b018d779d0406491f84c27b086f","hash":"0xd69e7a1f62225a35fed91ca578f33447d93fa0fd2b2f662b957e19c38c1dab1e"},"id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getblockcount", "params": [] }`, + "getblockcount", + `{"jsonrpc":"2.0","result":12349,"id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getconnectioncount", "params": [] }`, + "getconnectioncount", + `{"jsonrpc":"2.0","result":0,"id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getversion", "params": [] }`, + "getversion", + fmt.Sprintf(`{"jsonrpc":"2.0","result":{"port":20333,"nonce":%s,"useragent":"/NEO-GO:/"},"id":1}`, strconv.FormatUint(uint64(server.ID()), 10))}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getbestblockhash", "params": [] }`, + "getbestblockhash", + `{"jsonrpc":"2.0","result":"877f5f2084181b85ce4726ab0a86bea6cc82cdbcb6f2eb59e6b04d27fd10929c","id":1}`}, + + {`{"jsonrpc": "2.0", "id": 1, "method": "getpeers", "params": [] }`, + "getpeers", + `{"jsonrpc":"2.0","result":{"unconnected":[],"connected":[],"bad":[]},"id":1}`}, + } + + for _, tc := range testCases { + + t.Run(fmt.Sprintf("method: %s, rpc call: %s", tc.method, tc.rpcCall), func(t *testing.T) { + + jsonStr := []byte(tc.rpcCall) + + req := httptest.NewRequest("POST", "http://0.0.0.0:20333/", bytes.NewBuffer(jsonStr)) + req.Header.Set("Content-Type", "application/json") + + w := httptest.NewRecorder() + handler(w, req) + + resp := w.Result() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("could not read response from the request: %s", tc.rpcCall) + } + + assert.Equal(t, tc.expectedResult, string(bytes.TrimSpace(body))) + }) + + } +}