diff --git a/bitcoin/client_test.go b/bitcoin/client_test.go index 554e3dc..4e1ab94 100644 --- a/bitcoin/client_test.go +++ b/bitcoin/client_test.go @@ -431,6 +431,109 @@ func TestNetworkStatus(t *testing.T) { } } +func TestGetPeers(t *testing.T) { + tests := map[string]struct { + responses []responseFixture + + expectedPeers []*types.Peer + expectedError error + }{ + "successful": { + responses: []responseFixture{ + { + status: http.StatusOK, + body: loadFixture("get_peer_info_response.json"), + url: url, + }, + }, + expectedPeers: []*types.Peer{ + { + PeerID: "77.93.223.9:8333", + Metadata: forceMarshalMap(t, &PeerInfo{ + Addr: "77.93.223.9:8333", + Version: 70015, + SubVer: "/Satoshi:0.14.2/", + StartingHeight: 643579, + RelayTxes: true, + LastSend: 1597606676, + LastRecv: 1597606677, + BanScore: 0, + SyncedHeaders: 644046, + SyncedBlocks: 644046, + }), + }, + { + PeerID: "172.105.93.179:8333", + Metadata: forceMarshalMap(t, &PeerInfo{ + Addr: "172.105.93.179:8333", + RelayTxes: true, + LastSend: 1597606678, + LastRecv: 1597606676, + Version: 70015, + SubVer: "/Satoshi:0.18.1/", + StartingHeight: 643579, + BanScore: 0, + SyncedHeaders: 644046, + SyncedBlocks: 644046, + }), + }, + }, + }, + "blockchain warming up error": { + responses: []responseFixture{ + { + status: http.StatusOK, + body: loadFixture("rpc_in_warmup_response.json"), + url: url, + }, + }, + expectedError: errors.New("rpc in warmup"), + }, + "peer info error": { + responses: []responseFixture{ + { + status: http.StatusInternalServerError, + body: "{}", + url: url, + }, + }, + expectedError: errors.New("invalid response: 500 Internal Server Error"), + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var ( + assert = assert.New(t) + ) + + responses := make(chan responseFixture, len(test.responses)) + for _, response := range test.responses { + responses <- response + } + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response := <-responses + assert.Equal("application/json", r.Header.Get("Content-Type")) + assert.Equal("POST", r.Method) + assert.Equal(response.url, r.URL.RequestURI()) + + w.WriteHeader(response.status) + fmt.Fprintln(w, response.body) + })) + + client := NewClient(ts.URL, MainnetGenesisBlockIdentifier, MainnetCurrency) + peers, err := client.GetPeers(context.Background()) + if test.expectedError != nil { + assert.Contains(err.Error(), test.expectedError.Error()) + } else { + assert.NoError(err) + assert.Equal(test.expectedPeers, peers) + } + }) + } +} + func TestGetRawBlock(t *testing.T) { tests := map[string]struct { blockIdentifier *types.PartialBlockIdentifier diff --git a/mocks/services/client.go b/mocks/services/client.go index 838124f..a47044e 100644 --- a/mocks/services/client.go +++ b/mocks/services/client.go @@ -15,16 +15,16 @@ type Client struct { mock.Mock } -// NetworkStatus provides a mock function with given fields: _a0 -func (_m *Client) NetworkStatus(_a0 context.Context) (*types.NetworkStatusResponse, error) { +// GetPeers provides a mock function with given fields: _a0 +func (_m *Client) GetPeers(_a0 context.Context) ([]*types.Peer, error) { ret := _m.Called(_a0) - var r0 *types.NetworkStatusResponse - if rf, ok := ret.Get(0).(func(context.Context) *types.NetworkStatusResponse); ok { + var r0 []*types.Peer + if rf, ok := ret.Get(0).(func(context.Context) []*types.Peer); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.NetworkStatusResponse) + r0 = ret.Get(0).([]*types.Peer) } } diff --git a/services/network_service.go b/services/network_service.go index 0d1932b..92046cc 100644 --- a/services/network_service.go +++ b/services/network_service.go @@ -65,7 +65,7 @@ func (s *NetworkAPIService) NetworkStatus( return nil, wrapErr(ErrUnavailableOffline, nil) } - rawStatus, err := s.client.NetworkStatus(ctx) + peers, err := s.client.GetPeers(ctx) if err != nil { return nil, wrapErr(ErrBitcoind, err) } @@ -75,9 +75,12 @@ func (s *NetworkAPIService) NetworkStatus( return nil, wrapErr(ErrNotReady, nil) } - rawStatus.CurrentBlockIdentifier = cachedBlockResponse.Block.BlockIdentifier - - return rawStatus, nil + return &types.NetworkStatusResponse{ + CurrentBlockIdentifier: cachedBlockResponse.Block.BlockIdentifier, + CurrentBlockTimestamp: cachedBlockResponse.Block.Timestamp, + GenesisBlockIdentifier: s.config.GenesisBlockIdentifier, + Peers: peers, + }, nil } // NetworkOptions implements the /network/options endpoint. diff --git a/services/network_service_test.go b/services/network_service_test.go index 8d8dbb2..d60d6ed 100644 --- a/services/network_service_test.go +++ b/services/network_service_test.go @@ -27,7 +27,7 @@ import ( ) var ( - middlewareVersion = "0.0.2" + middlewareVersion = "0.0.3" defaultNetworkOptions = &types.NetworkOptionsResponse{ Version: &types.Version{ RosettaVersion: "1.4.4", @@ -78,8 +78,9 @@ func TestNetworkEndpoints_Offline(t *testing.T) { func TestNetworkEndpoints_Online(t *testing.T) { cfg := &configuration.Configuration{ - Mode: configuration.Online, - Network: networkIdentifier, + Mode: configuration.Online, + Network: networkIdentifier, + GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier, } mockIndexer := &mocks.Indexer{} mockClient := &mocks.Client{} @@ -92,9 +93,6 @@ func TestNetworkEndpoints_Online(t *testing.T) { networkIdentifier, }, networkList.NetworkIdentifiers) - rawStatus := &types.NetworkStatusResponse{ - GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier, - } blockResponse := &types.BlockResponse{ Block: &types.Block{ BlockIdentifier: &types.BlockIdentifier{ @@ -103,7 +101,11 @@ func TestNetworkEndpoints_Online(t *testing.T) { }, }, } - mockClient.On("NetworkStatus", ctx).Return(rawStatus, nil) + mockClient.On("GetPeers", ctx).Return([]*types.Peer{ + { + PeerID: "77.93.223.9:8333", + }, + }, nil) mockIndexer.On( "GetBlockLazy", ctx, @@ -117,6 +119,11 @@ func TestNetworkEndpoints_Online(t *testing.T) { assert.Equal(t, &types.NetworkStatusResponse{ GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier, CurrentBlockIdentifier: blockResponse.Block.BlockIdentifier, + Peers: []*types.Peer{ + { + PeerID: "77.93.223.9:8333", + }, + }, }, networkStatus) networkOptions, err := servicer.NetworkOptions(ctx, nil) diff --git a/services/types.go b/services/types.go index 158c0b3..5d83625 100644 --- a/services/types.go +++ b/services/types.go @@ -38,13 +38,13 @@ var ( // variable instead of a constant because // we typically need the pointer of this // value. - MiddlewareVersion = "0.0.2" + MiddlewareVersion = "0.0.3" ) // Client is used by the servicers to get Peer information // and to submit transactions. type Client interface { - NetworkStatus(context.Context) (*types.NetworkStatusResponse, error) + GetPeers(context.Context) ([]*types.Peer, error) SendRawTransaction(context.Context, string) (string, error) SuggestedFeeRate(context.Context, int64) (float64, error) RawMempool(context.Context) ([]string, error)