|
|
@@ -1,10 +1,8 @@
|
|
|
package discover
|
|
|
|
|
|
import (
|
|
|
- "bytes"
|
|
|
"crypto/ecdsa"
|
|
|
"crypto/elliptic"
|
|
|
- "encoding/binary"
|
|
|
"encoding/hex"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
@@ -13,16 +11,12 @@ import (
|
|
|
"math/rand"
|
|
|
"net"
|
|
|
"net/url"
|
|
|
- "os"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
|
|
"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
|
|
|
@@ -310,111 +304,3 @@ func randomID(a NodeID, n int) (b NodeID) {
|
|
|
}
|
|
|
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()
|
|
|
-}
|