diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index 41e1034e9..dee25e44e 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -35,6 +35,7 @@ const ( var ( versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`)) + testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")) testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}` ) @@ -72,6 +73,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) { ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore")) am := accounts.NewManager(ks) ethereum, err := eth.New(ð.Config{ + NodeKey: testNodeKey, DataDir: tmp, AccountManager: am, MaxPeers: 0, @@ -122,7 +124,7 @@ func TestNodeInfo(t *testing.T) { } defer ethereum.Stop() defer os.RemoveAll(tmp) - want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0"}` + want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5","NodeUrl":"enode://4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5@0.0.0.0:0","TCPPort":0,"Td":"131072"}` checkEvalJSON(t, repl, `admin.nodeInfo()`, want) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 56f383b77..9d935efbd 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -260,6 +260,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.AutoDAGFlag, utils.NATFlag, utils.NatspecEnabledFlag, + utils.NoDiscoverFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.RPCEnabledFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cb774aa5b..155110ddc 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -235,6 +235,10 @@ var ( Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", Value: "any", } + NoDiscoverFlag = cli.BoolFlag{ + Name: "nodiscover", + Usage: "Disables the peer discovery mechanism (manual peer addition)", + } WhisperEnabledFlag = cli.BoolFlag{ Name: "shh", Usage: "Enable whisper", @@ -312,6 +316,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config { Port: ctx.GlobalString(ListenPortFlag.Name), NAT: GetNAT(ctx), NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name), + Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name), NodeKey: GetNodeKey(ctx), Shh: ctx.GlobalBool(WhisperEnabledFlag.Name), Dial: true, @@ -320,7 +325,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config { SolcPath: ctx.GlobalString(SolcPathFlag.Name), AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name), } - } func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Database) { diff --git a/eth/backend.go b/eth/backend.go index aeaac788a..18e214d44 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -72,6 +72,7 @@ type Config struct { MaxPeers int MaxPendingPeers int + Discovery bool Port string // Space-separated list of discovery node URLs @@ -311,6 +312,7 @@ func New(config *Config) (*Ethereum, error) { Name: config.Name, MaxPeers: config.MaxPeers, MaxPendingPeers: config.MaxPendingPeers, + Discovery: config.Discovery, Protocols: protocols, NAT: config.NAT, NoDial: !config.Dial, @@ -449,14 +451,10 @@ func (s *Ethereum) Start() error { ClientString: s.net.Name, ProtocolVersion: ProtocolVersion, }) - - if s.net.MaxPeers > 0 { - err := s.net.Start() - if err != nil { - return err - } + err := s.net.Start() + if err != nil { + return err } - // periodically flush databases go s.syncDatabases() diff --git a/p2p/server.go b/p2p/server.go index af08380e1..589041810 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -55,6 +55,10 @@ type Server struct { // Zero defaults to preset values. MaxPendingPeers int + // Discovery specifies whether the peer discovery mechanism should be started + // or not. Disabling is usually useful for protocol debugging (manual topology). + Discovery bool + // Name sets the node name of this server. // Use common.MakeName to create a name that follows existing conventions. Name string @@ -237,9 +241,26 @@ func (srv *Server) AddPeer(node *discover.Node) { func (srv *Server) Self() *discover.Node { srv.lock.Lock() defer srv.lock.Unlock() + + // If the server's not running, return an empty node if !srv.running { return &discover.Node{IP: net.ParseIP("0.0.0.0")} } + // If the node is running but discovery is off, manually assemble the node infos + if srv.ntab == nil { + // Inbound connections disabled, use zero address + if srv.listener == nil { + return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} + } + // Otherwise inject the listener address too + addr := srv.listener.Addr().(*net.TCPAddr) + return &discover.Node{ + ID: discover.PubkeyID(&srv.PrivateKey.PublicKey), + IP: addr.IP, + TCP: uint16(addr.Port), + } + } + // Otherwise return the live node infos return srv.ntab.Self() } @@ -275,9 +296,6 @@ func (srv *Server) Start() (err error) { if srv.PrivateKey == nil { return fmt.Errorf("Server.PrivateKey must be set to a non-nil key") } - if srv.MaxPeers <= 0 { - return fmt.Errorf("Server.MaxPeers must be > 0") - } if srv.newTransport == nil { srv.newTransport = newRLPX } @@ -293,15 +311,22 @@ func (srv *Server) Start() (err error) { srv.peerOpDone = make(chan struct{}) // node table - ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT, srv.NodeDatabase) - if err != nil { - return err + if srv.Discovery { + ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT, srv.NodeDatabase) + if err != nil { + return err + } + srv.ntab = ntab } - srv.ntab = ntab - dialer := newDialState(srv.StaticNodes, srv.ntab, srv.MaxPeers/2) + + dynPeers := srv.MaxPeers / 2 + if !srv.Discovery { + dynPeers = 0 + } + dialer := newDialState(srv.StaticNodes, srv.ntab, dynPeers) // handshake - srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self().ID} + srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} for _, p := range srv.Protocols { srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) } @@ -457,7 +482,9 @@ running: } // Terminate discovery. If there is a running lookup it will terminate soon. - srv.ntab.Close() + if srv.ntab != nil { + srv.ntab.Close() + } // Disconnect all peers. for _, p := range peers { p.Disconnect(DiscQuitting) @@ -489,7 +516,7 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) return DiscTooManyPeers case peers[c.id] != nil: return DiscAlreadyConnected - case c.id == srv.ntab.Self().ID: + case c.id == srv.Self().ID: return DiscSelf default: return nil