From 8564eb9f7efcc7a0e639f6a45d7e67037fedac5f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Feb 2015 14:40:53 +0100 Subject: p2p/discover: add node URL functions, distinguish TCP/UDP ports The discovery RPC protocol does not yet distinguish TCP and UDP ports. But it can't hurt to do so in our internal model. --- p2p/discover/table.go | 197 +------------------------------------------------- 1 file changed, 4 insertions(+), 193 deletions(-) (limited to 'p2p/discover/table.go') diff --git a/p2p/discover/table.go b/p2p/discover/table.go index ea9680404..6025507eb 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -7,20 +7,10 @@ package discover import ( - "crypto/ecdsa" - "crypto/elliptic" - "encoding/hex" - "fmt" - "io" - "math/rand" "net" "sort" - "strings" "sync" "time" - - "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/ethereum/go-ethereum/rlp" ) const ( @@ -53,36 +43,10 @@ type bucket struct { entries []*Node } -// Node represents node metadata that is stored in the table. -type Node struct { - Addr *net.UDPAddr - ID NodeID - - active time.Time -} - -type rpcNode struct { - IP string - Port uint16 - ID NodeID -} - -func (n Node) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, rpcNode{IP: n.Addr.IP.String(), Port: uint16(n.Addr.Port), ID: n.ID}) -} -func (n *Node) DecodeRLP(s *rlp.Stream) (err error) { - var ext rpcNode - if err = s.Decode(&ext); err == nil { - n.Addr = &net.UDPAddr{IP: net.ParseIP(ext.IP), Port: int(ext.Port)} - n.ID = ext.ID - } - return err -} - func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table { - tab := &Table{net: t, self: &Node{ID: ourID, Addr: ourAddr}} + tab := &Table{net: t, self: newNode(ourID, ourAddr)} for i := range tab.buckets { - tab.buckets[i] = &bucket{} + tab.buckets[i] = new(bucket) } return tab } @@ -217,7 +181,7 @@ func (tab *Table) len() (n int) { func (tab *Table) bumpOrAdd(node NodeID, from *net.UDPAddr) (n *Node) { b := tab.buckets[logdist(tab.self.ID, node)] if n = b.bump(node); n == nil { - n = &Node{ID: node, Addr: from, active: time.Now()} + n = newNode(node, from) if len(b.entries) == bucketSize { tab.pingReplace(n, b) } else { @@ -238,6 +202,7 @@ func (tab *Table) pingReplace(n *Node, b *bucket) { tab.mutex.Lock() if len(b.entries) > 0 && b.entries[len(b.entries)-1] == old { // slide down other entries and put the new one in front. + // TODO: insert in correct position to keep the order copy(b.entries[1:], b.entries) b.entries[0] = n } @@ -312,157 +277,3 @@ func (h *nodesByDistance) push(n *Node, maxElems int) { h.entries[ix] = n } } - -// NodeID is a unique identifier for each node. -// The node identifier is a marshaled elliptic curve public key. -type NodeID [512 / 8]byte - -// NodeID prints as a long hexadecimal number. -func (n NodeID) String() string { - return fmt.Sprintf("%#x", n[:]) -} - -// The Go syntax representation of a NodeID is a call to HexID. -func (n NodeID) GoString() string { - return fmt.Sprintf("HexID(\"%#x\")", n[:]) -} - -// HexID converts a hex string to a NodeID. -// The string may be prefixed with 0x. -func HexID(in string) (NodeID, error) { - if strings.HasPrefix(in, "0x") { - in = in[2:] - } - var id NodeID - b, err := hex.DecodeString(in) - if err != nil { - return id, err - } else if len(b) != len(id) { - return id, fmt.Errorf("wrong length, need %d hex bytes", len(id)) - } - copy(id[:], b) - return id, nil -} - -// MustHexID converts a hex string to a NodeID. -// It panics if the string is not a valid NodeID. -func MustHexID(in string) NodeID { - id, err := HexID(in) - if err != nil { - panic(err) - } - return id -} - -func PubkeyID(pub *ecdsa.PublicKey) NodeID { - var id NodeID - pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) - if len(pbytes)-1 != len(id) { - panic(fmt.Errorf("invalid key: need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) - } - copy(id[:], pbytes[1:]) - return id -} - -// recoverNodeID computes the public key used to sign the -// given hash from the signature. -func recoverNodeID(hash, sig []byte) (id NodeID, err error) { - pubkey, err := secp256k1.RecoverPubkey(hash, sig) - if err != nil { - return id, err - } - if len(pubkey)-1 != len(id) { - return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) - } - for i := range id { - id[i] = pubkey[i+1] - } - return id, nil -} - -// 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 { - for i := range target { - da := a[i] ^ target[i] - db := b[i] ^ target[i] - if da > db { - return 1 - } else if da < db { - return -1 - } - } - return 0 -} - -// table of leading zero counts for bytes [0..255] -var lzcount = [256]int{ - 8, 7, 6, 6, 5, 5, 5, 5, - 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -} - -// logdist returns the logarithmic distance between a and b, log2(a ^ b). -func logdist(a, b NodeID) int { - lz := 0 - for i := range a { - x := a[i] ^ b[i] - if x == 0 { - lz += 8 - } else { - lz += lzcount[x] - break - } - } - return len(a)*8 - lz -} - -// randomID returns a random NodeID such that logdist(a, b) == n -func randomID(a NodeID, n int) (b NodeID) { - if n == 0 { - return a - } - // flip bit at position n, fill the rest with random bits - b = a - pos := len(a) - n/8 - 1 - bit := byte(0x01) << (byte(n%8) - 1) - if bit == 0 { - pos++ - bit = 0x80 - } - b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits - for i := pos + 1; i < len(a); i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} -- cgit