swarm/network, pot, swarm/pss: kademlia fixes

This commit is contained in:
zelig 2017-06-09 13:41:29 +02:00 committed by Lewis Marshall
parent 77b5ff3ff1
commit 82150d65cb
14 changed files with 693 additions and 801 deletions

View file

@ -255,7 +255,7 @@ func (self *Network) newConn(oneID, otherID discover.NodeID) (*Conn, error) {
if other == nil { if other == nil {
return nil, fmt.Errorf("other %v does not exist", other) return nil, fmt.Errorf("other %v does not exist", other)
} }
distance, _ := pot.NewBytesVal(one.Addr(), nil).PO(pot.NewBytesVal(other.Addr(), nil), 0) distance, _ := pot.DefaultPof(256)(one.Addr(), other.Addr(), 0)
return &Conn{ return &Conn{
One: oneID, One: oneID,
Other: otherID, Other: otherID,

View file

@ -13,6 +13,8 @@
// //
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package pot see doc.go
package pot package pot
import ( import (
@ -26,35 +28,40 @@ import (
) )
var ( var (
zeroAddr = &common.Hash{}
zerosHex = zeroAddr.Hex()[2:]
zerosBin = Address{}.Bin() zerosBin = Address{}.Bin()
) )
var ( // Address is an alias for common.Hash
addrlen = keylen
)
type Address common.Hash type Address common.Hash
// NewAddressFromBytes constructs an Address from a byte slice
func NewAddressFromBytes(b []byte) Address {
h := common.Hash{}
copy(h[:], b)
return Address(h)
}
func (a Address) String() string { func (a Address) String() string {
return fmt.Sprintf("%x", a[:]) return fmt.Sprintf("%x", a[:])
} }
// MarshalJSON Address serialisation
func (a *Address) MarshalJSON() (out []byte, err error) { func (a *Address) MarshalJSON() (out []byte, err error) {
return []byte(`"` + a.String() + `"`), nil return []byte(`"` + a.String() + `"`), nil
} }
// UnmarshalJSON Address deserialisation
func (a *Address) UnmarshalJSON(value []byte) error { func (a *Address) UnmarshalJSON(value []byte) error {
*a = Address(common.HexToHash(string(value[1 : len(value)-1]))) *a = Address(common.HexToHash(string(value[1 : len(value)-1])))
return nil return nil
} }
// the string form of the binary representation of an address (only first 8 bits) // Bin returns the string form of the binary representation of an address (only first 8 bits)
func (a Address) Bin() string { func (a Address) Bin() string {
return ToBin(a[:]) return ToBin(a[:])
} }
// ToBin converts a byteslice to the string binary representation
func ToBin(a []byte) string { func ToBin(a []byte) string {
var bs []string var bs []string
for _, b := range a { for _, b := range a {
@ -63,6 +70,7 @@ func ToBin(a []byte) string {
return strings.Join(bs, "") return strings.Join(bs, "")
} }
// Bytes returns the Address as a byte slice
func (a Address) Bytes() []byte { func (a Address) Bytes() []byte {
return a[:] return a[:]
} }
@ -107,23 +115,23 @@ func posProximity(one, other Address, pos int) (ret int, eq bool) {
return len(one) * 8, true return len(one) * 8, true
} }
// Address.ProxCmp compares the distances a->target and b->target. // ProxCmp compares the distances a->target and b->target.
// Returns -1 if a is closer to target, 1 if b is closer to target // Returns -1 if a is closer to target, 1 if b is closer to target
// and 0 if they are equal. // and 0 if they are equal.
func (target Address) ProxCmp(a, b Address) int { func (a Address) ProxCmp(x, y Address) int {
for i := range target { for i := range a {
da := a[i] ^ target[i] dx := x[i] ^ a[i]
db := b[i] ^ target[i] dy := y[i] ^ a[i]
if da > db { if dx > dy {
return 1 return 1
} else if da < db { } else if dx < dy {
return -1 return -1
} }
} }
return 0 return 0
} }
// randomAddressAt(address, prox) generates a random address // RandomAddressAt (address, prox) generates a random address
// at proximity order prox relative to address // at proximity order prox relative to address
// if prox is negative a random address is generated // if prox is negative a random address is generated
func RandomAddressAt(self Address, prox int) (addr Address) { func RandomAddressAt(self Address, prox int) (addr Address) {
@ -148,71 +156,12 @@ func RandomAddressAt(self Address, prox int) (addr Address) {
return return
} }
// KeyRange(a0, a1, proxLimit) returns the address inclusive address // RandomAddress generates a random address
// range that contain addresses closer to one than other
// func KeyRange(one, other Address, proxLimit int) (start, stop Address) {
// prox := proximity(one, other)
// if prox >= proxLimit {
// prox = proxLimit
// }
// start = CommonBitsAddrByte(one, other, byte(0x00), prox)
// stop = CommonBitsAddrByte(one, other, byte(0xff), prox)
// return
// }
func CommonBitsAddrF(self, other Address, f func() byte, p int) (addr Address) {
prox, _ := proximity(self, other)
var pos int
if p <= prox {
prox = p
}
pos = prox / 8
addr = self
trans := byte(prox % 8)
var transbytea byte
if p > prox {
transbytea = byte(0x7f)
} else {
transbytea = byte(0xff)
}
transbytea >>= trans
transbyteb := transbytea ^ byte(0xff)
addrpos := addr[pos]
addrpos &= transbyteb
if p > prox {
addrpos ^= byte(0x80 >> trans)
}
addrpos |= transbytea & f()
addr[pos] = addrpos
for i := pos + 1; i < len(addr); i++ {
addr[i] = f()
}
return
}
func CommonBitsAddr(self, other Address, prox int) (addr Address) {
return CommonBitsAddrF(self, other, func() byte { return byte(rand.Intn(255)) }, prox)
}
func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) {
return CommonBitsAddrF(self, other, func() byte { return b }, prox)
}
// randomAddressAt() generates a random address
func RandomAddress() Address { func RandomAddress() Address {
return RandomAddressAt(Address{}, -1) return RandomAddressAt(Address{}, -1)
} }
// wraps an Address to implement the PotVal interface // NewAddressFromString creates a byte slice from a string in binary representation
type HashAddress struct {
Address
}
func (a *HashAddress) String() string {
return a.Address.Bin()
}
func NewAddressFromString(s string) []byte { func NewAddressFromString(s string) []byte {
ha := [32]byte{} ha := [32]byte{}
@ -227,85 +176,16 @@ func NewAddressFromString(s string) []byte {
return ha[:] return ha[:]
} }
func NewHashAddress(s string) *HashAddress { // BytesAddress is an interface for elements addressable by a byte slice
ha := NewAddressFromString(s)
h := common.Hash{}
copy(h[:], ha)
return &HashAddress{Address(h)}
}
func NewHashAddressFromBytes(b []byte) *HashAddress {
h := common.Hash{}
copy(h[:], b)
return &HashAddress{Address(h)}
}
// PO(addr, pos) return the proximity order of addr wrt to
// the pinned address of the tree
// assuming it is greater than or equal to pos
func (self *HashAddress) PO(val PotVal, pos int) (po int, eq bool) {
return posProximity(self.Address, val.(*HashAddress).Address, pos)
}
type BoolAddress struct {
addr []bool
}
func NewBoolAddress(s string) *BoolAddress {
return NewBoolAddressXOR(s, zerosBin[:len(s)])
}
func NewBoolAddressXOR(s, t string) *BoolAddress {
if len(s) != len(t) {
panic("lengths do not match")
}
addr := make([]bool, len(s))
for i, _ := range addr {
addr[i] = s[i] != t[i]
}
return &BoolAddress{addr}
}
func (self *BoolAddress) String() string {
a := self.addr
s := []byte(zerosBin)[:len(a)]
for i, one := range a {
if one {
s[i] = byte('1')
}
}
return string(s)
}
func (self *BoolAddress) PO(val PotVal, pos int) (po int, eq bool) {
a := self.addr
b := val.(*BoolAddress).addr
for po = pos; po < len(b); po++ {
if a[po] != b[po] {
return po, false
}
}
return po, true
}
type BytesAddress interface { type BytesAddress interface {
Address() []byte Address() []byte
} }
type bytesAddress struct { // ToBytes turns the Val into bytes
bytes []byte func ToBytes(v Val) []byte {
toBytes func(v AnyVal) []byte if v == nil {
} return nil
func NewBytesVal(v AnyVal, f func(v AnyVal) []byte) *bytesAddress {
if f == nil {
f = ToBytes
} }
b := f(v)
return &bytesAddress{b, f}
}
func ToBytes(v AnyVal) []byte {
b, ok := v.([]byte) b, ok := v.([]byte)
if !ok { if !ok {
ba, ok := v.(BytesAddress) ba, ok := v.(BytesAddress)
@ -317,15 +197,17 @@ func ToBytes(v AnyVal) []byte {
return b return b
} }
func (a *bytesAddress) String() string { // DefaultPof returns a proximity order operator function
return fmt.Sprintf("%08b", a.bytes) // where all
} func DefaultPof(max int) func(one, other Val, pos int) (int, bool) {
func (a *bytesAddress) Address() []byte { return func(one, other Val, pos int) (int, bool) {
return a.bytes po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos)
} if po >= max {
eq = true
func (a *bytesAddress) PO(val PotVal, i int) (int, bool) { po = max
return proximityOrder(a.bytes, a.toBytes(val), i) }
return po, eq
}
} }
func proximityOrder(one, other []byte, pos int) (int, bool) { func proximityOrder(one, other []byte, pos int) (int, bool) {
@ -346,3 +228,17 @@ func proximityOrder(one, other []byte, pos int) (int, bool) {
} }
return len(one) * 8, true return len(one) * 8, true
} }
// Label displays the node's key in binary format
func Label(v Val) string {
if v == nil {
return "<nil>"
}
if s, ok := v.(fmt.Stringer); ok {
return s.String()
}
if b, ok := v.([]byte); ok {
return ToBin(b)
}
panic(fmt.Sprintf("unsupported value type %T", v))
}

View file

@ -15,127 +15,128 @@
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package pot package pot
import ( //
"math/rand" // import (
"reflect" // "math/rand"
"testing" // "reflect"
// "testing"
"github.com/ethereum/go-ethereum/common" //
) // "github.com/ethereum/go-ethereum/common"
// )
func (Address) Generate(rand *rand.Rand, size int) reflect.Value { // //
var id Address // // func (Address) Generate(rand *rand.Rand, size int) reflect.Value {
for i := 0; i < len(id); i++ { // // var id Address
id[i] = byte(uint8(rand.Intn(255))) // // for i := 0; i < len(id); i++ {
} // // id[i] = byte(uint8(rand.Intn(255)))
return reflect.ValueOf(id) // // }
} // // return reflect.ValueOf(id)
// // }
func TestCommonBitsAddrF(t *testing.T) { //
a := Address(common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) // func TestCommonBitsAddrF(t *testing.T) {
b := Address(common.HexToHash("0x8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) // a := Address(common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
c := Address(common.HexToHash("0x4123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) // b := Address(common.HexToHash("0x8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
d := Address(common.HexToHash("0x0023456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) // c := Address(common.HexToHash("0x4123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
e := Address(common.HexToHash("0x01A3456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) // d := Address(common.HexToHash("0x0023456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
ab := CommonBitsAddrF(a, b, func() byte { return byte(0x00) }, 10) // e := Address(common.HexToHash("0x01A3456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
expab := Address(common.HexToHash("0x8000000000000000000000000000000000000000000000000000000000000000")) // ab := CommonBitsAddrF(a, b, func() byte { return byte(0x00) }, 10)
// expab := Address(common.HexToHash("0x8000000000000000000000000000000000000000000000000000000000000000"))
if ab != expab { //
t.Fatalf("%v != %v", ab, expab) // if ab != expab {
} // t.Fatalf("%v != %v", ab, expab)
ac := CommonBitsAddrF(a, c, func() byte { return byte(0x00) }, 10) // }
expac := Address(common.HexToHash("0x4000000000000000000000000000000000000000000000000000000000000000")) // ac := CommonBitsAddrF(a, c, func() byte { return byte(0x00) }, 10)
// expac := Address(common.HexToHash("0x4000000000000000000000000000000000000000000000000000000000000000"))
if ac != expac { //
t.Fatalf("%v != %v", ac, expac) // if ac != expac {
} // t.Fatalf("%v != %v", ac, expac)
ad := CommonBitsAddrF(a, d, func() byte { return byte(0x00) }, 10) // }
expad := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) // ad := CommonBitsAddrF(a, d, func() byte { return byte(0x00) }, 10)
// expad := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"))
if ad != expad { //
t.Fatalf("%v != %v", ad, expad) // if ad != expad {
} // t.Fatalf("%v != %v", ad, expad)
ae := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 10) // }
expae := Address(common.HexToHash("0x0180000000000000000000000000000000000000000000000000000000000000")) // ae := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 10)
// expae := Address(common.HexToHash("0x0180000000000000000000000000000000000000000000000000000000000000"))
if ae != expae { //
t.Fatalf("%v != %v", ae, expae) // if ae != expae {
} // t.Fatalf("%v != %v", ae, expae)
acf := CommonBitsAddrF(a, c, func() byte { return byte(0xff) }, 10) // }
expacf := Address(common.HexToHash("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // acf := CommonBitsAddrF(a, c, func() byte { return byte(0xff) }, 10)
// expacf := Address(common.HexToHash("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
if acf != expacf { //
t.Fatalf("%v != %v", acf, expacf) // if acf != expacf {
} // t.Fatalf("%v != %v", acf, expacf)
aeo := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 2) // }
expaeo := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) // aeo := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 2)
// expaeo := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"))
if aeo != expaeo { //
t.Fatalf("%v != %v", aeo, expaeo) // if aeo != expaeo {
} // t.Fatalf("%v != %v", aeo, expaeo)
aep := CommonBitsAddrF(a, e, func() byte { return byte(0xff) }, 2) // }
expaep := Address(common.HexToHash("0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // aep := CommonBitsAddrF(a, e, func() byte { return byte(0xff) }, 2)
// expaep := Address(common.HexToHash("0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
if aep != expaep { //
t.Fatalf("%v != %v", aep, expaep) // if aep != expaep {
} // t.Fatalf("%v != %v", aep, expaep)
// }
} //
// }
func TestRandomAddressAt(t *testing.T) { //
var a Address // func TestRandomAddressAt(t *testing.T) {
for i := 0; i < 100; i++ { // var a Address
a = RandomAddress() // for i := 0; i < 100; i++ {
prox := rand.Intn(255) // a = RandomAddress()
b := RandomAddressAt(a, prox) // prox := rand.Intn(255)
p, _ := proximity(a, b) // b := RandomAddressAt(a, prox)
if p != prox { // p, _ := proximity(a, b)
t.Fatalf("incorrect address prox(%v, %v) == %v (expected %v)", a, b, p, prox) // if p != prox {
} // t.Fatalf("incorrect address prox(%v, %v) == %v (expected %v)", a, b, p, prox)
} // }
} // }
// }
const ( //
maxTestPOs = 1000 // const (
testPOkeylen = 9 // maxTestPOs = 1000
) // testPOkeylen = 9
// )
func TestPOs(t *testing.T) { //
for i := 0; i < maxTestPOs; i++ { // func TestPOs(t *testing.T) {
length := rand.Intn(256) + 1 // for i := 0; i < maxTestPOs; i++ {
v0 := RandomAddress().Bin()[:length] // length := rand.Intn(256) + 1
v1 := RandomAddress().Bin()[:length] // v0 := RandomAddress().Bin()[:length]
a0 := NewBoolAddress(v0) // v1 := RandomAddress().Bin()[:length]
a1 := NewBoolAddress(v1) // a0 := NewBoolAddress(v0)
b0 := NewHashAddress(v0) // a1 := NewBoolAddress(v1)
b1 := NewHashAddress(v1) // b0 := NewHashAddress(v0)
pos := rand.Intn(length) + 1 // b1 := NewHashAddress(v1)
apo, aeq := a0.PO(a1, pos) // pos := rand.Intn(length) + 1
bpo, beq := b0.PO(b1, pos) // apo, aeq := a0.PO(a1, pos)
if bpo == 256 { // bpo, beq := b0.PO(b1, pos)
bpo = length // if bpo == 256 {
} // bpo = length
a0s := a0.String() // }
if a0s != v0 { // a0s := a0.String()
t.Fatalf("incorrect bool address. expected %v, got %v", v0, a0s) // if a0s != v0 {
} // t.Fatalf("incorrect bool address. expected %v, got %v", v0, a0s)
a1s := a1.String() // }
if a1s != v1 { // a1s := a1.String()
t.Fatalf("incorrect bool address. expected %v, got %v", v1, a1s) // if a1s != v1 {
} // t.Fatalf("incorrect bool address. expected %v, got %v", v1, a1s)
b0s := b0.String()[:length] // }
if b0s != v0 { // b0s := b0.String()[:length]
t.Fatalf("incorrect hash address. expected %v, got %v", v0, b0s) // if b0s != v0 {
} // t.Fatalf("incorrect hash address. expected %v, got %v", v0, b0s)
b1s := b1.String()[:length] // }
if b1s != v1 { // b1s := b1.String()[:length]
t.Fatalf("incorrect hash address. expected %v, got %v", v1, b1s) // if b1s != v1 {
} // t.Fatalf("incorrect hash address. expected %v, got %v", v1, b1s)
if apo != bpo { // }
t.Fatalf("PO does not match for %v X %v (pos: %v): expected %v, got %v", v0, v1, pos, apo, bpo) // if apo != bpo {
} // t.Fatalf("PO does not match for %v X %v (pos: %v): expected %v, got %v", v0, v1, pos, apo, bpo)
if aeq != beq { // }
t.Fatalf("PO equality does not match for %v X %v (pos: %v): expected %v, got %v", v0, v1, pos, aeq, beq) // if aeq != beq {
} // t.Fatalf("PO equality does not match for %v X %v (pos: %v): expected %v, got %v", v0, v1, pos, aeq, beq)
} // }
} // }
// }

View file

@ -1,5 +1,21 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
/* /*
POT: proximity order tree implements a container similar to a binary tree. Package pot (proximity order tree) implements a container similar to a binary tree.
Value types implement the PoVal interface which provides the PO (proximity order) Value types implement the PoVal interface which provides the PO (proximity order)
comparison operator. comparison operator.
Each fork in the trie is itself a value. Values of the subtree contained under Each fork in the trie is itself a value. Values of the subtree contained under

View file

@ -13,6 +13,8 @@
// //
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package pot see doc.go
package pot package pot
import ( import (
@ -33,66 +35,69 @@ type Pot struct {
// pot is the node type (same for root, branching node and leaf) // pot is the node type (same for root, branching node and leaf)
type pot struct { type pot struct {
pin PotVal pin Val
bins []*pot bins []*pot
size int size int
po int po int
pof Pof
} }
// PotVal is the interface the generic container item should implement // Val is the element type for pots
type PotVal interface { type Val interface{}
PO(PotVal, int) (po int, eq bool)
String() string
}
type AnyVal interface{} // Pof is the proximity order function
type Pof func(Val, Val, int) (int, bool)
// Pot constructor. Requires value of type PotVal to pin // NewPot constructor. Requires value of type Val to pin
// and po to point to a span in the PotVal key // and po to point to a span in the Val key
// The pinned item counts towards the size // The pinned item counts towards the size
func NewPot(v PotVal, po int) *Pot { func NewPot(v Val, po int, pof Pof) *Pot {
var size int var size int
if v != nil { if v != nil {
size++ size++
} }
if pof == nil {
pof = DefaultPof(keylen)
}
return &Pot{ return &Pot{
pot: &pot{ pot: &pot{
pin: v, pin: v,
po: po, po: po,
size: size, size: size,
pof: pof,
}, },
} }
} }
// Pin() returns the pinned element (key) of the Pot // Pin returns the pinned element (key) of the Pot
func (t *Pot) Pin() PotVal { func (t *Pot) Pin() Val {
return t.pin return t.pin
} }
// Size() returns the number of values in the Pot // Size returns the number of values in the Pot
func (t *Pot) Size() int { func (t *Pot) Size() int {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
return t.size return t.size
} }
// Add(v) inserts v into the Pot and // Add inserts v into the Pot and
// returns the proximity order of v and a boolean // returns the proximity order of v and a boolean
// indicating if the item was found // indicating if the item was found
// Add locks the Pot while using applicative add on its pot // Add locks the Pot while using applicative add on its pot
func (t *Pot) Add(val PotVal) (po int, found bool) { func (t *Pot) Add(val Val) (po int, found bool) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
t.pot, po, found = add(t.pot, val) t.pot, po, found = add(t.pot, val)
return po, found return po, found
} }
// Add(t, v) returns a new Pot that contains all the elements of t // Add called on (t, v) returns a new Pot that contains all the elements of t
// plus the value v, using the applicative add // plus the value v, using the applicative add
// the second return value is the proximity order of the inserted element // the second return value is the proximity order of the inserted element
// the third is boolean indicating if the item was found // the third is boolean indicating if the item was found
// it only readlocks the Pot while reading its pot // it only readlocks the Pot while reading its pot
func Add(t *Pot, val PotVal) (*Pot, int, bool) { func Add(t *Pot, val Val) (*Pot, int, bool) {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
@ -100,25 +105,28 @@ func Add(t *Pot, val PotVal) (*Pot, int, bool) {
return &Pot{pot: r}, po, found return &Pot{pot: r}, po, found
} }
func add(t *pot, val PotVal) (*pot, int, bool) { func (t *pot) clone() *pot {
return &pot{
pin: t.pin,
size: t.size,
po: t.po,
bins: t.bins,
pof: t.pof,
}
}
func add(t *pot, val Val) (*pot, int, bool) {
var r *pot var r *pot
if t == nil || t.pin == nil { if t == nil || t.pin == nil {
r = &pot{ r = t.clone()
pin: val, r.pin = val
size: t.size + 1, r.size++
po: t.po,
bins: t.bins,
}
return r, 0, false return r, 0, false
} }
po, found := t.pin.PO(val, t.po) po, found := t.pof(t.pin, val, t.po)
if found { if found {
r = &pot{ r = t.clone()
pin: val, r.pin = val
size: t.size,
po: t.po,
bins: t.bins,
}
return r, po, true return r, po, true
} }
@ -147,6 +155,7 @@ func add(t *pot, val PotVal) (*pot, int, bool) {
pin: val, pin: val,
size: 1, size: 1,
po: po, po: po,
pof: t.pof,
} }
} }
@ -158,28 +167,29 @@ func add(t *pot, val PotVal) (*pot, int, bool) {
size: size, size: size,
po: t.po, po: t.po,
bins: bins, bins: bins,
pof: t.pof,
} }
return r, po, found return r, po, found
} }
// T.Re move(v) deletes v from the Pot and returns // Remove called on (v) deletes v from the Pot and returns
// the proximity order of v and a boolean value indicating // the proximity order of v and a boolean value indicating
// if the value was found // if the value was found
// Remove locks Pot while using applicative remove on its pot // Remove locks Pot while using applicative remove on its pot
func (t *Pot) Remove(val PotVal) (po int, found bool) { func (t *Pot) Remove(val Val) (po int, found bool) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
t.pot, po, found = remove(t.pot, val) t.pot, po, found = remove(t.pot, val)
return po, found return po, found
} }
// Remove(t, v) returns a new Pot that contains all the elements of t // Remove called on (t, v) returns a new Pot that contains all the elements of t
// minus the value v, using the applicative remove // minus the value v, using the applicative remove
// the second return value is the proximity order of the inserted element // the second return value is the proximity order of the inserted element
// the third is boolean indicating if the item was found // the third is boolean indicating if the item was found
// it only readlocks the Pot while reading its pot // it only readlocks the Pot while reading its pot
func Remove(t *Pot, v PotVal) (*Pot, int, bool) { func Remove(t *Pot, v Val) (*Pot, int, bool) {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
@ -187,14 +197,15 @@ func Remove(t *Pot, v PotVal) (*Pot, int, bool) {
return &Pot{pot: r}, po, found return &Pot{pot: r}, po, found
} }
func remove(t *pot, val PotVal) (r *pot, po int, found bool) { func remove(t *pot, val Val) (r *pot, po int, found bool) {
size := t.size size := t.size
po, found = t.pin.PO(val, t.po) po, found = t.pof(t.pin, val, t.po)
if found { if found {
size-- size--
if size == 0 { if size == 0 {
r = &pot{ r = &pot{
po: t.po, po: t.po,
pof: t.pof,
} }
return r, po, true return r, po, true
} }
@ -205,6 +216,7 @@ func remove(t *pot, val PotVal) (r *pot, po int, found bool) {
bins: append(t.bins[:i], last.bins...), bins: append(t.bins[:i], last.bins...),
size: size, size: size,
po: t.po, po: t.po,
pof: t.pof,
} }
return r, t.po, true return r, t.po, true
} }
@ -237,58 +249,56 @@ func remove(t *pot, val PotVal) (r *pot, po int, found bool) {
size: size, size: size,
po: t.po, po: t.po,
bins: bins, bins: bins,
pof: t.pof,
} }
return r, po, found return r, po, found
} }
// Swap(k, f) looks up the item at k // Swap called on (k, f) looks up the item at k
// and applies the function f to the value v at k or nil if the item is not found // and applies the function f to the value v at k or nil if the item is not found
// if f returns nil, the element is removed // if f returns nil, the element is removed
// if f returns v' <> v then v' is inserted into the Pot // if f returns v' <> v then v' is inserted into the Pot
// if v' == v the pot is not changed // if v' == v the pot is not changed
// it panics if v'.PO(k, 0) says v and k are not equal // it panics if v'.PO(k, 0) says v and k are not equal
func (t *Pot) Swap(val AnyVal, f func(v PotVal) PotVal) (po int, found bool, change bool) { func (t *Pot) Swap(val Val, f func(v Val) Val) (po int, found bool, change bool) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
ba := NewBytesVal(val, nil)
var t0 *pot var t0 *pot
t0, po, found, change = swap(t.pot, ba, f) t0, po, found, change = swap(t.pot, val, f)
if change { if change {
t.pot = t0 t.pot = t0
} }
return po, found, change return po, found, change
} }
func swap(t *pot, k PotVal, f func(v PotVal) PotVal) (r *pot, po int, found bool, change bool) { func swap(t *pot, k Val, f func(v Val) Val) (r *pot, po int, found bool, change bool) {
var val PotVal var val Val
if t == nil || t.pin == nil { if t == nil || t.pin == nil {
val = f(nil) val = f(nil)
if val == nil { if val == nil {
return t, t.po, false, false return t, t.po, false, false
} }
if _, eq := val.PO(k, t.po); !eq { // if _, eq := t.pof(k, t.pin, t.po); !eq {
panic("value key mismatch") // panic("value key mismatch")
} // }
r = &pot{ r = t.clone()
pin: val, r.pin = val
size: t.size + 1, r.size++
po: t.po,
bins: t.bins,
}
return r, t.po, false, true return r, t.po, false, true
} }
size := t.size size := t.size
if k == nil { if k == nil {
panic("k is nil") panic("k is nil")
} }
po, found = k.PO(t.pin, t.po) po, found = t.pof(k, t.pin, t.po)
if found { if found {
val = f(t.pin) val = f(t.pin)
if val == nil { if val == nil {
size-- size--
if size == 0 { if size == 0 {
r = &pot{ r = &pot{
po: t.po, po: t.po,
pof: t.pof,
} }
return r, po, true, true return r, po, true, true
} }
@ -299,18 +309,15 @@ func swap(t *pot, k PotVal, f func(v PotVal) PotVal) (r *pot, po int, found bool
bins: append(t.bins[:i], last.bins...), bins: append(t.bins[:i], last.bins...),
size: size, size: size,
po: t.po, po: t.po,
pof: t.pof,
} }
return r, t.po, true, true return r, t.po, true, true
// remove element // remove element
} else if val == t.pin { } else if val == t.pin {
return nil, po, true, false return nil, po, true, false
} else { // add element } else { // add element
r = &pot{ r = t.clone()
pin: val, r.pin = val
size: t.size,
po: t.po,
bins: t.bins,
}
return r, po, true, true return r, po, true, true
} }
} }
@ -344,6 +351,7 @@ func swap(t *pot, k PotVal, f func(v PotVal) PotVal) (r *pot, po int, found bool
pin: val, pin: val,
size: 1, size: 1,
po: po, po: po,
pof: t.pof,
} }
} }
@ -357,12 +365,13 @@ func swap(t *pot, k PotVal, f func(v PotVal) PotVal) (r *pot, po int, found bool
size: size, size: size,
po: t.po, po: t.po,
bins: bins, bins: bins,
pof: t.pof,
} }
return r, po, found, true return r, po, found, true
} }
// t0.Merge(t1) changes t0 to contain all the elements of t1 // Merge called on (t1) changes t0 to contain all the elements of t1
// it locks t0, but only readlocks t1 while taking its pot // it locks t0, but only readlocks t1 while taking its pot
// uses applicative union // uses applicative union
func (t *Pot) Merge(t1 *Pot) (c int) { func (t *Pot) Merge(t1 *Pot) (c int) {
@ -388,9 +397,7 @@ func Union(t0, t1 *Pot) (*Pot, int) {
t1.lock.RUnlock() t1.lock.RUnlock()
p, c := union(n0, n1) p, c := union(n0, n1)
return &Pot{ return &Pot{pot: p}, c
pot: p,
}, c
} }
func union(t0, t1 *pot) (*pot, int) { func union(t0, t1 *pot) (*pot, int) {
@ -400,7 +407,7 @@ func union(t0, t1 *pot) (*pot, int) {
if t1 == nil || t1.size == 0 { if t1 == nil || t1.size == 0 {
return t0, 0 return t0, 0
} }
var pin PotVal var pin Val
var bins []*pot var bins []*pot
var mis []int var mis []int
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
@ -411,7 +418,7 @@ func union(t0, t1 *pot) (*pot, int) {
var i0, i1 int var i0, i1 int
var common int var common int
po, eq := pin0.PO(pin1, 0) po, eq := t0.pof(pin0, pin1, 0)
for { for {
l0 := len(bins0) l0 := len(bins0)
@ -486,6 +493,7 @@ func union(t0, t1 *pot) (*pot, int) {
bins: bins0[i:], bins: bins0[i:],
size: size0 + 1, size: size0 + 1,
po: po, po: po,
pof: t0.pof,
} }
bins2 := []*pot{np} bins2 := []*pot{np}
@ -499,7 +507,7 @@ func union(t0, t1 *pot) (*pot, int) {
bins2 = append(bins2, n0.bins...) bins2 = append(bins2, n0.bins...)
pin0 = pin1 pin0 = pin1
pin1 = n0.pin pin1 = n0.pin
po, eq = pin0.PO(pin1, n0.po) po, eq = t0.pof(pin0, pin1, n0.po)
} }
bins0 = bins1 bins0 = bins1
@ -518,21 +526,22 @@ func union(t0, t1 *pot) (*pot, int) {
bins: bins, bins: bins,
size: t0.size + t1.size - common, size: t0.size + t1.size - common,
po: t0.po, po: t0.po,
pof: t0.pof,
} }
return n, common return n, common
} }
// Each(f) is a synchronous iterator over the bins of a node // Each called with (f) is a synchronous iterator over the bins of a node
// respecting an ordering // respecting an ordering
// proximity > pinnedness // proximity > pinnedness
func (t *Pot) Each(f func(PotVal, int) bool) bool { func (t *Pot) Each(f func(Val, int) bool) bool {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
return n.each(f) return n.each(f)
} }
func (t *pot) each(f func(PotVal, int) bool) bool { func (t *pot) each(f func(Val, int) bool) bool {
var next bool var next bool
for _, n := range t.bins { for _, n := range t.bins {
if n == nil { if n == nil {
@ -546,7 +555,7 @@ func (t *pot) each(f func(PotVal, int) bool) bool {
return f(t.pin, t.po) return f(t.pin, t.po)
} }
// EachFrom(f, start) is a synchronous iterator over the elements of a pot // EachFrom called with (f, start) is a synchronous iterator over the elements of a pot
// within the inclusive range starting from proximity order start // within the inclusive range starting from proximity order start
// the function argument is passed the value and the proximity order wrt the root pin // the function argument is passed the value and the proximity order wrt the root pin
// it does NOT include the pinned item of the root // it does NOT include the pinned item of the root
@ -554,14 +563,14 @@ func (t *pot) each(f func(PotVal, int) bool) bool {
// proximity > pinnedness // proximity > pinnedness
// the iteration ends if the function return false or there are no more elements // the iteration ends if the function return false or there are no more elements
// end of a po range can be implemented since po is passed to the function // end of a po range can be implemented since po is passed to the function
func (t *Pot) EachFrom(f func(PotVal, int) bool, po int) bool { func (t *Pot) EachFrom(f func(Val, int) bool, po int) bool {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
return n.eachFrom(f, po) return n.eachFrom(f, po)
} }
func (t *pot) eachFrom(f func(PotVal, int) bool, po int) bool { func (t *pot) eachFrom(f func(Val, int) bool, po int) bool {
var next bool var next bool
_, lim := t.getPos(po) _, lim := t.getPos(po)
for i := lim; i < len(t.bins); i++ { for i := lim; i < len(t.bins); i++ {
@ -578,18 +587,18 @@ func (t *pot) eachFrom(f func(PotVal, int) bool, po int) bool {
// subtree passing the proximity order and the size // subtree passing the proximity order and the size
// the iteration continues until the function's return value is false // the iteration continues until the function's return value is false
// or there are no more subtries // or there are no more subtries
func (t *Pot) EachBin(val PotVal, po int, f func(int, int, func(func(val PotVal, i int) bool) bool) bool) { func (t *Pot) EachBin(val Val, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
n.eachBin(val, po, f) n.eachBin(val, po, f)
} }
func (t *pot) eachBin(val PotVal, po int, f func(int, int, func(func(val PotVal, i int) bool) bool) bool) { func (t *pot) eachBin(val Val, po int, f func(int, int, func(func(val Val, i int) bool) bool) bool) {
if t == nil || t.size == 0 { if t == nil || t.size == 0 {
return return
} }
spr, _ := t.pin.PO(val, t.po) spr, _ := t.pof(t.pin, val, t.po)
_, lim := t.getPos(spr) _, lim := t.getPos(spr)
var size int var size int
var n *pot var n *pot
@ -604,7 +613,7 @@ func (t *pot) eachBin(val PotVal, po int, f func(int, int, func(func(val PotVal,
} }
} }
if lim == len(t.bins) { if lim == len(t.bins) {
f(spr, 1, func(g func(PotVal, int) bool) bool { f(spr, 1, func(g func(Val, int) bool) bool {
return g(t.pin, spr) return g(t.pin, spr)
}) })
return return
@ -616,8 +625,8 @@ func (t *pot) eachBin(val PotVal, po int, f func(int, int, func(func(val PotVal,
spo++ spo++
size += n.size size += n.size
} }
if !f(spr, t.size-size, func(g func(PotVal, int) bool) bool { if !f(spr, t.size-size, func(g func(Val, int) bool) bool {
return t.eachFrom(func(v PotVal, j int) bool { return t.eachFrom(func(v Val, j int) bool {
return g(v, spr) return g(v, spr)
}, spo) }, spo)
}) { }) {
@ -628,17 +637,17 @@ func (t *pot) eachBin(val PotVal, po int, f func(int, int, func(func(val PotVal,
} }
} }
// syncronous iterator over neighbours of any target val // EachNeighbour is a syncronous iterator over neighbours of any target val
// the order of elements retrieved reflect proximity order to the target // the order of elements retrieved reflect proximity order to the target
// TODO: add maximum proxbin to start range of iteration // TODO: add maximum proxbin to start range of iteration
func (t *Pot) EachNeighbour(val PotVal, f func(PotVal, int) bool) bool { func (t *Pot) EachNeighbour(val Val, f func(Val, int) bool) bool {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
return n.eachNeighbour(val, f) return n.eachNeighbour(val, f)
} }
func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool { func (t *pot) eachNeighbour(val Val, f func(Val, int) bool) bool {
if t == nil || t.size == 0 { if t == nil || t.size == 0 {
return false return false
} }
@ -647,7 +656,7 @@ func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool {
var n *pot var n *pot
ir := l ir := l
il := l il := l
po, eq := t.pin.PO(val, t.po) po, eq := t.pof(t.pin, val, t.po)
if !eq { if !eq {
n, il = t.getPos(po) n, il = t.getPos(po)
if n != nil { if n != nil {
@ -667,7 +676,7 @@ func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool {
} }
for i := l - 1; i > ir; i-- { for i := l - 1; i > ir; i-- {
next = t.bins[i].each(func(v PotVal, _ int) bool { next = t.bins[i].each(func(v Val, _ int) bool {
return f(v, po) return f(v, po)
}) })
if !next { if !next {
@ -677,7 +686,7 @@ func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool {
for i := il - 1; i >= 0; i-- { for i := il - 1; i >= 0; i-- {
n := t.bins[i] n := t.bins[i]
next = n.each(func(v PotVal, _ int) bool { next = n.each(func(v Val, _ int) bool {
return f(v, n.po) return f(v, n.po)
}) })
if !next { if !next {
@ -687,7 +696,7 @@ func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool {
return true return true
} }
// EachNeighnbourAsync(val, max, maxPos, f, wait) is an asyncronous iterator // EachNeighbourAsync called on (val, max, maxPos, f, wait) is an asyncronous iterator
// over elements not closer than maxPos wrt val. // over elements not closer than maxPos wrt val.
// val does not need to be match an element of the pot, but if it does, and // val does not need to be match an element of the pot, but if it does, and
// maxPos is keylength than it is included in the iteration // maxPos is keylength than it is included in the iteration
@ -698,7 +707,7 @@ func (t *pot) eachNeighbour(val PotVal, f func(PotVal, int) bool) bool {
// or if the entire there are no nodes not closer than maxPos that is not visited // or if the entire there are no nodes not closer than maxPos that is not visited
// if wait is true, the iterator returns only if all calls to f are finished // if wait is true, the iterator returns only if all calls to f are finished
// TODO: implement minPos for proper prox range iteration // TODO: implement minPos for proper prox range iteration
func (t *Pot) EachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal, int), wait bool) { func (t *Pot) EachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int), wait bool) {
t.lock.RLock() t.lock.RLock()
n := t.pot n := t.pot
t.lock.RUnlock() t.lock.RUnlock()
@ -715,15 +724,14 @@ func (t *Pot) EachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal,
} }
} }
func (t *pot) eachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal, int), wg *sync.WaitGroup) (extra int) { func (t *pot) eachNeighbourAsync(val Val, max int, maxPos int, f func(Val, int), wg *sync.WaitGroup) (extra int) {
l := len(t.bins) l := len(t.bins)
var n *pot var n *pot
il := l il := l
ir := l ir := l
// ic := l // ic := l
po, eq := t.pin.PO(val, t.po) po, eq := t.pof(t.pin, val, t.po)
// if po is too close, set the pivot branch (pom) to maxPos // if po is too close, set the pivot branch (pom) to maxPos
pom := po pom := po
@ -799,7 +807,7 @@ func (t *pot) eachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal,
wg.Add(m) wg.Add(m)
} }
go func(pn *pot, pm int) { go func(pn *pot, pm int) {
pn.each(func(v PotVal, _ int) bool { pn.each(func(v Val, _ int) bool {
if wg != nil { if wg != nil {
defer wg.Done() defer wg.Done()
} }
@ -826,7 +834,7 @@ func (t *pot) eachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal,
wg.Add(m) wg.Add(m)
} }
go func(pn *pot, pm int) { go func(pn *pot, pm int) {
pn.each(func(v PotVal, _ int) bool { pn.each(func(v Val, _ int) bool {
if wg != nil { if wg != nil {
defer wg.Done() defer wg.Done()
} }
@ -840,7 +848,7 @@ func (t *pot) eachNeighbourAsync(val PotVal, max int, maxPos int, f func(PotVal,
return max + extra return max + extra
} }
// getPos(n) returns the forking node at PO n and its index if it exists // getPos called on (n) returns the forking node at PO n and its index if it exists
// otherwise nil // otherwise nil
// caller is suppoed to hold the lock // caller is suppoed to hold the lock
func (t *pot) getPos(po int) (n *pot, i int) { func (t *pot) getPos(po int) (n *pot, i int) {
@ -856,7 +864,7 @@ func (t *pot) getPos(po int) (n *pot, i int) {
return nil, len(t.bins) return nil, len(t.bins)
} }
// need(m, max, extra) uses max m out of extra, and then max // need called on (m, max, extra) uses max m out of extra, and then max
// if needed, returns the adjusted counts // if needed, returns the adjusted counts
func need(m, max, extra int) (int, int, int) { func need(m, max, extra int) (int, int, int) {
if m <= extra { if m <= extra {

View file

@ -37,55 +37,45 @@ func init() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
} }
type testBVAddr struct {
*HashAddress
i int
}
func NewTestBVAddr(s string, i int) *testBVAddr {
return &testBVAddr{NewHashAddress(s), i}
}
func (a *testBVAddr) String() string {
return a.HashAddress.String()[:keylen]
}
func (self *testBVAddr) PO(val PotVal, po int) (int, bool) {
return self.HashAddress.PO(val.(*testBVAddr).HashAddress, po)
}
type testAddr struct { type testAddr struct {
*BoolAddress a []byte
i int i int
} }
func NewTestAddr(s string, i int) *testAddr { //
return &testAddr{NewBoolAddress(s), i} // func newTestAddr(s string, i int) *testAddr {
// b := NewAddressFromString(s)
// h := &common.Hash{}
// copy((*h)[:], b)
// a := Address(*h)
// return &testAddr{&a, i}
// }
func newTestAddr(s string, i int) *testAddr {
return &testAddr{NewAddressFromString(s), i}
} }
func (self *testAddr) PO(val PotVal, po int) (int, bool) { func (a *testAddr) Address() []byte {
return self.BoolAddress.PO(val.(*testAddr).BoolAddress, po) return a.a
} }
func str(v PotVal) string { func (a *testAddr) String() string {
if v == nil { return Label(a.a)
return "" // return a.Address.String()[:keylen]
}
return v.(*testAddr).String()
} }
func randomTestAddr(n int, i int) *testAddr { func randomTestAddr(n int, i int) *testAddr {
v := RandomAddress().Bin()[:n] v := RandomAddress().Bin()[:n]
return NewTestAddr(v, i) return newTestAddr(v, i)
} }
func randomTestBVAddr(n int, i int) *testBVAddr { func randomtestAddr(n int, i int) *testAddr {
v := RandomAddress().Bin()[:n] v := RandomAddress().Bin()[:n]
return NewTestBVAddr(v, i) return newTestAddr(v, i)
} }
func indexes(t *Pot) (i []int, po []int) { func indexes(t *Pot) (i []int, po []int) {
t.Each(func(v PotVal, p int) bool { t.Each(func(v Val, p int) bool {
a := v.(*testAddr) a := v.(*testAddr)
i = append(i, a.i) i = append(i, a.i)
po = append(po, p) po = append(po, p)
@ -96,16 +86,16 @@ func indexes(t *Pot) (i []int, po []int) {
func testAdd(t *Pot, n int, values ...string) { func testAdd(t *Pot, n int, values ...string) {
for i, val := range values { for i, val := range values {
t.Add(NewTestAddr(val, i+n)) t.Add(newTestAddr(val, i+n))
} }
} }
// func RandomBoolAddress() // func RandomBoolAddress()
func TestPotAdd(t *testing.T) { func TestPotAdd(t *testing.T) {
n := NewPot(NewTestAddr("001111", 0), 0) n := NewPot(newTestAddr("00111100", 0), 0, DefaultPof(8))
// Pin set correctly // Pin set correctly
exp := "001111" exp := "00111100"
got := str(n.Pin())[:6] got := Label(n.Pin())[:8]
if got != exp { if got != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
} }
@ -116,7 +106,7 @@ func TestPotAdd(t *testing.T) {
t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti)
} }
testAdd(n, 1, "011111", "001111", "011111", "000111") testAdd(n, 1, "01111100", "00111100", "01111100", "00011100")
// check size // check size
goti = n.Size() goti = n.Size()
expi = 3 expi = 3
@ -138,15 +128,15 @@ func TestPotAdd(t *testing.T) {
// func RandomBoolAddress() // func RandomBoolAddress()
func TestPotRemove(t *testing.T) { func TestPotRemove(t *testing.T) {
n := NewPot(NewTestAddr("001111", 0), 0) n := NewPot(newTestAddr("00111100", 0), 0, DefaultPof(8))
n.Remove(NewTestAddr("001111", 0)) n.Remove(newTestAddr("00111100", 0))
exp := "" exp := "<nil>"
got := str(n.Pin()) got := Label(n.Pin())
if got != exp { if got != exp {
t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got)
} }
testAdd(n, 1, "000000", "011111", "001111", "000111") testAdd(n, 1, "00000000", "01111100", "00111100", "00011100")
n.Remove(NewTestAddr("001111", 0)) n.Remove(newTestAddr("00111100", 0))
goti := n.Size() goti := n.Size()
expi := 3 expi := 3
if goti != expi { if goti != expi {
@ -164,7 +154,7 @@ func TestPotRemove(t *testing.T) {
t.Fatalf("incorrect po-s in iteration over Pot. Expected %v, got %v", exp, got) t.Fatalf("incorrect po-s in iteration over Pot. Expected %v, got %v", exp, got)
} }
// remove again // remove again
n.Remove(NewTestAddr("001111", 0)) n.Remove(newTestAddr("00111100", 0))
inds, po = indexes(n) inds, po = indexes(n)
got = fmt.Sprintf("%v", inds) got = fmt.Sprintf("%v", inds)
exp = "[2 4]" exp = "[2 4]"
@ -175,31 +165,32 @@ func TestPotRemove(t *testing.T) {
} }
func TestPotSwap(t *testing.T) { func TestPotSwap(t *testing.T) {
// t.Skip("")
max := maxEachNeighbour max := maxEachNeighbour
n := NewPot(nil, 0) n := NewPot(nil, 0, nil)
var m []*testBVAddr var m []*testAddr
for j := 0; j < 2*max; { for j := 0; j < 2*max; {
v := randomTestBVAddr(keylen, j) v := randomtestAddr(keylen, j)
_, found := n.Add(v) _, found := n.Add(v)
if !found { if !found {
m = append(m, v) m = append(m, v)
j++ j++
} }
} }
k := make(map[string]*testBVAddr) k := make(map[string]*testAddr)
for j := 0; j < max; { for j := 0; j < max; {
v := randomTestBVAddr(keylen, 1) v := randomtestAddr(keylen, 1)
_, found := k[v.String()] _, found := k[Label(v)]
if !found { if !found {
k[v.String()] = v k[Label(v)] = v
j++ j++
} }
} }
for _, v := range k { for _, v := range k {
m = append(m, v) m = append(m, v)
} }
f := func(v PotVal) PotVal { f := func(v Val) Val {
tv := v.(*testBVAddr) tv := v.(*testAddr)
if tv.i < max { if tv.i < max {
return nil return nil
} }
@ -207,7 +198,7 @@ func TestPotSwap(t *testing.T) {
return v return v
} }
for _, val := range m { for _, val := range m {
n.Swap(val, func(v PotVal) PotVal { n.Swap(val, func(v Val) Val {
if v == nil { if v == nil {
return val return val
} }
@ -215,9 +206,9 @@ func TestPotSwap(t *testing.T) {
}) })
} }
sum := 0 sum := 0
n.Each(func(v PotVal, i int) bool { n.Each(func(v Val, i int) bool {
sum++ sum++
tv := v.(*testBVAddr) tv := v.(*testAddr)
if tv.i > 1 { if tv.i > 1 {
t.Fatalf("item value incorrect, expected 0, got %v", tv.i) t.Fatalf("item value incorrect, expected 0, got %v", tv.i)
} }
@ -231,10 +222,10 @@ func TestPotSwap(t *testing.T) {
} }
} }
func checkPo(val PotVal) func(PotVal, int) error { func checkPo(val Val, pof Pof) func(Val, int) error {
return func(v PotVal, po int) error { return func(v Val, po int) error {
// check the po // check the po
exp, _ := val.PO(v, 0) exp, _ := pof(val, v, 0)
if po != exp { if po != exp {
return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po) return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po)
} }
@ -242,9 +233,9 @@ func checkPo(val PotVal) func(PotVal, int) error {
} }
} }
func checkOrder(val PotVal) func(PotVal, int) error { func checkOrder(val Val) func(Val, int) error {
var po int = keylen var po int = keylen
return func(v PotVal, p int) error { return func(v Val, p int) error {
if po < p { if po < p {
return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, p, po) return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, p, po)
} }
@ -253,26 +244,26 @@ func checkOrder(val PotVal) func(PotVal, int) error {
} }
} }
func checkValues(m map[string]bool, val PotVal) func(PotVal, int) error { func checkValues(m map[string]bool, val Val) func(Val, int) error {
return func(v PotVal, po int) error { return func(v Val, po int) error {
duplicate, ok := m[v.String()] duplicate, ok := m[Label(v)]
if !ok { if !ok {
return fmt.Errorf("alien value %v", v) return fmt.Errorf("alien value %v", v)
} }
if duplicate { if duplicate {
return fmt.Errorf("duplicate value returned: %v", v) return fmt.Errorf("duplicate value returned: %v", v)
} }
m[v.String()] = true m[Label(v)] = true
return nil return nil
} }
} }
var errNoCount = errors.New("not count") var errNoCount = errors.New("not count")
func testPotEachNeighbour(n *Pot, val PotVal, expCount int, fs ...func(PotVal, int) error) error { func testPotEachNeighbour(n *Pot, val Val, expCount int, fs ...func(Val, int) error) error {
var err error var err error
var count int var count int
n.EachNeighbour(val, func(v PotVal, po int) bool { n.EachNeighbour(val, func(v Val, po int) bool {
for _, f := range fs { for _, f := range fs {
err = f(v, po) err = f(v, po)
if err != nil { if err != nil {
@ -297,15 +288,14 @@ const (
) )
func TestPotMergeOne(t *testing.T) { func TestPotMergeOne(t *testing.T) {
pot1 := NewPot(nil, 0) pot1 := NewPot(nil, 0, DefaultPof(2))
pot1.Add(NewTestAddr("10", 0)) pot1.Add(newTestAddr("10", 0))
pot1.Add(NewTestAddr("00", 0)) pot1.Add(newTestAddr("00", 0))
pot2 := NewPot(nil, 0) pot2 := NewPot(nil, 0, DefaultPof(2))
pot2.Add(NewTestAddr("01", 0)) pot2.Add(newTestAddr("01", 0))
log.Debug(fmt.Sprintf("\n%v\n%v", pot2, pot1))
pot1.Merge(pot2) pot1.Merge(pot2)
count := 0 count := 0
pot1.Each(func(val PotVal, i int) bool { pot1.Each(func(val Val, i int) bool {
count++ count++
return true return true
}) })
@ -315,25 +305,25 @@ func TestPotMergeOne(t *testing.T) {
} }
func TestPotMergeCommon(t *testing.T) { func TestPotMergeCommon(t *testing.T) {
vs := make([]*testBVAddr, mergeTestCount) vs := make([]*testAddr, mergeTestCount)
// vs := make([]*testAddr, mergeTestCount)
for i := 0; i < maxEachNeighbourTests; i++ { for i := 0; i < maxEachNeighbourTests; i++ {
for i := 0; i < len(vs); i++ { for i := 0; i < len(vs); i++ {
vs[i] = randomTestBVAddr(keylen, i) vs[i] = randomtestAddr(keylen, i)
} }
max0 := rand.Intn(mergeTestChoose) + 1 max0 := rand.Intn(mergeTestChoose) + 1
max1 := rand.Intn(mergeTestChoose) + 1 max1 := rand.Intn(mergeTestChoose) + 1
n0 := NewPot(nil, 0) n0 := NewPot(nil, 0, nil)
n1 := NewPot(nil, 0) n1 := NewPot(nil, 0, nil)
log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1))
m := make(map[string]bool) m := make(map[string]bool)
for j := 0; j < max0; { for j := 0; j < max0; {
r := rand.Intn(max0) r := rand.Intn(max0)
v := vs[r] v := vs[r]
// v := randomTestBVAddr(keylen, j)
_, found := n0.Add(v) _, found := n0.Add(v)
if !found { if !found {
m[v.String()] = false m[Label(v)] = false
j++ j++
} }
} }
@ -346,10 +336,10 @@ func TestPotMergeCommon(t *testing.T) {
if !found { if !found {
j++ j++
} }
_, found = m[v.String()] _, found = m[Label(v)]
if !found { if !found {
expAdded++ expAdded++
m[v.String()] = false m[Label(v)] = false
} }
} }
if i < 6 { if i < 6 {
@ -372,8 +362,8 @@ func TestPotMergeCommon(t *testing.T) {
if !checkDuplicates(n.pot) { if !checkDuplicates(n.pot) {
t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n) t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n)
} }
for k, _ := range m { for k := range m {
_, found := n.Add(NewTestBVAddr(k, 0)) _, found := n.Add(newTestAddr(k, 0))
if !found { if !found {
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n) t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n)
} }
@ -385,32 +375,32 @@ func TestPotMergeScale(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ { for i := 0; i < maxEachNeighbourTests; i++ {
max0 := rand.Intn(maxEachNeighbour) + 1 max0 := rand.Intn(maxEachNeighbour) + 1
max1 := rand.Intn(maxEachNeighbour) + 1 max1 := rand.Intn(maxEachNeighbour) + 1
n0 := NewPot(nil, 0) n0 := NewPot(nil, 0, nil)
n1 := NewPot(nil, 0) n1 := NewPot(nil, 0, nil)
log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1))
m := make(map[string]bool) m := make(map[string]bool)
for j := 0; j < max0; { for j := 0; j < max0; {
v := randomTestBVAddr(keylen, j) v := randomtestAddr(keylen, j)
// v := randomTestBVAddr(keylen, j) // v := randomtestAddr(keylen, j)
_, found := n0.Add(v) _, found := n0.Add(v)
if !found { if !found {
m[v.String()] = false m[Label(v)] = false
j++ j++
} }
} }
expAdded := 0 expAdded := 0
for j := 0; j < max1; { for j := 0; j < max1; {
v := randomTestBVAddr(keylen, j) v := randomtestAddr(keylen, j)
// v := randomTestBVAddr(keylen, j) // v := randomtestAddr(keylen, j)
_, found := n1.Add(v) _, found := n1.Add(v)
if !found { if !found {
j++ j++
} }
_, found = m[v.String()] _, found = m[Label(v)]
if !found { if !found {
expAdded++ expAdded++
m[v.String()] = false m[Label(v)] = false
} }
} }
if i < 6 { if i < 6 {
@ -433,8 +423,8 @@ func TestPotMergeScale(t *testing.T) {
if !checkDuplicates(n.pot) { if !checkDuplicates(n.pot) {
t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n) t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n)
} }
for k, _ := range m { for k := range m {
_, found := n.Add(NewTestBVAddr(k, 0)) _, found := n.Add(newTestAddr(k, 0))
if !found { if !found {
t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n) t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v\n%v", i, size, added, k, n)
} }
@ -443,7 +433,7 @@ func TestPotMergeScale(t *testing.T) {
} }
func checkDuplicates(t *pot) bool { func checkDuplicates(t *pot) bool {
var po int = -1 po := -1
for _, c := range t.bins { for _, c := range t.bins {
if c == nil { if c == nil {
return false return false
@ -460,13 +450,13 @@ func TestPotEachNeighbourSync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ { for i := 0; i < maxEachNeighbourTests; i++ {
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
pin := randomTestAddr(keylen, 0) pin := randomTestAddr(keylen, 0)
n := NewPot(pin, 0) n := NewPot(pin, 0, nil)
m := make(map[string]bool) m := make(map[string]bool)
m[pin.String()] = false m[Label(pin)] = false
for j := 1; j <= max; j++ { for j := 1; j <= max; j++ {
v := randomTestAddr(keylen, j) v := randomTestAddr(keylen, j)
n.Add(v) n.Add(v)
m[v.String()] = false m[Label(v)] = false
} }
size := n.Size() size := n.Size()
@ -476,14 +466,14 @@ func TestPotEachNeighbourSync(t *testing.T) {
count := rand.Intn(size/2) + size/2 count := rand.Intn(size/2) + size/2
val := randomTestAddr(keylen, max+1) val := randomTestAddr(keylen, max+1)
log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count)) log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count))
err := testPotEachNeighbour(n, val, count, checkPo(val), checkOrder(val), checkValues(m, val)) err := testPotEachNeighbour(n, val, count, checkPo(val, n.pof), checkOrder(val), checkValues(m, val))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
minPoFound := keylen minPoFound := keylen
maxPoNotFound := 0 maxPoNotFound := 0
for k, found := range m { for k, found := range m {
po, _ := val.PO(NewTestAddr(k, 0), 0) po, _ := n.pof(val, newTestAddr(k, 0), 0)
if found { if found {
if po < minPoFound { if po < minPoFound {
minPoFound = po minPoFound = po
@ -503,8 +493,8 @@ func TestPotEachNeighbourSync(t *testing.T) {
func TestPotEachNeighbourAsync(t *testing.T) { func TestPotEachNeighbourAsync(t *testing.T) {
for i := 0; i < maxEachNeighbourTests; i++ { for i := 0; i < maxEachNeighbourTests; i++ {
max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2
n := NewPot(randomTestAddr(keylen, 0), 0) n := NewPot(randomTestAddr(keylen, 0), 0, nil)
var size int = 1 size := 1
for j := 1; j <= max; j++ { for j := 1; j <= max; j++ {
v := randomTestAddr(keylen, j) v := randomTestAddr(keylen, j)
_, found := n.Add(v) _, found := n.Add(v)
@ -526,32 +516,24 @@ func TestPotEachNeighbourAsync(t *testing.T) {
maxPos := rand.Intn(keylen) maxPos := rand.Intn(keylen)
log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos)) log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos))
msize := 0 msize := 0
remember := func(v PotVal, po int) error { remember := func(v Val, po int) error {
// mu.Lock()
// defer mu.Unlock()
if po > maxPos { if po > maxPos {
// log.Trace(fmt.Sprintf("NOT ADD %v", v))
return errNoCount return errNoCount
} }
// log.Trace(fmt.Sprintf("ADD %v, %v", v, msize)) m[Label(v)] = true
m[v.String()] = true
msize++ msize++
return nil return nil
} }
if i == 0 { if i == 0 {
continue continue
} }
err := testPotEachNeighbour(n, val, count, remember) testPotEachNeighbour(n, val, count, remember)
if err != nil {
log.Error(err.Error())
}
d := 0 d := 0
forget := func(v PotVal, po int) { forget := func(v Val, po int) {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
d++ d++
// log.Trace(fmt.Sprintf("DEL %v", v)) delete(m, Label(v))
delete(m, v.String())
} }
n.EachNeighbourAsync(val, count, maxPos, forget, true) n.EachNeighbourAsync(val, count, maxPos, forget, true)
@ -567,7 +549,7 @@ func TestPotEachNeighbourAsync(t *testing.T) {
func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) { func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs() t.ReportAllocs()
pin := randomTestAddr(keylen, 0) pin := randomTestAddr(keylen, 0)
n := NewPot(pin, 0) n := NewPot(pin, 0, nil)
for j := 1; j <= max; { for j := 1; j <= max; {
v := randomTestAddr(keylen, j) v := randomTestAddr(keylen, j)
_, found := n.Add(v) _, found := n.Add(v)
@ -579,7 +561,7 @@ func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
for i := 0; i < t.N; i++ { for i := 0; i < t.N; i++ {
val := randomTestAddr(keylen, max+1) val := randomTestAddr(keylen, max+1)
m := 0 m := 0
n.EachNeighbour(val, func(v PotVal, po int) bool { n.EachNeighbour(val, func(v Val, po int) bool {
time.Sleep(d) time.Sleep(d)
m++ m++
if m == count { if m == count {
@ -597,7 +579,7 @@ func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) {
func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) { func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) {
t.ReportAllocs() t.ReportAllocs()
pin := randomTestAddr(keylen, 0) pin := randomTestAddr(keylen, 0)
n := NewPot(pin, 0) n := NewPot(pin, 0, nil)
for j := 1; j <= max; { for j := 1; j <= max; {
v := randomTestAddr(keylen, j) v := randomTestAddr(keylen, j)
_, found := n.Add(v) _, found := n.Add(v)
@ -608,7 +590,7 @@ func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration)
t.ResetTimer() t.ResetTimer()
for i := 0; i < t.N; i++ { for i := 0; i < t.N; i++ {
val := randomTestAddr(keylen, max+1) val := randomTestAddr(keylen, max+1)
n.EachNeighbourAsync(val, count, keylen, func(v PotVal, po int) { n.EachNeighbourAsync(val, count, keylen, func(v Val, po int) {
time.Sleep(d) time.Sleep(d)
}, true) }, true)
} }

View file

@ -89,9 +89,10 @@ type Hive struct {
tick <-chan time.Time tick <-chan time.Time
} }
// Hive constructor embeds both arguments // NewHive constructs a new hive
// HiveParams: config parameters // HiveParams: config parameters
// Overlay: Topology Driver Interface // Overlay: Topology Driver Interface
// StateStore: to save peers across sessions
func NewHive(params *HiveParams, overlay Overlay, store StateStore) *Hive { func NewHive(params *HiveParams, overlay Overlay, store StateStore) *Hive {
return &Hive{ return &Hive{
HiveParams: params, HiveParams: params,
@ -105,105 +106,98 @@ func NewHive(params *HiveParams, overlay Overlay, store StateStore) *Hive {
// these are called on the p2p.Server which runs on the node // these are called on the p2p.Server which runs on the node
// af() returns an arbitrary ticker channel // af() returns an arbitrary ticker channel
// rw is a read writer for json configs // rw is a read writer for json configs
func (self *Hive) Start(server *p2p.Server) error { func (h *Hive) Start(server *p2p.Server) error {
if self.store != nil { if h.store != nil {
if err := self.loadPeers(); err != nil { if err := h.loadPeers(); err != nil {
return err return err
} }
} }
self.more = make(chan bool, 1) h.more = make(chan bool, 1)
self.quit = make(chan bool) h.quit = make(chan bool)
log.Debug("hive started")
// this loop is doing bootstrapping and maintains a healthy table // this loop is doing bootstrapping and maintains a healthy table
go self.keepAlive() go h.keepAlive()
go func() { go func() {
// each iteration, ask kademlia about most preferred peer // each iteration, ask kademlia about most preferred peer
for more := range self.more { for more := range h.more {
if !more { if !more {
// receiving false closes the loop while allowing parallel routines // receiving false closes the loop while allowing parallel routines
// to attempt to write to more (remove Peer when shutting down) // to attempt to write to more (remove Peer when shutting down)
return return
} }
log.Debug("hive delegate to overlay driver: suggest addr to connect to") log.Trace(fmt.Sprintf("%x: hive delegate to overlay driver: suggest addr to connect to", h.BaseAddr()[:4]))
// log.Trace("hive delegate to overlay driver: suggest addr to connect to") // log.Trace("hive delegate to overlay driver: suggest addr to connect to")
addr, order, want := self.SuggestPeer() addr, order, want := h.SuggestPeer()
if self.Discovery { if h.Discovery {
if addr != nil { if addr != nil {
log.Info(fmt.Sprintf("========> connect to bee %v", addr)) log.Trace(fmt.Sprintf("%x ========> connect to bee %x", h.BaseAddr()[:4], addr.Address()[:4]))
under, err := discover.ParseNode(string(addr.(Addr).Under())) under, err := discover.ParseNode(string(addr.(Addr).Under()))
if err == nil { if err == nil {
server.AddPeer(under) server.AddPeer(under)
} else { } else {
log.Error(fmt.Sprintf("===X====> connect to bee %v failed: invalid node URL: %v", addr, err)) log.Error(fmt.Sprintf("%x ===X====> connect to bee %x failed: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err))
} }
} else { } else {
log.Trace("cannot suggest peers") log.Trace(fmt.Sprintf("%x cannot suggest peers", h.BaseAddr()[:4]))
} }
if want { if want {
log.Debug(fmt.Sprintf("========> request peers nearest %v", addr)) log.Trace(fmt.Sprintf("%x ========> request peers for PO%0d", h.BaseAddr()[:4], order))
RequestOrder(self.Overlay, uint8(order), self.PeersBroadcastSetSize, self.MaxPeersPerRequest) RequestOrder(h.Overlay, uint8(order), h.PeersBroadcastSetSize, h.MaxPeersPerRequest)
} }
} }
log.Info(fmt.Sprintf("%v", self)) log.Trace(fmt.Sprintf("%v", h))
select {
case <-self.quit:
return
default:
}
} }
}() }()
return nil return nil
} }
// Stop terminates the updateloop and saves the peers // Stop terminates the updateloop and saves the peers
func (self *Hive) Stop() { func (h *Hive) Stop() {
if self.store != nil { if h.store != nil {
self.savePeers() h.savePeers()
} }
// closing toggle channel quits the updateloop // closing toggle channel quits the updateloop
close(self.quit) close(h.quit)
} }
func (self *Hive) Run(p *bzzPeer) error { // Run protocol run function
dp := NewDiscovery(p, self) func (h *Hive) Run(p *bzzPeer) error {
dp := NewDiscovery(p, h)
log.Debug(fmt.Sprintf("to add new bee %v", p)) log.Debug(fmt.Sprintf("to add new bee %v", p))
self.On(dp) h.On(dp)
self.wake() h.wake()
defer self.wake() defer h.wake()
defer self.Off(dp) defer h.Off(dp)
return p.Run(dp.HandleMsg) return p.Run(dp.HandleMsg)
} }
// NodeInfo function is used by the p2p.server RPC interface to display // NodeInfo function is used by the p2p.server RPC interface to display
// protocol specific node information // protocol specific node information
func (self *Hive) NodeInfo() interface{} { func (h *Hive) NodeInfo() interface{} {
return self.String() return h.String()
} }
// PeerInfo function is used by the p2p.server RPC interface to display // PeerInfo function is used by the p2p.server RPC interface to display
// protocol specific information any connected peer referred to by their NodeID // protocol specific information any connected peer referred to by their NodeID
func (self *Hive) PeerInfo(id discover.NodeID) interface{} { func (h *Hive) PeerInfo(id discover.NodeID) interface{} {
self.lock.Lock() h.lock.Lock()
defer self.lock.Unlock() defer h.lock.Unlock()
addr := NewAddrFromNodeID(id) addr := NewAddrFromNodeID(id)
return interface{}(addr) return interface{}(addr)
} }
func (self *Hive) Register(peers chan OverlayAddr) error { func (h *Hive) Register(peers chan OverlayAddr) error {
defer self.wake() defer h.wake()
return self.Overlay.Register(peers) return h.Overlay.Register(peers)
} }
// wake triggers // wake triggers
func (self *Hive) wake() { func (h *Hive) wake() {
select { select {
case self.more <- true: case h.more <- true:
log.Trace("hive woken up") case <-h.quit:
case <-self.quit:
default: default:
log.Trace("hive already awake")
} }
} }
@ -233,30 +227,30 @@ func (t *timeTicker) Ch() <-chan time.Time {
// keepAlive is a forever loop // keepAlive is a forever loop
// in its awake state it periodically triggers connection attempts // in its awake state it periodically triggers connection attempts
// by writing to self.more until Kademlia Table is saturated // by writing to h.more until Kademlia Table is saturated
// wake state is toggled by writing to self.toggle // wake state is toggled by writing to h.toggle
// it goes to sleep mode if table is saturated // it goes to sleep mode if table is saturated
// it restarts if the table becomes non-full again due to disconnections // it restarts if the table becomes non-full again due to disconnections
func (self *Hive) keepAlive() { func (h *Hive) keepAlive() {
if self.tick == nil { if h.tick == nil {
ticker := time.NewTicker(self.KeepAliveInterval) ticker := time.NewTicker(h.KeepAliveInterval)
defer ticker.Stop() defer ticker.Stop()
self.tick = ticker.C h.tick = ticker.C
} }
for { for {
select { select {
case <-self.tick: case <-h.tick:
log.Debug("wake up: make hive alive") h.wake()
self.wake() case <-h.quit:
case <-self.quit: h.more <- false
return return
} }
} }
} }
// loadPeers, savePeer implement persistence callback/ // loadPeers, savePeer implement persistence callback/
func (self *Hive) loadPeers() error { func (h *Hive) loadPeers() error {
data, err := self.store.Load("peers") data, err := h.store.Load("peers")
if err != nil { if err != nil {
return err return err
} }
@ -275,13 +269,13 @@ func (self *Hive) loadPeers() error {
c <- a c <- a
} }
}() }()
return self.Overlay.Register(c) return h.Overlay.Register(c)
} }
// savePeers, savePeer implement persistence callback/ // savePeers, savePeer implement persistence callback/
func (self *Hive) savePeers() error { func (h *Hive) savePeers() error {
var peers []*bzzAddr var peers []*bzzAddr
self.Overlay.EachAddr(nil, 256, func(pa OverlayAddr, i int) bool { h.Overlay.EachAddr(nil, 256, func(pa OverlayAddr, i int) bool {
if pa == nil { if pa == nil {
log.Warn(fmt.Sprintf("empty addr: %v", i)) log.Warn(fmt.Sprintf("empty addr: %v", i))
return true return true
@ -293,7 +287,7 @@ func (self *Hive) savePeers() error {
if err != nil { if err != nil {
return fmt.Errorf("could not encode peers: %v", err) return fmt.Errorf("could not encode peers: %v", err)
} }
if err := self.store.Save("peers", data); err != nil { if err := h.store.Save("peers", data); err != nil {
return fmt.Errorf("could not save peers: %v", err) return fmt.Errorf("could not save peers: %v", err)
} }
return nil return nil

View file

@ -93,11 +93,12 @@ func NewKademlia(addr []byte, params *KadParams) *Kademlia {
return &Kademlia{ return &Kademlia{
base: addr, base: addr,
KadParams: params, KadParams: params,
addrs: pot.NewPot(nil, 0), addrs: pot.NewPot(nil, 0, nil),
conns: pot.NewPot(nil, 0), conns: pot.NewPot(nil, 0, nil),
} }
} }
// Notifier interface type for peer allowing / requesting peer and depth notifications
type Notifier interface { type Notifier interface {
NotifyPeer(OverlayAddr, uint8) error NotifyPeer(OverlayAddr, uint8) error
NotifyDepth(uint8) error NotifyDepth(uint8) error
@ -116,16 +117,14 @@ type OverlayConn interface {
Off() OverlayAddr // call to return a persitent OverlayAddr Off() OverlayAddr // call to return a persitent OverlayAddr
} }
// OverlayAddr represents a kademlia peer record
type OverlayAddr interface { type OverlayAddr interface {
OverlayPeer OverlayPeer
Update(OverlayAddr) OverlayAddr // returns the updated version of the original Update(OverlayAddr) OverlayAddr // returns the updated version of the original
} }
// entry represents a Kademlia table entry (an extension of OverlayPeer) // entry represents a Kademlia table entry (an extension of OverlayPeer)
// implements the pot.PotVal interface via BytesAddress, so entry can be
// used directly as a pot element
type entry struct { type entry struct {
pot.PotVal
OverlayPeer OverlayPeer
seenAt time.Time seenAt time.Time
retries int retries int
@ -134,51 +133,56 @@ type entry struct {
// newEntry creates a kademlia peer from an OverlayPeer interface // newEntry creates a kademlia peer from an OverlayPeer interface
func newEntry(p OverlayPeer) *entry { func newEntry(p OverlayPeer) *entry {
return &entry{ return &entry{
PotVal: pot.NewBytesVal(p, nil),
OverlayPeer: p, OverlayPeer: p,
seenAt: time.Now(), seenAt: time.Now(),
} }
} }
func (self *entry) addr() OverlayAddr { // Bin is the binary (bitvector) serialisation of the entry address
a, _ := self.OverlayPeer.(OverlayAddr) func (e *entry) Bin() string {
return pot.ToBin(e.addr().Address())
}
// Label is a short tag for the entry for debug
func Label(e *entry) string {
return fmt.Sprintf("%s (%d)", e.Bin()[:8], e.retries)
}
// Hex is the hexadecimal serialisation of the entry address
func (e *entry) Hex() string {
return fmt.Sprintf("%x", e.addr().Address())
}
// String is the short tag for the entry
func (e *entry) String() string {
return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries)
}
// addr returns the kad peer record (OverlayAddr) corresponding to the entry
func (e *entry) addr() OverlayAddr {
a, _ := e.OverlayPeer.(OverlayAddr)
return a return a
} }
func (self *entry) conn() OverlayConn { // conn returns the connected peer (OverlayPeer) corresponding to the entry
c, _ := self.OverlayPeer.(OverlayConn) func (e *entry) conn() OverlayConn {
c, _ := e.OverlayPeer.(OverlayConn)
return c return c
} }
func (self *entry) String() string {
return fmt.Sprintf("%x", self.OverlayPeer.Address())
}
// Register enters each OverlayAddr as kademlia peer record into the // Register enters each OverlayAddr as kademlia peer record into the
// database of known peer addresses // database of known peer addresses
func (self *Kademlia) Register(peers chan OverlayAddr) error { func (k *Kademlia) Register(peers chan OverlayAddr) error {
np := pot.NewPot(nil, 0) np := pot.NewPot(nil, 0, nil)
for p := range peers { for p := range peers {
// error if self received, peer should know better // error if k received, peer should know better
if bytes.Equal(p.Address(), self.base) { if bytes.Equal(p.Address(), k.base) {
return fmt.Errorf("add peers: %x is self", self.base) return fmt.Errorf("add peers: %x is k", k.base)
} }
np, _, _ = pot.Add(np, newEntry(p)) np, _, _ = pot.Add(np, newEntry(p))
} }
com := self.addrs.Merge(np) com := k.addrs.Merge(np)
log.Debug(fmt.Sprintf("merged %v peers, %v known, total: %v", np.Size(), com, self.addrs.Size())) log.Trace(fmt.Sprintf("%x merged %v peers, %v known, total: %v", k.BaseAddr()[:4], np.Size(), com, k.addrs.Size()))
// log.Trace(fmt.Sprintf("merged %v peers, %v known", np.Size(), com))
// TODO: remove this check
m := make(map[string]bool)
self.addrs.Each(func(val pot.PotVal, i int) bool {
_, found := m[val.String()]
if found {
panic("duplicate found")
}
m[val.String()] = true
return true
})
return nil return nil
} }
@ -186,32 +190,31 @@ func (self *Kademlia) Register(peers chan OverlayAddr) error {
// lowest bincount below depth // lowest bincount below depth
// naturally if there is an empty row it returns a peer for that // naturally if there is an empty row it returns a peer for that
// //
func (self *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) { func (k *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
minsize := self.MinBinSize minsize := k.MinBinSize
depth := self.Depth() depth := k.Depth()
empty := self.FirstEmptyBin() // empty := k.FirstEmptyBin()
// if there is a callable neighbour within the current proxBin, connect // if there is a callable neighbour within the current proxBin, connect
// this makes sure nearest neighbour set is fully connected // this makes sure nearest neighbour set is fully connected
log.Debug(fmt.Sprintf("candidate nearest neighbour checking above PO %v", depth))
// log.Trace(fmt.Sprintf("candidate nearest neighbour checking above PO %v", depth))
var ppo int var ppo int
ba := pot.NewBytesVal(self.base, nil) k.addrs.EachNeighbour(k.base, func(val pot.Val, po int) bool {
self.addrs.EachNeighbour(ba, func(val pot.PotVal, po int) bool { if po < depth {
a = self.callable(val) return false
log.Trace(fmt.Sprintf("candidate nearest neighbour at %x: %v (%v). a == nil is %v", val.(*entry).Address(), a, po, a == nil)) }
a = k.callable(val)
log.Trace(fmt.Sprintf("%x candidate nearest neighbour at %v: %v (%v)", k.BaseAddr()[:4], val.(*entry), a, po))
ppo = po ppo = po
return a == nil && po >= depth return a == nil
}) })
if a != nil { if a != nil {
log.Debug(fmt.Sprintf("candidate nearest neighbour found: %v (%v)", a, ppo)) log.Trace(fmt.Sprintf("%x candidate nearest neighbour found: %v (%v)", k.BaseAddr()[:4], a, ppo))
return a, 0, false return a, 0, false
} }
log.Debug(fmt.Sprintf("no candidate nearest neighbours to connect to (Depth: %v, minProxSize: %v) %#v", depth, self.MinProxBinSize, a)) log.Trace(fmt.Sprintf("%x no candidate nearest neighbours to connect to (Depth: %v, minProxSize: %v) %#v", k.BaseAddr()[:4], depth, k.MinProxBinSize, a))
var bpo []int var bpo []int
prev := -1 prev := -1
self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
log.Trace(fmt.Sprintf("check PO%02d: ", po))
prev++ prev++
for ; prev < po; prev++ { for ; prev < po; prev++ {
bpo = append(bpo, prev) bpo = append(bpo, prev)
@ -224,34 +227,31 @@ func (self *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
return size > 0 && po < depth return size > 0 && po < depth
}) })
// all buckets are full // all buckets are full
// minsize == self.MinBinSize // minsize == k.MinBinSize
if len(bpo) == 0 { if len(bpo) == 0 {
log.Trace(fmt.Sprintf("all bins saturated")) log.Debug(fmt.Sprintf("%x: all bins saturated", k.BaseAddr()[:4]))
return nil, 0, false return nil, 0, false
} }
// as long as we got candidate peers to connect to // as long as we got candidate peers to connect to
// dont ask for new peers (want = false) // dont ask for new peers (want = false)
// try to select a candidate peer // try to select a candidate peer
// for i := len(bpo) - 1; i >= 0; i-- {
// find the first callable peer // find the first callable peer
i := 0 i := 0
nxt := bpo[0] nxt := bpo[0]
self.addrs.EachBin(ba, nxt, func(po, size int, f func(func(pot.PotVal, int) bool) bool) bool { k.addrs.EachBin(k.base, nxt, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
// for each bin we find callable candidate peers // for each bin we find callable candidate peers
if po == nxt { if i >= depth {
if i == len(bpo)-1 { return false
return false
}
i++
nxt = bpo[i]
} }
log.Trace(fmt.Sprintf("check PO%02d: ", po)) if po == nxt {
f(func(val pot.PotVal, j int) bool { i++
a = self.callable(val) if i < len(bpo) {
if po == empty { nxt = bpo[i]
log.Debug(fmt.Sprintf("candidate nearest neighbour found: %v (%v)", a, ppo))
} }
return a == nil && po <= depth }
f(func(val pot.Val, j int) bool {
a = k.callable(val)
return a == nil && i < len(bpo) && po <= depth
}) })
return false return false
}) })
@ -259,22 +259,17 @@ func (self *Kademlia) SuggestPeer() (a OverlayAddr, o int, want bool) {
if a != nil { if a != nil {
return a, 0, false return a, 0, false
} }
return a, bpo[i], true return a, nxt, true
// cannot find a candidate, ask for more for this proximity bin specifically
// o = bpo[i]
// want = true
// // }
// return a, o, want
} }
// On inserts the peer as a kademlia peer into the live peers // On inserts the peer as a kademlia peer into the live peers
func (self *Kademlia) On(p OverlayConn) { func (k *Kademlia) On(p OverlayConn) {
e := newEntry(p) e := newEntry(p)
self.conns.Swap(p, func(v pot.PotVal) pot.PotVal { k.conns.Swap(p, func(v pot.Val) pot.Val {
// if not found live // if not found live
if v == nil { if v == nil {
// insert new online peer into addrs // insert new online peer into addrs
self.addrs.Swap(p, func(v pot.PotVal) pot.PotVal { k.addrs.Swap(p, func(v pot.Val) pot.Val {
return e return e
}) })
// insert new online peer into conns // insert new online peer into conns
@ -289,36 +284,34 @@ func (self *Kademlia) On(p OverlayConn) {
return return
} }
depth := uint8(self.Depth()) depth := uint8(k.Depth())
if depth != self.depth { if depth != k.depth {
self.depth = depth k.depth = depth
} else { } else {
depth = 0 depth = 0
} }
go np.NotifyDepth(depth) go np.NotifyDepth(depth)
f := func(val pot.PotVal, po int) { f := func(val pot.Val, po int) {
dp := val.(*entry).OverlayPeer.(Notifier) dp := val.(*entry).OverlayPeer.(Notifier)
dp.NotifyPeer(p.Off(), uint8(po)) dp.NotifyPeer(p.Off(), uint8(po))
// log.Trace(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po)) log.Trace(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po))
log.Debug(fmt.Sprintf("peer %v notified of %v (%v)", dp, p, po))
if depth > 0 { if depth > 0 {
dp.NotifyDepth(depth) dp.NotifyDepth(depth)
log.Debug(fmt.Sprintf("peer %v notified of new depth %v", dp, depth)) log.Trace(fmt.Sprintf("peer %v notified of new depth %v", dp, depth))
// log.Trace(fmt.Sprintf("peer %v notified of new depth %v", dp, depth))
} }
} }
self.conns.EachNeighbourAsync(e, 1024, 255, f, false) k.conns.EachNeighbourAsync(e, 1024, 255, f, false)
} }
// Off removes a peer from among live peers // Off removes a peer from among live peers
func (self *Kademlia) Off(p OverlayConn) { func (k *Kademlia) Off(p OverlayConn) {
self.addrs.Swap(p, func(v pot.PotVal) pot.PotVal { k.addrs.Swap(p, func(v pot.Val) pot.Val {
// v cannot be nil, must check otherwise we overwrite entry // v cannot be nil, must check otherwise we overwrite entry
if v == nil { if v == nil {
panic(fmt.Sprintf("connected peer not found %v", p)) panic(fmt.Sprintf("connected peer not found %v", p))
} }
self.conns.Swap(p, func(v pot.PotVal) pot.PotVal { k.conns.Swap(p, func(_ pot.Val) pot.Val {
// v cannot be nil, but no need to check // v cannot be nil, but no need to check
return nil return nil
}) })
@ -329,13 +322,12 @@ func (self *Kademlia) Off(p OverlayConn) {
// EachConn is an iterator with args (base, po, f) applies f to each live peer // EachConn is an iterator with args (base, po, f) applies f to each live peer
// that has proximity order po or less as measured from the base // that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used // if base is nil, kademlia base address is used
func (self *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) { func (k *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool) bool) {
if len(base) == 0 { if len(base) == 0 {
base = self.base base = k.base
} }
p := pot.NewBytesVal(base, nil) depth := k.Depth()
depth := self.Depth() k.conns.EachNeighbour(base, func(val pot.Val, po int) bool {
self.conns.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o { if po > o {
return true return true
} }
@ -343,15 +335,14 @@ func (self *Kademlia) EachConn(base []byte, o int, f func(OverlayConn, int, bool
}) })
} }
// EachAddr(base, po, f) is an iterator applying f to each known peer // EachAddr called with (base, po, f) is an iterator applying f to each known peer
// that has proximity order po or less as measured from the base // that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used // if base is nil, kademlia base address is used
func (self *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) { func (k *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool) {
if len(base) == 0 { if len(base) == 0 {
base = self.base base = k.base
} }
p := pot.NewBytesVal(base, nil) k.addrs.EachNeighbour(base, func(val pot.Val, po int) bool {
self.addrs.EachNeighbour(p, func(val pot.PotVal, po int) bool {
if po > o { if po > o {
return true return true
} }
@ -362,39 +353,39 @@ func (self *Kademlia) EachAddr(base []byte, o int, f func(OverlayAddr, int) bool
// Depth returns the proximity order that defines the distance of // Depth returns the proximity order that defines the distance of
// the nearest neighbour set with cardinality >= MinProxBinSize // the nearest neighbour set with cardinality >= MinProxBinSize
// if there is altogether less than MinProxBinSize peers it returns 0 // if there is altogether less than MinProxBinSize peers it returns 0
func (self *Kademlia) Depth() (depth int) { func (k *Kademlia) Depth() (depth int) {
if self.conns.Size() < self.MinProxBinSize { if k.conns.Size() < k.MinProxBinSize {
return 0 return 0
} }
var size int var size int
f := func(v pot.PotVal, i int) bool { f := func(v pot.Val, i int) bool {
size++ size++
depth = i depth = i
return size < self.MinProxBinSize return size < k.MinProxBinSize
} }
self.conns.EachNeighbour(pot.NewBytesVal(self.base, nil), f) k.conns.EachNeighbour(k.base, f)
return depth return depth
} }
func (self *Kademlia) callable(val pot.PotVal) OverlayAddr { // calleble when called with val,
func (k *Kademlia) callable(val pot.Val) OverlayAddr {
e := val.(*entry) e := val.(*entry)
// not callable if peer is live or exceeded maxRetries // not callable if peer is live or exceeded maxRetries
if e.conn() != nil || e.retries > self.MaxRetries { if e.conn() != nil || e.retries > k.MaxRetries {
log.Trace(fmt.Sprintf("peer %v (%T) not callable", e, e.OverlayPeer)) log.Trace(fmt.Sprintf("peer %v (%T) not callable", e, e.OverlayPeer))
return nil return nil
} }
// calculate the allowed number of retries based on time lapsed since last seen // calculate the allowed number of retries based on time lapsed since last seen
timeAgo := time.Since(e.seenAt) timeAgo := time.Since(e.seenAt)
var retries int var retries int
for delta := int(timeAgo) / self.RetryInterval; delta > 0; delta /= self.RetryExponent { for delta := int(timeAgo) / k.RetryInterval; delta > 0; delta /= k.RetryExponent {
log.Trace(fmt.Sprintf("delta: %v", delta))
retries++ retries++
} }
// this is never called concurrently, so safe to increment // this is never called concurrently, so safe to increment
// peer can be retried again // peer can be retried again
if retries < e.retries { if retries < e.retries {
log.Trace(fmt.Sprintf("long time since last try (at %v) needed before retry %v, wait only warrants %v", timeAgo, e.retries, retries)) log.Trace(fmt.Sprintf("%v long time since last try (at %v) needed before retry %v, wait only warrants %v", e, timeAgo, e.retries, retries))
return nil return nil
} }
e.retries++ e.retries++
@ -404,64 +395,61 @@ func (self *Kademlia) callable(val pot.PotVal) OverlayAddr {
} }
// BaseAddr return the kademlia base addres // BaseAddr return the kademlia base addres
func (self *Kademlia) BaseAddr() []byte { func (k *Kademlia) BaseAddr() []byte {
return self.base return k.base
} }
// String returns kademlia table + kaddb table displayed with ascii // String returns kademlia table + kaddb table displayed with ascii
func (self *Kademlia) String() string { func (k *Kademlia) String() string {
wsrow := " "
var rows []string var rows []string
rows = append(rows, "=========================================================================") rows = append(rows, "=========================================================================")
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), self.BaseAddr()[:3])) rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr()[:3]))
rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", self.conns.Size(), self.addrs.Size(), self.MinProxBinSize, self.MinBinSize, self.MaxBinSize)) rows = append(rows, fmt.Sprintf("population: %d (%d), MinProxBinSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.MinProxBinSize, k.MinBinSize, k.MaxBinSize))
liverows := make([]string, self.MaxProxDisplay) liverows := make([]string, k.MaxProxDisplay)
peersrows := make([]string, self.MaxProxDisplay) peersrows := make([]string, k.MaxProxDisplay)
var depth int var depth int
prev := -1 prev := -1
var depthSet bool var depthSet bool
rest := self.conns.Size() rest := k.conns.Size()
self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= self.MaxProxDisplay { if po >= k.MaxProxDisplay {
po = self.MaxProxDisplay - 1 po = k.MaxProxDisplay - 1
} }
row := []string{fmt.Sprintf("%2d", size)} row := []string{fmt.Sprintf("%2d", size)}
rest -= size rest -= size
f(func(val pot.PotVal, vpo int) bool { f(func(val pot.Val, vpo int) bool {
e := val.(*entry) e := val.(*entry)
label := e.String()[:6] row = append(row, e.String())
row = append(row, fmt.Sprintf("%s (%d)", label, e.retries))
row = append(row, val.(*entry).String()[:6])
rowlen++ rowlen++
return rowlen < 4 return rowlen < 4
}) })
if !depthSet && (po > prev+1 || rest < self.MinProxBinSize) { if !depthSet && (po > prev+1 || rest < k.MinProxBinSize) {
depthSet = true depthSet = true
depth = prev + 1 depth = prev + 1
} }
for ; rowlen <= 5; rowlen++ { row = append(row, wsrow)
row = append(row, " ") r := strings.Join(row, " ")
} liverows[po] = r[:35]
liverows[po] = strings.Join(row, " ")
prev = po prev = po
return true return true
}) })
self.addrs.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { k.addrs.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= self.MaxProxDisplay { if po >= k.MaxProxDisplay {
po = self.MaxProxDisplay - 1 po = k.MaxProxDisplay - 1
} }
if size < 0 { if size < 0 {
panic("wtf") panic("wtf")
} }
row := []string{fmt.Sprintf("%2d", size)} row := []string{fmt.Sprintf("%2d", size)}
// we are displaying live peers too // we are displaying live peers too
f(func(val pot.PotVal, vpo int) bool { f(func(val pot.Val, vpo int) bool {
row = append(row, val.(*entry).String()[:6]) row = append(row, val.(*entry).String())
rowlen++ rowlen++
return rowlen < 4 return rowlen < 4
}) })
@ -469,7 +457,7 @@ func (self *Kademlia) String() string {
return true return true
}) })
for i := 0; i < self.MaxProxDisplay; i++ { for i := 0; i < k.MaxProxDisplay; i++ {
if i == depth { if i == depth {
rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i))
} }
@ -494,15 +482,15 @@ func (self *Kademlia) String() string {
// the MaxBinSize parameter it drops the oldest n peers such that // the MaxBinSize parameter it drops the oldest n peers such that
// the bin is reduced to MinBinSize peers thus leaving slots to newly // the bin is reduced to MinBinSize peers thus leaving slots to newly
// connecting peers // connecting peers
func (self *Kademlia) Prune(c <-chan time.Time) { func (k *Kademlia) Prune(c <-chan time.Time) {
go func() { go func() {
for range c { for range c {
total := 0 total := 0
self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(pot.PotVal, int) bool) bool) bool { k.conns.EachBin(k.base, 0, func(po, size int, f func(func(pot.Val, int) bool) bool) bool {
extra := size - self.MinBinSize extra := size - k.MinBinSize
if size > self.MaxBinSize { if size > k.MaxBinSize {
n := 0 n := 0
f(func(v pot.PotVal, po int) bool { f(func(v pot.Val, po int) bool {
v.(*entry).conn().Drop(fmt.Errorf("bucket full")) v.(*entry).conn().Drop(fmt.Errorf("bucket full"))
n++ n++
return n < extra return n < extra
@ -511,25 +499,28 @@ func (self *Kademlia) Prune(c <-chan time.Time) {
} }
return true return true
}) })
log.Debug(fmt.Sprintf("pruned %v peers", total)) log.Trace(fmt.Sprintf("pruned %v peers", total))
} }
}() }()
} }
// NewPeerPot just creates a new pot record OverlayAddr
func NewPeerPot(kadMinProxSize int, ids ...discover.NodeID) map[discover.NodeID][][]byte { func NewPeerPot(kadMinProxSize int, ids ...discover.NodeID) map[discover.NodeID][][]byte {
// create a table of all nodes for health check // create a table of all nodes for health check
np := pot.NewPot(nil, 0) np := pot.NewPot(nil, 0, nil)
for _, id := range ids { for _, id := range ids {
o := ToOverlayAddr(id.Bytes()) o := ToOverlayAddr(id.Bytes())
np, _, _ = pot.Add(np, pot.NewBytesVal(o, nil)) np, _, _ = pot.Add(np, o)
} }
nnmap := make(map[discover.NodeID][][]byte) nnmap := make(map[discover.NodeID][][]byte)
for _, id := range ids { for _, id := range ids {
pl := 0 pl := 0
var nns [][]byte var nns [][]byte
np.EachNeighbour(pot.NewBytesVal(id.Bytes(), nil), func(val pot.PotVal, po int) bool { np.EachNeighbour(id.Bytes(), func(val pot.Val, po int) bool {
a := val.(pot.BytesAddress).Address() // a := val.(pot.BytesAddress).Address()
// nns = append(nns, a)
a := val.([]byte)
nns = append(nns, a) nns = append(nns, a)
if len(nns) >= kadMinProxSize { if len(nns) >= kadMinProxSize {
pl = po pl = po
@ -541,9 +532,10 @@ func NewPeerPot(kadMinProxSize int, ids ...discover.NodeID) map[discover.NodeID]
return nnmap return nnmap
} }
func (self *Kademlia) FirstEmptyBin() (i int) { // FirstEmptyBin returns the farthest proximity order (int) that has no peer records
func (k *Kademlia) FirstEmptyBin() (i int) {
i = -1 i = -1
self.conns.EachBin(pot.NewBytesVal(self.base, nil), 0, func(po, size int, f func(func(val pot.PotVal, i int) bool) bool) bool { k.conns.EachBin(k.base, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
if po > i+1 { if po > i+1 {
i = po i = po
return false return false
@ -554,22 +546,22 @@ func (self *Kademlia) FirstEmptyBin() (i int) {
return i return i
} }
func (self *Kademlia) Full() bool { // Full returns a bool if the kademlia table is healthy and complete
return self.FirstEmptyBin() >= self.Depth() func (k *Kademlia) Full() bool {
return k.FirstEmptyBin() >= k.Depth()
} }
// Healthy reports the health state of the kademlia connectivity // Healthy reports the health state of the kademlia connectivity
// func (k *Kademlia) Healthy(peers [][]byte) bool {
func (self *Kademlia) Healthy(peers [][]byte) bool { return k.gotNearestNeighbours(peers) && k.Full()
return self.gotNearestNeighbours(peers) && self.Full()
} }
func (self *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool) { func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool) {
pm := make(map[string]bool) pm := make(map[string]bool)
for _, p := range peers { for _, p := range peers {
pm[string(p)] = true pm[string(p)] = true
} }
self.EachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool { k.EachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool {
if !nn { if !nn {
return false return false
} }

View file

@ -28,12 +28,13 @@ import (
func init() { func init() {
h := log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))) h := log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))
// h := log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))
// h := log.CallerFileHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(true))) // h := log.CallerFileHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(true)))
log.Root().SetHandler(h) log.Root().SetHandler(h)
} }
func testKadPeerAddr(s string) *bzzAddr { func testKadPeerAddr(s string) *bzzAddr {
a := pot.NewHashAddress(s).Bytes() a := pot.NewAddressFromString(s)
return &bzzAddr{OAddr: a, UAddr: a} return &bzzAddr{OAddr: a, UAddr: a}
} }
@ -54,7 +55,7 @@ type testPeerNotification struct {
po uint8 po uint8
} }
type testProxNotification struct { type testDepthNotification struct {
rec string rec string
po uint8 po uint8
} }
@ -99,7 +100,7 @@ func newTestKademlia(b string) *testKademlia {
params := NewKadParams() params := NewKadParams()
params.MinBinSize = 1 params.MinBinSize = 1
params.MinProxBinSize = 2 params.MinProxBinSize = 2
base := pot.NewHashAddress(b).Bytes() base := pot.NewAddressFromString(b)
return &testKademlia{ return &testKademlia{
NewKademlia(base, params), NewKademlia(base, params),
false, false,
@ -119,8 +120,7 @@ func (k *testKademlia) newTestKadPeer(s string) Peer {
func (k *testKademlia) On(ons ...string) *testKademlia { func (k *testKademlia) On(ons ...string) *testKademlia {
for _, s := range ons { for _, s := range ons {
p := k.newTestKadPeer(s) k.Kademlia.On(k.newTestKadPeer(s).(OverlayConn))
k.Kademlia.On(p)
} }
return k return k
} }
@ -158,6 +158,7 @@ func testSuggestPeer(t *testing.T, k *testKademlia, expAddr string, expPo int, e
if want != expWant { if want != expWant {
return fmt.Errorf("expected SuggestPeer to want peers: %v", expWant) return fmt.Errorf("expected SuggestPeer to want peers: %v", expWant)
} }
// t.Logf("%v", k)
return nil return nil
} }
@ -165,50 +166,50 @@ func binStr(a OverlayPeer) string {
if a == nil { if a == nil {
return "<nil>" return "<nil>"
} }
return pot.ToBin(a.Address())[:6] return pot.ToBin(a.Address())[:8]
} }
func TestSuggestPeerFindPeers(t *testing.T) { func TestSuggestPeerFindPeers(t *testing.T) {
// 2 row gap, unsaturated proxbin, no callables -> want PO 0 // 2 row gap, unsaturated proxbin, no callables -> want PO 0
k := newTestKademlia("000000").On("001000") k := newTestKademlia("00000000").On("00100000")
// k.MinProxBinSize = 2
// k.MinBinSize = 2
err := testSuggestPeer(t, k, "<nil>", 0, true) err := testSuggestPeer(t, k, "<nil>", 0, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// 2 row gap, saturated proxbin, no callables -> want PO 0 // 2 row gap, saturated proxbin, no callables -> want PO 0
k.On("000100") k.On("00010000")
err = testSuggestPeer(t, k, "<nil>", 0, true) err = testSuggestPeer(t, k, "<nil>", 0, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// 1 row gap (1 less), saturated proxbin, no callables -> want PO 1 // 1 row gap (1 less), saturated proxbin, no callables -> want PO 1
k.On("100000") k.On("10000000")
err = testSuggestPeer(t, k, "<nil>", 1, true) err = testSuggestPeer(t, k, "<nil>", 1, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// no gap (1 less), saturated proxbin, no callables -> do not want more // no gap (1 less), saturated proxbin, no callables -> do not want more
k.On("010000", "001001") k.On("01000000", "00100001")
err = testSuggestPeer(t, k, "<nil>", 0, false) err = testSuggestPeer(t, k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// oversaturated proxbin, > do not want more // oversaturated proxbin, > do not want more
k.On("001001") k.On("00100001")
err = testSuggestPeer(t, k, "<nil>", 0, false) err = testSuggestPeer(t, k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// reintroduce gap, disconnected peer callable // reintroduce gap, disconnected peer callable
k.Off("010000") log.Info(k.String())
err = testSuggestPeer(t, k, "010000", 0, false) k.Off("01000000")
log.Info(k.String())
err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -221,31 +222,33 @@ func TestSuggestPeerFindPeers(t *testing.T) {
} }
// on and off again, peer callable again // on and off again, peer callable again
k.On("010000") k.On("01000000")
k.Off("010000") k.Off("01000000")
err = testSuggestPeer(t, k, "010000", 0, false) err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("010000") k.On("01000000")
// new closer peer appears, it is immediately wanted // new closer peer appears, it is immediately wanted
k.Register("000101") k.Register("00010001")
err = testSuggestPeer(t, k, "000101", 0, false) err = testSuggestPeer(t, k, "00010001", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
// PO1 disconnects // PO1 disconnects
k.On("000101") k.On("00010001")
k.Off("010000") log.Info(k.String())
k.Off("01000000")
log.Info(k.String())
// second time, gap filling // second time, gap filling
err = testSuggestPeer(t, k, "010000", 0, false) err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("010000") k.On("01000000")
err = testSuggestPeer(t, k, "<nil>", 0, false) err = testSuggestPeer(t, k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
@ -257,53 +260,53 @@ func TestSuggestPeerFindPeers(t *testing.T) {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.Register("010001") k.Register("01000001")
err = testSuggestPeer(t, k, "<nil>", 0, true) err = testSuggestPeer(t, k, "<nil>", 0, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("100001") k.On("10000001")
log.Trace("Kad:\n%v", k.String()) log.Trace("Kad:\n%v", k.String())
err = testSuggestPeer(t, k, "010001", 0, false) err = testSuggestPeer(t, k, "01000001", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("100001") k.On("10000001")
k.On("010001") k.On("01000001")
err = testSuggestPeer(t, k, "<nil>", 0, false) err = testSuggestPeer(t, k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.MinBinSize = 3 k.MinBinSize = 3
k.Register("100010") k.Register("10000010")
err = testSuggestPeer(t, k, "100010", 0, false) err = testSuggestPeer(t, k, "10000010", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("100010") k.On("10000010")
err = testSuggestPeer(t, k, "<nil>", 1, true) err = testSuggestPeer(t, k, "<nil>", 1, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("010010") k.On("01000010")
err = testSuggestPeer(t, k, "<nil>", 2, true) err = testSuggestPeer(t, k, "<nil>", 2, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("001010") k.On("00100010")
err = testSuggestPeer(t, k, "<nil>", 3, true) err = testSuggestPeer(t, k, "<nil>", 3, true)
if err != nil { if err != nil {
log.Trace("Kad:\n%v", k.String()) log.Trace("Kad:\n%v", k.String())
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k.On("000110") k.On("00010010")
err = testSuggestPeer(t, k, "<nil>", 0, false) err = testSuggestPeer(t, k, "<nil>", 0, false)
if err != nil { if err != nil {
log.Trace("Kad:\n%v", k.String()) log.Trace("Kad:\n%v", k.String())
@ -314,14 +317,14 @@ func TestSuggestPeerFindPeers(t *testing.T) {
func TestSuggestPeerRetries(t *testing.T) { func TestSuggestPeerRetries(t *testing.T) {
// 2 row gap, unsaturated proxbin, no callables -> want PO 0 // 2 row gap, unsaturated proxbin, no callables -> want PO 0
k := newTestKademlia("000000") k := newTestKademlia("00000000")
cycle := 50 * time.Millisecond cycle := 50 * time.Millisecond
k.RetryInterval = int(cycle) k.RetryInterval = int(cycle)
k.MaxRetries = 3 k.MaxRetries = 3
k.RetryExponent = 3 k.RetryExponent = 3
k.Register("010000") k.Register("01000000")
k.On("000001", "000010") k.On("00000001", "00000010")
err := testSuggestPeer(t, k, "010000", 0, false) err := testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -333,7 +336,7 @@ func TestSuggestPeerRetries(t *testing.T) {
// cycle *= time.Duration(k.RetryExponent) // cycle *= time.Duration(k.RetryExponent)
time.Sleep(cycle) time.Sleep(cycle)
err = testSuggestPeer(t, k, "010000", 0, false) err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -345,7 +348,7 @@ func TestSuggestPeerRetries(t *testing.T) {
cycle *= time.Duration(k.RetryExponent) cycle *= time.Duration(k.RetryExponent)
time.Sleep(cycle) time.Sleep(cycle)
err = testSuggestPeer(t, k, "010000", 0, false) err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -357,7 +360,7 @@ func TestSuggestPeerRetries(t *testing.T) {
cycle *= time.Duration(k.RetryExponent) cycle *= time.Duration(k.RetryExponent)
time.Sleep(cycle) time.Sleep(cycle)
err = testSuggestPeer(t, k, "010000", 0, false) err = testSuggestPeer(t, k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -378,10 +381,10 @@ func TestSuggestPeerRetries(t *testing.T) {
} }
func TestPruning(t *testing.T) { func TestPruning(t *testing.T) {
k := newTestKademlia("000000") k := newTestKademlia("00000000")
k.On("100000", "110000", "101000", "100100", "100010") k.On("10000000", "11000000", "10100000", "10010000", "10000010")
k.On("010000", "011000", "010100", "010010", "010001") k.On("01000000", "01100000", "01000100", "01000010", "01000001")
k.On("001000", "001100", "001010", "001001") k.On("00100000", "00110000", "00100010", "00100001")
k.MaxBinSize = 4 k.MaxBinSize = 4
k.MinBinSize = 3 k.MinBinSize = 3
prune := make(chan time.Time) prune := make(chan time.Time)
@ -411,10 +414,10 @@ func TestPruning(t *testing.T) {
// TODO: this is now based on just taking the first 2 peers // TODO: this is now based on just taking the first 2 peers
// in order of connecting // in order of connecting
expDropped := []string{ expDropped := []string{
"101000", "10100000",
"110000", "11000000",
"010100", "01000100",
"011000", "01100000",
} }
for _, addr := range expDropped { for _, addr := range expDropped {
err := dropped[addr] err := dropped[addr]
@ -428,7 +431,7 @@ func TestPruning(t *testing.T) {
} }
func TestKademliaHiveString(t *testing.T) { func TestKademliaHiveString(t *testing.T) {
k := newTestKademlia("000000").On("010000", "001000").Register("100000", "100001") k := newTestKademlia("00000000").On("01000000", "00100000").Register("10000000", "10000001")
h := k.String() h := k.String()
expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), MinProxBinSize: 2, MinBinSize: 1, MaxBinSize: 4\n============ PROX LIMIT: 0 ==========================================\n000 0 | 2 840000 800000\n001 1 400000 | 1 400000\n002 1 200000 | 1 200000\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n=========================================================================" expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), MinProxBinSize: 2, MinBinSize: 1, MaxBinSize: 4\n============ PROX LIMIT: 0 ==========================================\n000 0 | 2 840000 800000\n001 1 400000 | 1 400000\n002 1 200000 | 1 200000\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n========================================================================="
if expH[100:] != h[100:] { if expH[100:] != h[100:] {
@ -436,7 +439,7 @@ func TestKademliaHiveString(t *testing.T) {
} }
} }
func (self *testKademlia) checkNotifications(npeers []*testPeerNotification, nprox []*testProxNotification) error { func (self *testKademlia) checkNotifications(npeers []*testPeerNotification, nprox []*testDepthNotification) error {
for _, pn := range npeers { for _, pn := range npeers {
key := pn.rec + pn.addr key := pn.rec + pn.addr
po, found := self.notifications[key] po, found := self.notifications[key]
@ -460,50 +463,50 @@ func (self *testKademlia) checkNotifications(npeers []*testPeerNotification, npr
} }
func TestNotifications(t *testing.T) { func TestNotifications(t *testing.T) {
k := newTestKademlia("000000") k := newTestKademlia("00000000")
k.Discovery = true k.Discovery = true
k.MinProxBinSize = 3 k.MinProxBinSize = 3
k.On("010000", "001000") k.On("01000000", "00100000")
time.Sleep(1000 * time.Millisecond) time.Sleep(1000 * time.Millisecond)
err := k.checkNotifications( err := k.checkNotifications(
[]*testPeerNotification{ []*testPeerNotification{
&testPeerNotification{"010000", "001000", 1}, &testPeerNotification{"01000000", "00100000", 1},
}, },
[]*testProxNotification{ []*testDepthNotification{
&testProxNotification{"001000", 0}, &testDepthNotification{"00100000", 0},
&testProxNotification{"010000", 0}, &testDepthNotification{"01000000", 0},
}, },
) )
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
k = k.On("100000") k = k.On("10000000")
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
k.checkNotifications( k.checkNotifications(
[]*testPeerNotification{ []*testPeerNotification{
&testPeerNotification{"010000", "100000", 0}, &testPeerNotification{"01000000", "10000000", 0},
&testPeerNotification{"001000", "100000", 0}, &testPeerNotification{"00100000", "10000000", 0},
}, },
[]*testProxNotification{ []*testDepthNotification{
&testProxNotification{"100000", 0}, &testDepthNotification{"10000000", 0},
}, },
) )
k = k.On("010001") k = k.On("01000001")
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
k.checkNotifications( k.checkNotifications(
[]*testPeerNotification{ []*testPeerNotification{
&testPeerNotification{"010000", "010001", 5}, &testPeerNotification{"01000000", "01000001", 5},
&testPeerNotification{"001000", "010001", 1}, &testPeerNotification{"00100000", "01000001", 1},
&testPeerNotification{"100000", "010001", 0}, &testPeerNotification{"10000000", "01000001", 0},
}, },
[]*testProxNotification{ []*testDepthNotification{
&testProxNotification{"100000", 0}, &testDepthNotification{"10000000", 0},
&testProxNotification{"010000", 0}, &testDepthNotification{"01000000", 0},
&testProxNotification{"010001", 0}, &testDepthNotification{"01000001", 0},
&testProxNotification{"001000", 0}, &testDepthNotification{"00100000", 0},
}, },
) )
} }

View file

@ -333,15 +333,15 @@ func RandomAddr() *bzzAddr {
pubkey := crypto.FromECDSAPub(&key.PublicKey) pubkey := crypto.FromECDSAPub(&key.PublicKey)
var id discover.NodeID var id discover.NodeID
copy(id[:], pubkey[1:]) copy(id[:], pubkey[1:])
return &bzzAddr{ return NewAddrFromNodeID(id)
OAddr: crypto.Keccak256(pubkey[1:]),
UAddr: id[:],
}
} }
// NewNodeIDFromAddr transforms the underlay address to an adapters.NodeID // NewNodeIDFromAddr transforms the underlay address to an adapters.NodeID
func NewNodeIDFromAddr(addr Addr) discover.NodeID { func NewNodeIDFromAddr(addr Addr) discover.NodeID {
return discover.MustBytesID(addr.Under()) log.Info(fmt.Sprintf("uaddr=%s", string(addr.Under())))
node := discover.MustParseNode(string(addr.Under()))
// return discover.MustBytesID(addr.Under())
return node.ID
} }
// NewAddrFromNodeID constucts a bzzAddr from a discover.NodeID // NewAddrFromNodeID constucts a bzzAddr from a discover.NodeID

View file

@ -57,7 +57,7 @@ func TestDiscoverySimulationSimAdapter(t *testing.T) {
} }
func testDiscoverySimulation(t *testing.T, adapter adapters.NodeAdapter) { func testDiscoverySimulation(t *testing.T, adapter adapters.NodeAdapter) {
// create 10 node network // create network
nodeCount := 10 nodeCount := 10
net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
ID: "0", ID: "0",

View file

@ -209,8 +209,9 @@ func main() {
config := &simulations.ServerConfig{ config := &simulations.ServerConfig{
NewAdapter: func() adapters.NodeAdapter { return adapters.NewSimAdapter(services) }, NewAdapter: func() adapters.NodeAdapter { return adapters.NewSimAdapter(services) },
DefaultMockerID: "bootNet", DefaultMockerID: "randomNodes",
Mockers: mockers, // DefaultMockerID: "bootNet",
Mockers: mockers,
} }
log.Info("starting simulation server on 0.0.0.0:8888...") log.Info("starting simulation server on 0.0.0.0:8888...")

View file

@ -133,8 +133,8 @@ func (self *Pss) Protocols() []p2p.Protocol {
func (self *Pss) Run(p *p2p.Peer, rw p2p.MsgReadWriter) error { func (self *Pss) Run(p *p2p.Peer, rw p2p.MsgReadWriter) error {
pp := protocols.NewPeer(p, rw, pssSpec) pp := protocols.NewPeer(p, rw, pssSpec)
id := p.ID() id := p.ID()
h := pot.NewHashAddressFromBytes(network.ToOverlayAddr(id[:])) a := pot.NewAddressFromBytes(network.ToOverlayAddr(id[:]))
self.fwdPool[h.Address] = pp self.fwdPool[a] = pp
return pp.Run(self.handlePssMsg) return pp.Run(self.handlePssMsg)
} }
@ -315,9 +315,8 @@ func (self *Pss) Forward(msg *PssMsg) error {
// send with kademlia // send with kademlia
// find the closest peer to the recipient and attempt to send // find the closest peer to the recipient and attempt to send
self.Overlay.EachConn(msg.To, 256, func(op network.OverlayConn, po int, isproxbin bool) bool { self.Overlay.EachConn(msg.To, 256, func(op network.OverlayConn, po int, isproxbin bool) bool {
//p, ok := op.(senderPeer) a := pot.NewAddressFromBytes(op.Address())
h := pot.NewHashAddressFromBytes(op.Address()) pp := self.fwdPool[a]
pp := self.fwdPool[h.Address]
addr := self.Overlay.BaseAddr() addr := self.Overlay.BaseAddr()
sendMsg := fmt.Sprintf("%x: msg to %x via %x", common.ByteLabel(addr), common.ByteLabel(msg.To), common.ByteLabel(op.Address())) sendMsg := fmt.Sprintf("%x: msg to %x via %x", common.ByteLabel(addr), common.ByteLabel(msg.To), common.ByteLabel(op.Address()))
if self.checkFwdCache(op.Address(), digest) { if self.checkFwdCache(op.Address(), digest) {
@ -459,7 +458,7 @@ func RegisterPssProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprot
} }
func (self *PssProtocol) handle(msg []byte, p *p2p.Peer, senderAddr []byte) error { func (self *PssProtocol) handle(msg []byte, p *p2p.Peer, senderAddr []byte) error {
hashoaddr := pot.NewHashAddressFromBytes(senderAddr).Address hashoaddr := pot.NewAddressFromBytes(senderAddr)
if !self.isActive(hashoaddr, *self.topic) { if !self.isActive(hashoaddr, *self.topic) {
rw := &PssReadWriter{ rw := &PssReadWriter{
Pss: self.Pss, Pss: self.Pss,

View file

@ -199,8 +199,8 @@ func TestSimpleLinear(t *testing.T) {
Peer: pp, Peer: pp,
addr: network.ToOverlayAddr(id[:]), addr: network.ToOverlayAddr(id[:]),
} }
h := pot.NewHashAddressFromBytes(bp.addr) a := pot.NewAddressFromBytes(bp.addr)
ps.fwdPool[h.Address] = pp ps.fwdPool[a] = pp
ps.Overlay.On(bp) ps.Overlay.On(bp)
defer ps.Overlay.Off(bp) defer ps.Overlay.Off(bp)
log.Debug(fmt.Sprintf("%v", ps.Overlay)) log.Debug(fmt.Sprintf("%v", ps.Overlay))