Skip to content

Commit

Permalink
Try #5592:
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemesh-bors[bot] authored Feb 26, 2024
2 parents b96b00b + be94b15 commit 482b23a
Show file tree
Hide file tree
Showing 30 changed files with 1,141 additions and 582 deletions.
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,55 @@ configuration is as follows:
}
```

#### Extend go-spacemesh with option to manage multiple identities/PoST services

A node can now manage multiple identities and will manage the lifecycle for those identities. This reduces the amount of
data that is needed to be broadcasted / fetched from the network and reduces the amount of data that needs to be stored
locally, because only one database is needed for all identities instead of one for each identity.

To ensure you are eligible for rewards of any given identity, the associated PoST service must be running and connected
to the node during the cyclegap set in the node's configuration. After successfully broadcasting the ATX and registering
at a PoET server the PoST services can be stopped with only the node having to be online.

This change moves the private keys associated for an identity from the PoST data directory to the node's data directory
and into the folder `identities` (i.e. if `state.sql` is in folder `data` the keys will now be stored in `data/identities`).
The node will automatically migrate the `key.bin` file from the PoST data directory during the first startup and copy
it to the new location as `identity.key`. The content of the file stays unchanged (= the private key of the identity hex-encoded).

##### Adding new identities/PoST services to a node

To add a new identity to a node initialize PoST data and with `postcli` and let the tool generate a new private key for
you:

```shell
./postcli -provider=2 -numUnits=4 -datadir=/path/to/data \
-commitmentAtxId=c230c51669d1fcd35860131e438e234726b2bd5f9adbbd91bd88a718e7e98ecb
```

Make sure to replace `provider` with your provider of choice and `numUnits` with the number of PoST units you want to
initialize. The `commitmentAtxId` is the commitment ATX ID of the identity you want to initialize. For details on the
usage of `postcli` please refer to [postcli README](https://github.com/spacemeshos/post/cmd/postcli/README.md).

During initialization `postcli` will generate a new private key and store it in the PoST data directory as `key.bin`.
Copy this file to your `data/identities` directory and rename it to `xxx.key` where `xxx` is a unique identifier for
the identity. The node will automatically pick up the new identity and manage its lifecycle after a restart.

Setup the `post-service` [binary](https://github.com/spacemeshos/post-rs/releases) or
[docker image](https://hub.docker.com/r/spacemeshos/post-service/tags) with the data and configure it to connect to your
node. For details refer to the [post-service README](https://github.com/spacemeshos/post-rs/blob/main/service/README.md).

##### Migrating existing identities/PoST services to a node

If you have multiple nodes running and want to migrate to use only one node for both identities:

1. Stop all nodes.
2. Copy the `key.bin` files from the PoST data directories of all nodes to the data directory of the node you want to
use for both identities and into the folder `data/identities`. Rename the files to `xxx.key` where `xxx` is a unique
identifier for each identity.
3. Start the node managing the identities.
4. For every identity setup a post service to use the existing PoST data for that identity and connect to the node.
For details refer to the [post-service README](https://github.com/spacemeshos/post-rs/blob/main/service/README.md).

### Highlights

* [#5293](https://github.com/spacemeshos/go-spacemesh/pull/5293) change poet servers configuration
Expand All @@ -100,6 +149,13 @@ configuration is as follows:
Publishing is blocked during sync because `Syncer::ListenToATXGossip()` returns false, and thus every malicious ATX being
synced was causing an error resulting in an interruption of sync.

* [#5592](https://gihtub.com/spacemeshos/go-spacemesh/pull/5592)
Extend node with option to have multiple PoST services connect. This allows users to run multiple PoST services,
without the need to run multiple nodes. A node can now manage multiple identities and will manage the lifecycle of
those identities.
To collect rewards for every identity, the associated PoST service must be running and connected to the node during
the cyclegap set in the node's configuration.

### Features

### Improvements
Expand Down
6 changes: 3 additions & 3 deletions activation/e2e/activation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ func Test_BuilderWithMultipleClients(t *testing.T) {
opts := opts
eg.Go(func() error {
validator := activation.NewMocknipostValidator(ctrl)
mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX, syncer, validator)
mgr, err := activation.NewPostSetupManager(cfg, logger, cdb, goldenATX, syncer, validator)
require.NoError(t, err)

opts.DataDir = t.TempDir()
initPost(t, mgr, opts)
t.Cleanup(launchPostSupervisor(t, logger, mgr, grpcCfg, opts))
initPost(t, mgr, opts, sig.NodeID())
t.Cleanup(launchPostSupervisor(t, logger, mgr, sig.NodeID(), grpcCfg, opts))

require.Eventually(t, func() bool {
_, err := svc.Client(sig.NodeID())
Expand Down
25 changes: 13 additions & 12 deletions activation/e2e/nipost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func launchPostSupervisor(
tb testing.TB,
log *zap.Logger,
mgr *activation.PostSetupManager,
id types.NodeID,
cfg grpcserver.Config,
postOpts activation.PostSetupOpts,
) func() {
Expand All @@ -76,7 +77,7 @@ func launchPostSupervisor(
ps, err := activation.NewPostSupervisor(log, cmdCfg, postCfg, provingOpts, mgr)
require.NoError(tb, err)
require.NotNil(tb, ps)
require.NoError(tb, ps.Start(postOpts))
require.NoError(tb, ps.Start(postOpts, id))
return func() { assert.NoError(tb, ps.Stop(false)) }
}

Expand All @@ -99,12 +100,12 @@ func launchServer(tb testing.TB, services ...grpcserver.ServiceAPI) (grpcserver.
return cfg, func() { assert.NoError(tb, server.Close()) }
}

func initPost(tb testing.TB, mgr *activation.PostSetupManager, opts activation.PostSetupOpts) {
func initPost(tb testing.TB, mgr *activation.PostSetupManager, opts activation.PostSetupOpts, id types.NodeID) {
tb.Helper()

// Create data.
require.NoError(tb, mgr.PrepareInitializer(context.Background(), opts))
require.NoError(tb, mgr.StartSession(context.Background()))
require.NoError(tb, mgr.PrepareInitializer(context.Background(), opts, id))
require.NoError(tb, mgr.StartSession(context.Background(), id))
require.Equal(tb, activation.PostSetupStateComplete, mgr.Status().State)
}

Expand All @@ -128,14 +129,14 @@ func TestNIPostBuilderWithClients(t *testing.T) {
})

validator := activation.NewMocknipostValidator(ctrl)
mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX, syncer, validator)
mgr, err := activation.NewPostSetupManager(cfg, logger, cdb, goldenATX, syncer, validator)
require.NoError(t, err)

opts := activation.DefaultPostSetupOpts()
opts.DataDir = t.TempDir()
opts.ProviderID.SetUint32(initialization.CPUProviderID())
opts.Scrypt.N = 2 // Speedup initialization in tests.
initPost(t, mgr, opts)
initPost(t, mgr, opts, sig.NodeID())

// ensure that genesis aligns with layer timings
genesis := time.Now().Add(layerDuration).Round(layerDuration)
Expand Down Expand Up @@ -173,7 +174,7 @@ func TestNIPostBuilderWithClients(t *testing.T) {
grpcCfg, cleanup := launchServer(t, svc)
t.Cleanup(cleanup)

t.Cleanup(launchPostSupervisor(t, logger, mgr, grpcCfg, opts))
t.Cleanup(launchPostSupervisor(t, logger, mgr, sig.NodeID(), grpcCfg, opts))

require.Eventually(t, func() bool {
_, err := svc.Client(sig.NodeID())
Expand Down Expand Up @@ -274,7 +275,7 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) {
})

validator := activation.NewMocknipostValidator(ctrl)
mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX, syncer, validator)
mgr, err := activation.NewPostSetupManager(cfg, logger, cdb, goldenATX, syncer, validator)
require.NoError(t, err)

// ensure that genesis aligns with layer timings
Expand Down Expand Up @@ -325,7 +326,7 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) {
opts.DataDir = t.TempDir()
opts.ProviderID.SetUint32(initialization.CPUProviderID())
opts.Scrypt.N = 2 // Speedup initialization in tests.
t.Cleanup(launchPostSupervisor(t, logger, mgr, grpcCfg, opts))
t.Cleanup(launchPostSupervisor(t, logger, mgr, sig.NodeID(), grpcCfg, opts))

require.Eventually(t, func() bool {
_, err := svc.Client(sig.NodeID())
Expand Down Expand Up @@ -393,12 +394,12 @@ func Test_NIPostBuilderWithMultipleClients(t *testing.T) {
sig := sig
opts := opts
eg.Go(func() error {
mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX, syncer, validator)
mgr, err := activation.NewPostSetupManager(cfg, logger, cdb, goldenATX, syncer, validator)
require.NoError(t, err)

opts.DataDir = t.TempDir()
initPost(t, mgr, opts)
t.Cleanup(launchPostSupervisor(t, logger, mgr, grpcCfg, opts))
initPost(t, mgr, opts, sig.NodeID())
t.Cleanup(launchPostSupervisor(t, logger, mgr, sig.NodeID(), grpcCfg, opts))

require.Eventually(t, func() bool {
_, err := svc.Client(sig.NodeID())
Expand Down
6 changes: 3 additions & 3 deletions activation/e2e/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ func TestValidator_Validate(t *testing.T) {
return synced
})

mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX, syncer, validator)
mgr, err := activation.NewPostSetupManager(cfg, logger, cdb, goldenATX, syncer, validator)
require.NoError(t, err)

opts := activation.DefaultPostSetupOpts()
opts.DataDir = t.TempDir()
opts.ProviderID.SetUint32(initialization.CPUProviderID())
opts.Scrypt.N = 2 // Speedup initialization in tests.
initPost(t, mgr, opts)
initPost(t, mgr, opts, sig.NodeID())

// ensure that genesis aligns with layer timings
genesis := time.Now().Add(layerDuration).Round(layerDuration)
Expand Down Expand Up @@ -87,7 +87,7 @@ func TestValidator_Validate(t *testing.T) {
grpcCfg, cleanup := launchServer(t, svc)
t.Cleanup(cleanup)

t.Cleanup(launchPostSupervisor(t, logger, mgr, grpcCfg, opts))
t.Cleanup(launchPostSupervisor(t, logger, mgr, sig.NodeID(), grpcCfg, opts))

require.Eventually(t, func() bool {
_, err := svc.Client(sig.NodeID())
Expand Down
4 changes: 2 additions & 2 deletions activation/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ type atxProvider interface {
// This interface is used by the atx builder and currently implemented by the PostSetupManager.
// Eventually most of the functionality will be moved to the PoSTClient.
type postSetupProvider interface {
PrepareInitializer(ctx context.Context, opts PostSetupOpts) error
StartSession(context context.Context) error
PrepareInitializer(ctx context.Context, opts PostSetupOpts, id types.NodeID) error
StartSession(context context.Context, id types.NodeID) error
Status() *PostSetupStatus
Reset() error
}
Expand Down
24 changes: 12 additions & 12 deletions activation/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 482b23a

Please sign in to comment.