Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move go-libp2p-discovery to p2p/discovery/generic #1280

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
729ccf7
interface and utility functions
vyzo Oct 12, 2018
6f35407
discovery implementation using ContentRouting
vyzo Oct 12, 2018
18d33e6
niceties and best practices
vyzo Oct 18, 2018
78e044b
test and gx package update
vyzo Oct 18, 2018
529d255
document the use of SHA256 as the cid hash function
vyzo Oct 18, 2018
78be55e
use 6hrs as ttl for routing based advertisements
vyzo Feb 12, 2019
28991ad
Merge pull request #8 from libp2p/fix/ttl
vyzo Feb 12, 2019
d79d2b3
correctly encode ns to CID
vyzo Feb 14, 2019
74c1088
Merge pull request #11 from libp2p/fix/issue-10
vyzo Feb 14, 2019
ad52aea
add a timeout to Provide in routing.Advertise
vyzo Feb 14, 2019
431fb82
clarify comment.
raulk Feb 14, 2019
f87fdaa
Merge pull request #12 from libp2p/fix/provide-timeout
vyzo Feb 14, 2019
f2dbbfc
remove Jenkinsfile.
raulk Mar 11, 2019
ff747ff
use 3hrs as routing advertisement ttl
vyzo Apr 13, 2019
2914cd6
Merge pull request #23 from libp2p/fix/routing-advertisement-period
Stebalien Apr 16, 2019
6b503a0
allow user-spceified TTL in routing advertisements
vyzo May 16, 2019
8780de3
add options to utility interface
vyzo May 16, 2019
548f847
fix test
vyzo May 16, 2019
740aa16
Merge pull request #25 from libp2p/feat/options
vyzo May 17, 2019
9ecee91
Consolidate abstractions and core types into go-libp2p-core (#24)
raulk May 26, 2019
4af0294
added initial backoff cache discovery
aschmahmann Sep 6, 2019
321bb64
added discovery based content routing
aschmahmann Sep 6, 2019
7b39072
added discovery options to discovery based content routing
aschmahmann Sep 6, 2019
aab2fe9
refactored backoffcache and increased an internal channel size.
aschmahmann Sep 8, 2019
6b0ce1b
refactor constructor functions for BackoffFactory implementations. re…
aschmahmann Sep 8, 2019
4e95d0b
polynomialbackoff: added checks for small degree polynomials
aschmahmann Oct 11, 2019
8b246a3
add backoff connector
aschmahmann Oct 11, 2019
feebad9
Merge branch 'feat/backoff' of github.com:libp2p/go-libp2p-discovery …
aschmahmann Oct 11, 2019
786613c
fix and tests for backoff connector
aschmahmann Oct 13, 2019
82c6465
added configurable channel buffer sizes to the backoff cache.
aschmahmann Oct 13, 2019
8427751
Merge pull request #27 from libp2p/feat/content-routing
aschmahmann Oct 16, 2019
c1adae4
added backoff docstrings
aschmahmann Oct 25, 2019
e73e1f4
Merge branch 'master' into feat/backoff
aschmahmann Oct 25, 2019
443c5e0
merge in discovery based content routing changes. moved mock discover…
aschmahmann Oct 25, 2019
9e6f484
cleanup some function signatures
aschmahmann Oct 29, 2019
646b138
cleanup backoffcache event dispatching logic
aschmahmann Oct 29, 2019
da0575a
more documentation and function argument coalescing
aschmahmann Oct 29, 2019
5b180a2
Merge pull request #26 from libp2p/feat/backoff
Stebalien Oct 30, 2019
7637c9d
add tests for backoff factory reuse
aschmahmann Apr 22, 2020
b6d7176
backoff strategy factory constructors take random seeds instead of ra…
aschmahmann Apr 22, 2020
f700a5d
backoff strategy factory constructors take sources instead of seeds f…
aschmahmann Apr 22, 2020
d24d24c
Merge pull request #54 from libp2p/fix/53
Stebalien Apr 23, 2020
76b48d8
Put period at end of sentence
edwargix Jun 5, 2020
4cfb5d8
Merge pull request #65 from edwargix/master
vyzo Jun 5, 2020
ce31d03
Fix hang in BackoffDiscovery.FindPeers when requesting limit lower th…
iand May 4, 2021
1814268
fix staticcheck
marten-seemann May 19, 2021
91366aa
Merge pull request #70 from libp2p/fix-staticcheck
marten-seemann May 19, 2021
b9be440
Merge pull request #69 from iand/issue-67
marten-seemann Jun 14, 2021
5a98da6
remove deprecated types
marten-seemann Jul 22, 2021
e7ee122
Merge pull request #73 from libp2p/remove-deprecated-types
Stebalien Jul 22, 2021
d8eeb78
feat: plumb peerstore contexts changes through (#75)
guseggert Nov 10, 2021
706f740
chore: update go-log to v2
marten-seemann Dec 7, 2021
f93a41d
fix flaky TestBackoffDiscoveryMultipleBackoff test on CI (#80)
marten-seemann Jan 3, 2022
8d17b35
remove dependency on the go-libp2p-peerstore/addr package (#82)
marten-seemann Jan 3, 2022
b53ee87
Merge remote-tracking branch 'p2p/discovery/generic/master' into merg…
marten-seemann Jan 3, 2022
d2ad848
fix import paths
marten-seemann Jan 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/libp2p/go-libp2p-core/transport"
"github.com/libp2p/go-libp2p-peerstore/pstoremem"

discovery "github.com/libp2p/go-libp2p/p2p/discovery/generic"
"github.com/libp2p/go-libp2p/p2p/host/autonat"
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
Expand All @@ -26,7 +27,6 @@ import (
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"

blankhost "github.com/libp2p/go-libp2p-blankhost"
discovery "github.com/libp2p/go-libp2p-discovery"
swarm "github.com/libp2p/go-libp2p-swarm"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"

Expand Down
8 changes: 4 additions & 4 deletions examples/chat-with-rendezvous/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ for _, addr := range bootstrapPeers {

5. **Announce your presence using a rendezvous point.**

[routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.Advertise) makes this node announce that it can provide a value for the given key. Where a key in this case is ```rendezvousString```. Other peers will hit the same key to find other peers.
[routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery/generic#RoutingDiscovery.Advertise) makes this node announce that it can provide a value for the given key. Where a key in this case is ```rendezvousString```. Other peers will hit the same key to find other peers.

```go
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT)
Expand All @@ -89,15 +89,15 @@ discovery.Advertise(ctx, routingDiscovery, config.RendezvousString)

6. **Find nearby peers.**

[routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.FindPeers) will return a channel of peers who have announced their presence.
[routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery/generic#RoutingDiscovery.FindPeers) will return a channel of peers who have announced their presence.

```go
peerChan, err := routingDiscovery.FindPeers(ctx, config.RendezvousString)
```

The [discovery](https://godoc.org/github.com/libp2p/go-libp2p-discovery#pkg-index) package uses the DHT internally to [provide](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.Provide) and [findProviders](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.FindProviders).
The [discovery](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery/generic#pkg-index) package uses the DHT internally to [provide](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.Provide) and [findProviders](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.FindProviders).

**Note:** Although [routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.Advertise) and [routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.FindPeers) works for a rendezvous peer discovery, this is not the right way of doing it. Libp2p is currently working on an actual rendezvous protocol ([libp2p/specs#56](https://github.com/libp2p/specs/pull/56)) which can be used for bootstrap purposes, real time peer discovery and application specific routing.
**Note:** Although [routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery/generic#RoutingDiscovery.Advertise) and [routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery/generic#RoutingDiscovery.FindPeers) works for a rendezvous peer discovery, this is not the right way of doing it. Libp2p is currently working on an actual rendezvous protocol ([libp2p/specs#56](https://github.com/libp2p/specs/pull/56)) which can be used for bootstrap purposes, real time peer discovery and application specific routing.

7. **Open streams to newly discovered peers.**

Expand Down
6 changes: 3 additions & 3 deletions examples/chat-with-rendezvous/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import (
"sync"

"github.com/libp2p/go-libp2p"
discovery "github.com/libp2p/go-libp2p/p2p/discovery/generic"

"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/protocol"
discovery "github.com/libp2p/go-libp2p-discovery"

"github.com/ipfs/go-log/v2"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/multiformats/go-multiaddr"

"github.com/ipfs/go-log/v2"
)

var logger = log.Logger("rendezvous")
Expand Down
1 change: 0 additions & 1 deletion examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ require (
github.com/libp2p/go-libp2p v0.14.4
github.com/libp2p/go-libp2p-connmgr v0.2.4
github.com/libp2p/go-libp2p-core v0.13.0
github.com/libp2p/go-libp2p-discovery v0.6.0
github.com/libp2p/go-libp2p-kad-dht v0.15.0
github.com/libp2p/go-libp2p-noise v0.3.0
github.com/libp2p/go-libp2p-swarm v0.9.0
Expand Down
2 changes: 0 additions & 2 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,6 @@ github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQR
github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
github.com/libp2p/go-libp2p-core v0.13.0 h1:IFG/s8dN6JN2OTrXX9eq2wNU/Zlz2KLdwZUp5FplgXI=
github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
github.com/libp2p/go-libp2p-discovery v0.6.0 h1:1XdPmhMJr8Tmj/yUfkJMIi8mgwWrLUsCB3bMxdT+DSo=
github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVCWPna2dXmPNHc2zR9S8=
github.com/libp2p/go-libp2p-kad-dht v0.15.0 h1:Ke+Oj78gX5UDXnA6HBdrgvi+fStJxgYTDa51U0TsCLo=
github.com/libp2p/go-libp2p-kad-dht v0.15.0/go.mod h1:rZtPxYu1TnHHz6n1RggdGrxUX/tA1C2/Wiw3ZMUDrU0=
github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
Expand Down
7 changes: 5 additions & 2 deletions examples/ipfs-camp-2019/06-Pubsub/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ import (
"syscall"

"github.com/libp2p/go-libp2p"
disc "github.com/libp2p/go-libp2p/p2p/discovery/generic"
"github.com/libp2p/go-libp2p/p2p/discovery/mdns"

"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/routing"
disc "github.com/libp2p/go-libp2p-discovery"

kaddht "github.com/libp2p/go-libp2p-kad-dht"
mplex "github.com/libp2p/go-libp2p-mplex"
tls "github.com/libp2p/go-libp2p-tls"
yamux "github.com/libp2p/go-libp2p-yamux"
"github.com/libp2p/go-libp2p/p2p/discovery/mdns"
"github.com/libp2p/go-tcp-transport"
ws "github.com/libp2p/go-ws-transport"

"github.com/multiformats/go-multiaddr"
)

Expand Down
2 changes: 1 addition & 1 deletion examples/ipfs-camp-2019/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/libp2p/go-libp2p v0.14.4
github.com/libp2p/go-libp2p-core v0.13.0
github.com/libp2p/go-libp2p-discovery v0.6.0
github.com/libp2p/go-libp2p-discovery v0.6.0 // indirect
github.com/libp2p/go-libp2p-kad-dht v0.15.0
github.com/libp2p/go-libp2p-mplex v0.4.1
github.com/libp2p/go-libp2p-pubsub v0.5.3
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/golang-lru v0.5.4
github.com/huin/goupnp v1.0.2 // indirect
github.com/ipfs/go-cid v0.0.7
github.com/ipfs/go-datastore v0.5.0
Expand All @@ -22,7 +23,6 @@ require (
github.com/libp2p/go-libp2p-blankhost v0.3.0
github.com/libp2p/go-libp2p-circuit v0.4.0
github.com/libp2p/go-libp2p-core v0.13.0
github.com/libp2p/go-libp2p-discovery v0.6.0
github.com/libp2p/go-libp2p-mplex v0.4.1
github.com/libp2p/go-libp2p-nat v0.1.0
github.com/libp2p/go-libp2p-netutil v0.1.0
Expand All @@ -42,6 +42,7 @@ require (
github.com/libp2p/zeroconf/v2 v2.1.1
github.com/multiformats/go-multiaddr v0.5.0
github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/multiformats/go-multihash v0.0.15
github.com/multiformats/go-multistream v0.2.2
github.com/multiformats/go-varint v0.0.6
github.com/prometheus/common v0.30.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,6 @@ github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQR
github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
github.com/libp2p/go-libp2p-core v0.13.0 h1:IFG/s8dN6JN2OTrXX9eq2wNU/Zlz2KLdwZUp5FplgXI=
github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
github.com/libp2p/go-libp2p-discovery v0.6.0 h1:1XdPmhMJr8Tmj/yUfkJMIi8mgwWrLUsCB3bMxdT+DSo=
github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVCWPna2dXmPNHc2zR9S8=
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
Expand Down
228 changes: 228 additions & 0 deletions p2p/discovery/generic/backoff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package discovery

import (
"math"
"math/rand"
"sync"
"time"
)

type BackoffFactory func() BackoffStrategy

// BackoffStrategy describes how backoff will be implemented. BackoffStratgies are stateful.
type BackoffStrategy interface {
// Delay calculates how long the next backoff duration should be, given the prior calls to Delay
Delay() time.Duration
// Reset clears the internal state of the BackoffStrategy
Reset()
}

// Jitter implementations taken roughly from https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/

// Jitter must return a duration between min and max. Min must be lower than, or equal to, max.
type Jitter func(duration, min, max time.Duration, rng *rand.Rand) time.Duration

// FullJitter returns a random number uniformly chose from the range [min, boundedDur].
// boundedDur is the duration bounded between min and max.
func FullJitter(duration, min, max time.Duration, rng *rand.Rand) time.Duration {
if duration <= min {
return min
}

normalizedDur := boundedDuration(duration, min, max) - min

return boundedDuration(time.Duration(rng.Int63n(int64(normalizedDur)))+min, min, max)
}

// NoJitter returns the duration bounded between min and max
func NoJitter(duration, min, max time.Duration, rng *rand.Rand) time.Duration {
return boundedDuration(duration, min, max)
}

type randomizedBackoff struct {
min time.Duration
max time.Duration
rng *rand.Rand
}

func (b *randomizedBackoff) BoundedDelay(duration time.Duration) time.Duration {
return boundedDuration(duration, b.min, b.max)
}

func boundedDuration(d, min, max time.Duration) time.Duration {
if d < min {
return min
}
if d > max {
return max
}
return d
}

type attemptBackoff struct {
attempt int
jitter Jitter
randomizedBackoff
}

func (b *attemptBackoff) Reset() {
b.attempt = 0
}

// NewFixedBackoff creates a BackoffFactory with a constant backoff duration
func NewFixedBackoff(delay time.Duration) BackoffFactory {
return func() BackoffStrategy {
return &fixedBackoff{delay: delay}
}
}

type fixedBackoff struct {
delay time.Duration
}

func (b *fixedBackoff) Delay() time.Duration {
return b.delay
}

func (b *fixedBackoff) Reset() {}

// NewPolynomialBackoff creates a BackoffFactory with backoff of the form c0*x^0, c1*x^1, ...cn*x^n where x is the attempt number
// jitter is the function for adding randomness around the backoff
// timeUnits are the units of time the polynomial is evaluated in
// polyCoefs is the array of polynomial coefficients from [c0, c1, ... cn]
func NewPolynomialBackoff(min, max time.Duration, jitter Jitter,
timeUnits time.Duration, polyCoefs []float64, rngSrc rand.Source) BackoffFactory {
rng := rand.New(&lockedSource{src: rngSrc})
return func() BackoffStrategy {
return &polynomialBackoff{
attemptBackoff: attemptBackoff{
randomizedBackoff: randomizedBackoff{
min: min,
max: max,
rng: rng,
},
jitter: jitter,
},
timeUnits: timeUnits,
poly: polyCoefs,
}
}
}

type polynomialBackoff struct {
attemptBackoff
timeUnits time.Duration
poly []float64
}

func (b *polynomialBackoff) Delay() time.Duration {
var polySum float64
switch len(b.poly) {
case 0:
return 0
case 1:
polySum = b.poly[0]
default:
polySum = b.poly[0]
exp := 1
attempt := b.attempt
b.attempt++

for _, c := range b.poly[1:] {
exp *= attempt
polySum += float64(exp) * c
}
}
return b.jitter(time.Duration(float64(b.timeUnits)*polySum), b.min, b.max, b.rng)
}

// NewExponentialBackoff creates a BackoffFactory with backoff of the form base^x + offset where x is the attempt number
// jitter is the function for adding randomness around the backoff
// timeUnits are the units of time the base^x is evaluated in
func NewExponentialBackoff(min, max time.Duration, jitter Jitter,
timeUnits time.Duration, base float64, offset time.Duration, rngSrc rand.Source) BackoffFactory {
rng := rand.New(&lockedSource{src: rngSrc})
return func() BackoffStrategy {
return &exponentialBackoff{
attemptBackoff: attemptBackoff{
randomizedBackoff: randomizedBackoff{
min: min,
max: max,
rng: rng,
},
jitter: jitter,
},
timeUnits: timeUnits,
base: base,
offset: offset,
}
}
}

type exponentialBackoff struct {
attemptBackoff
timeUnits time.Duration
base float64
offset time.Duration
}

func (b *exponentialBackoff) Delay() time.Duration {
attempt := b.attempt
b.attempt++
return b.jitter(
time.Duration(math.Pow(b.base, float64(attempt))*float64(b.timeUnits))+b.offset, b.min, b.max, b.rng)
}

// NewExponentialDecorrelatedJitter creates a BackoffFactory with backoff of the roughly of the form base^x where x is the attempt number.
// Delays start at the minimum duration and after each attempt delay = rand(min, delay * base), bounded by the max
// See https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ for more information
func NewExponentialDecorrelatedJitter(min, max time.Duration, base float64, rngSrc rand.Source) BackoffFactory {
rng := rand.New(&lockedSource{src: rngSrc})
return func() BackoffStrategy {
return &exponentialDecorrelatedJitter{
randomizedBackoff: randomizedBackoff{
min: min,
max: max,
rng: rng,
},
base: base,
}
}
}

type exponentialDecorrelatedJitter struct {
randomizedBackoff
base float64
lastDelay time.Duration
}

func (b *exponentialDecorrelatedJitter) Delay() time.Duration {
if b.lastDelay < b.min {
b.lastDelay = b.min
return b.lastDelay
}

nextMax := int64(float64(b.lastDelay) * b.base)
b.lastDelay = boundedDuration(time.Duration(b.rng.Int63n(nextMax-int64(b.min)))+b.min, b.min, b.max)
return b.lastDelay
}

func (b *exponentialDecorrelatedJitter) Reset() { b.lastDelay = 0 }

type lockedSource struct {
lk sync.Mutex
src rand.Source
}

func (r *lockedSource) Int63() (n int64) {
r.lk.Lock()
n = r.src.Int63()
r.lk.Unlock()
return
}

func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
r.lk.Unlock()
}
Loading