Skip to content

Commit 1ba83a6

Browse files
Merge pull request #6489 from oasisprotocol/martin/breaking/explicit-observer-mode
Config: Add explicit observer mode and storage kind
2 parents bacad10 + b2b7a01 commit 1ba83a6

17 files changed

Lines changed: 145 additions & 71 deletions

File tree

.changelog/6488.cfg.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
oasis-node/config: Add explicit observer mode

.changelog/6488.cfg.1.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
go/config: Add explicit local storage config
2+
3+
Explicit `config.Config.Consensus.LocalStorage` (default `true`) was added.
4+
When set to `false`, remote authenticated storage is used and verified
5+
by the node's light client.
6+
7+
Mode `stateless-client` no longer exists. It should be instead configured by
8+
`config.Config.Mode: client` and
9+
`config.Config.Consensus.LocalStorage: false`.

go/config/config.go

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,42 +31,23 @@ const (
3131
ModeValidator NodeMode = "validator"
3232
// ModeCompute is the name of the compute node mode.
3333
ModeCompute NodeMode = "compute"
34+
// ModeObserver is the name of the observer node mode.
35+
ModeObserver NodeMode = "observer"
3436
// ModeKeyManager is the name of the key manager node mode.
3537
ModeKeyManager NodeMode = "keymanager"
3638
// ModeClient is the name of the client node mode.
3739
ModeClient NodeMode = "client"
38-
// ModeStatelessClient is the name of the stateless client node mode.
39-
ModeStatelessClient NodeMode = "client-stateless"
4040
// ModeSeed is the name of the seed node mode.
4141
ModeSeed NodeMode = "seed"
4242
// ModeArchive is the name of the archive node mode.
4343
ModeArchive NodeMode = "archive"
4444
)
4545

46-
// IsClientOnly returns true iff the mode is one that has the node running
47-
// as a client for all configured runtimes.
48-
func (m NodeMode) IsClientOnly() bool {
49-
switch m {
50-
case ModeClient, ModeStatelessClient:
51-
return true
52-
}
53-
return false
54-
}
55-
5646
// IsArchive returns true iff the mode is set to archive node mode.
5747
func (m NodeMode) IsArchive() bool {
5848
return m == ModeArchive
5949
}
6050

61-
// HasLocalStorage returns true iff the mode is one that has local storage.
62-
func (m NodeMode) HasLocalStorage() bool {
63-
switch m {
64-
case ModeClient, ModeCompute, ModeArchive:
65-
return true
66-
}
67-
return false
68-
}
69-
7051
// GlobalConfig holds the global configuration options.
7152
var GlobalConfig Config
7253

