aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/ethereum/admin.go259
-rw-r--r--cmd/ethereum/js.go1
-rw-r--r--cmd/ethereum/js_test.go290
-rw-r--r--eth/backend.go68
-rw-r--r--p2p/discover/table.go6
-rw-r--r--p2p/server.go14
6 files changed, 627 insertions, 11 deletions
diff --git a/cmd/ethereum/admin.go b/cmd/ethereum/admin.go
new file mode 100644
index 000000000..2f95bc3cb
--- /dev/null
+++ b/cmd/ethereum/admin.go
@@ -0,0 +1,259 @@
+package main
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/xeth"
+ "github.com/obscuren/otto"
+)
+
+/*
+node admin bindings
+*/
+
+func (js *jsre) adminBindings() {
+ js.re.Set("admin", struct{}{})
+ t, _ := js.re.Get("admin")
+ admin := t.Object()
+ admin.Set("suggestPeer", js.suggestPeer)
+ admin.Set("startRPC", js.startRPC)
+ admin.Set("startMining", js.startMining)
+ admin.Set("stopMining", js.stopMining)
+ admin.Set("nodeInfo", js.nodeInfo)
+ admin.Set("peers", js.peers)
+ admin.Set("newAccount", js.newAccount)
+ admin.Set("unlock", js.unlock)
+ admin.Set("import", js.importChain)
+ admin.Set("export", js.exportChain)
+ admin.Set("dumpBlock", js.dumpBlock)
+}
+
+func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
+ _, err := call.Argument(0).ToInteger()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ // threads now ignored
+ err = js.ethereum.StartMining()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ return otto.TrueValue()
+}
+
+func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
+ js.ethereum.StopMining()
+ return otto.TrueValue()
+}
+
+func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
+ addr, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ port, err := call.Argument(1).ToInteger()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ dataDir := js.ethereum.DataDir
+
+ l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
+ if err != nil {
+ fmt.Printf("Can't listen on %s:%d: %v", addr, port, err)
+ return otto.FalseValue()
+ }
+ go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil), dataDir))
+ return otto.TrueValue()
+}
+
+func (js *jsre) suggestPeer(call otto.FunctionCall) otto.Value {
+ nodeURL, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ err = js.ethereum.SuggestPeer(nodeURL)
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ return otto.TrueValue()
+}
+
+func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
+ addr, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ seconds, err := call.Argument(2).ToInteger()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ arg := call.Argument(1)
+ var passphrase string
+ if arg.IsUndefined() {
+ fmt.Println("Please enter a passphrase now.")
+ passphrase, err = readPassword("Passphrase: ", true)
+ if err != nil {
+ utils.Fatalf("%v", err)
+ }
+ } else {
+ passphrase, err = arg.ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ }
+ am := js.ethereum.AccountManager()
+ // err := am.Unlock(ethutil.FromHex(split[0]), split[1])
+ // if err != nil {
+ // utils.Fatalf("Unlock account failed '%v'", err)
+ // }
+ err = am.TimedUnlock(ethutil.FromHex(addr), passphrase, time.Duration(seconds)*time.Second)
+ if err != nil {
+ fmt.Printf("Unlock account failed '%v'\n", err)
+ return otto.FalseValue()
+ }
+ return otto.TrueValue()
+}
+
+func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
+ arg := call.Argument(0)
+ var passphrase string
+ if arg.IsUndefined() {
+ fmt.Println("The new account will be encrypted with a passphrase.")
+ fmt.Println("Please enter a passphrase now.")
+ auth, err := readPassword("Passphrase: ", true)
+ if err != nil {
+ utils.Fatalf("%v", err)
+ }
+ confirm, err := readPassword("Repeat Passphrase: ", false)
+ if err != nil {
+ utils.Fatalf("%v", err)
+ }
+ if auth != confirm {
+ utils.Fatalf("Passphrases did not match.")
+ }
+ passphrase = auth
+ } else {
+ var err error
+ passphrase, err = arg.ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ }
+ acct, err := js.ethereum.AccountManager().NewAccount(passphrase)
+ if err != nil {
+ fmt.Printf("Could not create the account: %v", err)
+ return otto.UndefinedValue()
+ }
+ return js.re.ToVal(ethutil.Bytes2Hex(acct.Address))
+}
+
+func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
+ return js.re.ToVal(js.ethereum.NodeInfo())
+}
+
+func (js *jsre) peers(call otto.FunctionCall) otto.Value {
+ return js.re.ToVal(js.ethereum.PeersInfo())
+}
+
+func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
+ if len(call.ArgumentList) == 0 {
+ fmt.Println("err: require file name")
+ return otto.FalseValue()
+ }
+
+ fn, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ var fh *os.File
+ fh, err = os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+ defer fh.Close()
+
+ var blocks types.Blocks
+ if err = rlp.Decode(fh, &blocks); err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ js.ethereum.ChainManager().Reset()
+ if err = js.ethereum.ChainManager().InsertChain(blocks); err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ return otto.TrueValue()
+}
+
+func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
+ if len(call.ArgumentList) == 0 {
+ fmt.Println("err: require file name")
+ return otto.FalseValue()
+ }
+
+ fn, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ data := js.ethereum.ChainManager().Export()
+ if err := ethutil.WriteFile(fn, data); err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ return otto.TrueValue()
+}
+
+func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
+ var block *types.Block
+ if len(call.ArgumentList) > 0 {
+ if call.Argument(0).IsNumber() {
+ num, _ := call.Argument(0).ToInteger()
+ block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
+ } else if call.Argument(0).IsString() {
+ hash, _ := call.Argument(0).ToString()
+ block = js.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
+ } else {
+ fmt.Println("invalid argument for dump. Either hex string or number")
+ }
+
+ } else {
+ block = js.ethereum.ChainManager().CurrentBlock()
+ }
+ if block == nil {
+ fmt.Println("block not found")
+ return otto.UndefinedValue()
+ }
+
+ statedb := state.New(block.Root(), js.ethereum.StateDb())
+ dump := statedb.RawDump()
+ return js.re.ToVal(dump)
+
+}
diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go
index 361aaf7ea..b4b54b7e6 100644
--- a/cmd/ethereum/js.go
+++ b/cmd/ethereum/js.go
@@ -71,6 +71,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath string) *jsre {
js.xeth = xeth.New(ethereum, js)
js.re = re.New(libPath)
js.apiBindings()
+ js.adminBindings()
if !liner.TerminalSupported() {
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
diff --git a/cmd/ethereum/js_test.go b/cmd/ethereum/js_test.go
new file mode 100644
index 000000000..132101912
--- /dev/null
+++ b/cmd/ethereum/js_test.go
@@ -0,0 +1,290 @@
+package main
+
+import (
+ "fmt"
+ "github.com/obscuren/otto"
+ "os"
+ "path"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+var port = 30300
+
+func testJEthRE(t *testing.T) (repl *jsre, ethereum *eth.Ethereum, err error) {
+ os.RemoveAll("/tmp/eth/")
+ err = os.MkdirAll("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/", os.ModePerm)
+ if err != nil {
+ t.Errorf("%v", err)
+ return
+ }
+ err = os.MkdirAll("/tmp/eth/data", os.ModePerm)
+ if err != nil {
+ t.Errorf("%v", err)
+ return
+ }
+ // FIXME: this does not work ATM
+ ks := crypto.NewKeyStorePlain("/tmp/eth/keys")
+ ethutil.WriteFile("/tmp/eth/keys/e273f01c99144c438695e10f24926dc1f9fbf62d/e273f01c99144c438695e10f24926dc1f9fbf62d",
+ []byte(`{"Id":"RhRXD+fNRKS4jx+7ZfEsNA==","Address":"4nPwHJkUTEOGleEPJJJtwfn79i0=","PrivateKey":"h4ACVpe74uIvi5Cg/2tX/Yrm2xdr3J7QoMbMtNX2CNc="}`))
+
+ port++
+ ethereum, err = eth.New(&eth.Config{
+ DataDir: "/tmp/eth",
+ AccountManager: accounts.NewManager(ks),
+ Port: fmt.Sprintf("%d", port),
+ MaxPeers: 10,
+ Name: "test",
+ })
+
+ if err != nil {
+ t.Errorf("%v", err)
+ return
+ }
+ assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
+ repl = newJSRE(ethereum, assetPath)
+ return
+}
+
+func TestNodeInfo(t *testing.T) {
+ repl, ethereum, err := testJEthRE(t)
+ if err != nil {
+ t.Errorf("error creating jsre, got %v", err)
+ return
+ }
+ err = ethereum.Start()
+ if err != nil {
+ t.Errorf("error starting ethereum: %v", err)
+ return
+ }
+ defer ethereum.Stop()
+
+ val, err := repl.re.Run("admin.nodeInfo()")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ exp, err := val.Export()
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ nodeInfo, ok := exp.(*eth.NodeInfo)
+ if !ok {
+ t.Errorf("expected nodeInfo, got %v", err)
+ }
+ exp = "test"
+ got := nodeInfo.Name
+ if exp != got {
+ t.Errorf("expected %v, got %v", exp, got)
+ }
+ exp = 30301
+ port := nodeInfo.DiscPort
+ if exp != port {
+ t.Errorf("expected %v, got %v", exp, port)
+ }
+ exp = 30301
+ port = nodeInfo.TCPPort
+ if exp != port {
+ t.Errorf("expected %v, got %v", exp, port)
+ }
+}
+
+func TestAccounts(t *testing.T) {
+ repl, ethereum, err := testJEthRE(t)
+ if err != nil {
+ t.Errorf("error creating jsre, got %v", err)
+ return
+ }
+ err = ethereum.Start()
+ if err != nil {
+ t.Errorf("error starting ethereum: %v", err)
+ return
+ }
+ defer ethereum.Stop()
+
+ val, err := repl.re.Run("eth.coinbase")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ pp, err := repl.re.PrettyPrint(val)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+
+ if !val.IsString() {
+ t.Errorf("incorrect type, expected string, got %v: %v", val, pp)
+ }
+ strVal, _ := val.ToString()
+ expected := "0xe273f01c99144c438695e10f24926dc1f9fbf62d"
+ if strVal != expected {
+ t.Errorf("incorrect result, expected %s, got %v", expected, strVal)
+ }
+
+ val, err = repl.re.Run(`admin.newAccount("password")`)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ addr, err := val.ToString()
+ if err != nil {
+ t.Errorf("expected string, got %v", err)
+ }
+
+ val, err = repl.re.Run("eth.accounts")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ exp, err := val.Export()
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ addrs, ok := exp.([]string)
+ if !ok {
+ t.Errorf("expected []string, got %v", err)
+ }
+ if len(addrs) != 2 || (addr != addrs[0][2:] && addr != addrs[1][2:]) {
+ t.Errorf("expected addrs == [<default>, <new>], got %v (%v)", addrs, addr)
+ }
+
+}
+
+func TestBlockChain(t *testing.T) {
+ repl, ethereum, err := testJEthRE(t)
+ if err != nil {
+ t.Errorf("error creating jsre, got %v", err)
+ return
+ }
+ err = ethereum.Start()
+ if err != nil {
+ t.Errorf("error starting ethereum: %v", err)
+ return
+ }
+ defer ethereum.Stop()
+
+ // should get current block
+ val0, err := repl.re.Run("admin.dumpBlock()")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ fn := "/tmp/eth/data/blockchain.0"
+ _, err = repl.re.Run("admin.export(\"" + fn + "\")")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ if _, err = os.Stat(fn); err != nil {
+ t.Errorf("expected no error on file, got %v", err)
+ }
+
+ _, err = repl.re.Run("admin.import(\"" + fn + "\")")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ var val1 otto.Value
+
+ // should get current block
+ val1, err = repl.re.Run("admin.dumpBlock()")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ // FIXME: neither != , nor reflect.DeepEqual works, doing string comparison
+ v0 := fmt.Sprintf("%v", val0)
+ v1 := fmt.Sprintf("%v", val1)
+ if v0 != v1 {
+ t.Errorf("expected same head after export-import, got %v (!=%v)", v1, v0)
+ }
+}
+
+func TestMining(t *testing.T) {
+ repl, ethereum, err := testJEthRE(t)
+ if err != nil {
+ t.Errorf("error creating jsre, got %v", err)
+ return
+ }
+ err = ethereum.Start()
+ if err != nil {
+ t.Errorf("error starting ethereum: %v", err)
+ return
+ }
+ defer ethereum.Stop()
+
+ val, err := repl.re.Run("eth.mining")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ var mining bool
+ mining, err = val.ToBoolean()
+ if err != nil {
+ t.Errorf("expected boolean, got %v", err)
+ }
+ if mining {
+ t.Errorf("expected false (not mining), got true")
+ }
+
+ val, err = repl.re.Run("admin.startMining(4)")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ mining, _ = val.ToBoolean()
+ if !mining {
+ t.Errorf("expected true (mining), got false")
+ }
+ val, err = repl.re.Run("eth.mining")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ mining, err = val.ToBoolean()
+ if err != nil {
+ t.Errorf("expected boolean, got %v", err)
+ }
+ if !mining {
+ t.Errorf("expected true (mining), got false")
+ }
+
+ val, err = repl.re.Run("admin.startMining(4)")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ mining, _ = val.ToBoolean()
+ if !mining {
+ t.Errorf("expected true (mining), got false")
+ }
+
+ val, err = repl.re.Run("admin.stopMining()")
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ mining, _ = val.ToBoolean()
+ if !mining {
+ t.Errorf("expected true (mining), got false")
+ }
+
+}
+
+func TestRPC(t *testing.T) {
+ repl, ethereum, err := testJEthRE(t)
+ if err != nil {
+ t.Errorf("error creating jsre, got %v", err)
+ return
+ }
+ err = ethereum.Start()
+ if err != nil {
+ t.Errorf("error starting ethereum: %v", err)
+ return
+ }
+ defer ethereum.Stop()
+
+ val, err := repl.re.Run(`admin.startRPC("127.0.0.1", 5004)`)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ success, _ := val.ToBoolean()
+ if !success {
+ t.Errorf("expected true (started), got false")
+ }
+}
diff --git a/eth/backend.go b/eth/backend.go
index 346fc43bc..1d637c367 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -219,6 +219,64 @@ func New(config *Config) (*Ethereum, error) {
return eth, nil
}
+type NodeInfo struct {
+ Name string
+ NodeUrl string
+ NodeID string
+ IP string
+ DiscPort int // UDP listening port for discovery protocol
+ TCPPort int // TCP listening port for RLPx
+ Td string
+ ListenAddr string
+}
+
+func (s *Ethereum) NodeInfo() *NodeInfo {
+ node := s.net.Self()
+
+ return &NodeInfo{
+ Name: s.Name(),
+ NodeUrl: node.String(),
+ NodeID: node.ID.String(),
+ IP: node.IP.String(),
+ DiscPort: node.DiscPort,
+ TCPPort: node.TCPPort,
+ ListenAddr: s.net.ListenAddr,
+ Td: s.ChainManager().Td().String(),
+ }
+}
+
+type PeerInfo struct {
+ ID string
+ Name string
+ Caps string
+ RemoteAddress string
+ LocalAddress string
+}
+
+func newPeerInfo(peer *p2p.Peer) *PeerInfo {
+ var caps []string
+ for _, cap := range peer.Caps() {
+ caps = append(caps, cap.String())
+ }
+ return &PeerInfo{
+ ID: peer.ID().String(),
+ Name: peer.Name(),
+ Caps: strings.Join(caps, ", "),
+ RemoteAddress: peer.RemoteAddr().String(),
+ LocalAddress: peer.LocalAddr().String(),
+ }
+}
+
+// PeersInfo returns an array of PeerInfo objects describing connected peers
+func (s *Ethereum) PeersInfo() (peersinfo []*PeerInfo) {
+ for _, peer := range s.net.Peers() {
+ if peer != nil {
+ peersinfo = append(peersinfo, newPeerInfo(peer))
+ }
+ }
+ return
+}
+
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
s.chainManager.ResetWithGenesisBlock(gb)
s.pow.UpdateCache(true)
@@ -251,6 +309,7 @@ func (s *Ethereum) StateDb() ethutil.Database { return s.stateDb }
func (s *Ethereum) ExtraDb() ethutil.Database { return s.extraDb }
func (s *Ethereum) IsListening() bool { return true } // Always listening
func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
+func (s *Ethereum) PeerInfo() int { return s.net.PeerCount() }
func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() }
func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers }
func (s *Ethereum) Version() string { return s.version }
@@ -262,9 +321,11 @@ func (s *Ethereum) Start() error {
ProtocolVersion: ProtocolVersion,
})
- err := s.net.Start()
- if err != nil {
- return err
+ if s.net.MaxPeers > 0 {
+ err := s.net.Start()
+ if err != nil {
+ return err
+ }
}
// Start services
@@ -311,6 +372,7 @@ func (s *Ethereum) Stop() {
// Close the database
defer s.blockDb.Close()
defer s.stateDb.Close()
+ defer s.extraDb.Close()
s.txSub.Unsubscribe() // quits txBroadcastLoop
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
diff --git a/p2p/discover/table.go b/p2p/discover/table.go
index e3bec9328..33b705a12 100644
--- a/p2p/discover/table.go
+++ b/p2p/discover/table.go
@@ -51,9 +51,9 @@ func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table {
return tab
}
-// Self returns the local node ID.
-func (tab *Table) Self() NodeID {
- return tab.self.ID
+// Self returns the local node.
+func (tab *Table) Self() *Node {
+ return tab.self
}
// Close terminates the network listener.
diff --git a/p2p/server.go b/p2p/server.go
index 9762fcc6d..4d1437d80 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -180,7 +180,7 @@ func (srv *Server) Start() (err error) {
srv.ntab = ntab
// handshake
- srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self()}
+ srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self().ID}
for _, p := range srv.Protocols {
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
}
@@ -298,7 +298,7 @@ func (srv *Server) dialLoop() {
srv.lock.Lock()
_, isconnected := srv.peers[dest.ID]
srv.lock.Unlock()
- if isconnected || dialing[dest.ID] || dest.ID == srv.ntab.Self() {
+ if isconnected || dialing[dest.ID] || dest.ID == srv.Self().ID {
continue
}
@@ -332,12 +332,16 @@ func (srv *Server) dialNode(dest *discover.Node) {
srv.startPeer(conn, dest)
}
+func (srv *Server) Self() *discover.Node {
+ return srv.ntab.Self()
+}
+
func (srv *Server) findPeers() {
- far := srv.ntab.Self()
+ far := srv.Self().ID
for i := range far {
far[i] = ^far[i]
}
- closeToSelf := srv.ntab.Lookup(srv.ntab.Self())
+ closeToSelf := srv.ntab.Lookup(srv.Self().ID)
farFromSelf := srv.ntab.Lookup(far)
for i := 0; i < len(closeToSelf) || i < len(farFromSelf); i++ {
@@ -402,7 +406,7 @@ func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) {
return false, DiscTooManyPeers
case srv.peers[id] != nil:
return false, DiscAlreadyConnected
- case id == srv.ntab.Self():
+ case id == srv.Self().ID:
return false, DiscSelf
}
srv.peers[id] = p