Skip to content

Commit 062fa04

Browse files
committed
fixed merge issue
2 parents 24d44f3 + 4accc18 commit 062fa04

File tree

7 files changed

+317
-39
lines changed

7 files changed

+317
-39
lines changed

cmd/geth/admin.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (js *jsre) adminBindings() {
3232
js.re.Set("admin", struct{}{})
3333
t, _ := js.re.Get("admin")
3434
admin := t.Object()
35-
admin.Set("suggestPeer", js.suggestPeer)
35+
admin.Set("addPeer", js.addPeer)
3636
admin.Set("startRPC", js.startRPC)
3737
admin.Set("stopRPC", js.stopRPC)
3838
admin.Set("nodeInfo", js.nodeInfo)
@@ -314,13 +314,13 @@ func (js *jsre) stopRPC(call otto.FunctionCall) otto.Value {
314314
return otto.FalseValue()
315315
}
316316

317-
func (js *jsre) suggestPeer(call otto.FunctionCall) otto.Value {
317+
func (js *jsre) addPeer(call otto.FunctionCall) otto.Value {
318318
nodeURL, err := call.Argument(0).ToString()
319319
if err != nil {
320320
fmt.Println(err)
321321
return otto.FalseValue()
322322
}
323-
err = js.ethereum.SuggestPeer(nodeURL)
323+
err = js.ethereum.AddPeer(nodeURL)
324324
if err != nil {
325325
fmt.Println(err)
326326
return otto.FalseValue()

cmd/mist/ui_lib.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ func (ui *UiLib) Connect(button qml.Object) {
104104
}
105105

106106
func (ui *UiLib) ConnectToPeer(nodeURL string) {
107-
if err := ui.eth.SuggestPeer(nodeURL); err != nil {
108-
guilogger.Infoln("SuggestPeer error: " + err.Error())
107+
if err := ui.eth.AddPeer(nodeURL); err != nil {
108+
guilogger.Infoln("AddPeer error: " + err.Error())
109109
}
110110
}
111111

eth/backend.go

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ package eth
22

33
import (
44
"crypto/ecdsa"
5+
"encoding/json"
56
"fmt"
7+
"io/ioutil"
8+
"os"
69
"path"
10+
"path/filepath"
711
"strings"
812
"time"
913

@@ -36,6 +40,9 @@ var (
3640
// ETH/DEV cpp-ethereum (poc-9.ethdev.com)
3741
discover.MustParseNode("enode://487611428e6c99a11a9795a6abe7b529e81315ca6aad66e2a2fc76e3adf263faba0d35466c2f8f68d561dbefa8878d4df5f1f2ddb1fbeab7f42ffb8cd328bd4a@5.1.83.226:30303"),
3842
}
43+
44+
staticNodes = "static-nodes.json" // Path within <datadir> to search for the static node list
45+
trustedNodes = "trusted-nodes.json" // Path within <datadir> to search for the trusted node list
3946
)
4047

4148
type Config struct {
@@ -56,8 +63,7 @@ type Config struct {
5663
MaxPeers int
5764
Port string
5865

59-
// This should be a space-separated list of
60-
// discovery node URLs.
66+
// Space-separated list of discovery node URLs
6167
BootNodes string
6268

6369
// This key is used to identify the node on the network.
@@ -96,6 +102,40 @@ func (cfg *Config) parseBootNodes() []*discover.Node {
96102
return ns
97103
}
98104

105+
// parseNodes parses a list of discovery node URLs loaded from a .json file.
106+
func (cfg *Config) parseNodes(file string) []*discover.Node {
107+
// Short circuit if no node config is present
108+
path := filepath.Join(cfg.DataDir, file)
109+
if _, err := os.Stat(path); err != nil {
110+
return nil
111+
}
112+
// Load the nodes from the config file
113+
blob, err := ioutil.ReadFile(path)
114+
if err != nil {
115+
glog.V(logger.Error).Infof("Failed to access nodes: %v", err)
116+
return nil
117+
}
118+
nodelist := []string{}
119+
if err := json.Unmarshal(blob, &nodelist); err != nil {
120+
glog.V(logger.Error).Infof("Failed to load nodes: %v", err)
121+
return nil
122+
}
123+
// Interpret the list as a discovery node array
124+
var nodes []*discover.Node
125+
for _, url := range nodelist {
126+
if url == "" {
127+
continue
128+
}
129+
node, err := discover.ParseNode(url)
130+
if err != nil {
131+
glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err)
132+
continue
133+
}
134+
nodes = append(nodes, node)
135+
}
136+
return nodes
137+
}
138+
99139
func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
100140
// use explicit key from command line args if set
101141
if cfg.NodeKey != nil {
@@ -247,6 +287,8 @@ func New(config *Config) (*Ethereum, error) {
247287
NAT: config.NAT,
248288
NoDial: !config.Dial,
249289
BootstrapNodes: config.parseBootNodes(),
290+
StaticNodes: config.parseNodes(staticNodes),
291+
TrustedNodes: config.parseNodes(trustedNodes),
250292
NodeDatabase: nodeDb,
251293
}
252294
if len(config.Port) > 0 {
@@ -441,12 +483,15 @@ func (s *Ethereum) StartForTest() {
441483
s.txPool.Start()
442484
}
443485

444-
func (self *Ethereum) SuggestPeer(nodeURL string) error {
486+
// AddPeer connects to the given node and maintains the connection until the
487+
// server is shut down. If the connection fails for any reason, the server will
488+
// attempt to reconnect the peer.
489+
func (self *Ethereum) AddPeer(nodeURL string) error {
445490
n, err := discover.ParseNode(nodeURL)
446491
if err != nil {
447492
return fmt.Errorf("invalid node URL: %v", err)
448493
}
449-
self.net.SuggestPeer(n)
494+
self.net.AddPeer(n)
450495
return nil
451496
}
452497

p2p/handshake.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,21 @@ type protoHandshake struct {
7070
// If dial is non-nil, the connection the local node is the initiator.
7171
// If atcap is true, the connection will be disconnected with DiscTooManyPeers
7272
// after the key exchange.
73-
func setupConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node, atcap bool) (*conn, error) {
73+
func setupConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node, atcap bool, trusted map[discover.NodeID]bool) (*conn, error) {
7474
if dial == nil {
75-
return setupInboundConn(fd, prv, our, atcap)
75+
return setupInboundConn(fd, prv, our, atcap, trusted)
7676
} else {
77-
return setupOutboundConn(fd, prv, our, dial, atcap)
77+
return setupOutboundConn(fd, prv, our, dial, atcap, trusted)
7878
}
7979
}
8080

81-
func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, atcap bool) (*conn, error) {
81+
func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, atcap bool, trusted map[discover.NodeID]bool) (*conn, error) {
8282
secrets, err := receiverEncHandshake(fd, prv, nil)
8383
if err != nil {
8484
return nil, fmt.Errorf("encryption handshake failed: %v", err)
8585
}
8686
rw := newRlpxFrameRW(fd, secrets)
87-
if atcap {
87+
if atcap && !trusted[secrets.RemoteID] {
8888
SendItems(rw, discMsg, DiscTooManyPeers)
8989
return nil, errors.New("we have too many peers")
9090
}
@@ -99,13 +99,13 @@ func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, a
9999
return &conn{rw, rhs}, nil
100100
}
101101

102-
func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node, atcap bool) (*conn, error) {
102+
func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node, atcap bool, trusted map[discover.NodeID]bool) (*conn, error) {
103103
secrets, err := initiatorEncHandshake(fd, prv, dial.ID, nil)
104104
if err != nil {
105105
return nil, fmt.Errorf("encryption handshake failed: %v", err)
106106
}
107107
rw := newRlpxFrameRW(fd, secrets)
108-
if atcap {
108+
if atcap && !trusted[secrets.RemoteID] {
109109
SendItems(rw, discMsg, DiscTooManyPeers)
110110
return nil, errors.New("we have too many peers")
111111
}

p2p/handshake_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func TestSetupConn(t *testing.T) {
143143
done := make(chan struct{})
144144
go func() {
145145
defer close(done)
146-
conn0, err := setupConn(fd0, prv0, hs0, node1, false)
146+
conn0, err := setupConn(fd0, prv0, hs0, node1, false, nil)
147147
if err != nil {
148148
t.Errorf("outbound side error: %v", err)
149149
return
@@ -156,7 +156,7 @@ func TestSetupConn(t *testing.T) {
156156
}
157157
}()
158158

159-
conn1, err := setupConn(fd1, prv1, hs1, nil, false)
159+
conn1, err := setupConn(fd1, prv1, hs1, nil, false, nil)
160160
if err != nil {
161161
t.Fatalf("inbound side error: %v", err)
162162
}

p2p/server.go

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import (
1818
)
1919

2020
const (
21-
defaultDialTimeout = 10 * time.Second
22-
refreshPeersInterval = 30 * time.Second
21+
defaultDialTimeout = 10 * time.Second
22+
refreshPeersInterval = 30 * time.Second
23+
staticPeerCheckInterval = 15 * time.Second
2324

2425
// This is the maximum number of inbound connection
2526
// that are allowed to linger between 'accepted' and
@@ -59,6 +60,14 @@ type Server struct {
5960
// with the rest of the network.
6061
BootstrapNodes []*discover.Node
6162

63+
// Static nodes are used as pre-configured connections which are always
64+
// maintained and re-connected on disconnects.
65+
StaticNodes []*discover.Node
66+
67+
// Trusted nodes are used as pre-configured connections which are always
68+
// allowed to connect, even above the peer limit.
69+
TrustedNodes []*discover.Node
70+
6271
// NodeDatabase is the path to the database containing the previously seen
6372
// live nodes in the network.
6473
NodeDatabase string
@@ -95,20 +104,23 @@ type Server struct {
95104

96105
ourHandshake *protoHandshake
97106

98-
lock sync.RWMutex // protects running and peers
99-
running bool
100-
peers map[discover.NodeID]*Peer
107+
lock sync.RWMutex // protects running, peers and the trust fields
108+
running bool
109+
peers map[discover.NodeID]*Peer
110+
staticNodes map[discover.NodeID]*discover.Node // Map of currently maintained static remote nodes
111+
staticDial chan *discover.Node // Dial request channel reserved for the static nodes
112+
staticCycle time.Duration // Overrides staticPeerCheckInterval, used for testing
113+
trustedNodes map[discover.NodeID]bool // Set of currently trusted remote nodes
101114

102115
ntab *discover.Table
103116
listener net.Listener
104117

105-
quit chan struct{}
106-
loopWG sync.WaitGroup // {dial,listen,nat}Loop
107-
peerWG sync.WaitGroup // active peer goroutines
108-
peerConnect chan *discover.Node
118+
quit chan struct{}
119+
loopWG sync.WaitGroup // {dial,listen,nat}Loop
120+
peerWG sync.WaitGroup // active peer goroutines
109121
}
110122

111-
type setupFunc func(net.Conn, *ecdsa.PrivateKey, *protoHandshake, *discover.Node, bool) (*conn, error)
123+
type setupFunc func(net.Conn, *ecdsa.PrivateKey, *protoHandshake, *discover.Node, bool, map[discover.NodeID]bool) (*conn, error)
112124
type newPeerHook func(*Peer)
113125

114126
// Peers returns all connected peers.
@@ -131,10 +143,14 @@ func (srv *Server) PeerCount() int {
131143
return n
132144
}
133145

134-
// SuggestPeer creates a connection to the given Node if it
135-
// is not already connected.
136-
func (srv *Server) SuggestPeer(n *discover.Node) {
137-
srv.peerConnect <- n
146+
// AddPeer connects to the given node and maintains the connection until the
147+
// server is shut down. If the connection fails for any reason, the server will
148+
// attempt to reconnect the peer.
149+
func (srv *Server) AddPeer(node *discover.Node) {
150+
srv.lock.Lock()
151+
defer srv.lock.Unlock()
152+
153+
srv.staticNodes[node.ID] = node
138154
}
139155

140156
// Broadcast sends an RLP-encoded message to all connected peers.
@@ -195,7 +211,18 @@ func (srv *Server) Start() (err error) {
195211
}
196212
srv.quit = make(chan struct{})
197213
srv.peers = make(map[discover.NodeID]*Peer)
198-
srv.peerConnect = make(chan *discover.Node)
214+
215+
// Create the current trust maps, and the associated dialing channel
216+
srv.trustedNodes = make(map[discover.NodeID]bool)
217+
for _, node := range srv.TrustedNodes {
218+
srv.trustedNodes[node.ID] = true
219+
}
220+
srv.staticNodes = make(map[discover.NodeID]*discover.Node)
221+
for _, node := range srv.StaticNodes {
222+
srv.staticNodes[node.ID] = node
223+
}
224+
srv.staticDial = make(chan *discover.Node)
225+
199226
if srv.setupFunc == nil {
200227
srv.setupFunc = setupConn
201228
}
@@ -229,6 +256,8 @@ func (srv *Server) Start() (err error) {
229256
if srv.NoDial && srv.ListenAddr == "" {
230257
glog.V(logger.Warn).Infoln("I will be kind-of useless, neither dialing nor listening.")
231258
}
259+
// maintain the static peers
260+
go srv.staticNodesLoop()
232261

233262
srv.running = true
234263
return nil
@@ -323,6 +352,45 @@ func (srv *Server) listenLoop() {
323352
}
324353
}
325354

355+
// staticNodesLoop is responsible for periodically checking that static
356+
// connections are actually live, and requests dialing if not.
357+
func (srv *Server) staticNodesLoop() {
358+
// Create a default maintenance ticker, but override it requested
359+
cycle := staticPeerCheckInterval
360+
if srv.staticCycle != 0 {
361+
cycle = srv.staticCycle
362+
}
363+
tick := time.NewTicker(cycle)
364+
365+
for {
366+
select {
367+
case <-srv.quit:
368+
return
369+
370+
case <-tick.C:
371+
// Collect all the non-connected static nodes
372+
needed := []*discover.Node{}
373+
srv.lock.RLock()
374+
for id, node := range srv.staticNodes {
375+
if _, ok := srv.peers[id]; !ok {
376+
needed = append(needed, node)
377+
}
378+
}
379+
srv.lock.RUnlock()
380+
381+
// Try to dial each of them (don't hang if server terminates)
382+
for _, node := range needed {
383+
glog.V(logger.Debug).Infof("Dialing static peer %v", node)
384+
select {
385+
case srv.staticDial <- node:
386+
case <-srv.quit:
387+
return
388+
}
389+
}
390+
}
391+
}
392+
}
393+
326394
func (srv *Server) dialLoop() {
327395
var (
328396
dialed = make(chan *discover.Node)
@@ -373,7 +441,7 @@ func (srv *Server) dialLoop() {
373441
// below MaxPeers.
374442
refresh.Reset(refreshPeersInterval)
375443
}
376-
case dest := <-srv.peerConnect:
444+
case dest := <-srv.staticDial:
377445
dial(dest)
378446
case dests := <-findresults:
379447
for _, dest := range dests {
@@ -416,10 +484,18 @@ func (srv *Server) startPeer(fd net.Conn, dest *discover.Node) {
416484
// returns during that exchange need to call peerWG.Done because
417485
// the callers of startPeer added the peer to the wait group already.
418486
fd.SetDeadline(time.Now().Add(handshakeTimeout))
487+
488+
// Check capacity, but override for static nodes
419489
srv.lock.RLock()
420490
atcap := len(srv.peers) == srv.MaxPeers
491+
if dest != nil {
492+
if _, ok := srv.staticNodes[dest.ID]; ok {
493+
atcap = false
494+
}
495+
}
421496
srv.lock.RUnlock()
422-
conn, err := srv.setupFunc(fd, srv.PrivateKey, srv.ourHandshake, dest, atcap)
497+
498+
conn, err := srv.setupFunc(fd, srv.PrivateKey, srv.ourHandshake, dest, atcap, srv.trustedNodes)
423499
if err != nil {
424500
fd.Close()
425501
glog.V(logger.Debug).Infof("Handshake with %v failed: %v", fd.RemoteAddr(), err)
@@ -472,11 +548,18 @@ func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) {
472548
return true, 0
473549
}
474550

551+
// checkPeer verifies whether a peer looks promising and should be allowed/kept
552+
// in the pool, or if it's of no use.
475553
func (srv *Server) checkPeer(id discover.NodeID) (bool, DiscReason) {
554+
// First up, figure out if the peer is static or trusted
555+
_, static := srv.staticNodes[id]
556+
trusted := srv.trustedNodes[id]
557+
558+
// Make sure the peer passes all required checks
476559
switch {
477560
case !srv.running:
478561
return false, DiscQuitting
479-
case len(srv.peers) >= srv.MaxPeers:
562+
case !static && !trusted && len(srv.peers) >= srv.MaxPeers:
480563
return false, DiscTooManyPeers
481564
case srv.peers[id] != nil:
482565
return false, DiscAlreadyConnected

0 commit comments

Comments
 (0)