@@ -97,15 +78,26 @@ func (c *Config) Validate() error {
9778
switch c.Mode {
9879
case ModeValidator:
9980
case ModeCompute:
81+
case ModeObserver:
10082
case ModeKeyManager:
10183
case ModeClient:
102-
case ModeStatelessClient:
10384
case ModeSeed:
10485
case ModeArchive:
10586
default:
10687
return fmt.Errorf("unknown node mode: %s", c.Mode)
10788
}
10889

90+
if !c.Consensus.LocalStorage {
91+
if c.Consensus.Validator {
92+
return fmt.Errorf("local storage not available in specified mode")
93+
}
94+
switch c.Mode {
95+
case ModeClient, ModeObserver:
96+
default:
97+
return fmt.Errorf("local storage not available in specified mode")
98+
}
99+
}
100+
109101
if err = c.Common.Validate(); err != nil {
110102
return fmt.Errorf("common: %w", err)
111103
}

go/config/config_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestRemoteStorageValidation(t *testing.T) {
10+
for _, tc := range []struct {
11+
name string
12+
mode NodeMode
13+
validator bool
14+
mustErr bool
15+
}{
16+
{name: "client", mode: ModeClient},
17+
{name: "observer", mode: ModeObserver},
18+
{name: "validator", mode: ModeValidator, mustErr: true},
19+
{name: "compute", mode: ModeCompute, mustErr: true},
20+
{name: "keymanager", mode: ModeKeyManager, mustErr: true},
21+
{name: "seed", mode: ModeSeed, mustErr: true},
22+
{name: "archive", mode: ModeArchive, mustErr: true},
23+
{name: "consensus validator and observer", mode: ModeObserver, validator: true, mustErr: true},
24+
} {
25+
t.Run(tc.name, func(t *testing.T) {
26+
cfg := DefaultConfig()
27+
cfg.Mode = tc.mode
28+
cfg.Consensus.LocalStorage = false
29+
cfg.Consensus.Validator = tc.validator
30+
31+
err := cfg.Validate()
32+
if tc.mustErr {
33+
require.ErrorContains(t, err, "local storage not available in specified mode")
34+
} else {
35+
require.NoError(t, err)
36+
}
37+
})
38+
}
39+
}

go/consensus/cometbft/cometbft.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,27 @@ func New(
3737
return nil, err
3838
}
3939

40-
switch config.GlobalConfig.Mode {
41-
case config.ModeArchive:
40+
if config.GlobalConfig.Mode == config.ModeArchive {
4241
node, err := createArchiveNode(ctx, dataDir, identity, genesis, doc, genesisDoc)
4342
if err != nil {
4443
return nil, fmt.Errorf("failed to create archive node: %w", err)
4544
}
4645
return node, nil
47-
case config.ModeStatelessClient:
46+
}
47+
48+
if !config.GlobalConfig.Consensus.LocalStorage {
4849
node, err := createStatelessNode(ctx, dataDir, identity, genesis, doc, genesisDoc, p2p)
4950
if err != nil {
5051
return nil, fmt.Errorf("failed to create stateless node: %w", err)
5152
}
5253
return node, nil
53-
default:
54-
node, err := createFullNode(ctx, dataDir, identity, genesis, doc, genesisDoc, upgrader, p2p)
55-
if err != nil {
56-
return nil, fmt.Errorf("failed to create full node: %w", err)
57-
}
58-
return node, nil
5954
}
55+
56+
node, err := createFullNode(ctx, dataDir, identity, genesis, doc, genesisDoc, upgrader, p2p)
57+
if err != nil {
58+
return nil, fmt.Errorf("failed to create full node: %w", err)
59+
}
60+
return node, nil
6061
}
6162

6263
func createArchiveNode(

go/consensus/cometbft/config/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ type Config struct {
3939
// Average amount of time to delay shutting down the node on upgrade.
4040
UpgradeStopDelay time.Duration `yaml:"upgrade_stop_delay,omitempty"`
4141

42+
// LocalStorage specifies whether consensus state is stored locally.
43+
//
44+
// If false and the node has additional runtime storage configured,
45+
// that runtime storage is also accessed remotely.
46+
LocalStorage bool `yaml:"local_storage,omitempty"`
47+
4248
// ABCI state pruning configuration.
4349
Prune PruneConfig `yaml:"prune,omitempty"`
4450

@@ -233,6 +239,7 @@ func DefaultConfig() Config {
233239
MaxFee: 10_000_000_000,
234240
},
235241
UpgradeStopDelay: time.Minute,
242+
LocalStorage: true,
236243
Prune: PruneConfig{
237244
Strategy: PruneStrategyNone,
238245
NumKept: 250_000,

go/oasis-node/cmd/node/node.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,11 @@ func (n *Node) initRuntimeWorkers(genesisDoc *genesisAPI.Document) error {
277277
n.svcMgr.Register(n.BeaconWorker)
278278

279279
// Initialize the storage worker.
280+
storageCfg := workerStorage.Config{
281+
HasLocalStorage: config.GlobalConfig.Consensus.LocalStorage,
282+
}
280283
n.StorageWorker, err = workerStorage.New(
284+
storageCfg,
281285
n.grpcInternal,
282286
n.CommonWorker,
283287
n.RegistrationWorker,
@@ -475,6 +479,20 @@ func NewNode() (node *Node, err error) { // nolint: gocyclo
475479
}
476480
node.EntityID = entityID
477481

482+
requiresEntity := config.GlobalConfig.Consensus.Validator
483+
switch config.GlobalConfig.Mode {
484+
case config.ModeValidator, config.ModeCompute, config.ModeKeyManager, config.ModeObserver:
485+
requiresEntity = true
486+
}
487+
488+
if requiresEntity && entityID == nil {
489+
return nil, fmt.Errorf("node has no entity configured but expects one")
490+
}
491+
492+
if config.GlobalConfig.Mode == config.ModeClient && !config.GlobalConfig.Consensus.Validator && entityID != nil {
493+
return nil, fmt.Errorf("client node must not have entity configured, try using observer mode instead")
494+
}
495+
478496
// Load configured values for all registered crash points.
479497
crash.LoadViperArgValues()
480498

go/oasis-node/cmd/node/node_control.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ func (n *Node) getRuntimeStatus(ctx context.Context) (map[common.Namespace]contr
270270
}
271271

272272
// Take storage into account for last retained round.
273-
if config.GlobalConfig.Mode.HasLocalStorage() {
273+
if config.GlobalConfig.Consensus.LocalStorage {
274274
lsb, ok := rt.Storage().(storage.LocalBackend)
275275
switch ok {
276276
case false:

go/oasis-test-runner/oasis/oasis.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,12 @@ func (n *Node) Start() error {
303303
n.Config.Mode = config.ModeArchive
304304
}
305305

306-
switch n.Config.Mode {
307-
case config.ModeStatelessClient:
306+
if !n.Config.Consensus.LocalStorage {
308307
for _, worker := range n.net.computeWorkers {
309308
n.Config.Consensus.Providers = append(n.Config.Consensus.Providers, "unix:"+worker.SocketPath())
310309
}
311-
case config.ModeSeed:
310+
}
311+
if n.Config.Mode == config.ModeSeed {
312312
n.Config.P2P.Discovery.Bootstrap.AllowPrivateIPs = true
313313
}
314314

go/oasis-test-runner/oasis/observer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (o *Observer) ModifyConfig() error {
7272
o.Config.Registration.EntityID = string(entityID)
7373
}
7474

75-
o.Config.Mode = config.ModeClient
75+
o.Config.Mode = config.ModeObserver
7676
o.Config.Runtime.Provisioner = o.runtimeProvisioner
7777
o.Config.Runtime.SGX.Loader = o.net.cfg.RuntimeSGXLoaderBinary
7878
o.Config.Runtime.AttestInterval = o.net.cfg.RuntimeAttestInterval

0 commit comments

Comments
 (0)