cmd/bootnode, eth, p2p, p2p/discover: clean up the seeder and mesh into eth.
This commit is contained in:
parent
971702e7a1
commit
6def110c37
@ -71,7 +71,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := discover.ListenUDP(nodeKey, *listenAddr, natm, ""); err != nil {
|
if _, err := discover.ListenUDP(nodeKey, *listenAddr, natm, nil); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
select {}
|
select {}
|
||||||
|
@ -125,6 +125,8 @@ type Ethereum struct {
|
|||||||
blockDb common.Database // Block chain database
|
blockDb common.Database // Block chain database
|
||||||
stateDb common.Database // State changes database
|
stateDb common.Database // State changes database
|
||||||
extraDb common.Database // Extra database (txs, etc)
|
extraDb common.Database // Extra database (txs, etc)
|
||||||
|
seedDb *discover.Cache // Peer database seeding the bootstrap
|
||||||
|
|
||||||
// Closed when databases are flushed and closed
|
// Closed when databases are flushed and closed
|
||||||
databasesClosed chan bool
|
databasesClosed chan bool
|
||||||
|
|
||||||
@ -179,7 +181,10 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
seedDbPath := path.Join(config.DataDir, "seeds")
|
seedDb, err := discover.NewPersistentCache(path.Join(config.DataDir, "seeds"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Perform database sanity checks
|
// Perform database sanity checks
|
||||||
d, _ := blockDb.Get([]byte("ProtocolVersion"))
|
d, _ := blockDb.Get([]byte("ProtocolVersion"))
|
||||||
@ -207,6 +212,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
blockDb: blockDb,
|
blockDb: blockDb,
|
||||||
stateDb: stateDb,
|
stateDb: stateDb,
|
||||||
extraDb: extraDb,
|
extraDb: extraDb,
|
||||||
|
seedDb: seedDb,
|
||||||
eventMux: &event.TypeMux{},
|
eventMux: &event.TypeMux{},
|
||||||
accountManager: config.AccountManager,
|
accountManager: config.AccountManager,
|
||||||
DataDir: config.DataDir,
|
DataDir: config.DataDir,
|
||||||
@ -244,7 +250,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||||||
NAT: config.NAT,
|
NAT: config.NAT,
|
||||||
NoDial: !config.Dial,
|
NoDial: !config.Dial,
|
||||||
BootstrapNodes: config.parseBootNodes(),
|
BootstrapNodes: config.parseBootNodes(),
|
||||||
SeedCache: seedDbPath,
|
SeedCache: seedDb,
|
||||||
}
|
}
|
||||||
if len(config.Port) > 0 {
|
if len(config.Port) > 0 {
|
||||||
eth.net.ListenAddr = ":" + config.Port
|
eth.net.ListenAddr = ":" + config.Port
|
||||||
@ -423,6 +429,7 @@ done:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.seedDb.Close()
|
||||||
s.blockDb.Close()
|
s.blockDb.Close()
|
||||||
s.stateDb.Close()
|
s.stateDb.Close()
|
||||||
s.extraDb.Close()
|
s.extraDb.Close()
|
||||||
|
134
p2p/discover/cache.go
Normal file
134
p2p/discover/cache.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Contains the discovery cache, storing previously seen nodes to act as seed
|
||||||
|
// servers during bootstrapping the network.
|
||||||
|
|
||||||
|
package discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache stores all nodes we know about.
|
||||||
|
type Cache struct {
|
||||||
|
db *leveldb.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache version to allow dumping old data if it changes.
|
||||||
|
var cacheVersionKey = []byte("pv")
|
||||||
|
|
||||||
|
// NewMemoryCache creates a new in-memory peer cache without a persistent backend.
|
||||||
|
func NewMemoryCache() (*Cache, error) {
|
||||||
|
db, err := leveldb.Open(storage.NewMemStorage(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Cache{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPersistentCache creates/opens a leveldb backed persistent peer cache, also
|
||||||
|
// flushing its contents in case of a version mismatch.
|
||||||
|
func NewPersistentCache(path string) (*Cache, error) {
|
||||||
|
// Try to open the cache, recovering any corruption
|
||||||
|
db, err := leveldb.OpenFile(path, nil)
|
||||||
|
if _, iscorrupted := err.(leveldb.ErrCorrupted); iscorrupted {
|
||||||
|
db, err = leveldb.RecoverFile(path, nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// The nodes contained in the cache correspond to a certain protocol version.
|
||||||
|
// Flush all nodes if the version doesn't match.
|
||||||
|
currentVer := make([]byte, binary.MaxVarintLen64)
|
||||||
|
currentVer = currentVer[:binary.PutVarint(currentVer, Version)]
|
||||||
|
|
||||||
|
blob, err := db.Get(cacheVersionKey, nil)
|
||||||
|
switch err {
|
||||||
|
case leveldb.ErrNotFound:
|
||||||
|
// Version not found (i.e. empty cache), insert it
|
||||||
|
err = db.Put(cacheVersionKey, currentVer, nil)
|
||||||
|
|
||||||
|
case nil:
|
||||||
|
// Version present, flush if different
|
||||||
|
if !bytes.Equal(blob, currentVer) {
|
||||||
|
db.Close()
|
||||||
|
if err = os.RemoveAll(path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewPersistentCache(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clean up in case of an error
|
||||||
|
if err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Cache{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get retrieves a node with a given id from the seed da
|
||||||
|
func (c *Cache) get(id NodeID) *Node {
|
||||||
|
blob, err := c.db.Get(id[:], nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
node := new(Node)
|
||||||
|
if err := rlp.DecodeBytes(blob, node); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// list retrieves a batch of nodes from the database.
|
||||||
|
func (c *Cache) list(n int) []*Node {
|
||||||
|
it := c.db.NewIterator(nil, nil)
|
||||||
|
defer it.Release()
|
||||||
|
|
||||||
|
nodes := make([]*Node, 0, n)
|
||||||
|
for i := 0; i < n && it.Next(); i++ {
|
||||||
|
var id NodeID
|
||||||
|
copy(id[:], it.Key())
|
||||||
|
|
||||||
|
if node := c.get(id); node != nil {
|
||||||
|
nodes = append(nodes, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// update inserts - potentially overwriting - a node in the seed database.
|
||||||
|
func (c *Cache) update(node *Node) error {
|
||||||
|
blob, err := rlp.EncodeToBytes(node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.db.Put(node.ID[:], blob, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add inserts a new node into the seed database.
|
||||||
|
func (c *Cache) add(id NodeID, addr *net.UDPAddr, tcpPort uint16) *Node {
|
||||||
|
node := &Node{
|
||||||
|
ID: id,
|
||||||
|
IP: addr.IP,
|
||||||
|
DiscPort: addr.Port,
|
||||||
|
TCPPort: int(tcpPort),
|
||||||
|
}
|
||||||
|
c.update(node)
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete removes a node from the database.
|
||||||
|
func (c *Cache) delete(id NodeID) error {
|
||||||
|
return c.db.Delete(id[:], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close flushes and closes the database files.
|
||||||
|
func (c *Cache) Close() {
|
||||||
|
c.db.Close()
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
package discover
|
package discover
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -13,16 +11,12 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb/storage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeIDBits = 512
|
const nodeIDBits = 512
|
||||||
@ -310,111 +304,3 @@ func randomID(a NodeID, n int) (b NodeID) {
|
|||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodeDB stores all nodes we know about.
|
|
||||||
type nodeDB struct {
|
|
||||||
ldb *leveldb.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
var dbVersionKey = []byte("pv")
|
|
||||||
|
|
||||||
// Opens the backing LevelDB. If path is "", we use an in-memory database.
|
|
||||||
func newNodeDB(path string, version int64) (db *nodeDB, err error) {
|
|
||||||
db = new(nodeDB)
|
|
||||||
opts := new(opt.Options)
|
|
||||||
if path == "" {
|
|
||||||
db.ldb, err = leveldb.Open(storage.NewMemStorage(), opts)
|
|
||||||
} else {
|
|
||||||
db.ldb, err = openNodeDB(path, opts, version)
|
|
||||||
}
|
|
||||||
return db, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// openNodeDB opens a persistent seed cache, flushing old versions.
|
|
||||||
func openNodeDB(path string, opts *opt.Options, version int64) (*leveldb.DB, error) {
|
|
||||||
ldb, err := leveldb.OpenFile(path, opts)
|
|
||||||
if _, iscorrupted := err.(leveldb.ErrCorrupted); iscorrupted {
|
|
||||||
ldb, err = leveldb.RecoverFile(path, opts)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// The nodes contained in the database correspond to a certain
|
|
||||||
// protocol version. Flush all nodes if the DB version doesn't match.
|
|
||||||
// There is no need to do this for memory databases because they
|
|
||||||
// won't ever be used with a different protocol version.
|
|
||||||
shouldVal := make([]byte, binary.MaxVarintLen64)
|
|
||||||
shouldVal = shouldVal[:binary.PutVarint(shouldVal, version)]
|
|
||||||
val, err := ldb.Get(dbVersionKey, nil)
|
|
||||||
if err == leveldb.ErrNotFound {
|
|
||||||
err = ldb.Put(dbVersionKey, shouldVal, nil)
|
|
||||||
} else if err == nil && !bytes.Equal(val, shouldVal) {
|
|
||||||
// Delete and start over.
|
|
||||||
ldb.Close()
|
|
||||||
if err = os.RemoveAll(path); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return openNodeDB(path, opts, version)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
ldb.Close()
|
|
||||||
ldb = nil
|
|
||||||
}
|
|
||||||
return ldb, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get retrieves a node with a given id from the seed da
|
|
||||||
func (db *nodeDB) get(id NodeID) *Node {
|
|
||||||
v, err := db.ldb.Get(id[:], nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
n := new(Node)
|
|
||||||
if err := rlp.DecodeBytes(v, n); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// list retrieves a batch of nodes from the database.
|
|
||||||
func (db *nodeDB) list(n int) []*Node {
|
|
||||||
it := db.ldb.NewIterator(nil, nil)
|
|
||||||
defer it.Release()
|
|
||||||
|
|
||||||
nodes := make([]*Node, 0, n)
|
|
||||||
for i := 0; i < n && it.Next(); i++ {
|
|
||||||
var id NodeID
|
|
||||||
copy(id[:], it.Key())
|
|
||||||
|
|
||||||
if node := db.get(id); node != nil {
|
|
||||||
nodes = append(nodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// update inserts - potentially overwriting - a node in the seed database.
|
|
||||||
func (db *nodeDB) update(n *Node) error {
|
|
||||||
v, err := rlp.EncodeToBytes(n)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return db.ldb.Put(n.ID[:], v, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add inserts a new node into the seed database.
|
|
||||||
func (db *nodeDB) add(id NodeID, addr *net.UDPAddr, tcpPort uint16) *Node {
|
|
||||||
n := &Node{ID: id, IP: addr.IP, DiscPort: addr.Port, TCPPort: int(tcpPort)}
|
|
||||||
db.update(n)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete removes a node from the database.
|
|
||||||
func (db *nodeDB) delete(id NodeID) error {
|
|
||||||
return db.ldb.Delete(id[:], nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close flushes and closes the database files.
|
|
||||||
func (db *nodeDB) close() {
|
|
||||||
db.ldb.Close()
|
|
||||||
}
|
|
||||||
|
@ -27,6 +27,7 @@ type Table struct {
|
|||||||
mutex sync.Mutex // protects buckets, their content, and nursery
|
mutex sync.Mutex // protects buckets, their content, and nursery
|
||||||
buckets [nBuckets]*bucket // index of known nodes by distance
|
buckets [nBuckets]*bucket // index of known nodes by distance
|
||||||
nursery []*Node // bootstrap nodes
|
nursery []*Node // bootstrap nodes
|
||||||
|
cache *Cache // cache of known nodes
|
||||||
|
|
||||||
bondmu sync.Mutex
|
bondmu sync.Mutex
|
||||||
bonding map[NodeID]*bondproc
|
bonding map[NodeID]*bondproc
|
||||||
@ -34,7 +35,6 @@ type Table struct {
|
|||||||
|
|
||||||
net transport
|
net transport
|
||||||
self *Node // metadata of the local node
|
self *Node // metadata of the local node
|
||||||
db *nodeDB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type bondproc struct {
|
type bondproc struct {
|
||||||
@ -61,17 +61,15 @@ type bucket struct {
|
|||||||
entries []*Node
|
entries []*Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, seedCache string) *Table {
|
func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, seeder *Cache) *Table {
|
||||||
// Load the bootstrap seed cache (use in memory db upon failure)
|
// If no seed cache was given, use an in-memory one
|
||||||
db, err := newNodeDB(seedCache, Version)
|
if seeder == nil {
|
||||||
if err != nil {
|
seeder, _ = NewMemoryCache()
|
||||||
glog.V(logger.Warn).Infoln("Failed to open bootstrap seed cache:", err)
|
|
||||||
db, _ = newNodeDB("", Version)
|
|
||||||
}
|
}
|
||||||
// Create the bootstrap table
|
// Create the bootstrap table
|
||||||
tab := &Table{
|
tab := &Table{
|
||||||
net: t,
|
net: t,
|
||||||
db: db,
|
cache: seeder,
|
||||||
self: newNode(ourID, ourAddr),
|
self: newNode(ourID, ourAddr),
|
||||||
bonding: make(map[NodeID]*bondproc),
|
bonding: make(map[NodeID]*bondproc),
|
||||||
bondslots: make(chan struct{}, maxBondingPingPongs),
|
bondslots: make(chan struct{}, maxBondingPingPongs),
|
||||||
@ -93,7 +91,6 @@ func (tab *Table) Self() *Node {
|
|||||||
// Close terminates the network listener and flushes the seed cache.
|
// Close terminates the network listener and flushes the seed cache.
|
||||||
func (tab *Table) Close() {
|
func (tab *Table) Close() {
|
||||||
tab.net.close()
|
tab.net.close()
|
||||||
tab.db.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap sets the bootstrap nodes. These nodes are used to connect
|
// Bootstrap sets the bootstrap nodes. These nodes are used to connect
|
||||||
@ -178,10 +175,10 @@ func (tab *Table) refresh() {
|
|||||||
result := tab.Lookup(randomID(tab.self.ID, ld))
|
result := tab.Lookup(randomID(tab.self.ID, ld))
|
||||||
if len(result) == 0 {
|
if len(result) == 0 {
|
||||||
// Pick a batch of previously know seeds to lookup with and discard them (will come back if they are still live)
|
// Pick a batch of previously know seeds to lookup with and discard them (will come back if they are still live)
|
||||||
seeds := tab.db.list(10)
|
seeds := tab.cache.list(10)
|
||||||
for _, seed := range seeds {
|
for _, seed := range seeds {
|
||||||
glog.V(logger.Debug).Infoln("Seeding network with:", seed)
|
glog.V(logger.Debug).Infoln("Seeding network with:", seed)
|
||||||
tab.db.delete(seed.ID)
|
tab.cache.delete(seed.ID)
|
||||||
}
|
}
|
||||||
// Bootstrap the table with a self lookup
|
// Bootstrap the table with a self lookup
|
||||||
all := tab.bondall(append(tab.nursery, seeds...))
|
all := tab.bondall(append(tab.nursery, seeds...))
|
||||||
@ -252,7 +249,7 @@ func (tab *Table) bondall(nodes []*Node) (result []*Node) {
|
|||||||
// of the process can be skipped.
|
// of the process can be skipped.
|
||||||
func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) (*Node, error) {
|
func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) (*Node, error) {
|
||||||
var n *Node
|
var n *Node
|
||||||
if n = tab.db.get(id); n == nil {
|
if n = tab.cache.get(id); n == nil {
|
||||||
tab.bondmu.Lock()
|
tab.bondmu.Lock()
|
||||||
w := tab.bonding[id]
|
w := tab.bonding[id]
|
||||||
if w != nil {
|
if w != nil {
|
||||||
@ -297,7 +294,7 @@ func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAdd
|
|||||||
// waitping will simply time out.
|
// waitping will simply time out.
|
||||||
tab.net.waitping(id)
|
tab.net.waitping(id)
|
||||||
}
|
}
|
||||||
w.n = tab.db.add(id, addr, tcpPort)
|
w.n = tab.cache.add(id, addr, tcpPort)
|
||||||
close(w.done)
|
close(w.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func TestTable_pingReplace(t *testing.T) {
|
func TestTable_pingReplace(t *testing.T) {
|
||||||
doit := func(newNodeIsResponding, lastInBucketIsResponding bool) {
|
doit := func(newNodeIsResponding, lastInBucketIsResponding bool) {
|
||||||
transport := newPingRecorder()
|
transport := newPingRecorder()
|
||||||
tab := newTable(transport, NodeID{}, &net.UDPAddr{}, "")
|
tab := newTable(transport, NodeID{}, &net.UDPAddr{}, nil)
|
||||||
last := fillBucket(tab, 200)
|
last := fillBucket(tab, 200)
|
||||||
pingSender := randomID(tab.self.ID, 200)
|
pingSender := randomID(tab.self.ID, 200)
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ func TestTable_closest(t *testing.T) {
|
|||||||
|
|
||||||
test := func(test *closeTest) bool {
|
test := func(test *closeTest) bool {
|
||||||
// for any node table, Target and N
|
// for any node table, Target and N
|
||||||
tab := newTable(nil, test.Self, &net.UDPAddr{}, "")
|
tab := newTable(nil, test.Self, &net.UDPAddr{}, nil)
|
||||||
tab.add(test.All)
|
tab.add(test.All)
|
||||||
|
|
||||||
// check that doClosest(Target, N) returns nodes
|
// check that doClosest(Target, N) returns nodes
|
||||||
@ -217,7 +217,7 @@ func TestTable_Lookup(t *testing.T) {
|
|||||||
self := gen(NodeID{}, quickrand).(NodeID)
|
self := gen(NodeID{}, quickrand).(NodeID)
|
||||||
target := randomID(self, 200)
|
target := randomID(self, 200)
|
||||||
transport := findnodeOracle{t, target}
|
transport := findnodeOracle{t, target}
|
||||||
tab := newTable(transport, self, &net.UDPAddr{}, "")
|
tab := newTable(transport, self, &net.UDPAddr{}, nil)
|
||||||
|
|
||||||
// lookup on empty table returns no nodes
|
// lookup on empty table returns no nodes
|
||||||
if results := tab.Lookup(target); len(results) > 0 {
|
if results := tab.Lookup(target); len(results) > 0 {
|
||||||
|
@ -144,7 +144,7 @@ type reply struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListenUDP returns a new table that listens for UDP packets on laddr.
|
// ListenUDP returns a new table that listens for UDP packets on laddr.
|
||||||
func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, seedCache string) (*Table, error) {
|
func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, seeder *Cache) (*Table, error) {
|
||||||
addr, err := net.ResolveUDPAddr("udp", laddr)
|
addr, err := net.ResolveUDPAddr("udp", laddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -153,12 +153,12 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, seedCac
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tab, _ := newUDP(priv, conn, natm, seedCache)
|
tab, _ := newUDP(priv, conn, natm, seeder)
|
||||||
glog.V(logger.Info).Infoln("Listening,", tab.self)
|
glog.V(logger.Info).Infoln("Listening,", tab.self)
|
||||||
return tab, nil
|
return tab, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, seedCache string) (*Table, *udp) {
|
func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, seeder *Cache) (*Table, *udp) {
|
||||||
udp := &udp{
|
udp := &udp{
|
||||||
conn: c,
|
conn: c,
|
||||||
priv: priv,
|
priv: priv,
|
||||||
@ -176,7 +176,7 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, seedCache string
|
|||||||
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr, seedCache)
|
udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr, seeder)
|
||||||
go udp.loop()
|
go udp.loop()
|
||||||
go udp.readLoop()
|
go udp.readLoop()
|
||||||
return udp.Table, udp
|
return udp.Table, udp
|
||||||
@ -449,7 +449,7 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte
|
|||||||
if expired(req.Expiration) {
|
if expired(req.Expiration) {
|
||||||
return errExpired
|
return errExpired
|
||||||
}
|
}
|
||||||
if t.db.get(fromID) == nil {
|
if t.cache.get(fromID) == nil {
|
||||||
// No bond exists, we don't process the packet. This prevents
|
// No bond exists, we don't process the packet. This prevents
|
||||||
// an attack vector where the discovery protocol could be used
|
// an attack vector where the discovery protocol could be used
|
||||||
// to amplify traffic in a DDOS attack. A malicious actor
|
// to amplify traffic in a DDOS attack. A malicious actor
|
||||||
|
@ -41,7 +41,7 @@ func newUDPTest(t *testing.T) *udpTest {
|
|||||||
remotekey: newkey(),
|
remotekey: newkey(),
|
||||||
remoteaddr: &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 30303},
|
remoteaddr: &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 30303},
|
||||||
}
|
}
|
||||||
test.table, test.udp = newUDP(test.localkey, test.pipe, nil, "")
|
test.table, test.udp = newUDP(test.localkey, test.pipe, nil, nil)
|
||||||
return test
|
return test
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ func TestUDP_findnode(t *testing.T) {
|
|||||||
|
|
||||||
// ensure there's a bond with the test node,
|
// ensure there's a bond with the test node,
|
||||||
// findnode won't be accepted otherwise.
|
// findnode won't be accepted otherwise.
|
||||||
test.table.db.add(PubkeyID(&test.remotekey.PublicKey), test.remoteaddr, 99)
|
test.table.cache.add(PubkeyID(&test.remotekey.PublicKey), test.remoteaddr, 99)
|
||||||
|
|
||||||
// check that closest neighbors are returned.
|
// check that closest neighbors are returned.
|
||||||
test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
|
test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
|
||||||
|
@ -59,9 +59,9 @@ type Server struct {
|
|||||||
// with the rest of the network.
|
// with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*discover.Node
|
||||||
|
|
||||||
// SeedCache is the path to the database containing the previously seen live
|
// SeedCache is the database containing the previously seen live nodes in
|
||||||
// nodes in the network to use as potential bootstrap seeds.
|
// the network to use as potential bootstrap seeds.
|
||||||
SeedCache string
|
SeedCache *discover.Cache
|
||||||
|
|
||||||
// Protocols should contain the protocols supported
|
// Protocols should contain the protocols supported
|
||||||
// by the server. Matching protocols are launched for
|
// by the server. Matching protocols are launched for
|
||||||
|
Loading…
Reference in New Issue
Block a user