Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
f37f7967
Unverified
Commit
f37f7967
authored
May 17, 2021
by
Esad Akar
Committed by
GitHub
May 17, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: bootnodes drop peers from oversaturated bins (#1715)
parent
04e90294
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
160 additions
and
62 deletions
+160
-62
export_test.go
pkg/topology/kademlia/export_test.go
+4
-3
kademlia.go
pkg/topology/kademlia/kademlia.go
+68
-33
kademlia_test.go
pkg/topology/kademlia/kademlia_test.go
+88
-26
No files found.
pkg/topology/kademlia/export_test.go
View file @
f37f7967
...
...
@@ -5,7 +5,8 @@
package
kademlia
var
(
TimeToRetry
=
&
timeToRetry
SaturationPeers
=
&
saturationPeers
OverSaturationPeers
=
&
overSaturationPeers
TimeToRetry
=
&
timeToRetry
SaturationPeers
=
&
saturationPeers
OverSaturationPeers
=
&
overSaturationPeers
BootnodeOverSaturationPeers
=
&
bootnodeOverSaturationPeers
)
pkg/topology/kademlia/kademlia.go
View file @
f37f7967
...
...
@@ -34,16 +34,18 @@ const (
)
var
(
saturationPeers
=
4
overSaturationPeers
=
16
shortRetry
=
30
*
time
.
Second
timeToRetry
=
2
*
shortRetry
broadcastBinSize
=
4
saturationPeers
=
4
overSaturationPeers
=
16
bootnodeOverSaturationPeers
=
64
shortRetry
=
30
*
time
.
Second
timeToRetry
=
2
*
shortRetry
broadcastBinSize
=
4
)
var
(
errOverlayMismatch
=
errors
.
New
(
"overlay mismatch"
)
errPruneEntry
=
errors
.
New
(
"prune entry"
)
errEmptyBin
=
errors
.
New
(
"empty bin"
)
)
type
binSaturationFunc
func
(
bin
uint8
,
peers
,
connected
*
pslice
.
PSlice
)
(
saturated
bool
,
oversaturated
bool
)
...
...
@@ -101,7 +103,11 @@ func New(base swarm.Address,
logger
logging
.
Logger
,
o
Options
)
*
Kad
{
if
o
.
SaturationFunc
==
nil
{
o
.
SaturationFunc
=
binSaturated
os
:=
overSaturationPeers
if
o
.
BootnodeMode
{
os
=
bootnodeOverSaturationPeers
}
o
.
SaturationFunc
=
binSaturated
(
os
)
}
if
o
.
BitSuffixLength
==
0
{
o
.
BitSuffixLength
=
defaultBitSuffixLength
...
...
@@ -543,30 +549,32 @@ func (k *Kad) connectBootnodes(ctx context.Context) {
// binSaturated indicates whether a certain bin is saturated or not.
// when a bin is not saturated it means we would like to proactively
// initiate connections to other peers in the bin.
func
binSaturated
(
bin
uint8
,
peers
,
connected
*
pslice
.
PSlice
)
(
bool
,
bool
)
{
potentialDepth
:=
recalcDepth
(
peers
,
swarm
.
MaxPO
)
// short circuit for bins which are >= depth
if
bin
>=
potentialDepth
{
return
false
,
false
}
func
binSaturated
(
oversaturationAmount
int
)
binSaturationFunc
{
return
func
(
bin
uint8
,
peers
,
connected
*
pslice
.
PSlice
)
(
bool
,
bool
)
{
potentialDepth
:=
recalcDepth
(
peers
,
swarm
.
MaxPO
)
// lets assume for now that the minimum number of peers in a bin
// would be 2, under which we would always want to connect to new peers
// obviously this should be replaced with a better optimization
// the iterator is used here since when we check if a bin is saturated,
// the plain number of size of bin might not suffice (for example for squared
// gaps measurement)
size
:=
0
_
=
connected
.
EachBin
(
func
(
_
swarm
.
Address
,
po
uint8
)
(
bool
,
bool
,
error
)
{
if
po
==
bin
{
size
++
// short circuit for bins which are >= depth
if
bin
>=
potentialDepth
{
return
false
,
false
}
return
false
,
false
,
nil
})
return
size
>=
saturationPeers
,
size
>=
overSaturationPeers
// lets assume for now that the minimum number of peers in a bin
// would be 2, under which we would always want to connect to new peers
// obviously this should be replaced with a better optimization
// the iterator is used here since when we check if a bin is saturated,
// the plain number of size of bin might not suffice (for example for squared
// gaps measurement)
size
:=
0
_
=
connected
.
EachBin
(
func
(
_
swarm
.
Address
,
po
uint8
)
(
bool
,
bool
,
error
)
{
if
po
==
bin
{
size
++
}
return
false
,
false
,
nil
})
return
size
>=
saturationPeers
,
size
>=
oversaturationAmount
}
}
// recalcDepth calculates and returns the kademlia depth.
...
...
@@ -763,15 +771,26 @@ func (k *Kad) Pick(peer p2p.Peer) bool {
// Connected is called when a peer has dialed in.
func
(
k
*
Kad
)
Connected
(
ctx
context
.
Context
,
peer
p2p
.
Peer
)
error
{
if
!
k
.
bootnode
{
// don't run this check if we're a bootnode
po
:=
swarm
.
Proximity
(
k
.
base
.
Bytes
(),
peer
.
Address
.
Bytes
())
if
_
,
overSaturated
:=
k
.
saturationFunc
(
po
,
k
.
knownPeers
,
k
.
connectedPeers
);
overSaturated
{
return
topology
.
ErrOversaturated
address
:=
peer
.
Address
po
:=
swarm
.
Proximity
(
k
.
base
.
Bytes
(),
address
.
Bytes
())
if
_
,
overSaturated
:=
k
.
saturationFunc
(
po
,
k
.
knownPeers
,
k
.
connectedPeers
);
overSaturated
{
if
k
.
bootnode
{
randPeer
,
err
:=
k
.
randomPeer
(
po
)
if
err
!=
nil
{
return
err
}
_
=
k
.
p2p
.
Disconnect
(
randPeer
)
goto
connected
}
return
topology
.
ErrOversaturated
}
if
err
:=
k
.
connected
(
ctx
,
peer
.
Address
);
err
!=
nil
{
connected
:
if
err
:=
k
.
connected
(
ctx
,
address
);
err
!=
nil
{
return
err
}
...
...
@@ -1203,3 +1222,19 @@ func randomSubset(addrs []swarm.Address, count int) ([]swarm.Address, error) {
return
addrs
[
:
count
],
nil
}
func
(
k
*
Kad
)
randomPeer
(
bin
uint8
)
(
swarm
.
Address
,
error
)
{
peers
:=
k
.
connectedPeers
.
BinPeers
(
bin
)
if
len
(
peers
)
==
0
{
return
swarm
.
ZeroAddress
,
errEmptyBin
}
rndIndx
,
err
:=
random
.
Int
(
random
.
Reader
,
big
.
NewInt
(
int64
(
len
(
peers
))))
if
err
!=
nil
{
return
swarm
.
ZeroAddress
,
err
}
return
peers
[
rndIndx
.
Int64
()],
nil
}
pkg/topology/kademlia/kademlia_test.go
View file @
f37f7967
...
...
@@ -537,6 +537,60 @@ func TestOversaturationBootnode(t *testing.T) {
}
}
func
TestBootnodeMaxConnections
(
t
*
testing
.
T
)
{
defer
func
(
p
int
)
{
*
kademlia
.
BootnodeOverSaturationPeers
=
p
}(
*
kademlia
.
BootnodeOverSaturationPeers
)
*
kademlia
.
BootnodeOverSaturationPeers
=
4
var
(
conns
int32
// how many connect calls were made to the p2p mock
base
,
kad
,
ab
,
_
,
signer
=
newTestKademlia
(
&
conns
,
nil
,
kademlia
.
Options
{
BootnodeMode
:
true
})
)
kad
.
SetRadius
(
swarm
.
MaxPO
)
// don't use radius for checks
if
err
:=
kad
.
Start
(
context
.
Background
());
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
kad
.
Close
()
// Add maximum accepted number of peers up until bin 5 without problems
for
i
:=
0
;
i
<
6
;
i
++
{
for
j
:=
0
;
j
<
*
kademlia
.
BootnodeOverSaturationPeers
;
j
++
{
addr
:=
test
.
RandomAddressAt
(
base
,
i
)
// if error is not nil as specified, connectOne goes fatal
connectOne
(
t
,
signer
,
kad
,
ab
,
addr
,
nil
)
}
// see depth is limited to currently added peers proximity
kDepth
(
t
,
kad
,
i
)
}
// see depth is 5
kDepth
(
t
,
kad
,
5
)
depth
:=
5
outSideDepthPeers
:=
5
for
k
:=
0
;
k
<
depth
;
k
++
{
// further connections should succeed outside of depth
for
l
:=
0
;
l
<
outSideDepthPeers
;
l
++
{
addr
:=
test
.
RandomAddressAt
(
base
,
k
)
// if error is not as specified, connectOne goes fatal
connectOne
(
t
,
signer
,
kad
,
ab
,
addr
,
nil
)
// check that pick works correctly
if
!
kad
.
Pick
(
p2p
.
Peer
{
Address
:
addr
})
{
t
.
Fatal
(
"should pick the peer but didnt"
)
}
}
}
got
:=
atomic
.
LoadInt32
(
&
conns
)
want
:=
-
int32
(
depth
*
outSideDepthPeers
)
if
got
!=
want
{
t
.
Fatalf
(
"got %d, want %d"
,
got
,
want
)
}
}
// TestNotifierHooks tests that the Connected/Disconnected hooks
// result in the correct behavior once called.
func
TestNotifierHooks
(
t
*
testing
.
T
)
{
...
...
@@ -1055,38 +1109,46 @@ func newTestKademlia(connCounter, failedConnCounter *int32, kadOpts kademlia.Opt
}
func
p2pMock
(
ab
addressbook
.
Interface
,
signer
beeCrypto
.
Signer
,
counter
,
failedCounter
*
int32
)
p2p
.
Service
{
p2ps
:=
p2pmock
.
New
(
p2pmock
.
WithConnectFunc
(
func
(
ctx
context
.
Context
,
addr
ma
.
Multiaddr
)
(
*
bzz
.
Address
,
error
)
{
if
addr
.
Equal
(
nonConnectableAddress
)
{
_
=
atomic
.
AddInt32
(
failedCounter
,
1
)
return
nil
,
errors
.
New
(
"non reachable node"
)
}
if
counter
!=
nil
{
_
=
atomic
.
AddInt32
(
counter
,
1
)
}
p2ps
:=
p2pmock
.
New
(
p2pmock
.
WithConnectFunc
(
func
(
ctx
context
.
Context
,
addr
ma
.
Multiaddr
)
(
*
bzz
.
Address
,
error
)
{
if
addr
.
Equal
(
nonConnectableAddress
)
{
_
=
atomic
.
AddInt32
(
failedCounter
,
1
)
return
nil
,
errors
.
New
(
"non reachable node"
)
}
if
counter
!=
nil
{
_
=
atomic
.
AddInt32
(
counter
,
1
)
}
addresses
,
err
:=
ab
.
Addresses
()
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"could not fetch addresbook addresses"
)
}
addresses
,
err
:=
ab
.
Addresses
()
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"could not fetch addresbook addresses"
)
}
for
_
,
a
:=
range
addresses
{
if
a
.
Underlay
.
Equal
(
addr
)
{
return
&
a
,
nil
for
_
,
a
:=
range
addresses
{
if
a
.
Underlay
.
Equal
(
addr
)
{
return
&
a
,
nil
}
}
}
address
:=
test
.
RandomAddress
()
bzzAddr
,
err
:=
bzz
.
NewAddress
(
signer
,
addr
,
address
,
0
)
if
err
!=
nil
{
return
nil
,
err
}
address
:=
test
.
RandomAddress
()
bzzAddr
,
err
:=
bzz
.
NewAddress
(
signer
,
addr
,
address
,
0
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
ab
.
Put
(
address
,
*
bzzAddr
);
err
!=
nil
{
return
nil
,
err
}
if
err
:=
ab
.
Put
(
address
,
*
bzzAddr
);
err
!=
nil
{
return
nil
,
err
}
return
bzzAddr
,
nil
}))
return
bzzAddr
,
nil
}),
p2pmock
.
WithDisconnectFunc
(
func
(
swarm
.
Address
)
error
{
if
counter
!=
nil
{
_
=
atomic
.
AddInt32
(
counter
,
-
1
)
}
return
nil
}),
)
return
p2ps
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment