Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dot/rpc/modules): add system_addReservedPeer and system_removeReservedPeer RPC call #1712

Merged
merged 25 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d844913
chore: include rpc methods and adding peers on store
EclesioMeloJunior Jul 29, 2021
8099d21
chore: add unit tests for reserved peers on net layer
EclesioMeloJunior Jul 29, 2021
965b843
chore: add unit tests for reserved peers on net layer
EclesioMeloJunior Jul 29, 2021
3e7812b
chore: replace test method name
EclesioMeloJunior Jul 29, 2021
8455f22
chore: remove redundancy conditionals
EclesioMeloJunior Jul 29, 2021
240326b
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Jul 31, 2021
0e90758
chore: add and remove peers from protected map
EclesioMeloJunior Aug 1, 2021
cfeac1a
increase the system RPC methods qtt
EclesioMeloJunior Aug 3, 2021
ef3dec0
chore: test add and remove protected peers
EclesioMeloJunior Aug 3, 2021
31f4255
chore: improve comment at removeReservedPeers
EclesioMeloJunior Aug 3, 2021
7984fb1
chore: improve comment at addReservedPeers
EclesioMeloJunior Aug 3, 2021
c060382
Merge branch 'eclesio/rpc-add-reserved-peer' of github.com:ChainSafe/…
EclesioMeloJunior Aug 3, 2021
77f003a
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 3, 2021
f3a0e0d
chore: jump when there is no peer to disconect
EclesioMeloJunior Aug 4, 2021
3bb15b6
chore: fix lint issues
EclesioMeloJunior Aug 4, 2021
0fd592f
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 4, 2021
2a6f328
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 5, 2021
5c0b997
chore: remove unused checks and use trim space
EclesioMeloJunior Aug 5, 2021
774b438
Merge branch 'eclesio/rpc-add-reserved-peer' of github.com:ChainSafe/…
EclesioMeloJunior Aug 5, 2021
08214a7
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 6, 2021
e0a4a14
chore: improve test coverage
EclesioMeloJunior Aug 6, 2021
5d90025
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 6, 2021
95439dc
chore: remove global websocket test variable
EclesioMeloJunior Aug 6, 2021
75e09d3
chore: improve tests on modules/system
EclesioMeloJunior Aug 6, 2021
d5749ac
Merge branch 'development' into eclesio/rpc-add-reserved-peer
EclesioMeloJunior Aug 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions dot/network/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,42 @@ func (h *host) peers() []peer.ID {
return h.h.Network().Peers()
}

// addReservedPeers adds the peers `addrs` to the protected peers list and connects to them
func (h *host) addReservedPeers(addrs ...string) error {
for _, addr := range addrs {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return err
}

addinfo, err := peer.AddrInfoFromP2pAddr(maddr)
if err != nil {
return err
}

h.h.ConnManager().Protect(addinfo.ID, "")
if err := h.connect(*addinfo); err != nil {
return err
}
}

return nil
}

// removeReservedPeers will remove the given peers from the protected peers list
func (h *host) removeReservedPeers(ids ...string) error {
for _, id := range ids {
peerID, err := peer.Decode(id)
if err != nil {
return err
}

h.h.ConnManager().Unprotect(peerID, "")
}

return nil
}

// supportsProtocol checks if the protocol is supported by peerID
// returns an error if could not get peer protocols
func (h *host) supportsProtocol(peerID peer.ID, protocol protocol.ID) (bool, error) {
Expand Down
70 changes: 70 additions & 0 deletions dot/network/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,73 @@ func Test_PeerSupportsProtocol(t *testing.T) {
require.Equal(t, test.expect, output)
}
}

func Test_AddReservedPeers(t *testing.T) {
basePathA := utils.NewTestBasePath(t, "nodeA")
configA := &Config{
BasePath: basePathA,
Port: 7001,
NoBootstrap: true,
NoMDNS: true,
}

nodeA := createTestService(t, configA)
nodeA.noGossip = true

basePathB := utils.NewTestBasePath(t, "nodeB")
configB := &Config{
BasePath: basePathB,
Port: 7002,
NoBootstrap: true,
NoMDNS: true,
}

nodeB := createTestService(t, configB)
nodeB.noGossip = true

nodeBPeerAddr := nodeB.host.multiaddrs()[0].String()
err := nodeA.host.addReservedPeers(nodeBPeerAddr)
require.NoError(t, err)

isProtected := nodeA.host.h.ConnManager().IsProtected(nodeB.host.addrInfo().ID, "")
require.True(t, isProtected)
}

func Test_RemoveReservedPeers(t *testing.T) {
basePathA := utils.NewTestBasePath(t, "nodeA")
configA := &Config{
BasePath: basePathA,
Port: 7001,
NoBootstrap: true,
NoMDNS: true,
}

nodeA := createTestService(t, configA)
nodeA.noGossip = true

basePathB := utils.NewTestBasePath(t, "nodeB")
configB := &Config{
BasePath: basePathB,
Port: 7002,
NoBootstrap: true,
NoMDNS: true,
}

nodeB := createTestService(t, configB)
nodeB.noGossip = true

nodeBPeerAddr := nodeB.host.multiaddrs()[0].String()
err := nodeA.host.addReservedPeers(nodeBPeerAddr)
require.NoError(t, err)

pID := nodeB.host.addrInfo().ID.String()

err = nodeA.host.removeReservedPeers(pID)
require.NoError(t, err)

isProtected := nodeA.host.h.ConnManager().IsProtected(nodeB.host.addrInfo().ID, "")
require.False(t, isProtected)

err = nodeA.host.removeReservedPeers("failing peer ID")
require.Error(t, err)
}
10 changes: 10 additions & 0 deletions dot/network/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,16 @@ func (s *Service) Peers() []common.PeerInfo {
return peers
}

// AddReservedPeers insert new peers to the peerstore with PermanentAddrTTL
func (s *Service) AddReservedPeers(addrs ...string) error {
return s.host.addReservedPeers(addrs...)
}

// RemoveReservedPeers closes all connections with the target peers and remove it from the peerstore
func (s *Service) RemoveReservedPeers(addrs ...string) error {
return s.host.removeReservedPeers(addrs...)
}

