Add interface to verify trusted MailServers (#1112)
The goal of this PR is to add an interface to verify MailServers. In this PR, MailServers are hardcoded in status-go. The next iteration will use a smart contract.
This commit is contained in:
parent
408ba5a7e6
commit
3b8c6c8260
|
@ -327,6 +327,14 @@ func parseNodesV5(enodes []string) []*discv5.Node {
|
|||
return nodes
|
||||
}
|
||||
|
||||
func parseNodesToNodeID(enodes []string) []discover.NodeID {
|
||||
nodeIDs := make([]discover.NodeID, 0, len(enodes))
|
||||
for _, node := range parseNodes(enodes) {
|
||||
nodeIDs = append(nodeIDs, node.ID)
|
||||
}
|
||||
return nodeIDs
|
||||
}
|
||||
|
||||
// whisperTimeSource get timeSource to be used by whisper
|
||||
func whisperTimeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
||||
var timeSource *timesource.NTPTimeSource
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
. "github.com/status-im/status-go/t/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
@ -57,3 +59,12 @@ func TestMakeNodeMalformedBootnodes(t *testing.T) {
|
|||
_, err = MakeNode(config, db)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestParseNodesToNodeID(t *testing.T) {
|
||||
nodeIDs := parseNodesToNodeID([]string{
|
||||
"enode://badkey@127.0.0.1:30303",
|
||||
fmt.Sprintf("enode://%s@127.0.0.1:30303", discover.NodeID{1}),
|
||||
})
|
||||
require.Len(t, nodeIDs, 1)
|
||||
require.Equal(t, discover.NodeID{1}, nodeIDs[0])
|
||||
}
|
||||
|
|
|
@ -223,6 +223,7 @@ func (n *StatusNode) startDiscovery() error {
|
|||
options := peers.NewDefaultOptions()
|
||||
// TODO(dshulyak) consider adding a flag to define this behaviour
|
||||
options.AllowStop = len(n.config.RegisterTopics) == 0
|
||||
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
||||
n.peerPool = peers.NewPeerPool(
|
||||
n.discovery,
|
||||
n.config.RequireTopics,
|
||||
|
|
|
@ -12,6 +12,7 @@ type cluster struct {
|
|||
NetworkID int `json:"networkID"`
|
||||
StaticNodes []string `json:"staticnodes"`
|
||||
BootNodes []string `json:"bootnodes"`
|
||||
MailServers []string `json:"mailservers"` // list of trusted mail servers
|
||||
}
|
||||
|
||||
var ropstenCluster = cluster{
|
||||
|
@ -26,6 +27,14 @@ var ropstenCluster = cluster{
|
|||
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304", // node-01.do-ams3.eth.beta
|
||||
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304", // node-01.gc-us-central1-a.eth.beta
|
||||
},
|
||||
MailServers: []string{
|
||||
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.108.78:30504", // mail-01.do-ams3.eth.beta
|
||||
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.108.63:30504", // mail-02.do-ams3.eth.beta
|
||||
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.7.30:30504", // mail-03.do-ams3.eth.beta
|
||||
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504", // mail-01.gc-us-central1-a.eth.beta
|
||||
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504", // mail-02.gc-us-central1-a.eth.beta
|
||||
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504", // mail-03.gc-us-central1-a.eth.beta
|
||||
},
|
||||
}
|
||||
|
||||
var rinkebyCluster = cluster{
|
||||
|
@ -40,6 +49,10 @@ var rinkebyCluster = cluster{
|
|||
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
|
||||
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303",
|
||||
},
|
||||
MailServers: []string{
|
||||
"enode://43829580446ad138386dadb7fa50b6bd4d99f7c28659a0bc08115f8c0380005922a340962496f6af756a42b94a1522baa38a694fa27de59c3a73d4e08d5dbb31@206.189.6.48:30504",
|
||||
"enode://70a2004e78399075f566033c42e9a0b1d43c683d4742755bb5457d03191be66a1b48c2b4fb259696839f28646a5828a1958b900860e27897f984ad0fc8482404@206.189.56.154:30504",
|
||||
},
|
||||
}
|
||||
|
||||
var mainnetCluster = cluster{
|
||||
|
@ -54,6 +67,14 @@ var mainnetCluster = cluster{
|
|||
"enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.243.176:30304", // node-01.do-ams3.eth.beta
|
||||
"enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304", // node-01.gc-us-central1-a.eth.beta
|
||||
},
|
||||
MailServers: []string{
|
||||
"enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@206.189.108.78:30504", // mail-01.do-ams3.eth.beta
|
||||
"enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@206.189.108.63:30504", // mail-02.do-ams3.eth.beta
|
||||
"enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@206.189.7.30:30504", // mail-03.do-ams3.eth.beta
|
||||
"enode://7de99e4cb1b3523bd26ca212369540646607c721ad4f3e5c821ed9148150ce6ce2e72631723002210fac1fd52dfa8bbdf3555e05379af79515e1179da37cc3db@35.188.19.210:30504", // mail-01.gc-us-central1-a.eth.beta
|
||||
"enode://015e22f6cd2b44c8a51bd7a23555e271e0759c7d7f52432719665a74966f2da456d28e154e836bee6092b4d686fe67e331655586c57b718be3997c1629d24167@35.226.21.19:30504", // mail-02.gc-us-central1-a.eth.beta
|
||||
"enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eabfb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6@35.225.227.79:30504", // mail-03.gc-us-central1-a.eth.beta
|
||||
},
|
||||
}
|
||||
|
||||
var betaCluster = []cluster{ropstenCluster, rinkebyCluster, mainnetCluster}
|
||||
|
|
|
@ -200,6 +200,9 @@ type ClusterConfig struct {
|
|||
// for a given mode (production vs development)
|
||||
BootNodes []string
|
||||
|
||||
// TrustedMailServers is a list of verified Mail Servers.
|
||||
TrustedMailServers []string
|
||||
|
||||
// RendezvousNodes is a rendezvous discovery server.
|
||||
RendezvousNodes []string
|
||||
}
|
||||
|
@ -644,6 +647,7 @@ func (c *NodeConfig) updateClusterConfig() error {
|
|||
if len(cluster.BootNodes) == 0 {
|
||||
c.NoDiscovery = true
|
||||
}
|
||||
c.ClusterConfig.TrustedMailServers = cluster.MailServers
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
|
@ -8,22 +10,29 @@ import (
|
|||
"github.com/status-im/status-go/signal"
|
||||
)
|
||||
|
||||
// Verifier verifies if a give node is trusted.
|
||||
type Verifier interface {
|
||||
VerifyNode(context.Context, discover.NodeID) bool
|
||||
}
|
||||
|
||||
// MailServerDiscoveryTopic topic name for mailserver discovery.
|
||||
const MailServerDiscoveryTopic = "whispermail"
|
||||
|
||||
// MailServerDiscoveryLimits default mailserver discovery limits.
|
||||
var MailServerDiscoveryLimits = params.Limits{Min: 3, Max: 3}
|
||||
|
||||
// newCacheOnlyTopicPool returns instance of CacheOnlyTopicPool.
|
||||
func newCacheOnlyTopicPool(t *TopicPool) *cacheOnlyTopicPool {
|
||||
return &cacheOnlyTopicPool{
|
||||
TopicPool: t,
|
||||
}
|
||||
}
|
||||
|
||||
// cacheOnlyTopicPool handles a mail server topic pool.
|
||||
type cacheOnlyTopicPool struct {
|
||||
*TopicPool
|
||||
verifier Verifier
|
||||
}
|
||||
|
||||
// newCacheOnlyTopicPool returns instance of CacheOnlyTopicPool.
|
||||
func newCacheOnlyTopicPool(t *TopicPool, verifier Verifier) *cacheOnlyTopicPool {
|
||||
return &cacheOnlyTopicPool{
|
||||
TopicPool: t,
|
||||
verifier: verifier,
|
||||
}
|
||||
}
|
||||
|
||||
// MaxReached checks if the max allowed peers is reached or not. When true
|
||||
|
@ -45,14 +54,34 @@ var sendEnodeDiscovered = signal.SendEnodeDiscovered
|
|||
// ConfirmAdded calls base TopicPool ConfirmAdded method and sends a signal
|
||||
// confirming the enode has been discovered.
|
||||
func (t *cacheOnlyTopicPool) ConfirmAdded(server *p2p.Server, nodeID discover.NodeID) {
|
||||
t.TopicPool.ConfirmAdded(server, nodeID)
|
||||
sendEnodeDiscovered(nodeID.String(), string(t.topic))
|
||||
trusted := t.verifier.VerifyNode(context.TODO(), nodeID)
|
||||
if trusted {
|
||||
// add to cache only if trusted
|
||||
t.TopicPool.ConfirmAdded(server, nodeID)
|
||||
sendEnodeDiscovered(nodeID.String(), string(t.topic))
|
||||
t.subtractToLimits()
|
||||
}
|
||||
|
||||
id := discv5.NodeID(nodeID)
|
||||
|
||||
// If a peer was trusted, it was moved to connectedPeers,
|
||||
// signal was sent and we can safely remove it.
|
||||
if peer, ok := t.connectedPeers[id]; ok {
|
||||
t.removeServerPeer(server, peer)
|
||||
// Delete it from `connectedPeers` immediately to
|
||||
// prevent removing it from the cache which logic is
|
||||
// implemented in TopicPool.
|
||||
delete(t.connectedPeers, id)
|
||||
t.subtractToLimits()
|
||||
}
|
||||
|
||||
// It a peer was not trusted, it is still in pendingPeers.
|
||||
// We should remove it from the p2p.Server.
|
||||
if peer, ok := t.pendingPeers[id]; ok {
|
||||
t.removeServerPeer(server, peer.peerInfo)
|
||||
// Delete it from `connectedPeers` immediately to
|
||||
// prevent removing it from the cache which logic is
|
||||
// implemented in TopicPool.
|
||||
delete(t.pendingPeers, id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -42,7 +43,7 @@ func (s *CacheOnlyTopicPoolSuite) SetupTest() {
|
|||
cache, err := newInMemoryCache()
|
||||
s.Require().NoError(err)
|
||||
t := newTopicPool(nil, MailServerDiscoveryTopic, limits, 100*time.Millisecond, 200*time.Millisecond, cache)
|
||||
s.topicPool = newCacheOnlyTopicPool(t)
|
||||
s.topicPool = newCacheOnlyTopicPool(t, &testTrueVerifier{})
|
||||
s.topicPool.running = 1
|
||||
// This is a buffered channel to simplify testing.
|
||||
// If your test generates more than 10 mode changes,
|
||||
|
@ -70,15 +71,15 @@ func (s *CacheOnlyTopicPoolSuite) TestReplacementPeerIsCounted() {
|
|||
// When we stop searching for peers (when Max limit is reached)
|
||||
s.topicPool.StopSearch(s.peer)
|
||||
s.True(s.topicPool.MaxReached())
|
||||
s.Equal(s.topicPool.limits.Max, 0)
|
||||
s.Equal(s.topicPool.limits.Min, 0)
|
||||
s.Equal(0, s.topicPool.limits.Max)
|
||||
s.Equal(0, s.topicPool.limits.Min)
|
||||
|
||||
// Then we should drop all connected peers
|
||||
s.Equal(len(s.topicPool.connectedPeers), 0)
|
||||
|
||||
// And cached peers should remain
|
||||
cachedPeers := s.topicPool.cache.GetPeersRange(s.topicPool.topic, s.topicPool.maxCachedPeers)
|
||||
s.Equal(len(cachedPeers), 1)
|
||||
s.Equal(1, len(cachedPeers))
|
||||
}
|
||||
|
||||
func (s *CacheOnlyTopicPoolSuite) TestConfirmAddedSignals() {
|
||||
|
@ -94,3 +95,35 @@ func (s *CacheOnlyTopicPoolSuite) TestConfirmAddedSignals() {
|
|||
s.Equal((discv5.NodeID{1}).String(), sentNodeID)
|
||||
s.Equal(MailServerDiscoveryTopic, sentTopic)
|
||||
}
|
||||
|
||||
func (s *CacheOnlyTopicPoolSuite) TestNotTrustedPeer() {
|
||||
var signalCalled bool
|
||||
sendEnodeDiscovered = func(_, _ string) { signalCalled = true }
|
||||
|
||||
s.topicPool.limits = params.NewLimits(1, 1)
|
||||
s.topicPool.maxCachedPeers = 1
|
||||
s.topicPool.verifier = &testFalseVerifier{}
|
||||
|
||||
foundPeer := discv5.NewNode(discv5.NodeID{1}, s.peer.Self().IP, 32311, 32311)
|
||||
s.topicPool.processFoundNode(s.peer, foundPeer)
|
||||
s.topicPool.ConfirmAdded(s.peer, discover.NodeID(foundPeer.ID))
|
||||
|
||||
s.False(signalCalled)
|
||||
// limits should not change
|
||||
s.Equal(1, s.topicPool.limits.Max)
|
||||
s.Equal(1, s.topicPool.limits.Min)
|
||||
// not verified peer shoud not be added to the cache
|
||||
s.Equal(0, len(s.topicPool.cache.GetPeersRange(s.topicPool.topic, s.topicPool.limits.Max)))
|
||||
}
|
||||
|
||||
type testTrueVerifier struct{}
|
||||
|
||||
func (v *testTrueVerifier) VerifyNode(context.Context, discover.NodeID) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type testFalseVerifier struct{}
|
||||
|
||||
func (v *testFalseVerifier) VerifyNode(context.Context, discover.NodeID) bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/discovery"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/peers/verifier"
|
||||
"github.com/status-im/status-go/signal"
|
||||
)
|
||||
|
||||
|
@ -53,6 +54,8 @@ type Options struct {
|
|||
// TopicStopSearchDelay time stopSearch will be waiting for max cached peers to be
|
||||
// filled before really stopping the search.
|
||||
TopicStopSearchDelay time.Duration
|
||||
// TrustedMailServers is a list of trusted nodes.
|
||||
TrustedMailServers []discover.NodeID
|
||||
}
|
||||
|
||||
// NewDefaultOptions returns a struct with default Options.
|
||||
|
@ -140,7 +143,7 @@ func (p *PeerPool) Start(server *p2p.Server) error {
|
|||
var topicPool TopicPoolInterface
|
||||
t := newTopicPool(p.discovery, topic, limits, p.opts.SlowSync, p.opts.FastSync, p.cache)
|
||||
if topic == MailServerDiscoveryTopic {
|
||||
topicPool = newCacheOnlyTopicPool(t)
|
||||
topicPool = newCacheOnlyTopicPool(t, verifier.NewLocalVerifier(p.opts.TrustedMailServers))
|
||||
} else {
|
||||
topicPool = t
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ func (s *PeerPoolSimulationSuite) TestPeerPoolCacheEthV5() {
|
|||
config := map[discv5.Topic]params.Limits{
|
||||
topic: params.NewLimits(1, 1),
|
||||
}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
||||
cache, err := newInMemoryCache()
|
||||
s.Require().NoError(err)
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
|
@ -220,7 +220,7 @@ func (s *PeerPoolSimulationSuite) singleTopicDiscoveryWithFailover() {
|
|||
config := map[discv5.Topic]params.Limits{
|
||||
topic: params.NewLimits(1, 1), // limits are chosen for simplicity of the simulation
|
||||
}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 0}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 0, nil}
|
||||
cache, err := newInMemoryCache()
|
||||
s.Require().NoError(err)
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
|
@ -302,7 +302,7 @@ func TestPeerPoolMaxPeersOverflow(t *testing.T) {
|
|||
defer func() { assert.NoError(t, discovery.Stop()) }()
|
||||
require.True(t, discovery.Running())
|
||||
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond}
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond, nil}
|
||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||
require.NoError(t, pool.Start(peer))
|
||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||
|
@ -355,7 +355,7 @@ func TestPeerPoolDiscV5Timeout(t *testing.T) {
|
|||
require.True(t, discovery.Running())
|
||||
|
||||
// start PeerPool
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond}
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond, nil}
|
||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||
require.NoError(t, pool.Start(server))
|
||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||
|
@ -402,7 +402,7 @@ func TestPeerPoolNotAllowedStopping(t *testing.T) {
|
|||
require.True(t, discovery.Running())
|
||||
|
||||
// start PeerPool
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond}
|
||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond, nil}
|
||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||
require.NoError(t, pool.Start(server))
|
||||
|
||||
|
@ -419,7 +419,7 @@ func (s *PeerPoolSimulationSuite) TestUpdateTopicLimits() {
|
|||
config := map[discv5.Topic]params.Limits{
|
||||
topic: params.NewLimits(1, 1),
|
||||
}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond}
|
||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
||||
cache, err := newInMemoryCache()
|
||||
s.Require().NoError(err)
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
|
@ -447,3 +447,73 @@ func (s *PeerPoolSimulationSuite) TestUpdateTopicLimits() {
|
|||
s.Equal(5, tp.limits.Min)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
|
||||
s.setupEthV5()
|
||||
|
||||
// Buffered channels must be used because we expect the events
|
||||
// to be in the same order. Use a buffer length greater than
|
||||
// the expected number of events to avoid deadlock.
|
||||
poolEvents := make(chan string, 10)
|
||||
summaries := make(chan []*p2p.PeerInfo, 10)
|
||||
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
||||
var envelope struct {
|
||||
Type string
|
||||
Event json.RawMessage
|
||||
}
|
||||
s.NoError(json.Unmarshal([]byte(jsonEvent), &envelope))
|
||||
|
||||
switch typ := envelope.Type; typ {
|
||||
case signal.EventDiscoverySummary:
|
||||
poolEvents <- envelope.Type
|
||||
var summary []*p2p.PeerInfo
|
||||
s.NoError(json.Unmarshal(envelope.Event, &summary))
|
||||
summaries <- summary
|
||||
}
|
||||
})
|
||||
defer signal.ResetDefaultNodeNotificationHandler()
|
||||
|
||||
// subscribe for peer events before starting the peer pool
|
||||
events := make(chan *p2p.PeerEvent, 20)
|
||||
subscription := s.peers[1].SubscribeEvents(events)
|
||||
defer subscription.Unsubscribe()
|
||||
|
||||
// create and start topic registry
|
||||
register := NewRegister(s.discovery[0], MailServerDiscoveryTopic)
|
||||
s.Require().NoError(register.Start())
|
||||
|
||||
// create and start peer pool
|
||||
config := map[discv5.Topic]params.Limits{
|
||||
MailServerDiscoveryTopic: params.NewLimits(1, 1),
|
||||
}
|
||||
cache, err := newInMemoryCache()
|
||||
s.Require().NoError(err)
|
||||
peerPoolOpts := &Options{
|
||||
100 * time.Millisecond,
|
||||
100 * time.Millisecond,
|
||||
0,
|
||||
true,
|
||||
100 * time.Millisecond,
|
||||
[]discover.NodeID{s.peers[0].Self().ID},
|
||||
}
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
s.Require().NoError(peerPool.Start(s.peers[1]))
|
||||
defer peerPool.Stop()
|
||||
|
||||
// wait for and verify the mail server peer
|
||||
connectedPeer := s.getPeerFromEvent(events, p2p.PeerEventTypeAdd)
|
||||
s.Equal(s.peers[0].Self().ID, connectedPeer)
|
||||
|
||||
// wait for a summary event to be sure that ConfirmAdded() was called
|
||||
s.Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
|
||||
s.Equal(s.peers[0].Self().ID.String(), (<-summaries)[0].ID)
|
||||
|
||||
// check cache
|
||||
cachedPeers := peerPool.cache.GetPeersRange(MailServerDiscoveryTopic, 5)
|
||||
s.Require().Len(cachedPeers, 1)
|
||||
s.Equal(s.peers[0].Self().ID[:], cachedPeers[0].ID[:])
|
||||
|
||||
// wait for another summary event as the peer should be removed
|
||||
s.Equal(signal.EventDiscoverySummary, s.getPoolEvent(poolEvents))
|
||||
s.Len(<-summaries, 0)
|
||||
}
|
||||
|
|
|
@ -325,6 +325,6 @@ func (s *TopicPoolSuite) TestNewTopicPoolInterface() {
|
|||
s.IsType(&TopicPool{}, t)
|
||||
|
||||
tp := newTopicPool(nil, MailServerDiscoveryTopic, limits, 100*time.Millisecond, 200*time.Millisecond, cache)
|
||||
cacheTP := newCacheOnlyTopicPool(tp)
|
||||
cacheTP := newCacheOnlyTopicPool(tp, &testTrueVerifier{})
|
||||
s.IsType(&cacheOnlyTopicPool{}, cacheTP)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package verifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
)
|
||||
|
||||
// LocalVerifier verifies nodes based on a provided local list.
|
||||
type LocalVerifier struct {
|
||||
KnownPeers map[discover.NodeID]struct{}
|
||||
}
|
||||
|
||||
// NewLocalVerifier returns a new LocalVerifier instance.
|
||||
func NewLocalVerifier(peers []discover.NodeID) *LocalVerifier {
|
||||
knownPeers := make(map[discover.NodeID]struct{})
|
||||
for _, peer := range peers {
|
||||
knownPeers[peer] = struct{}{}
|
||||
}
|
||||
|
||||
return &LocalVerifier{KnownPeers: knownPeers}
|
||||
}
|
||||
|
||||
// VerifyNode checks if a given node is trusted using a local list.
|
||||
func (v *LocalVerifier) VerifyNode(_ context.Context, nodeID discover.NodeID) bool {
|
||||
if _, ok := v.KnownPeers[nodeID]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package verifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLocalVerifierForNodeIDTypes(t *testing.T) {
|
||||
nodeID := discover.NodeID{1}
|
||||
|
||||
v := NewLocalVerifier([]discover.NodeID{{1}})
|
||||
require.True(t, v.VerifyNode(context.TODO(), nodeID))
|
||||
require.False(t, v.VerifyNode(context.TODO(), discover.NodeID{2}))
|
||||
}
|
Loading…
Reference in New Issue