mirror of https://github.com/poanetwork/quorum.git
Fix DNS issue in 2.4.0 (#937)
* Fix DNS issue in v2.4.0 as well as code refactoring
This commit is contained in:
parent
a5d329391d
commit
29d53fb649
|
@ -191,7 +191,7 @@ func (pool *serverPool) discoverNodes() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pool.discNodes <- enode.NewV4(pubkey, n.IP, int(n.TCP), int(n.UDP), 0)
|
pool.discNodes <- enode.NewV4(pubkey, n.IP, int(n.TCP), int(n.UDP))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +667,7 @@ func (e *poolEntry) DecodeRLP(s *rlp.Stream) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
addr := &poolEntryAddress{ip: entry.IP, port: entry.Port, fails: entry.Fails, lastSeen: mclock.Now()}
|
addr := &poolEntryAddress{ip: entry.IP, port: entry.Port, fails: entry.Fails, lastSeen: mclock.Now()}
|
||||||
e.node = enode.NewV4(pubkey, entry.IP, int(entry.Port), int(entry.Port), 0)
|
e.node = enode.NewV4(pubkey, entry.IP, int(entry.Port), int(entry.Port))
|
||||||
e.addr = make(map[string]*poolEntryAddress)
|
e.addr = make(map[string]*poolEntryAddress)
|
||||||
e.addr[addr.strKey()] = addr
|
e.addr[addr.strKey()] = addr
|
||||||
e.addrSelect = *newWeightedRandomSelect()
|
e.addrSelect = *newWeightedRandomSelect()
|
||||||
|
|
|
@ -57,7 +57,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
|
||||||
|
|
||||||
// Fill up the sender's bucket.
|
// Fill up the sender's bucket.
|
||||||
pingKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
pingKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
||||||
pingSender := wrapNode(enode.NewV4(&pingKey.PublicKey, net.IP{}, 99, 99, 0))
|
pingSender := wrapNode(enode.NewV4(&pingKey.PublicKey, net.IP{}, 99, 99))
|
||||||
last := fillBucket(tab, pingSender)
|
last := fillBucket(tab, pingSender)
|
||||||
|
|
||||||
// Add the sender as if it just pinged us. Revalidate should replace the last node in
|
// Add the sender as if it just pinged us. Revalidate should replace the last node in
|
||||||
|
@ -289,7 +289,7 @@ func TestTable_Lookup(t *testing.T) {
|
||||||
}
|
}
|
||||||
// seed table with initial node (otherwise lookup will terminate immediately)
|
// seed table with initial node (otherwise lookup will terminate immediately)
|
||||||
seedKey, _ := decodePubkey(lookupTestnet.dists[256][0])
|
seedKey, _ := decodePubkey(lookupTestnet.dists[256][0])
|
||||||
seed := wrapNode(enode.NewV4(seedKey, net.IP{}, 0, 256, 0))
|
seed := wrapNode(enode.NewV4(seedKey, net.IP{}, 0, 256))
|
||||||
tab.stuff([]*node{seed})
|
tab.stuff([]*node{seed})
|
||||||
|
|
||||||
results := tab.lookup(lookupTestnet.target, true)
|
results := tab.lookup(lookupTestnet.target, true)
|
||||||
|
@ -524,7 +524,7 @@ func (tn *preminedTestnet) findnode(toid enode.ID, toaddr *net.UDPAddr, target e
|
||||||
var result []*node
|
var result []*node
|
||||||
for i, ekey := range tn.dists[toaddr.Port] {
|
for i, ekey := range tn.dists[toaddr.Port] {
|
||||||
key, _ := decodePubkey(ekey)
|
key, _ := decodePubkey(ekey)
|
||||||
node := wrapNode(enode.NewV4(key, net.ParseIP("127.0.0.1"), i, next, 0))
|
node := wrapNode(enode.NewV4(key, net.ParseIP("127.0.0.1"), i, next))
|
||||||
result = append(result, node)
|
result = append(result, node)
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*node, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP), 0))
|
n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)))
|
||||||
err = n.ValidateComplete()
|
err = n.ValidateComplete()
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
@ -628,7 +628,7 @@ func (req *ping) handle(t *udp, from *net.UDPAddr, fromKey encPubkey, mac []byte
|
||||||
ReplyTok: mac,
|
ReplyTok: mac,
|
||||||
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||||
})
|
})
|
||||||
n := wrapNode(enode.NewV4(key, from.IP, int(req.From.TCP), from.Port, 0))
|
n := wrapNode(enode.NewV4(key, from.IP, int(req.From.TCP), from.Port))
|
||||||
t.handleReply(n.ID(), pingPacket, req)
|
t.handleReply(n.ID(), pingPacket, req)
|
||||||
if time.Since(t.db.LastPongReceived(n.ID())) > bondExpiration {
|
if time.Since(t.db.LastPongReceived(n.ID())) > bondExpiration {
|
||||||
t.sendPing(n.ID(), from, func() { t.tab.addThroughPing(n) })
|
t.sendPing(n.ID(), from, func() { t.tab.addThroughPing(n) })
|
||||||
|
|
|
@ -244,7 +244,7 @@ func TestUDP_findnode(t *testing.T) {
|
||||||
nodes := &nodesByDistance{target: testTarget.id()}
|
nodes := &nodesByDistance{target: testTarget.id()}
|
||||||
for i := 0; i < bucketSize; i++ {
|
for i := 0; i < bucketSize; i++ {
|
||||||
key := newkey()
|
key := newkey()
|
||||||
n := wrapNode(enode.NewV4(&key.PublicKey, net.IP{10, 13, 0, 1}, 0, i, 0))
|
n := wrapNode(enode.NewV4(&key.PublicKey, net.IP{10, 13, 0, 1}, 0, i))
|
||||||
nodes.push(n, bucketSize)
|
nodes.push(n, bucketSize)
|
||||||
}
|
}
|
||||||
test.table.stuff(nodes.entries)
|
test.table.stuff(nodes.entries)
|
||||||
|
@ -311,7 +311,7 @@ func TestUDP_findnodeMultiReply(t *testing.T) {
|
||||||
rpclist := make([]rpcNode, len(list))
|
rpclist := make([]rpcNode, len(list))
|
||||||
for i := range list {
|
for i := range list {
|
||||||
rpclist[i] = nodeToRPC(list[i])
|
rpclist[i] = nodeToRPC(list[i])
|
||||||
list[i] = wrapNode(enode.NewV4(list[i].Pubkey(), list[i].IP(), list[i].TCP(), list[i].UDP(), 0))
|
list[i] = wrapNode(enode.NewV4(list[i].Pubkey(), list[i].IP(), list[i].TCP(), list[i].UDP()))
|
||||||
}
|
}
|
||||||
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[:2]})
|
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[:2]})
|
||||||
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[2:]})
|
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[2:]})
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
@ -59,9 +58,10 @@ func (n *Node) Seq() uint64 {
|
||||||
return n.r.Seq()
|
return n.r.Seq()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incomplete returns true for nodes with no IP address.
|
// Quorum
|
||||||
|
// Incomplete returns true for nodes with no IP address and no hostname if with raftport.
|
||||||
func (n *Node) Incomplete() bool {
|
func (n *Node) Incomplete() bool {
|
||||||
return n.IP() == nil
|
return n.IP() == nil && (!n.HasRaftPort() || (n.Host() == "" && n.HasRaftPort()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load retrieves an entry from the underlying record.
|
// Load retrieves an entry from the underlying record.
|
||||||
|
@ -70,21 +70,27 @@ func (n *Node) Load(k enr.Entry) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP returns the IP address of the node.
|
// IP returns the IP address of the node.
|
||||||
|
//
|
||||||
|
// Quorum
|
||||||
|
// To support DNS lookup in node ip. The function performs hostname lookup if hostname is defined in enr.Hostname
|
||||||
|
// and falls back to enr.IP value in case of failure. It also makes sure the resolved IP is in IPv4 or IPv6 format
|
||||||
func (n *Node) IP() net.IP {
|
func (n *Node) IP() net.IP {
|
||||||
// QUORUM
|
|
||||||
// no host is set, so use the IP directly
|
|
||||||
if n.Host() == "" {
|
if n.Host() == "" {
|
||||||
|
// no host is set, so use the IP directly
|
||||||
return n.loadIP()
|
return n.loadIP()
|
||||||
}
|
}
|
||||||
// attempt to look up IP addresses if host is a FQDN
|
// attempt to look up IP addresses if host is a FQDN
|
||||||
lookupIPs, err := net.LookupIP(n.Host())
|
lookupIPs, err := net.LookupIP(n.Host())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("hostname couldn't resolve, using IP instead", "hostname", n.Host(), "err", err.Error())
|
|
||||||
return n.loadIP()
|
return n.loadIP()
|
||||||
}
|
}
|
||||||
// set to first ip by default
|
// set to first ip by default & as Ethereum upstream
|
||||||
return lookupIPs[0]
|
ip := lookupIPs[0]
|
||||||
// END QUORUM
|
// Ensure the IP is 4 bytes long for IPv4 addresses.
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
ip = ipv4
|
||||||
|
}
|
||||||
|
return ip
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) loadIP() net.IP {
|
func (n *Node) loadIP() net.IP {
|
||||||
|
@ -99,6 +105,7 @@ func (n *Node) Host() string {
|
||||||
n.Load((*enr.Hostname)(&hostname))
|
n.Load((*enr.Hostname)(&hostname))
|
||||||
return hostname
|
return hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
// End-Quorum
|
// End-Quorum
|
||||||
|
|
||||||
// UDP returns the UDP port of the node.
|
// UDP returns the UDP port of the node.
|
||||||
|
|
|
@ -19,6 +19,7 @@ package enode
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
|
@ -60,3 +61,84 @@ func TestPythonInterop(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quorum
|
||||||
|
// test Incomplete
|
||||||
|
func TestIncomplete(t *testing.T) {
|
||||||
|
var testCases = []struct {
|
||||||
|
n *Node
|
||||||
|
isIncomplete bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
n: NewV4(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
net.IP{127, 0, 0, 1},
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
),
|
||||||
|
isIncomplete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
net.ParseIP("::"),
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
),
|
||||||
|
isIncomplete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
),
|
||||||
|
isIncomplete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
nil,
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
),
|
||||||
|
isIncomplete: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4Hostname(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
"hostname",
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
50400,
|
||||||
|
),
|
||||||
|
isIncomplete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4Hostname(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
"hostname",
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
isIncomplete: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: NewV4Hostname(
|
||||||
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
|
"",
|
||||||
|
52150,
|
||||||
|
52150,
|
||||||
|
50400,
|
||||||
|
),
|
||||||
|
isIncomplete: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range testCases {
|
||||||
|
if test.n.Incomplete() != test.isIncomplete {
|
||||||
|
t.Errorf("test %d: Node.Incomplete() mismatch:\ngot: %v\nwant: %v", i, test.n.Incomplete(), test.isIncomplete)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,6 @@ func TestDBFetchStore(t *testing.T) {
|
||||||
net.IP{192, 168, 0, 1},
|
net.IP{192, 168, 0, 1},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
inst := time.Now()
|
inst := time.Now()
|
||||||
num := 314
|
num := 314
|
||||||
|
@ -169,7 +168,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 3},
|
net.IP{127, 0, 0, 3},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-3 * time.Hour),
|
pong: time.Now().Add(-3 * time.Hour),
|
||||||
},
|
},
|
||||||
|
@ -181,7 +179,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 3},
|
net.IP{127, 0, 0, 3},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-4 * time.Second),
|
pong: time.Now().Add(-4 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -193,7 +190,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 1},
|
net.IP{127, 0, 0, 1},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-2 * time.Second),
|
pong: time.Now().Add(-2 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -203,7 +199,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 2},
|
net.IP{127, 0, 0, 2},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-3 * time.Second),
|
pong: time.Now().Add(-3 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -213,7 +208,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 3},
|
net.IP{127, 0, 0, 3},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-1 * time.Second),
|
pong: time.Now().Add(-1 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -223,7 +217,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 3},
|
net.IP{127, 0, 0, 3},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-2 * time.Second),
|
pong: time.Now().Add(-2 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -233,7 +226,6 @@ var nodeDBSeedQueryNodes = []struct {
|
||||||
net.IP{127, 0, 0, 3},
|
net.IP{127, 0, 0, 3},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-2 * time.Second),
|
pong: time.Now().Add(-2 * time.Second),
|
||||||
},
|
},
|
||||||
|
@ -339,7 +331,6 @@ var nodeDBExpirationNodes = []struct {
|
||||||
net.IP{127, 0, 0, 1},
|
net.IP{127, 0, 0, 1},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-dbNodeExpiration + time.Minute),
|
pong: time.Now().Add(-dbNodeExpiration + time.Minute),
|
||||||
exp: false,
|
exp: false,
|
||||||
|
@ -349,7 +340,6 @@ var nodeDBExpirationNodes = []struct {
|
||||||
net.IP{127, 0, 0, 2},
|
net.IP{127, 0, 0, 2},
|
||||||
30303,
|
30303,
|
||||||
30303,
|
30303,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
pong: time.Now().Add(-dbNodeExpiration - time.Minute),
|
pong: time.Now().Add(-dbNodeExpiration - time.Minute),
|
||||||
exp: true,
|
exp: true,
|
||||||
|
|
|
@ -56,7 +56,7 @@ func MustParseV4(rawurl string) *Node {
|
||||||
//
|
//
|
||||||
// For complete nodes, the node ID is encoded in the username portion
|
// For complete nodes, the node ID is encoded in the username portion
|
||||||
// of the URL, separated from the host by an @ sign. The hostname can
|
// of the URL, separated from the host by an @ sign. The hostname can
|
||||||
// only be given as an IP address, DNS domain names are not allowed.
|
// be given as an IP address or a DNS domain name.
|
||||||
// The port in the host name section is the TCP listening port. If the
|
// The port in the host name section is the TCP listening port. If the
|
||||||
// TCP and UDP (discovery) ports differ, the UDP port is specified as
|
// TCP and UDP (discovery) ports differ, the UDP port is specified as
|
||||||
// query parameter "discport".
|
// query parameter "discport".
|
||||||
|
@ -70,37 +70,32 @@ func ParseV4(rawurl string) (*Node, error) {
|
||||||
if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
|
if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
|
||||||
id, err := parsePubkey(m[1])
|
id, err := parsePubkey(m[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
return nil, fmt.Errorf("invalid public key (%v)", err)
|
||||||
}
|
}
|
||||||
return NewV4(id, nil, 0, 0, 0), nil
|
return NewV4(id, nil, 0, 0), nil
|
||||||
}
|
}
|
||||||
return parseComplete(rawurl)
|
return parseComplete(rawurl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewV4 creates a node from discovery v4 node information. The record
|
// NewV4 creates a node from discovery v4 node information. The record
|
||||||
// contained in the node has a zero-length signature.
|
// contained in the node has a zero-length signature.
|
||||||
func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp, raftPort int) *Node {
|
func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node {
|
||||||
var r enr.Record
|
var r enr.Record
|
||||||
if ip != nil {
|
if len(ip) > 0 {
|
||||||
r.Set(enr.IP(ip))
|
r.Set(enr.IP(ip))
|
||||||
}
|
}
|
||||||
return newV4(pubkey, r, tcp, udp, raftPort)
|
return newV4(pubkey, r, tcp, udp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// broken out from `func NewV4` (above) same in upstream go-ethereum, but taken out
|
// broken out from `func NewV4` (above) same in upstream go-ethereum, but taken out
|
||||||
// to avoid code duplication b/t NewV4 and NewV4Hostname
|
// to avoid code duplication b/t NewV4 and NewV4Hostname
|
||||||
func newV4(pubkey *ecdsa.PublicKey, r enr.Record, tcp, udp, raftPort int) *Node {
|
func newV4(pubkey *ecdsa.PublicKey, r enr.Record, tcp, udp int) *Node {
|
||||||
if udp != 0 {
|
if udp != 0 {
|
||||||
r.Set(enr.UDP(udp))
|
r.Set(enr.UDP(udp))
|
||||||
}
|
}
|
||||||
if tcp != 0 {
|
if tcp != 0 {
|
||||||
r.Set(enr.TCP(tcp))
|
r.Set(enr.TCP(tcp))
|
||||||
}
|
}
|
||||||
|
|
||||||
if raftPort != 0 { // Quorum
|
|
||||||
r.Set(enr.RaftPort(raftPort))
|
|
||||||
}
|
|
||||||
|
|
||||||
signV4Compat(&r, pubkey)
|
signV4Compat(&r, pubkey)
|
||||||
n, err := New(v4CompatID{}, &r)
|
n, err := New(v4CompatID{}, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -112,14 +107,22 @@ func newV4(pubkey *ecdsa.PublicKey, r enr.Record, tcp, udp, raftPort int) *Node
|
||||||
// Quorum
|
// Quorum
|
||||||
|
|
||||||
// NewV4Hostname creates a node from discovery v4 node information. The record
|
// NewV4Hostname creates a node from discovery v4 node information. The record
|
||||||
// contained in the node has a zero-length signature. It sets the hostname of
|
// contained in the node has a zero-length signature. It sets the hostname or ip
|
||||||
// the node instead of the IP address.
|
// of the node depends on hostname context
|
||||||
func NewV4Hostname(pubkey *ecdsa.PublicKey, hostname string, tcp, udp, raftPort int) *Node {
|
func NewV4Hostname(pubkey *ecdsa.PublicKey, hostname string, tcp, udp, raftPort int) *Node {
|
||||||
var r enr.Record
|
var r enr.Record
|
||||||
if hostname != "" {
|
|
||||||
|
if ip := net.ParseIP(hostname); ip == nil {
|
||||||
r.Set(enr.Hostname(hostname))
|
r.Set(enr.Hostname(hostname))
|
||||||
|
} else {
|
||||||
|
r.Set(enr.IP(ip))
|
||||||
}
|
}
|
||||||
return newV4(pubkey, r, tcp, udp, raftPort)
|
|
||||||
|
if raftPort != 0 {
|
||||||
|
r.Set(enr.RaftPort(raftPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
return newV4(pubkey, r, tcp, udp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// End-Quorum
|
// End-Quorum
|
||||||
|
@ -127,6 +130,7 @@ func NewV4Hostname(pubkey *ecdsa.PublicKey, hostname string, tcp, udp, raftPort
|
||||||
func parseComplete(rawurl string) (*Node, error) {
|
func parseComplete(rawurl string) (*Node, error) {
|
||||||
var (
|
var (
|
||||||
id *ecdsa.PublicKey
|
id *ecdsa.PublicKey
|
||||||
|
ip net.IP
|
||||||
tcpPort, udpPort uint64
|
tcpPort, udpPort uint64
|
||||||
)
|
)
|
||||||
u, err := url.Parse(rawurl)
|
u, err := url.Parse(rawurl)
|
||||||
|
@ -141,14 +145,29 @@ func parseComplete(rawurl string) (*Node, error) {
|
||||||
return nil, errors.New("does not contain node ID")
|
return nil, errors.New("does not contain node ID")
|
||||||
}
|
}
|
||||||
if id, err = parsePubkey(u.User.String()); err != nil {
|
if id, err = parsePubkey(u.User.String()); err != nil {
|
||||||
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
return nil, fmt.Errorf("invalid public key (%v)", err)
|
||||||
|
}
|
||||||
|
// move qv up to here
|
||||||
|
qv := u.Query()
|
||||||
|
// Parse the IP address.
|
||||||
|
ips, err := net.LookupIP(u.Hostname())
|
||||||
|
if err != nil {
|
||||||
|
// Quorum: if IP look up fail don't return error for raft url
|
||||||
|
if qv.Get("raftport") == "" {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ip = ips[0]
|
||||||
|
// Ensure the IP is 4 bytes long for IPv4 addresses.
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
ip = ipv4
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Parse the port numbers.
|
// Parse the port numbers.
|
||||||
if tcpPort, err = strconv.ParseUint(u.Port(), 10, 16); err != nil {
|
if tcpPort, err = strconv.ParseUint(u.Port(), 10, 16); err != nil {
|
||||||
return nil, errors.New("invalid port")
|
return nil, errors.New("invalid port")
|
||||||
}
|
}
|
||||||
udpPort = tcpPort
|
udpPort = tcpPort
|
||||||
qv := u.Query()
|
|
||||||
if qv.Get("discport") != "" {
|
if qv.Get("discport") != "" {
|
||||||
udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16)
|
udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,21 +175,20 @@ func parseComplete(rawurl string) (*Node, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var node *Node
|
|
||||||
|
|
||||||
// Quorum
|
// Quorum
|
||||||
if qv.Get("raftport") != "" {
|
if qv.Get("raftport") != "" {
|
||||||
raftPort, err := strconv.ParseUint(qv.Get("raftport"), 10, 16)
|
raftPort, err := strconv.ParseUint(qv.Get("raftport"), 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid raftport in query")
|
return nil, errors.New("invalid raftport in query")
|
||||||
}
|
}
|
||||||
node = NewV4Hostname(id, u.Hostname(), int(tcpPort), int(udpPort), int(raftPort))
|
if u.Hostname() == "" {
|
||||||
} else {
|
return nil, errors.New("empty hostname in raft url")
|
||||||
node = NewV4Hostname(id, u.Hostname(), int(tcpPort), int(udpPort), 0)
|
}
|
||||||
|
return NewV4Hostname(id, u.Hostname(), int(tcpPort), int(udpPort), int(raftPort)), nil
|
||||||
}
|
}
|
||||||
// End-Quorum
|
// End-Quorum
|
||||||
|
|
||||||
return node, nil
|
return NewV4(id, ip, int(tcpPort), int(udpPort)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HexPubkey(h string) (*ecdsa.PublicKey, error) {
|
func HexPubkey(h string) (*ecdsa.PublicKey, error) {
|
||||||
|
@ -229,9 +247,14 @@ func (n *Node) v4URL() string {
|
||||||
if n.Incomplete() {
|
if n.Incomplete() {
|
||||||
u.Host = nodeid
|
u.Host = nodeid
|
||||||
} else {
|
} else {
|
||||||
addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()}
|
|
||||||
u.User = url.User(nodeid)
|
u.User = url.User(nodeid)
|
||||||
|
if n.Host() != "" && net.ParseIP(n.Host()) == nil {
|
||||||
|
// Quorum
|
||||||
|
u.Host = net.JoinHostPort(n.Host(), strconv.Itoa(n.TCP()))
|
||||||
|
} else {
|
||||||
|
addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()}
|
||||||
u.Host = addr.String()
|
u.Host = addr.String()
|
||||||
|
}
|
||||||
if n.UDP() != n.TCP() {
|
if n.UDP() != n.TCP() {
|
||||||
u.RawQuery = "discport=" + strconv.Itoa(n.UDP())
|
u.RawQuery = "discport=" + strconv.Itoa(n.UDP())
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -37,7 +38,7 @@ var parseNodeTests = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://01010101@123.124.125.126:3",
|
rawurl: "enode://01010101@123.124.125.126:3",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: `invalid public key (wrong length, want 128 hex chars)`,
|
||||||
},
|
},
|
||||||
// Complete nodes with IP address.
|
// Complete nodes with IP address.
|
||||||
{
|
{
|
||||||
|
@ -50,42 +51,38 @@ var parseNodeTests = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
||||||
wantResult: NewV4Hostname(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
"127.0.0.1",
|
net.IP{127, 0, 0, 1},
|
||||||
52150,
|
52150,
|
||||||
52150,
|
52150,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
||||||
wantResult: NewV4Hostname(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
"::",
|
net.ParseIP("::"),
|
||||||
52150,
|
52150,
|
||||||
52150,
|
52150,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
|
||||||
wantResult: NewV4Hostname(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
"2001:db8:3c4d:15::abcd:ef12",
|
net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
|
||||||
52150,
|
52150,
|
||||||
52150,
|
52150,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
||||||
wantResult: NewV4Hostname(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
"127.0.0.1",
|
net.IP{0x7f, 0x0, 0x0, 0x1},
|
||||||
52150,
|
52150,
|
||||||
22334,
|
22334,
|
||||||
0,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
// Incomplete nodes with no address.
|
// Incomplete nodes with no address.
|
||||||
|
@ -93,30 +90,45 @@ var parseNodeTests = []struct {
|
||||||
rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
nil, 0, 0, 0,
|
nil, 0, 0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
nil, 0, 0, 0,
|
nil, 0, 0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
// Invalid URLs
|
// Invalid URLs
|
||||||
{
|
{
|
||||||
rawurl: "01010101",
|
rawurl: "01010101",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: `invalid public key (wrong length, want 128 hex chars)`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://01010101",
|
rawurl: "enode://01010101",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: `invalid public key (wrong length, want 128 hex chars)`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This test checks that errors from url.Parse are handled.
|
// This test checks that errors from url.Parse are handled.
|
||||||
rawurl: "://foo",
|
rawurl: "://foo",
|
||||||
wantError: `parse ://foo: missing protocol scheme`,
|
wantError: `parse ://foo: missing protocol scheme`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Quorum: raft url with invalid hostname (no error, hostname will be saved)
|
||||||
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3?raftport=50401",
|
||||||
|
wantResult: NewV4Hostname(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), "hostname", 3, 3, 50401),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Quorum: raft url with valid hostname
|
||||||
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@localhost:3?raftport=50401",
|
||||||
|
wantResult: NewV4Hostname(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), "localhost", 3, 3, 50401),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Quorum: raft url with no hostname
|
||||||
|
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@:3?raftport=50401",
|
||||||
|
wantError: `empty hostname in raft url`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func hexPubkey(h string) *ecdsa.PublicKey {
|
func hexPubkey(h string) *ecdsa.PublicKey {
|
||||||
|
@ -128,20 +140,7 @@ func hexPubkey(h string) *ecdsa.PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseNode(t *testing.T) {
|
func TestParseNode(t *testing.T) {
|
||||||
extraTests := []struct {
|
for _, test := range parseNodeTests {
|
||||||
rawurl string
|
|
||||||
wantError string
|
|
||||||
wantResult *Node
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
|
|
||||||
wantResult: NewV4Hostname(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), "hostname", 3, 3, 0, ),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testNodes := append(parseNodeTests, extraTests...)
|
|
||||||
|
|
||||||
for _, test := range testNodes {
|
|
||||||
n, err := ParseV4(test.rawurl)
|
n, err := ParseV4(test.rawurl)
|
||||||
if test.wantError != "" {
|
if test.wantError != "" {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -363,7 +363,7 @@ func (srv *Server) Self() *enode.Node {
|
||||||
srv.lock.Unlock()
|
srv.lock.Unlock()
|
||||||
|
|
||||||
if ln == nil {
|
if ln == nil {
|
||||||
return enode.NewV4(&srv.PrivateKey.PublicKey, net.ParseIP("0.0.0.0"), 0, 0, 0)
|
return enode.NewV4(&srv.PrivateKey.PublicKey, net.ParseIP("0.0.0.0"), 0, 0)
|
||||||
}
|
}
|
||||||
return ln.Node()
|
return ln.Node()
|
||||||
}
|
}
|
||||||
|
@ -1007,7 +1007,7 @@ func nodeFromConn(pubkey *ecdsa.PublicKey, conn net.Conn) *enode.Node {
|
||||||
ip = tcp.IP
|
ip = tcp.IP
|
||||||
port = tcp.Port
|
port = tcp.Port
|
||||||
}
|
}
|
||||||
return enode.NewV4(pubkey, ip, port, port, 0)
|
return enode.NewV4(pubkey, ip, port, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func truncateName(s string) string {
|
func truncateName(s string) string {
|
||||||
|
|
|
@ -152,7 +152,7 @@ func TestServerDial(t *testing.T) {
|
||||||
|
|
||||||
// tell the server to connect
|
// tell the server to connect
|
||||||
tcpAddr := listener.Addr().(*net.TCPAddr)
|
tcpAddr := listener.Addr().(*net.TCPAddr)
|
||||||
node := enode.NewV4(remid, tcpAddr.IP, tcpAddr.Port, 0, 0)
|
node := enode.NewV4(remid, tcpAddr.IP, tcpAddr.Port, 0)
|
||||||
srv.AddPeer(node)
|
srv.AddPeer(node)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -422,7 +422,7 @@ func TestServerAtCap(t *testing.T) {
|
||||||
func TestServerPeerLimits(t *testing.T) {
|
func TestServerPeerLimits(t *testing.T) {
|
||||||
srvkey := newkey()
|
srvkey := newkey()
|
||||||
clientkey := newkey()
|
clientkey := newkey()
|
||||||
clientnode := enode.NewV4(&clientkey.PublicKey, nil, 0, 0, 0)
|
clientnode := enode.NewV4(&clientkey.PublicKey, nil, 0, 0)
|
||||||
|
|
||||||
var tp = &setupTransport{
|
var tp = &setupTransport{
|
||||||
pubkey: &clientkey.PublicKey,
|
pubkey: &clientkey.PublicKey,
|
||||||
|
@ -512,21 +512,21 @@ func TestServerSetupConn(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{pubkey: clientpub},
|
tt: &setupTransport{pubkey: clientpub},
|
||||||
dialDest: enode.NewV4(&newkey().PublicKey, nil, 0, 0, 0),
|
dialDest: enode.NewV4(&newkey().PublicKey, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,close,",
|
wantCalls: "doEncHandshake,close,",
|
||||||
wantCloseErr: DiscUnexpectedIdentity,
|
wantCloseErr: DiscUnexpectedIdentity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: randomID().Bytes()}},
|
tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: randomID().Bytes()}},
|
||||||
dialDest: enode.NewV4(clientpub, nil, 0, 0, 0),
|
dialDest: enode.NewV4(clientpub, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
||||||
wantCloseErr: DiscUnexpectedIdentity,
|
wantCloseErr: DiscUnexpectedIdentity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errors.New("foo")},
|
tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errors.New("foo")},
|
||||||
dialDest: enode.NewV4(clientpub, nil, 0, 0, 0),
|
dialDest: enode.NewV4(clientpub, nil, 0, 0),
|
||||||
flags: dynDialedConn,
|
flags: dynDialedConn,
|
||||||
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
wantCalls: "doEncHandshake,doProtoHandshake,close,",
|
||||||
wantCloseErr: errors.New("foo"),
|
wantCloseErr: errors.New("foo"),
|
||||||
|
@ -578,7 +578,7 @@ func TestServerSetupConn_whenNotInRaftCluster(t *testing.T) {
|
||||||
clientpub = &clientkey.PublicKey
|
clientpub = &clientkey.PublicKey
|
||||||
)
|
)
|
||||||
|
|
||||||
clientNode := enode.NewV4(clientpub, nil, 0, 0, 0)
|
clientNode := enode.NewV4(clientpub, nil, 0, 0)
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
PrivateKey: srvkey,
|
PrivateKey: srvkey,
|
||||||
|
@ -616,7 +616,7 @@ func TestServerSetupConn_whenNotPermissioned(t *testing.T) {
|
||||||
clientkey, srvkey = newkey(), newkey()
|
clientkey, srvkey = newkey(), newkey()
|
||||||
clientpub = &clientkey.PublicKey
|
clientpub = &clientkey.PublicKey
|
||||||
)
|
)
|
||||||
clientNode := enode.NewV4(clientpub, nil, 0, 0, 0)
|
clientNode := enode.NewV4(clientpub, nil, 0, 0)
|
||||||
srv := &Server{
|
srv := &Server{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
PrivateKey: srvkey,
|
PrivateKey: srvkey,
|
||||||
|
|
|
@ -165,7 +165,7 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
|
||||||
// Node returns the node descriptor represented by the config.
|
// Node returns the node descriptor represented by the config.
|
||||||
func (n *NodeConfig) Node() *enode.Node {
|
func (n *NodeConfig) Node() *enode.Node {
|
||||||
return enode.NewV4(&n.PrivateKey.PublicKey, net.IP{127, 0, 0, 1}, int(n.Port), int(n.Port), 0)
|
return enode.NewV4(&n.PrivateKey.PublicKey, net.IP{127, 0, 0, 1}, int(n.Port), int(n.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomNodeConfig returns node configuration with a randomly generated ID and
|
// RandomNodeConfig returns node configuration with a randomly generated ID and
|
||||||
|
|
|
@ -325,17 +325,20 @@ func (pm *ProtocolManager) ProposeNewPeer(enodeId string, isLearner bool) (uint1
|
||||||
if pm.isLearnerNode() {
|
if pm.isLearnerNode() {
|
||||||
return 0, errors.New("learner node can't add peer or learner")
|
return 0, errors.New("learner node can't add peer or learner")
|
||||||
}
|
}
|
||||||
parsedUrl, _ := url.Parse(enodeId)
|
|
||||||
node, err := enode.ParseV4(enodeId)
|
node, err := enode.ParseV4(enodeId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//use the hostname instead of the IP, since if DNS is not enabled, the hostname should *be* the IP
|
if !pm.useDns {
|
||||||
ip := net.ParseIP(parsedUrl.Hostname())
|
// hostname is not allowed if DNS is not enabled
|
||||||
if !pm.useDns && (len(ip.To4()) != 4) {
|
if node.Host() != "" {
|
||||||
|
return 0, fmt.Errorf("raft must enable dns to use hostname")
|
||||||
|
}
|
||||||
|
if len(node.IP()) != 4 {
|
||||||
return 0, fmt.Errorf("expected IPv4 address (with length 4), but got IP of length %v", len(node.IP()))
|
return 0, fmt.Errorf("expected IPv4 address (with length 4), but got IP of length %v", len(node.IP()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !node.HasRaftPort() {
|
if !node.HasRaftPort() {
|
||||||
return 0, fmt.Errorf("enodeId is missing raftport querystring parameter: %v", enodeId)
|
return 0, fmt.Errorf("enodeId is missing raftport querystring parameter: %v", enodeId)
|
||||||
|
@ -357,7 +360,7 @@ func (pm *ProtocolManager) ProposeNewPeer(enodeId string, isLearner bool) (uint1
|
||||||
pm.confChangeProposalC <- raftpb.ConfChange{
|
pm.confChangeProposalC <- raftpb.ConfChange{
|
||||||
Type: confChangeType,
|
Type: confChangeType,
|
||||||
NodeID: uint64(raftId),
|
NodeID: uint64(raftId),
|
||||||
Context: address.toBytes(pm.useDns),
|
Context: address.toBytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return raftId, nil
|
return raftId, nil
|
||||||
|
@ -768,11 +771,6 @@ func (pm *ProtocolManager) entriesToApply(allEntries []raftpb.Entry) (entriesToA
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *ProtocolManager) raftUrl(address *Address) string {
|
func (pm *ProtocolManager) raftUrl(address *Address) string {
|
||||||
if !pm.useDns {
|
|
||||||
parsedIp := net.ParseIP(address.Hostname)
|
|
||||||
return fmt.Sprintf("http://%s:%d", parsedIp.To4(), address.RaftPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
if parsedIp := net.ParseIP(address.Hostname); parsedIp != nil {
|
if parsedIp := net.ParseIP(address.Hostname); parsedIp != nil {
|
||||||
if ipv4 := parsedIp.To4(); ipv4 != nil {
|
if ipv4 := parsedIp.To4(); ipv4 != nil {
|
||||||
//this is an IPv4 address
|
//this is an IPv4 address
|
||||||
|
@ -1001,7 +999,7 @@ func (pm *ProtocolManager) makeInitialRaftPeers() (raftPeers []etcdRaft.Peer, pe
|
||||||
address := newAddress(raftId, node.RaftPort(), node, pm.useDns)
|
address := newAddress(raftId, node.RaftPort(), node, pm.useDns)
|
||||||
raftPeers[i] = etcdRaft.Peer{
|
raftPeers[i] = etcdRaft.Peer{
|
||||||
ID: uint64(raftId),
|
ID: uint64(raftId),
|
||||||
Context: address.toBytes(pm.useDns),
|
Context: address.toBytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if raftId == pm.raftId {
|
if raftId == pm.raftId {
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestProtocolManager_whenAppliedIndexOutOfSync(t *testing.T) {
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
ports[i] = nextPort(t)
|
ports[i] = nextPort(t)
|
||||||
nodeKeys[i] = mustNewNodeKey(t)
|
nodeKeys[i] = mustNewNodeKey(t)
|
||||||
peers[i] = enode.NewV4(&(nodeKeys[i].PublicKey), net.IPv4(127, 0, 0, 1), 0, 0, int(ports[i]))
|
peers[i] = enode.NewV4Hostname(&(nodeKeys[i].PublicKey), net.IPv4(127, 0, 0, 1).String(), 0, 0, int(ports[i]))
|
||||||
}
|
}
|
||||||
raftNodes := make([]*RaftService, count)
|
raftNodes := make([]*RaftService, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
|
|
11
raft/peer.go
11
raft/peer.go
|
@ -33,13 +33,13 @@ type ClusterInfo struct {
|
||||||
NodeActive bool `json:"nodeActive"`
|
NodeActive bool `json:"nodeActive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAddress(raftId uint16, raftPort int, node *enode.Node, withHostname bool) *Address {
|
func newAddress(raftId uint16, raftPort int, node *enode.Node, useDns bool) *Address {
|
||||||
// derive 64 byte nodeID from 128 byte enodeID
|
// derive 64 byte nodeID from 128 byte enodeID
|
||||||
id, err := enode.RaftHexID(node.EnodeID())
|
id, err := enode.RaftHexID(node.EnodeID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if withHostname {
|
if useDns && node.Host() != "" {
|
||||||
return &Address{
|
return &Address{
|
||||||
RaftId: raftId,
|
RaftId: raftId,
|
||||||
NodeId: id,
|
NodeId: id,
|
||||||
|
@ -66,13 +66,14 @@ type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RLP Address encoding, for transport over raft and storage in LevelDB.
|
// RLP Address encoding, for transport over raft and storage in LevelDB.
|
||||||
func (addr *Address) toBytes(withHostname bool) []byte {
|
func (addr *Address) toBytes() []byte {
|
||||||
var toEncode interface{}
|
var toEncode interface{}
|
||||||
|
|
||||||
if withHostname {
|
// need to check if addr.Hostname is hostname/ip
|
||||||
|
if ip := net.ParseIP(addr.Hostname); ip == nil {
|
||||||
toEncode = addr
|
toEncode = addr
|
||||||
} else {
|
} else {
|
||||||
toEncode = []interface{}{addr.RaftId, addr.NodeId, net.ParseIP(addr.Hostname), addr.P2pPort, addr.RaftPort}
|
toEncode = []interface{}{addr.RaftId, addr.NodeId, ip, addr.P2pPort, addr.RaftPort}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer, err := rlp.EncodeToBytes(toEncode)
|
buffer, err := rlp.EncodeToBytes(toEncode)
|
||||||
|
|
|
@ -97,7 +97,7 @@ func (pm *ProtocolManager) triggerSnapshot(index uint64) {
|
||||||
|
|
||||||
//snapData := pm.blockchain.CurrentBlock().Hash().Bytes()
|
//snapData := pm.blockchain.CurrentBlock().Hash().Bytes()
|
||||||
//snap, err := pm.raftStorage.CreateSnapshot(pm.appliedIndex, &pm.confState, snapData)
|
//snap, err := pm.raftStorage.CreateSnapshot(pm.appliedIndex, &pm.confState, snapData)
|
||||||
snapData := pm.buildSnapshot().toBytes(pm.useDns)
|
snapData := pm.buildSnapshot().toBytes()
|
||||||
snap, err := pm.raftStorage.CreateSnapshot(index, &pm.confState, snapData)
|
snap, err := pm.raftStorage.CreateSnapshot(index, &pm.confState, snapData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -206,32 +206,43 @@ func (pm *ProtocolManager) loadSnapshot() *raftpb.Snapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (snapshot *SnapshotWithHostnames) toBytes(useDns bool) []byte {
|
func (snapshot *SnapshotWithHostnames) toBytes() []byte {
|
||||||
// we have DNS enabled, so only use the new snapshot type
|
var (
|
||||||
if useDns {
|
useOldSnapshot bool
|
||||||
buffer, err := rlp.EncodeToBytes(snapshot)
|
oldSnapshot SnapshotWithoutHostnames
|
||||||
if err != nil {
|
toEncode interface{}
|
||||||
panic(fmt.Sprintf("error: failed to RLP-encode Snapshot: %s", err.Error()))
|
)
|
||||||
}
|
|
||||||
return buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNS is not enabled, use the old snapshot type, converting from hostnames to IP addresses
|
// use old snapshot if all snapshot.Addresses are ips
|
||||||
oldSnapshot := new(SnapshotWithoutHostnames)
|
// but use the new snapshot if any of it is a hostname
|
||||||
|
useOldSnapshot = true
|
||||||
oldSnapshot.HeadBlockHash, oldSnapshot.RemovedRaftIds = snapshot.HeadBlockHash, snapshot.RemovedRaftIds
|
oldSnapshot.HeadBlockHash, oldSnapshot.RemovedRaftIds = snapshot.HeadBlockHash, snapshot.RemovedRaftIds
|
||||||
oldSnapshot.Addresses = make([]AddressWithoutHostname, len(snapshot.Addresses))
|
oldSnapshot.Addresses = make([]AddressWithoutHostname, len(snapshot.Addresses))
|
||||||
|
|
||||||
for index, addrWithHost := range snapshot.Addresses {
|
for index, addrWithHost := range snapshot.Addresses {
|
||||||
|
// validate addrWithHost.Hostname is a hostname/ip
|
||||||
|
ip := net.ParseIP(addrWithHost.Hostname)
|
||||||
|
if ip == nil {
|
||||||
|
// this is a hostname
|
||||||
|
useOldSnapshot = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// this is an ip
|
||||||
oldSnapshot.Addresses[index] = AddressWithoutHostname{
|
oldSnapshot.Addresses[index] = AddressWithoutHostname{
|
||||||
addrWithHost.RaftId,
|
addrWithHost.RaftId,
|
||||||
addrWithHost.NodeId,
|
addrWithHost.NodeId,
|
||||||
net.ParseIP(addrWithHost.Hostname),
|
ip,
|
||||||
addrWithHost.P2pPort,
|
addrWithHost.P2pPort,
|
||||||
addrWithHost.RaftPort,
|
addrWithHost.RaftPort,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer, err := rlp.EncodeToBytes(oldSnapshot)
|
if useOldSnapshot {
|
||||||
|
toEncode = oldSnapshot
|
||||||
|
} else {
|
||||||
|
toEncode = snapshot
|
||||||
|
}
|
||||||
|
buffer, err := rlp.EncodeToBytes(toEncode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error: failed to RLP-encode Snapshot: %s", err.Error()))
|
panic(fmt.Sprintf("error: failed to RLP-encode Snapshot: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
@ -247,6 +258,7 @@ func bytesToSnapshot(input []byte) *SnapshotWithHostnames {
|
||||||
return snapshot
|
return snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build new snapshot with hostname from legacy Address struct
|
||||||
snapshotOld := new(SnapshotWithoutHostnames)
|
snapshotOld := new(SnapshotWithoutHostnames)
|
||||||
streamOldSnapshot := rlp.NewStream(bytes.NewReader(input), 0)
|
streamOldSnapshot := rlp.NewStream(bytes.NewReader(input), 0)
|
||||||
if errOld = streamOldSnapshot.Decode(snapshotOld); errOld == nil {
|
if errOld = streamOldSnapshot.Decode(snapshotOld); errOld == nil {
|
||||||
|
|
|
@ -378,7 +378,7 @@ func RandomAddr() *BzzAddr {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("unable to generate key")
|
panic("unable to generate key")
|
||||||
}
|
}
|
||||||
node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303, 0)
|
node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303)
|
||||||
return NewAddr(node)
|
return NewAddr(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ func initialize(t *testing.T) {
|
||||||
peerNodeId := nodes[j].id
|
peerNodeId := nodes[j].id
|
||||||
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
||||||
peerPort := uint16(address.Port)
|
peerPort := uint16(address.Port)
|
||||||
peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, int(peerPort), int(peerPort), 0)
|
peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, int(peerPort), int(peerPort))
|
||||||
node.server.AddPeer(peer)
|
node.server.AddPeer(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ func initialize(t *testing.T) {
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
peerNodeId := nodes[j].id
|
peerNodeId := nodes[j].id
|
||||||
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr)
|
||||||
peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, address.Port, address.Port, 0)
|
peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, address.Port, address.Port)
|
||||||
nodes[i].server.AddPeer(peer)
|
nodes[i].server.AddPeer(peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue