Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
8646365b
Commit
8646365b
authored
Apr 24, 2015
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd/bootnode, eth, p2p, p2p/discover: use a fancier db design
parent
6def110c
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
280 additions
and
169 deletions
+280
-169
main.go
cmd/bootnode/main.go
+1
-1
backend.go
eth/backend.go
+2
-8
cache.go
p2p/discover/cache.go
+0
-134
database.go
p2p/discover/database.go
+233
-0
table.go
p2p/discover/table.go
+25
-11
table_test.go
p2p/discover/table_test.go
+3
-3
udp.go
p2p/discover/udp.go
+5
-5
udp_test.go
p2p/discover/udp_test.go
+7
-3
server.go
p2p/server.go
+4
-4
No files found.
cmd/bootnode/main.go
View file @
8646365b
...
...
@@ -71,7 +71,7 @@ func main() {
}
}
if
_
,
err
:=
discover
.
ListenUDP
(
nodeKey
,
*
listenAddr
,
natm
,
nil
);
err
!=
nil
{
if
_
,
err
:=
discover
.
ListenUDP
(
nodeKey
,
*
listenAddr
,
natm
,
""
);
err
!=
nil
{
log
.
Fatal
(
err
)
}
select
{}
...
...
eth/backend.go
View file @
8646365b
...
...
@@ -125,7 +125,6 @@ type Ethereum struct {
blockDb
common
.
Database
// Block chain database
stateDb
common
.
Database
// State changes database
extraDb
common
.
Database
// Extra database (txs, etc)
seedDb
*
discover
.
Cache
// Peer database seeding the bootstrap
// Closed when databases are flushed and closed
databasesClosed
chan
bool
...
...
@@ -181,10 +180,7 @@ func New(config *Config) (*Ethereum, error) {
if
err
!=
nil
{
return
nil
,
err
}
seedDb
,
err
:=
discover
.
NewPersistentCache
(
path
.
Join
(
config
.
DataDir
,
"seeds"
))
if
err
!=
nil
{
return
nil
,
err
}
nodeDb
:=
path
.
Join
(
config
.
DataDir
,
"nodes"
)
// Perform database sanity checks
d
,
_
:=
blockDb
.
Get
([]
byte
(
"ProtocolVersion"
))
...
...
@@ -212,7 +208,6 @@ func New(config *Config) (*Ethereum, error) {
blockDb
:
blockDb
,
stateDb
:
stateDb
,
extraDb
:
extraDb
,
seedDb
:
seedDb
,
eventMux
:
&
event
.
TypeMux
{},
accountManager
:
config
.
AccountManager
,
DataDir
:
config
.
DataDir
,
...
...
@@ -250,7 +245,7 @@ func New(config *Config) (*Ethereum, error) {
NAT
:
config
.
NAT
,
NoDial
:
!
config
.
Dial
,
BootstrapNodes
:
config
.
parseBootNodes
(),
SeedCache
:
seed
Db
,
NodeDatabase
:
node
Db
,
}
if
len
(
config
.
Port
)
>
0
{
eth
.
net
.
ListenAddr
=
":"
+
config
.
Port
...
...
@@ -429,7 +424,6 @@ done:
}
}
s
.
seedDb
.
Close
()
s
.
blockDb
.
Close
()
s
.
stateDb
.
Close
()
s
.
extraDb
.
Close
()
...
...
p2p/discover/cache.go
deleted
100644 → 0
View file @
6def110c
// 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
()
}
p2p/discover/database.go
0 → 100644
View file @
8646365b
// Contains the node database, storing previously seen nodes and any collected
// metadata about them for QoS purposes.
package
discover
import
(
"bytes"
"encoding/binary"
"os"
"time"
"github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
)
// nodeDB stores all nodes we know about.
type
nodeDB
struct
{
lvl
*
leveldb
.
DB
}
// Schema layout for the node database
var
(
nodeDBVersionKey
=
[]
byte
(
"version"
)
// Version of the database to flush if changes
nodeDBStartupKey
=
[]
byte
(
"startup"
)
// Time when the node discovery started (seed selection)
nodeDBItemPrefix
=
[]
byte
(
"n:"
)
// Identifier to prefix node entries with
nodeDBDiscoverRoot
=
":discover"
nodeDBDiscoverPing
=
nodeDBDiscoverRoot
+
":lastping"
nodeDBDiscoverBond
=
nodeDBDiscoverRoot
+
":lastbond"
)
// newNodeDB creates a new node database for storing and retrieving infos about
// known peers in the network. If no path is given, an in-memory, temporary
// database is constructed.
func
newNodeDB
(
path
string
)
(
*
nodeDB
,
error
)
{
if
path
==
""
{
return
newMemoryNodeDB
()
}
return
newPersistentNodeDB
(
path
)
}
// newMemoryNodeDB creates a new in-memory node database without a persistent
// backend.
func
newMemoryNodeDB
()
(
*
nodeDB
,
error
)
{
db
,
err
:=
leveldb
.
Open
(
storage
.
NewMemStorage
(),
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
nodeDB
{
lvl
:
db
},
nil
}
// newPersistentNodeDB creates/opens a leveldb backed persistent node database,
// also flushing its contents in case of a version mismatch.
func
newPersistentNodeDB
(
path
string
)
(
*
nodeDB
,
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
(
nodeDBVersionKey
,
nil
)
switch
err
{
case
leveldb
.
ErrNotFound
:
// Version not found (i.e. empty cache), insert it
err
=
db
.
Put
(
nodeDBVersionKey
,
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
newPersistentNodeDB
(
path
)
}
}
// Clean up in case of an error
if
err
!=
nil
{
db
.
Close
()
return
nil
,
err
}
return
&
nodeDB
{
lvl
:
db
},
nil
}
// key generates the leveldb key-blob from a node id and its particular field of
// interest.
func
(
db
*
nodeDB
)
key
(
id
NodeID
,
field
string
)
[]
byte
{
return
append
(
nodeDBItemPrefix
,
append
(
id
[
:
],
field
...
)
...
)
}
// splitKey tries to split a database key into a node id and a field part.
func
(
db
*
nodeDB
)
splitKey
(
key
[]
byte
)
(
id
NodeID
,
field
string
)
{
// If the key is not of a node, return it plainly
if
!
bytes
.
HasPrefix
(
key
,
nodeDBItemPrefix
)
{
return
NodeID
{},
string
(
key
)
}
// Otherwise split the id and field
item
:=
key
[
len
(
nodeDBItemPrefix
)
:
]
copy
(
id
[
:
],
item
[
:
len
(
id
)])
field
=
string
(
item
[
len
(
id
)
:
])
return
id
,
field
}
// fetchTime retrieves a time instance (encoded as a unix timestamp) associated
// with a particular database key.
func
(
db
*
nodeDB
)
fetchTime
(
key
[]
byte
)
time
.
Time
{
blob
,
err
:=
db
.
lvl
.
Get
(
key
,
nil
)
if
err
!=
nil
{
return
time
.
Time
{}
}
var
unix
int64
if
err
:=
rlp
.
DecodeBytes
(
blob
,
&
unix
);
err
!=
nil
{
return
time
.
Time
{}
}
return
time
.
Unix
(
unix
,
0
)
}
// storeTime update a specific database entry to the current time instance as a
// unix timestamp.
func
(
db
*
nodeDB
)
storeTime
(
key
[]
byte
,
instance
time
.
Time
)
error
{
blob
,
err
:=
rlp
.
EncodeToBytes
(
instance
.
Unix
())
if
err
!=
nil
{
return
err
}
return
db
.
lvl
.
Put
(
key
,
blob
,
nil
)
}
// startup retrieves the time instance when the bootstrapping last begun. Its
// purpose is to prevent contacting potential seed nodes multiple times in the
// same boot cycle.
func
(
db
*
nodeDB
)
startup
()
time
.
Time
{
return
db
.
fetchTime
(
nodeDBStartupKey
)
}
// updateStartup updates the bootstrap initiation time to the one specified.
func
(
db
*
nodeDB
)
updateStartup
(
instance
time
.
Time
)
error
{
return
db
.
storeTime
(
nodeDBStartupKey
,
instance
)
}
// node retrieves a node with a given id from the database.
func
(
db
*
nodeDB
)
node
(
id
NodeID
)
*
Node
{
blob
,
err
:=
db
.
lvl
.
Get
(
db
.
key
(
id
,
nodeDBDiscoverRoot
),
nil
)
if
err
!=
nil
{
return
nil
}
node
:=
new
(
Node
)
if
err
:=
rlp
.
DecodeBytes
(
blob
,
node
);
err
!=
nil
{
return
nil
}
return
node
}
// updateNode inserts - potentially overwriting - a node into the peer database.
func
(
db
*
nodeDB
)
updateNode
(
node
*
Node
)
error
{
blob
,
err
:=
rlp
.
EncodeToBytes
(
node
)
if
err
!=
nil
{
return
err
}
return
db
.
lvl
.
Put
(
db
.
key
(
node
.
ID
,
nodeDBDiscoverRoot
),
blob
,
nil
)
}
// lastPing retrieves the time of the last ping packet send to a remote node,
// requesting binding.
func
(
db
*
nodeDB
)
lastPing
(
id
NodeID
)
time
.
Time
{
return
db
.
fetchTime
(
db
.
key
(
id
,
nodeDBDiscoverPing
))
}
// updateLastPing updates the last time we tried contacting a remote node.
func
(
db
*
nodeDB
)
updateLastPing
(
id
NodeID
,
instance
time
.
Time
)
error
{
return
db
.
storeTime
(
db
.
key
(
id
,
nodeDBDiscoverPing
),
instance
)
}
// lastBond retrieves the time of the last successful bonding with a remote node.
func
(
db
*
nodeDB
)
lastBond
(
id
NodeID
)
time
.
Time
{
return
db
.
fetchTime
(
db
.
key
(
id
,
nodeDBDiscoverBond
))
}
// updateLastBond updates the last time we successfully bound to a remote node.
func
(
db
*
nodeDB
)
updateLastBond
(
id
NodeID
,
instance
time
.
Time
)
error
{
return
db
.
storeTime
(
db
.
key
(
id
,
nodeDBDiscoverBond
),
instance
)
}
// querySeeds retrieves a batch of nodes to be used as potential seed servers
// during bootstrapping the node into the network.
//
// Ideal seeds are the most recently seen nodes (highest probability to be still
// alive), but yet untried. However, since leveldb only supports dumb iteration
// we will instead start pulling in potential seeds that haven't been yet pinged
// since the start of the boot procedure.
//
// If the database runs out of potential seeds, we restart the startup counter
// and start iterating over the peers again.
func
(
db
*
nodeDB
)
querySeeds
(
n
int
)
[]
*
Node
{
startup
:=
db
.
startup
()
it
:=
db
.
lvl
.
NewIterator
(
nil
,
nil
)
defer
it
.
Release
()
nodes
:=
make
([]
*
Node
,
0
,
n
)
for
len
(
nodes
)
<
n
&&
it
.
Next
()
{
// Iterate until a discovery node is found
id
,
field
:=
db
.
splitKey
(
it
.
Key
())
if
field
!=
nodeDBDiscoverRoot
{
continue
}
// Retrieve the last ping time, and if older than startup, query
lastPing
:=
db
.
lastPing
(
id
)
if
lastPing
.
Before
(
startup
)
{
if
node
:=
db
.
node
(
id
);
node
!=
nil
{
nodes
=
append
(
nodes
,
node
)
}
}
}
// Reset the startup time if no seeds were found
if
len
(
nodes
)
==
0
{
db
.
updateStartup
(
time
.
Now
())
}
return
nodes
}
// close flushes and closes the database files.
func
(
db
*
nodeDB
)
close
()
{
db
.
lvl
.
Close
()
}
p2p/discover/table.go
View file @
8646365b
...
...
@@ -27,7 +27,7 @@ type Table struct {
mutex
sync
.
Mutex
// protects buckets, their content, and nursery
buckets
[
nBuckets
]
*
bucket
// index of known nodes by distance
nursery
[]
*
Node
// bootstrap nodes
cache
*
Cache
// cach
e of known nodes
db
*
nodeDB
// databas
e of known nodes
bondmu
sync
.
Mutex
bonding
map
[
NodeID
]
*
bondproc
...
...
@@ -61,15 +61,17 @@ type bucket struct {
entries
[]
*
Node
}
func
newTable
(
t
transport
,
ourID
NodeID
,
ourAddr
*
net
.
UDPAddr
,
seeder
*
Cache
)
*
Table
{
func
newTable
(
t
transport
,
ourID
NodeID
,
ourAddr
*
net
.
UDPAddr
,
nodeDBPath
string
)
*
Table
{
// If no seed cache was given, use an in-memory one
if
seeder
==
nil
{
seeder
,
_
=
NewMemoryCache
()
db
,
err
:=
newNodeDB
(
nodeDBPath
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infoln
(
"Failed to open node database:"
,
err
)
db
,
_
=
newNodeDB
(
""
)
}
// Create the bootstrap table
tab
:=
&
Table
{
net
:
t
,
cache
:
seeder
,
db
:
db
,
self
:
newNode
(
ourID
,
ourAddr
),
bonding
:
make
(
map
[
NodeID
]
*
bondproc
),
bondslots
:
make
(
chan
struct
{},
maxBondingPingPongs
),
...
...
@@ -91,6 +93,7 @@ func (tab *Table) Self() *Node {
// Close terminates the network listener and flushes the seed cache.
func
(
tab
*
Table
)
Close
()
{
tab
.
net
.
close
()
tab
.
db
.
close
()
}
// Bootstrap sets the bootstrap nodes. These nodes are used to connect
...
...
@@ -174,11 +177,10 @@ func (tab *Table) refresh() {
result
:=
tab
.
Lookup
(
randomID
(
tab
.
self
.
ID
,
ld
))
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)
seeds
:=
tab
.
cache
.
list
(
10
)
// Pick a batch of previously know seeds to lookup with
seeds
:=
tab
.
db
.
querySeeds
(
10
)
for
_
,
seed
:=
range
seeds
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"Seeding network with:"
,
seed
)
tab
.
cache
.
delete
(
seed
.
ID
)
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"Seeding network with"
,
seed
)
}
// Bootstrap the table with a self lookup
all
:=
tab
.
bondall
(
append
(
tab
.
nursery
,
seeds
...
))
...
...
@@ -249,7 +251,7 @@ func (tab *Table) bondall(nodes []*Node) (result []*Node) {
// of the process can be skipped.
func
(
tab
*
Table
)
bond
(
pinged
bool
,
id
NodeID
,
addr
*
net
.
UDPAddr
,
tcpPort
uint16
)
(
*
Node
,
error
)
{
var
n
*
Node
if
n
=
tab
.
cache
.
get
(
id
);
n
==
nil
{
if
n
=
tab
.
db
.
node
(
id
);
n
==
nil
{
tab
.
bondmu
.
Lock
()
w
:=
tab
.
bonding
[
id
]
if
w
!=
nil
{
...
...
@@ -282,8 +284,12 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
}
func
(
tab
*
Table
)
pingpong
(
w
*
bondproc
,
pinged
bool
,
id
NodeID
,
addr
*
net
.
UDPAddr
,
tcpPort
uint16
)
{
// Request a bonding slot to limit network usage
<-
tab
.
bondslots
defer
func
()
{
tab
.
bondslots
<-
struct
{}{}
}()
// Ping the remote side and wait for a pong
tab
.
db
.
updateLastPing
(
id
,
time
.
Now
())
if
w
.
err
=
tab
.
net
.
ping
(
id
,
addr
);
w
.
err
!=
nil
{
close
(
w
.
done
)
return
...
...
@@ -294,7 +300,15 @@ func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAdd
// waitping will simply time out.
tab
.
net
.
waitping
(
id
)
}
w
.
n
=
tab
.
cache
.
add
(
id
,
addr
,
tcpPort
)
// Bonding succeeded, update the node database
w
.
n
=
&
Node
{
ID
:
id
,
IP
:
addr
.
IP
,
DiscPort
:
addr
.
Port
,
TCPPort
:
int
(
tcpPort
),
}
tab
.
db
.
updateNode
(
w
.
n
)
tab
.
db
.
updateLastBond
(
id
,
time
.
Now
())
close
(
w
.
done
)
}
...
...
p2p/discover/table_test.go
View file @
8646365b
...
...
@@ -15,7 +15,7 @@ import (
func
TestTable_pingReplace
(
t
*
testing
.
T
)
{
doit
:=
func
(
newNodeIsResponding
,
lastInBucketIsResponding
bool
)
{
transport
:=
newPingRecorder
()
tab
:=
newTable
(
transport
,
NodeID
{},
&
net
.
UDPAddr
{},
nil
)
tab
:=
newTable
(
transport
,
NodeID
{},
&
net
.
UDPAddr
{},
""
)
last
:=
fillBucket
(
tab
,
200
)
pingSender
:=
randomID
(
tab
.
self
.
ID
,
200
)
...
...
@@ -145,7 +145,7 @@ func TestTable_closest(t *testing.T) {
test
:=
func
(
test
*
closeTest
)
bool
{
// for any node table, Target and N
tab
:=
newTable
(
nil
,
test
.
Self
,
&
net
.
UDPAddr
{},
nil
)
tab
:=
newTable
(
nil
,
test
.
Self
,
&
net
.
UDPAddr
{},
""
)
tab
.
add
(
test
.
All
)
// check that doClosest(Target, N) returns nodes
...
...
@@ -217,7 +217,7 @@ func TestTable_Lookup(t *testing.T) {
self
:=
gen
(
NodeID
{},
quickrand
)
.
(
NodeID
)
target
:=
randomID
(
self
,
200
)
transport
:=
findnodeOracle
{
t
,
target
}
tab
:=
newTable
(
transport
,
self
,
&
net
.
UDPAddr
{},
nil
)
tab
:=
newTable
(
transport
,
self
,
&
net
.
UDPAddr
{},
""
)
// lookup on empty table returns no nodes
if
results
:=
tab
.
Lookup
(
target
);
len
(
results
)
>
0
{
...
...
p2p/discover/udp.go
View file @
8646365b
...
...
@@ -144,7 +144,7 @@ type reply struct {
}
// ListenUDP returns a new table that listens for UDP packets on laddr.
func
ListenUDP
(
priv
*
ecdsa
.
PrivateKey
,
laddr
string
,
natm
nat
.
Interface
,
seeder
*
Cache
)
(
*
Table
,
error
)
{
func
ListenUDP
(
priv
*
ecdsa
.
PrivateKey
,
laddr
string
,
natm
nat
.
Interface
,
nodeDBPath
string
)
(
*
Table
,
error
)
{
addr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
laddr
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -153,12 +153,12 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, seeder
if
err
!=
nil
{
return
nil
,
err
}
tab
,
_
:=
newUDP
(
priv
,
conn
,
natm
,
seeder
)
tab
,
_
:=
newUDP
(
priv
,
conn
,
natm
,
nodeDBPath
)
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"Listening,"
,
tab
.
self
)
return
tab
,
nil
}
func
newUDP
(
priv
*
ecdsa
.
PrivateKey
,
c
conn
,
natm
nat
.
Interface
,
seeder
*
Cache
)
(
*
Table
,
*
udp
)
{
func
newUDP
(
priv
*
ecdsa
.
PrivateKey
,
c
conn
,
natm
nat
.
Interface
,
nodeDBPath
string
)
(
*
Table
,
*
udp
)
{
udp
:=
&
udp
{
conn
:
c
,
priv
:
priv
,
...
...
@@ -176,7 +176,7 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, seeder *Cache) (
realaddr
=
&
net
.
UDPAddr
{
IP
:
ext
,
Port
:
realaddr
.
Port
}
}
}
udp
.
Table
=
newTable
(
udp
,
PubkeyID
(
&
priv
.
PublicKey
),
realaddr
,
seeder
)
udp
.
Table
=
newTable
(
udp
,
PubkeyID
(
&
priv
.
PublicKey
),
realaddr
,
nodeDBPath
)
go
udp
.
loop
()
go
udp
.
readLoop
()
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
)
{
return
errExpired
}
if
t
.
cache
.
get
(
fromID
)
==
nil
{
if
t
.
db
.
node
(
fromID
)
==
nil
{
// No bond exists, we don't process the packet. This prevents
// an attack vector where the discovery protocol could be used
// to amplify traffic in a DDOS attack. A malicious actor
...
...
p2p/discover/udp_test.go
View file @
8646365b
...
...
@@ -41,7 +41,7 @@ func newUDPTest(t *testing.T) *udpTest {
remotekey
:
newkey
(),
remoteaddr
:
&
net
.
UDPAddr
{
IP
:
net
.
IP
{
1
,
2
,
3
,
4
},
Port
:
30303
},
}
test
.
table
,
test
.
udp
=
newUDP
(
test
.
localkey
,
test
.
pipe
,
nil
,
nil
)
test
.
table
,
test
.
udp
=
newUDP
(
test
.
localkey
,
test
.
pipe
,
nil
,
""
)
return
test
}
...
...
@@ -157,8 +157,12 @@ func TestUDP_findnode(t *testing.T) {
// ensure there's a bond with the test node,
// findnode won't be accepted otherwise.
test
.
table
.
cache
.
add
(
PubkeyID
(
&
test
.
remotekey
.
PublicKey
),
test
.
remoteaddr
,
99
)
test
.
table
.
db
.
updateNode
(
&
Node
{
ID
:
PubkeyID
(
&
test
.
remotekey
.
PublicKey
),
IP
:
test
.
remoteaddr
.
IP
,
DiscPort
:
test
.
remoteaddr
.
Port
,
TCPPort
:
99
,
})
// check that closest neighbors are returned.
test
.
packetIn
(
nil
,
findnodePacket
,
&
findnode
{
Target
:
testTarget
,
Expiration
:
futureExp
})
test
.
waitPacketOut
(
func
(
p
*
neighbors
)
{
...
...
p2p/server.go
View file @
8646365b
...
...
@@ -59,9 +59,9 @@ type Server struct {
// with the rest of the network.
BootstrapNodes
[]
*
discover
.
Node
//
SeedCache is the database containing the previously seen live nodes i
n
//
the network to use as potential bootstrap seeds
.
SeedCache
*
discover
.
Cache
//
NodeDatabase is the path to the database containing the previously see
n
//
live nodes in the network
.
NodeDatabase
string
// Protocols should contain the protocols supported
// by the server. Matching protocols are launched for
...
...
@@ -201,7 +201,7 @@ func (srv *Server) Start() (err error) {
}
// node table
ntab
,
err
:=
discover
.
ListenUDP
(
srv
.
PrivateKey
,
srv
.
ListenAddr
,
srv
.
NAT
,
srv
.
SeedCach
e
)
ntab
,
err
:=
discover
.
ListenUDP
(
srv
.
PrivateKey
,
srv
.
ListenAddr
,
srv
.
NAT
,
srv
.
NodeDatabas
e
)
if
err
!=
nil
{
return
err
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment