Skip to content

Commit 7f556f0

Browse files
authored
feat(share)!: add functional options to share pkg (#1798)
## Overview This PR introduces functional options to the share package and deprecates usage of default values directly in code, in favor of using parameterized values. ## Breaking This PR breaks the configuration. The on-disk configuration becomes (_note that `Share.Availability` is only available for light nodes_): ``` [Share] [Share.Availability] SampleAmount = 16 [Share.Discovery] PeersLimit = 5 AdvertiseInterval = "8h0m0s" ``` ## Checklist - [x] New and updated code has appropriate documentation - [x] New and updated code has new and/or updated testing - [x] Required CI checks are passing - [x] Visual proof for any user facing features like CLI or documentation updates - [x] Linked issues closed with keywords
1 parent ff65dff commit 7f556f0

File tree

16 files changed

+235
-117
lines changed

16 files changed

+235
-117
lines changed

nodebuilder/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func DefaultConfig(tp node.Type) *Config {
4444
P2P: p2p.DefaultConfig(tp),
4545
RPC: rpc.DefaultConfig(),
4646
Gateway: gateway.DefaultConfig(),
47-
Share: share.DefaultConfig(),
47+
Share: share.DefaultConfig(tp),
4848
Header: header.DefaultConfig(tp),
4949
}
5050

nodebuilder/share/config.go

+39-12
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,69 @@
11
package share
22

33
import (
4-
disc "github.com/celestiaorg/celestia-node/share/availability/discovery"
4+
"fmt"
5+
6+
"github.com/celestiaorg/celestia-node/nodebuilder/node"
7+
"github.com/celestiaorg/celestia-node/share/availability/discovery"
8+
"github.com/celestiaorg/celestia-node/share/availability/light"
59
"github.com/celestiaorg/celestia-node/share/p2p/peers"
610
"github.com/celestiaorg/celestia-node/share/p2p/shrexeds"
711
"github.com/celestiaorg/celestia-node/share/p2p/shrexnd"
812
)
913

14+
// TODO: some params are pointers and other are not, Let's fix this.
1015
type Config struct {
11-
// UseShareExchange is a flag toggling the usage of shrex protocols for blocksync.
1216
UseShareExchange bool
1317
// ShrExEDSParams sets shrexeds client and server configuration parameters
1418
ShrExEDSParams *shrexeds.Parameters
1519
// ShrExNDParams sets shrexnd client and server configuration parameters
1620
ShrExNDParams *shrexnd.Parameters
1721
// PeerManagerParams sets peer-manager configuration parameters
1822
PeerManagerParams peers.Parameters
19-
// Discovery sets peer discovery configuration parameters.
20-
Discovery disc.Parameters
23+
24+
LightAvailability light.Parameters `toml:",omitempty"`
25+
Discovery discovery.Parameters
2126
}
2227

23-
func DefaultConfig() Config {
24-
return Config{
25-
UseShareExchange: true,
28+
func DefaultConfig(tp node.Type) Config {
29+
cfg := Config{
30+
Discovery: discovery.DefaultParameters(),
2631
ShrExEDSParams: shrexeds.DefaultParameters(),
2732
ShrExNDParams: shrexnd.DefaultParameters(),
33+
UseShareExchange: true,
2834
PeerManagerParams: peers.DefaultParameters(),
29-
Discovery: disc.DefaultParameters(),
3035
}
36+
37+
if tp == node.Light {
38+
cfg.LightAvailability = light.DefaultParameters()
39+
}
40+
41+
return cfg
3142
}
3243

3344
// Validate performs basic validation of the config.
34-
func (cfg *Config) Validate() error {
45+
func (cfg *Config) Validate(tp node.Type) error {
46+
if tp == node.Light {
47+
if err := cfg.LightAvailability.Validate(); err != nil {
48+
return fmt.Errorf("nodebuilder/share: %w", err)
49+
}
50+
}
51+
52+
if err := cfg.Discovery.Validate(); err != nil {
53+
return fmt.Errorf("nodebuilder/share: %w", err)
54+
}
55+
3556
if err := cfg.ShrExNDParams.Validate(); err != nil {
36-
return err
57+
return fmt.Errorf("nodebuilder/share: %w", err)
3758
}
59+
3860
if err := cfg.ShrExEDSParams.Validate(); err != nil {
39-
return err
61+
return fmt.Errorf("nodebuilder/share: %w", err)
4062
}
41-
return cfg.PeerManagerParams.Validate()
63+
64+
if err := cfg.PeerManagerParams.Validate(); err != nil {
65+
return fmt.Errorf("nodebuilder/share: %w", err)
66+
}
67+
68+
return nil
4269
}

nodebuilder/share/constructors.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ import (
2121
"github.com/celestiaorg/celestia-node/share/getters"
2222
)
2323

24-
func discovery(cfg Config) func(routing.ContentRouting, host.Host) *disc.Discovery {
24+
func newDiscovery(cfg Config) func(routing.ContentRouting, host.Host) *disc.Discovery {
2525
return func(
2626
r routing.ContentRouting,
2727
h host.Host,
2828
) *disc.Discovery {
2929
return disc.NewDiscovery(
3030
h,
3131
routingdisc.NewRoutingDiscovery(r),
32-
cfg.Discovery,
32+
disc.WithPeersLimit(cfg.Discovery.PeersLimit),
33+
disc.WithAdvertiseInterval(cfg.Discovery.AdvertiseInterval),
3334
)
3435
}
3536
}

nodebuilder/share/module.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
func ConstructModule(tp node.Type, cfg *Config, options ...fx.Option) fx.Option {
2626
// sanitize config values before constructing module
27-
cfgErr := cfg.Validate()
27+
cfgErr := cfg.Validate(tp)
2828

2929
baseComponents := fx.Options(
3030
fx.Supply(*cfg),
@@ -33,7 +33,7 @@ func ConstructModule(tp node.Type, cfg *Config, options ...fx.Option) fx.Option
3333
fx.Provide(newModule),
3434
fx.Invoke(func(disc *disc.Discovery) {}),
3535
fx.Provide(fx.Annotate(
36-
discovery(*cfg),
36+
newDiscovery(*cfg),
3737
fx.OnStart(func(ctx context.Context, d *disc.Discovery) error {
3838
return d.Start(ctx)
3939
}),
@@ -170,6 +170,11 @@ func ConstructModule(tp node.Type, cfg *Config, options ...fx.Option) fx.Option
170170
return fx.Module(
171171
"share",
172172
baseComponents,
173+
fx.Provide(func() []light.Option {
174+
return []light.Option{
175+
light.WithSampleAmount(cfg.LightAvailability.SampleAmount),
176+
}
177+
}),
173178
shrexGetterComponents,
174179
fx.Invoke(share.EnsureEmptySquareExists),
175180
fx.Provide(getters.NewIPLDGetter),

share/availability.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"context"
55
"errors"
66

7-
"github.com/celestiaorg/celestia-app/pkg/da"
7+
da "github.com/celestiaorg/celestia-app/pkg/da"
88
)
99

1010
// ErrNotAvailable is returned whenever DA sampling fails.
@@ -15,11 +15,9 @@ var ErrNotAvailable = errors.New("share: data not available")
1515
type Root = da.DataAvailabilityHeader
1616

1717
// Availability defines interface for validation of Shares' availability.
18-
//
19-
//go:generate mockgen -destination=availability/mocks/availability.go -package=mocks . Availability
2018
type Availability interface {
2119
// SharesAvailable subjectively validates if Shares committed to the given Root are available on
22-
// the Network by requesting the EDS from the provided peers.
20+
// the Network.
2321
SharesAvailable(context.Context, *Root) error
2422
// ProbabilityOfAvailability calculates the probability of the data square
2523
// being available based on the number of samples collected.

share/availability/cache/availability.go

+9-11
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,12 @@ import (
1515
"github.com/celestiaorg/celestia-node/share"
1616
)
1717

18-
var log = logging.Logger("share/cache")
19-
2018
var (
21-
// DefaultWriteBatchSize defines the size of the batched header write.
22-
// Headers are written in batches not to thrash the underlying Datastore with writes.
23-
// TODO(@Wondertan, @renaynay): Those values must be configurable and proper defaults should be set
24-
// for specific node type. (#709)
25-
DefaultWriteBatchSize = 2048
26-
cacheAvailabilityPrefix = datastore.NewKey("sampling_result")
27-
19+
log = logging.Logger("share/cache")
2820
minRoot = da.MinDataAvailabilityHeader()
21+
22+
cacheAvailabilityPrefix = datastore.NewKey("sampling_result")
23+
writeBatchSize = 2048
2924
)
3025

3126
// ShareAvailability wraps a given share.Availability (whether it's light or full)
@@ -42,9 +37,12 @@ type ShareAvailability struct {
4237

4338
// NewShareAvailability wraps the given share.Availability with an additional datastore
4439
// for sampling result caching.
45-
func NewShareAvailability(avail share.Availability, ds datastore.Batching) *ShareAvailability {
40+
func NewShareAvailability(
41+
avail share.Availability,
42+
ds datastore.Batching,
43+
) *ShareAvailability {
4644
ds = namespace.Wrap(ds, cacheAvailabilityPrefix)
47-
autoDS := autobatch.NewAutoBatching(ds, DefaultWriteBatchSize)
45+
autoDS := autobatch.NewAutoBatching(ds, writeBatchSize)
4846

4947
return &ShareAvailability{
5048
avail: avail,

share/availability/discovery/discovery.go

+18-41
Original file line numberDiff line numberDiff line change
@@ -35,53 +35,24 @@ const (
3535
defaultRetryTimeout = time.Second
3636
)
3737

38-
type Parameters struct {
39-
// PeersLimit defines the soft limit of FNs to connect to via discovery.
40-
// Set 0 to disable.
41-
PeersLimit uint
42-
// AdvertiseInterval is a interval between advertising sessions.
43-
// Set -1 to disable.
44-
// NOTE: only full and bridge can advertise themselves.
45-
AdvertiseInterval time.Duration
46-
// discoveryRetryTimeout is an interval between discovery attempts
47-
// when we discovered lower than PeersLimit peers.
48-
// Set -1 to disable.
49-
discoveryRetryTimeout time.Duration
50-
}
51-
52-
func (p Parameters) withDefaults() Parameters {
53-
def := DefaultParameters()
54-
if p.AdvertiseInterval == 0 {
55-
p.AdvertiseInterval = def.AdvertiseInterval
56-
}
57-
if p.discoveryRetryTimeout == 0 {
58-
p.discoveryRetryTimeout = defaultRetryTimeout
59-
}
60-
return p
61-
}
62-
63-
func DefaultParameters() Parameters {
64-
return Parameters{
65-
PeersLimit: 5,
66-
// based on https://github.com/libp2p/go-libp2p-kad-dht/pull/793
67-
AdvertiseInterval: time.Hour * 22,
68-
}
69-
}
38+
// defaultRetryTimeout defines time interval between discovery attempts.
39+
var discoveryRetryTimeout = defaultRetryTimeout
7040

7141
// Discovery combines advertise and discover services and allows to store discovered nodes.
7242
// TODO: The code here gets horribly hairy, so we should refactor this at some point
7343
type Discovery struct {
74-
params Parameters
75-
76-
set *limitedSet
77-
host host.Host
78-
disc discovery.Discovery
79-
connector *backoffConnector
44+
set *limitedSet
45+
host host.Host
46+
disc discovery.Discovery
47+
connector *backoffConnector
48+
// onUpdatedPeers will be called on peer set changes
8049
onUpdatedPeers OnUpdatedPeers
8150

8251
triggerDisc chan struct{}
8352

8453
cancel context.CancelFunc
54+
55+
params Parameters
8556
}
8657

8758
type OnUpdatedPeers func(peerID peer.ID, isAdded bool)
@@ -90,15 +61,21 @@ type OnUpdatedPeers func(peerID peer.ID, isAdded bool)
9061
func NewDiscovery(
9162
h host.Host,
9263
d discovery.Discovery,
93-
params Parameters,
64+
opts ...Option,
9465
) *Discovery {
66+
params := DefaultParameters()
67+
68+
for _, opt := range opts {
69+
opt(&params)
70+
}
71+
9572
return &Discovery{
96-
params: params.withDefaults(),
9773
set: newLimitedSet(params.PeersLimit),
9874
host: h,
9975
disc: d,
10076
connector: newBackoffConnector(h, defaultBackoffFactory),
10177
onUpdatedPeers: func(peer.ID, bool) {},
78+
params: params,
10279
triggerDisc: make(chan struct{}),
10380
}
10481
}
@@ -191,7 +168,7 @@ func (d *Discovery) Advertise(ctx context.Context) {
191168
// discoveryLoop ensures we always have '~peerLimit' connected peers.
192169
// It starts peer discovery per request and restarts the process until the soft limit reached.
193170
func (d *Discovery) discoveryLoop(ctx context.Context) {
194-
t := time.NewTicker(d.params.discoveryRetryTimeout)
171+
t := time.NewTicker(discoveryRetryTimeout)
195172
defer t.Stop()
196173
for {
197174
// drain all previous ticks from channel

share/availability/discovery/discovery_test.go

+9-12
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ func TestDiscovery(t *testing.T) {
2424

2525
tn := newTestnet(ctx, t)
2626

27-
peerA := tn.discovery(Parameters{
28-
PeersLimit: nodes,
29-
discoveryRetryTimeout: time.Millisecond * 100,
30-
AdvertiseInterval: -1, // we don't want to be found but only find
31-
})
27+
peerA := tn.discovery(
28+
WithPeersLimit(nodes),
29+
WithAdvertiseInterval(-1),
30+
)
31+
discoveryRetryTimeout = time.Millisecond * 100 // defined in discovery.go
3232

3333
type peerUpdate struct {
3434
peerID peer.ID
@@ -41,11 +41,8 @@ func TestDiscovery(t *testing.T) {
4141

4242
discs := make([]*Discovery, nodes)
4343
for i := range discs {
44-
discs[i] = tn.discovery(Parameters{
45-
PeersLimit: 0,
46-
discoveryRetryTimeout: -1,
47-
AdvertiseInterval: time.Millisecond * 100,
48-
})
44+
discs[i] = tn.discovery(WithPeersLimit(0), WithAdvertiseInterval(time.Millisecond*100))
45+
discoveryRetryTimeout = -1 // defined in discovery.go
4946

5047
select {
5148
case res := <-updateCh:
@@ -98,9 +95,9 @@ func newTestnet(ctx context.Context, t *testing.T) *testnet {
9895
return &testnet{ctx: ctx, T: t, bootstrapper: *host.InfoFromHost(hst)}
9996
}
10097

101-
func (t *testnet) discovery(params Parameters) *Discovery {
98+
func (t *testnet) discovery(opts ...Option) *Discovery {
10299
hst, routingDisc := t.peer()
103-
disc := NewDiscovery(hst, routingDisc, params)
100+
disc := NewDiscovery(hst, routingDisc, opts...)
104101
err := disc.Start(t.ctx)
105102
require.NoError(t.T, err)
106103
t.T.Cleanup(func() {
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package discovery
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
// Parameters is the set of Parameters that must be configured for the Discovery module
9+
type Parameters struct {
10+
// PeersLimit defines the soft limit of FNs to connect to via discovery.
11+
// Set 0 to disable.
12+
PeersLimit uint
13+
// AdvertiseInterval is a interval between advertising sessions.
14+
// Set -1 to disable.
15+
// NOTE: only full and bridge can advertise themselves.
16+
AdvertiseInterval time.Duration
17+
}
18+
19+
// Option is a function that configures Discovery Parameters
20+
type Option func(*Parameters)
21+
22+
// DefaultParameters returns the default Parameters' configuration values
23+
// for the Discovery module
24+
func DefaultParameters() Parameters {
25+
return Parameters{
26+
PeersLimit: 5,
27+
// based on https://github.com/libp2p/go-libp2p-kad-dht/pull/793
28+
AdvertiseInterval: time.Hour * 22,
29+
}
30+
}
31+
32+
// Validate validates the values in Parameters
33+
func (p *Parameters) Validate() error {
34+
if p.AdvertiseInterval <= 0 {
35+
return fmt.Errorf(
36+
"discovery: invalid option: value AdvertiseInterval %s, %s",
37+
"is 0 or negative.",
38+
"value must be positive",
39+
)
40+
}
41+
42+
return nil
43+
}
44+
45+
// WithPeersLimit is a functional option that Discovery
46+
// uses to set the PeersLimit configuration param
47+
func WithPeersLimit(peersLimit uint) Option {
48+
return func(p *Parameters) {
49+
p.PeersLimit = peersLimit
50+
}
51+
}
52+
53+
// WithAdvertiseInterval is a functional option that Discovery
54+
// uses to set the AdvertiseInterval configuration param
55+
func WithAdvertiseInterval(advInterval time.Duration) Option {
56+
return func(p *Parameters) {
57+
p.AdvertiseInterval = advInterval
58+
}
59+
}

0 commit comments

Comments
 (0)