diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-05-07 04:48:57 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2015-05-07 04:48:57 +0800 |
commit | 24d44f35f2cf17b07330a7e7be79abc2b6b92fc6 (patch) | |
tree | a64252ccd5ed06a9553af310a572e1dc95e92e55 /p2p/discover/node.go | |
parent | 323216ed85b48abec07266a203b731e7491d4286 (diff) | |
parent | 2adcc31bb48af0dee979f2b4ab255d9af21fd097 (diff) | |
download | dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar.gz dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar.bz2 dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar.lz dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar.xz dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.tar.zst dexon-24d44f35f2cf17b07330a7e7be79abc2b6b92fc6.zip |
Merge pull request #791 from fjl/discover-sha3-distance
p2p/discover: sha3-based node distance
Diffstat (limited to 'p2p/discover/node.go')
-rw-r--r-- | p2p/discover/node.go | 98 |
1 files changed, 48 insertions, 50 deletions
diff --git a/p2p/discover/node.go b/p2p/discover/node.go index e66ca37a4..a365ade15 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "errors" "fmt" - "io" "math/big" "math/rand" "net" @@ -14,51 +13,55 @@ import ( "strconv" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/rlp" ) const nodeIDBits = 512 // Node represents a host on the network. type Node struct { - ID NodeID - IP net.IP + IP net.IP // len 4 for IPv4 or 16 for IPv6 + UDP, TCP uint16 // port numbers + ID NodeID // the node's public key - DiscPort int // UDP listening port for discovery protocol - TCPPort int // TCP listening port for RLPx + // This is a cached copy of sha3(ID) which is used for node + // distance calculations. This is part of Node in order to make it + // possible to write tests that need a node at a certain distance. + // In those tests, the content of sha will not actually correspond + // with ID. + sha common.Hash } -func newNode(id NodeID, addr *net.UDPAddr) *Node { +func newNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { + if ipv4 := ip.To4(); ipv4 != nil { + ip = ipv4 + } return &Node{ - ID: id, - IP: addr.IP, - DiscPort: addr.Port, - TCPPort: addr.Port, + IP: ip, + UDP: udpPort, + TCP: tcpPort, + ID: id, + sha: crypto.Sha3Hash(id[:]), } } -func (n *Node) isValid() bool { - // TODO: don't accept localhost, LAN addresses from internet hosts - return !n.IP.IsMulticast() && !n.IP.IsUnspecified() && n.TCPPort != 0 && n.DiscPort != 0 -} - func (n *Node) addr() *net.UDPAddr { - return &net.UDPAddr{IP: n.IP, Port: n.DiscPort} + return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} } // The string representation of a Node is a URL. // Please see ParseNode for a description of the format. func (n *Node) String() string { - addr := net.TCPAddr{IP: n.IP, Port: n.TCPPort} + addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} u := url.URL{ Scheme: "enode", User: url.User(fmt.Sprintf("%x", n.ID[:])), Host: addr.String(), } - if n.DiscPort != n.TCPPort { - u.RawQuery = "discport=" + strconv.Itoa(n.DiscPort) + if n.UDP != n.TCP { + u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) } return u.String() } @@ -80,36 +83,47 @@ func (n *Node) String() string { // // enode://<hex node id>@10.3.58.6:30303?discport=30301 func ParseNode(rawurl string) (*Node, error) { - var n Node + var ( + id NodeID + ip net.IP + tcpPort, udpPort uint64 + ) u, err := url.Parse(rawurl) if u.Scheme != "enode" { return nil, errors.New("invalid URL scheme, want \"enode\"") } + // Parse the Node ID from the user portion. if u.User == nil { return nil, errors.New("does not contain node ID") } - if n.ID, err = HexID(u.User.String()); err != nil { + if id, err = HexID(u.User.String()); err != nil { return nil, fmt.Errorf("invalid node ID (%v)", err) } - ip, port, err := net.SplitHostPort(u.Host) + // Parse the IP address. + host, port, err := net.SplitHostPort(u.Host) if err != nil { return nil, fmt.Errorf("invalid host: %v", err) } - if n.IP = net.ParseIP(ip); n.IP == nil { + if ip = net.ParseIP(host); ip == nil { return nil, errors.New("invalid IP address") } - if n.TCPPort, err = strconv.Atoi(port); err != nil { + // Ensure the IP is 4 bytes long for IPv4 addresses. + if ipv4 := ip.To4(); ipv4 != nil { + ip = ipv4 + } + // Parse the port numbers. + if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { return nil, errors.New("invalid port") } + udpPort = tcpPort qv := u.Query() - if qv.Get("discport") == "" { - n.DiscPort = n.TCPPort - } else { - if n.DiscPort, err = strconv.Atoi(qv.Get("discport")); err != nil { + if qv.Get("discport") != "" { + udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) + if err != nil { return nil, errors.New("invalid discport in query") } } - return &n, nil + return newNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil } // MustParseNode parses a node URL. It panics if the URL is not valid. @@ -121,22 +135,6 @@ func MustParseNode(rawurl string) *Node { return n } -func (n Node) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, rpcNode{IP: n.IP.String(), Port: uint16(n.TCPPort), ID: n.ID}) -} -func (n *Node) DecodeRLP(s *rlp.Stream) (err error) { - var ext rpcNode - if err = s.Decode(&ext); err == nil { - n.TCPPort = int(ext.Port) - n.DiscPort = int(ext.Port) - n.ID = ext.ID - if n.IP = net.ParseIP(ext.IP); n.IP == nil { - return errors.New("invalid IP string") - } - } - return err -} - // NodeID is a unique identifier for each node. // The node identifier is a marshaled elliptic curve public key. type NodeID [nodeIDBits / 8]byte @@ -221,7 +219,7 @@ func recoverNodeID(hash, sig []byte) (id NodeID, err error) { // distcmp compares the distances a->target and b->target. // Returns -1 if a is closer to target, 1 if b is closer to target // and 0 if they are equal. -func distcmp(target, a, b NodeID) int { +func distcmp(target, a, b common.Hash) int { for i := range target { da := a[i] ^ target[i] db := b[i] ^ target[i] @@ -271,7 +269,7 @@ var lzcount = [256]int{ } // logdist returns the logarithmic distance between a and b, log2(a ^ b). -func logdist(a, b NodeID) int { +func logdist(a, b common.Hash) int { lz := 0 for i := range a { x := a[i] ^ b[i] @@ -285,8 +283,8 @@ func logdist(a, b NodeID) int { return len(a)*8 - lz } -// randomID returns a random NodeID such that logdist(a, b) == n -func randomID(a NodeID, n int) (b NodeID) { +// hashAtDistance returns a random hash such that logdist(a, b) == n +func hashAtDistance(a common.Hash, n int) (b common.Hash) { if n == 0 { return a } |