// NodeRoles Returns the roles the node is running as.
func (s *Service) NodeRoles() byte {
return s.cfg.Roles
Expand Down
2 changes: 2 additions & 0 deletions dot/rpc/modules/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type NetworkAPI interface {
IsStopped() bool
HighestBlock() int64
StartingBlock() int64
AddReservedPeers(addrs ...string) error
RemoveReservedPeers(addrs ...string) error
}

// BlockProducerAPI is the interface for BlockProducer methods
Expand Down
40 changes: 40 additions & 0 deletions dot/rpc/modules/mocks/network_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions dot/rpc/modules/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"math/big"
"net/http"
"strings"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto"
Expand Down Expand Up @@ -280,3 +281,21 @@ func (sm *SystemModule) LocalPeerId(r *http.Request, req *EmptyRequest, res *str
*res = base58.Encode([]byte(netstate.PeerID))
return nil
}

// AddReservedPeer adds a reserved peer. The string parameter should encode a p2p multiaddr.
func (sm *SystemModule) AddReservedPeer(r *http.Request, req *StringRequest, res *[]byte) error {
if strings.TrimSpace(req.String) == "" {
return errors.New("cannot add an empty reserved peer")
}

return sm.networkAPI.AddReservedPeers(req.String)
}

// RemoveReservedPeer remove a reserved peer. The string should encode only the PeerId
func (sm *SystemModule) RemoveReservedPeer(r *http.Request, req *StringRequest, res *[]byte) error {
if strings.TrimSpace(req.String) == "" {
return errors.New("cannot remove an empty reserved peer")
}

return sm.networkAPI.RemoveReservedPeers(req.String)
}
60 changes: 59 additions & 1 deletion dot/rpc/modules/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func TestLocalListenAddresses(t *testing.T) {
}

mockNetAPI := new(mocks.MockNetworkAPI)
mockNetAPI.On("NetworkState").Return(mockedNetState)
mockNetAPI.On("NetworkState").Return(mockedNetState).Once()

res := make([]string, 0)

Expand All @@ -414,6 +414,10 @@ func TestLocalListenAddresses(t *testing.T) {

require.Len(t, res, 1)
require.Equal(t, res[0], ma.String())

mockNetAPI.On("NetworkState").Return(common.NetworkState{Multiaddrs: []multiaddr.Multiaddr{}}).Once()
err = sysmodule.LocalListenAddresses(nil, nil, &res)
require.Error(t, err, "multiaddress list is empty")
}

func TestLocalPeerId(t *testing.T) {
Expand Down Expand Up @@ -441,3 +445,57 @@ func TestLocalPeerId(t *testing.T) {
err = sysmodules.LocalPeerId(nil, nil, &res)
require.Error(t, err)
}

func TestAddReservedPeer(t *testing.T) {
t.Run("Test Add and Remove reserved peers with success", func(t *testing.T) {
networkMock := new(mocks.MockNetworkAPI)
networkMock.On("AddReservedPeers", mock.AnythingOfType("string")).Return(nil).Once()
networkMock.On("RemoveReservedPeers", mock.AnythingOfType("string")).Return(nil).Once()

multiAddrPeer := "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"
sysModule := &SystemModule{
networkAPI: networkMock,
}

var b *[]byte
err := sysModule.AddReservedPeer(nil, &StringRequest{String: multiAddrPeer}, b)
require.NoError(t, err)
require.Nil(t, b)

peerID := "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"
err = sysModule.RemoveReservedPeer(nil, &StringRequest{String: peerID}, b)
require.NoError(t, err)
require.Nil(t, b)
})

t.Run("Test Add and Remove reserved peers without success", func(t *testing.T) {
networkMock := new(mocks.MockNetworkAPI)
networkMock.On("AddReservedPeers", mock.AnythingOfType("string")).Return(errors.New("some problems")).Once()
networkMock.On("RemoveReservedPeers", mock.AnythingOfType("string")).Return(errors.New("other problems")).Once()

sysModule := &SystemModule{
networkAPI: networkMock,
}

var b *[]byte
err := sysModule.AddReservedPeer(nil, &StringRequest{String: ""}, b)
require.Error(t, err, "cannot add an empty reserved peer")
require.Nil(t, b)

multiAddrPeer := "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"
err = sysModule.AddReservedPeer(nil, &StringRequest{String: multiAddrPeer}, b)
require.Error(t, err, "some problems")
require.Nil(t, b)

peerID := "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV"
err = sysModule.RemoveReservedPeer(nil, &StringRequest{String: peerID}, b)
require.Error(t, err, "other problems")
require.Nil(t, b)
})

t.Run("Test trying to add or remove peers with empty or white space request", func(t *testing.T) {
sysModule := &SystemModule{}
require.Error(t, sysModule.AddReservedPeer(nil, &StringRequest{String: ""}, nil))
require.Error(t, sysModule.RemoveReservedPeer(nil, &StringRequest{String: " "}, nil))
})
}
2 changes: 1 addition & 1 deletion dot/rpc/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestNewService(t *testing.T) {
}

func TestService_Methods(t *testing.T) {
qtySystemMethods := 13
qtySystemMethods := 15
qtyRPCMethods := 1
qtyAuthorMethods := 8

Expand Down
49 changes: 7 additions & 42 deletions dot/rpc/subscription/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package subscription

import (
"fmt"
"log"
"math/big"
"net/http"
"os"
"testing"
"time"

Expand All @@ -20,47 +17,15 @@ import (
"github.com/stretchr/testify/require"
)

var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}

var wsconn = &WSConn{
Subscriptions: make(map[uint32]Listener),
}

func handler(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()

wsconn.Wsconn = c
wsconn.HandleComm()
}

func TestMain(m *testing.M) {
http.HandleFunc("/", handler)

go func() {
err := http.ListenAndServe("localhost:8546", nil)
if err != nil {
log.Fatal("error", err)
}
}()
time.Sleep(time.Millisecond * 100)
func TestWSConn_HandleComm(t *testing.T) {
wsconn, c, cancel := setupWSConn(t)
wsconn.Subscriptions = make(map[uint32]Listener)
defer cancel()

// Start all tests
os.Exit(m.Run())
}
go wsconn.HandleComm()
time.Sleep(time.Second * 2)

func TestWSConn_HandleComm(t *testing.T) {
c, _, err := websocket.DefaultDialer.Dial("ws://localhost:8546", nil) //nolint
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
fmt.Println("ws defined")

// test storageChangeListener
res, err := wsconn.initStorageChangeListener(1, nil)
Expand Down