mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 12:46:44 +00:00
cademlia improvements
- parameter are Cademlia public fields - compulsory Hash, verifiable HashBits, Hash, RowLength, adjustable MaxAge, PurgeInterval, ProxSize - they default to package level constants and vars - row initialisation - adjustProx, updateProx to 'update depth' - proper global locking thanks to Prox - map from entries to peerInfo for GetPeers - call disconnect on the worst peer expunged when inserting - locking for purge - extract self.Distance <- self.DistanceTo (made public method) - call disconnect when purging
This commit is contained in:
parent
15873f5e24
commit
26c625d8e6
1 changed files with 104 additions and 36 deletions
140
p2p/cademlia.go
140
p2p/cademlia.go
|
|
@ -13,31 +13,33 @@ var cadlogger = ethlogger.NewLogger("CAD")
|
||||||
const (
|
const (
|
||||||
hashBits = 160
|
hashBits = 160
|
||||||
rowLength = 10
|
rowLength = 10
|
||||||
maxAge = 1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var maxAge = 180 * time.Nanosecond
|
||||||
|
var purgeInterval = 300 * time.Second
|
||||||
|
|
||||||
type Cademlia struct {
|
type Cademlia struct {
|
||||||
hash []byte
|
Hash []byte
|
||||||
hashBits int
|
HashBits int
|
||||||
rowLength int
|
RowLength int
|
||||||
rows [hashBits]*row
|
|
||||||
|
|
||||||
depth int
|
MaxProxSize int
|
||||||
|
|
||||||
maxAge time.Duration
|
MaxAge time.Duration
|
||||||
purgeInterval time.Duration
|
PurgeInterval time.Duration
|
||||||
|
|
||||||
|
proxLimit int
|
||||||
|
proxSize int
|
||||||
|
|
||||||
|
rows []*row
|
||||||
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
quitC chan bool
|
quitC chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCademlia(hash []byte) *Cademlia {
|
func NewCademlia(hash []byte) *Cademlia {
|
||||||
return &Cademlia{
|
return &Cademlia{
|
||||||
hash: hash,
|
Hash: hash, // compulsory fields without default
|
||||||
hashBits: hashBits,
|
|
||||||
rowLength: rowLength,
|
|
||||||
maxAge: maxAge * time.Second,
|
|
||||||
rows: [hashBits]*row{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +49,28 @@ func (self *Cademlia) Start() error {
|
||||||
if self.quitC != nil {
|
if self.quitC != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// these + self.Hash can and should be checked against the
|
||||||
|
// saved file/db
|
||||||
|
if self.HashBits == 0 {
|
||||||
|
self.HashBits = hashBits
|
||||||
|
}
|
||||||
|
if self.RowLength == 0 {
|
||||||
|
self.RowLength = rowLength
|
||||||
|
}
|
||||||
|
// runtime parameters
|
||||||
|
if self.MaxProxSize == 0 {
|
||||||
|
self.MaxProxSize = self.RowLength
|
||||||
|
}
|
||||||
|
if self.MaxAge == time.Duration(0) {
|
||||||
|
self.MaxAge = maxAge
|
||||||
|
}
|
||||||
|
if self.PurgeInterval == time.Duration(0) {
|
||||||
|
self.PurgeInterval = purgeInterval
|
||||||
|
}
|
||||||
|
self.rows = make([]*row, self.HashBits)
|
||||||
|
for i, _ := range self.rows {
|
||||||
|
self.rows[i] = &row{} // will initialise row{int(0),[]*entry(nil),sync.Mutex}
|
||||||
|
}
|
||||||
self.quitC = make(chan bool)
|
self.quitC = make(chan bool)
|
||||||
go self.purgeLoop()
|
go self.purgeLoop()
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -63,12 +87,14 @@ func (self *Cademlia) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Cademlia) AddPeer(peer peerInfo) (err error) {
|
func (self *Cademlia) AddPeer(peer peerInfo) (err error) {
|
||||||
index := self.commonPrefixLength(peer.Hash())
|
self.lock.Lock()
|
||||||
|
defer self.lock.Unlock()
|
||||||
|
index := self.DistanceTo(peer.Hash())
|
||||||
row := self.rows[index]
|
row := self.rows[index]
|
||||||
needed := row.insert(&entry{peer: peer})
|
added := row.insert(&entry{peer: peer})
|
||||||
if needed {
|
if added {
|
||||||
if index >= self.depth {
|
if index >= self.proxLimit {
|
||||||
go self.updateDepth()
|
go self.adjustProx(index, 1)
|
||||||
}
|
}
|
||||||
cadlogger.Infof("accept peer %x...", peer.Hash()[:8])
|
cadlogger.Infof("accept peer %x...", peer.Hash()[:8])
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -78,16 +104,43 @@ func (self *Cademlia) AddPeer(peer peerInfo) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Cademlia) adjustProx(r int, add int) {
|
||||||
|
if self.proxSize+add > self.MaxProxSize &&
|
||||||
|
self.rows[r].len() > 0 {
|
||||||
|
self.proxLimit--
|
||||||
|
} else {
|
||||||
|
self.proxSize += add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Cademlia) updateProx() {
|
||||||
|
var sum, proxSize int
|
||||||
|
for _, r := range self.rows {
|
||||||
|
sum += r.len()
|
||||||
|
if sum <= self.MaxProxSize || r.len() == 0 {
|
||||||
|
proxSize = sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.lock.Lock()
|
||||||
|
self.proxSize = proxSize
|
||||||
|
self.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Cademlia) GetPeers(target []byte) (peers []peerInfo) {
|
func (self *Cademlia) GetPeers(target []byte) (peers []peerInfo) {
|
||||||
index := self.commonPrefixLength(target)
|
self.lock.RLock()
|
||||||
|
defer self.lock.RUnlock()
|
||||||
|
index := self.DistanceTo(target)
|
||||||
var entries []*entry
|
var entries []*entry
|
||||||
if index >= self.depth {
|
if index >= self.proxLimit {
|
||||||
for i := self.depth; i < self.hashBits; i++ {
|
for i := self.proxLimit; i < self.HashBits; i++ {
|
||||||
entries = append(entries, self.rows[i].row...)
|
entries = append(entries, self.rows[i].row...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entries = self.rows[index].row
|
entries = self.rows[index].row
|
||||||
}
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
peers = append(peers, entry.peer)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,16 +155,23 @@ type row struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *row) insert(entry *entry) (ok bool) {
|
func (self *row) len() int {
|
||||||
|
self.lock.RLock()
|
||||||
|
defer self.lock.RUnlock()
|
||||||
|
return self.length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *row) insert(entry *entry) (added bool) {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
if len(self.row) >= self.length {
|
if len(self.row) >= self.length { // >= allows us to add peers beyond the Rowlength limitation
|
||||||
worst := self.worst()
|
worst := self.worst()
|
||||||
// err = diconnectF(self.row[worst])
|
self.row[worst].peer.Disconnect(DiscSubprotocolError)
|
||||||
self.row[worst] = entry
|
self.row[worst] = entry
|
||||||
} else {
|
} else {
|
||||||
self.row = append(self.row, entry)
|
self.row = append(self.row, entry)
|
||||||
ok = true
|
added = true
|
||||||
|
self.length++
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -128,33 +188,37 @@ func (self *row) worst() (index int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *row) purge(recently time.Time) {
|
func (self *row) purge(recently time.Time) {
|
||||||
|
self.lock.Lock()
|
||||||
var newRow []*entry
|
var newRow []*entry
|
||||||
for _, entry := range self.row {
|
for _, entry := range self.row {
|
||||||
if !entry.peer.LastActive().Before(recently) {
|
if !entry.peer.LastActive().Before(recently) {
|
||||||
newRow = append(newRow, entry)
|
newRow = append(newRow, entry)
|
||||||
} else {
|
} else {
|
||||||
// self.DisconnectF(entry.peer)
|
entry.peer.Disconnect(DiscSubprotocolError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.row = newRow
|
||||||
|
self.length = len(newRow)
|
||||||
|
self.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Hash(key []byte) []byte {
|
func Hash(key []byte) []byte {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Cademlia) updateDepth() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Cademlia) purgeLoop() {
|
func (self *Cademlia) purgeLoop() {
|
||||||
ticker := time.Tick(self.purgeInterval)
|
ticker := time.Tick(self.PurgeInterval)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-self.quitC:
|
||||||
return
|
return
|
||||||
case <-ticker:
|
case <-ticker:
|
||||||
|
self.lock.Lock()
|
||||||
for _, r := range self.rows {
|
for _, r := range self.rows {
|
||||||
r.purge(time.Now().Add(-self.maxAge))
|
r.purge(time.Now().Add(-self.MaxAge))
|
||||||
}
|
}
|
||||||
|
self.updateProx()
|
||||||
|
self.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,14 +230,18 @@ func Xor(one, other []byte) (xor []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Cademlia) commonPrefixLength(other []byte) (ret int) {
|
func (self *Cademlia) DistanceTo(other []byte) (ret int) {
|
||||||
xor := Xor(self.hash, other)
|
return self.Distance(self.Hash, other)
|
||||||
for i := 0; i < self.hashBits; i++ {
|
}
|
||||||
|
|
||||||
|
func (self *Cademlia) Distance(one, other []byte) (ret int) {
|
||||||
|
xor := Xor(one, other)
|
||||||
|
for i := 0; i < self.HashBits; i++ {
|
||||||
for j := 0; j < 8; j++ {
|
for j := 0; j < 8; j++ {
|
||||||
if (xor[i]>>uint8(7-j))&0x1 != 0 {
|
if (xor[i]>>uint8(7-j))&0x1 != 0 {
|
||||||
return i*8 + j
|
return i*8 + j
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.hashBits*8 - 1
|
return self.HashBits*8 - 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue