Skip to content

Commit

Permalink
Use dedicated PoST service for Proof generation (#5061)
Browse files Browse the repository at this point in the history
## Motivation
Part of #5042
Merge after #5091 

## Changes

- Generating poofs is now done via the GRPC API
  - Foundation laid in #5091
  - Upon connection `PostClient` is passed to services via the `postConnectionListener` interface. At the moment these are: `activation::Builder` and `activation::NIPostBuilder` who use it to generate a proof
  - Instead of starting the `PostSupervisor` when `PostServiceCmd` is set it is started when `StartSmeshing == true`
  - The connection does not require authentication (yet) - will be addressed in #5131 
  - Connection cannot handle multiple post services (yet)
- NiPoSTBuilder doesn't verify PoST proofs any more
  - PoST Service does this already before providing the proof
  - additionally when publishing the ATX it goes through the ATX handler that validates the ATX again before broadcasting it.
- Refactored tests in `activation` package to use new API
  - Integration tests that do not use mocks for generating PoST proofs have been moved to `activation/e2e` to allow the use of the `api/grpcserver` package in them
  - `e2e` tests spin up a post service using the post supervisor and query a proof from there
- Slimmed down `postSetupProvider` interface:
  - it is used by the `activation::Builder` and implemented by `activation::PostSetupManager`
  - some of its functionality has been moved into `PostClient` (`GenerateProof` -> `Proof`)
- Replaced `go-spacemesh/log` with `zap` in a few components in the `activation` package.

## Test Plan
- All existing tests involving proof generation have been migrated to use the new PoST service
- New tests added to test the connection specifically.
- Test added for custom types in config.

## TODO
<!-- This section should be removed when all items are complete -->
- [x] Explain motivation or link existing issue(s)
- [x] Test changes and document test plan
- [x] Update documentation as needed
- [x] Update [changelog](../CHANGELOG.md) as needed
  • Loading branch information
fasmat committed Oct 11, 2023
1 parent fa44c7d commit 0befd88
Show file tree
Hide file tree
Showing 44 changed files with 1,798 additions and 1,588 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ See [RELEASE](./RELEASE.md) for workflow instructions.

* [#5118](https://github.com/spacemeshos/go-spacemesh/pull/5118) reduce number of tortoise results returned after recovery.

this is hotfix for a bug introduced in v1.2.0. in rare conditions node may loop with the following warning:
this is hotfix for a bug introduced in v1.2.0. in rare conditions node may loop with the following warning:

> 2023-10-02T15:28:14.002+0200 WARN fd68b.sync mesh failed to process layer from sync {"node_id": "fd68b9397572556c2f329f3e5af2faf23aef85dbbbb7e38447fae2f4ef38899f", "module": "sync", "sessionId": "29422935-68d6-47d1-87a8-02293aa181f3", "layer_id": 23104, "errmsg": "requested layer 8063 is before evicted 13102", "name": "sync"}
> 2023-10-02T15:28:14.002+0200 WARN fd68b.sync mesh failed to process layer from sync {"node_id": "fd68b9397572556c2f329f3e5af2faf23aef85dbbbb7e38447fae2f4ef38899f", "module": "sync", "sessionId": "29422935-68d6-47d1-87a8-02293aa181f3", "layer_id": 23104, "errmsg": "requested layer 8063 is before evicted 13102", "name": "sync"}
* [#5091](https://github.com/spacemeshos/go-spacemesh/pull/5091) First stage of separating PoST from the node into its own service.
* [#5061](https://github.com/spacemeshos/go-spacemesh/pull/5061) Proof generation is now done via a dedicated service instead of the node.

Operating a node doesn't require any changes at the moment. The service will be automatically started by the node if needed and will be stopped when the node is stopped.

* [#5138](https://github.com/spacemeshos/go-spacemesh/pull/5138) Bump poet to v0.9.7

Expand Down
41 changes: 39 additions & 2 deletions activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"sync"
"time"

"github.com/spacemeshos/post/proving"
"github.com/spacemeshos/post/shared"
"go.uber.org/atomic"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -88,6 +87,9 @@ type Builder struct {
initialPost *types.Post
validator nipostValidator

postMux sync.Mutex
postClient PostClient

// smeshingMutex protects `StartSmeshing` and `StopSmeshing` from concurrent access
smeshingMutex sync.Mutex

Expand Down Expand Up @@ -183,6 +185,41 @@ func NewBuilder(
return b
}

func (b *Builder) Connected(client PostClient) {
b.postMux.Lock()
defer b.postMux.Unlock()

if b.postClient != nil {
b.log.With().Error("post service already connected")
return
}

b.postClient = client
}

func (b *Builder) Disconnected(client PostClient) {
b.postMux.Lock()
defer b.postMux.Unlock()

if b.postClient != client {
b.log.With().Debug("post service not connected")
return
}

b.postClient = nil
}

func (b *Builder) proof(ctx context.Context, challenge []byte) (*types.Post, *types.PostMetadata, error) {
b.postMux.Lock()
defer b.postMux.Unlock()

if b.postClient == nil {
return nil, nil, errors.New("post service not connected")
}

return b.postClient.Proof(ctx, challenge)
}

// Smeshing returns true iff atx builder is smeshing.
func (b *Builder) Smeshing() bool {
return b.started.Load()
Expand Down Expand Up @@ -333,7 +370,7 @@ func (b *Builder) generateInitialPost(ctx context.Context) error {
startTime := time.Now()
var err error
events.EmitPostStart(shared.ZeroChallenge)
post, metadata, err := b.postSetupProvider.GenerateProof(ctx, shared.ZeroChallenge, proving.WithPowCreator(b.nodeID.Bytes()))
post, metadata, err := b.proof(ctx, shared.ZeroChallenge)
if err != nil {
events.EmitPostFailure()
return fmt.Errorf("post execution: %w", err)
Expand Down
31 changes: 17 additions & 14 deletions activation/activation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,13 @@ type testAtxBuilder struct {
coinbase types.Address
goldenATXID types.ATXID

mpub *mocks.MockPublisher
mnipost *MocknipostBuilder
mpost *MockpostSetupProvider
mclock *MocklayerClock
msync *Mocksyncer
mValidator *MocknipostValidator
mpub *mocks.MockPublisher
mnipost *MocknipostBuilder
mpost *MockpostSetupProvider
mpostClient *MockPostClient
mclock *MocklayerClock
msync *Mocksyncer
mValidator *MocknipostValidator
}

func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder {
Expand All @@ -118,6 +119,7 @@ func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder {
mpub: mocks.NewMockPublisher(ctrl),
mnipost: NewMocknipostBuilder(ctrl),
mpost: NewMockpostSetupProvider(ctrl),
mpostClient: NewMockPostClient(ctrl),
mclock: NewMocklayerClock(ctrl),
msync: NewMocksyncer(ctrl),
mValidator: NewMocknipostValidator(ctrl),
Expand All @@ -143,6 +145,7 @@ func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder {
Nonce: 0,
Indices: make([]byte, 10),
}
b.Connected(tab.mpostClient)
tab.Builder = b
dir := tb.TempDir()
tab.mnipost.EXPECT().DataDir().Return(dir).AnyTimes()
Expand Down Expand Up @@ -250,7 +253,7 @@ func TestBuilder_StartSmeshingCoinbase(t *testing.T) {
tab.mpost.EXPECT().StartSession(gomock.Any()).AnyTimes()
tab.mpost.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes()
tab.mpost.EXPECT().CommitmentAtx().Return(tab.goldenATXID, nil).AnyTimes()
tab.mpost.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpostClient.EXPECT().Proof(gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
tab.mclock.EXPECT().AwaitLayer(gomock.Any()).Return(make(chan struct{})).AnyTimes()
require.NoError(t, tab.StartSmeshing(coinbase, postSetupOpts))
Expand All @@ -271,7 +274,7 @@ func TestBuilder_RestartSmeshing(t *testing.T) {
tab.mpost.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes()
tab.mpost.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes()
tab.mpost.EXPECT().StartSession(gomock.Any()).AnyTimes()
tab.mpost.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{
tab.mpostClient.EXPECT().Proof(gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{
Challenge: shared.ZeroChallenge,
}, nil)
tab.mpost.EXPECT().Reset().AnyTimes()
Expand Down Expand Up @@ -382,7 +385,7 @@ func TestBuilder_StartSmeshing_PanicsOnErrInStartSession(t *testing.T) {
tab.log = l

// Stub these methods in case they get called
tab.mpost.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpostClient.EXPECT().Proof(gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mclock.EXPECT().AwaitLayer(gomock.Any()).AnyTimes()

// Set expectations
Expand All @@ -407,7 +410,7 @@ func TestBuilder_StartSmeshing_SessionNotStartedOnFailPrepare(t *testing.T) {
tab.log = l

// Stub these methods in case they get called
tab.mpost.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpostClient.EXPECT().Proof(gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mclock.EXPECT().AwaitLayer(gomock.Any()).AnyTimes()

// Set PrepareInitializer to fail
Expand All @@ -430,7 +433,7 @@ func TestBuilder_StopSmeshing_OnPoSTError(t *testing.T) {
tab.mpost.EXPECT().StartSession(gomock.Any()).Return(nil).AnyTimes()
tab.mpost.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes()
tab.mpost.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes()
tab.mpost.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.Post{}, &types.PostMetadata{}, nil).AnyTimes()
tab.mpostClient.EXPECT().Proof(gomock.Any(), gomock.Any()).AnyTimes().Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
ch := make(chan struct{})
close(ch)
Expand Down Expand Up @@ -1089,7 +1092,7 @@ func TestBuilder_RetryPublishActivationTx(t *testing.T) {

func TestBuilder_InitialProofGeneratedOnce(t *testing.T) {
tab := newTestBuilder(t, WithPoetConfig(PoetConfig{PhaseShift: layerDuration * 4}))
tab.mpost.EXPECT().GenerateProof(gomock.Any(), shared.ZeroChallenge, gomock.Any()).Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpost.EXPECT().LastOpts().Return(&PostSetupOpts{})
tab.mpost.EXPECT().CommitmentAtx().Return(tab.goldenATXID, nil)
tab.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
Expand Down Expand Up @@ -1121,7 +1124,7 @@ func TestBuilder_InitialPostIsPersisted(t *testing.T) {
tab.mpost.EXPECT().Config().AnyTimes().Return(PostConfig{})
tab.mpost.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes()
tab.mpost.EXPECT().CommitmentAtx().Return(tab.goldenATXID, nil).Times(3)
tab.mpost.EXPECT().GenerateProof(gomock.Any(), shared.ZeroChallenge, gomock.Any()).Return(&types.Post{}, &types.PostMetadata{
tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostMetadata{
Challenge: shared.ZeroChallenge,
}, nil)
tab.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
Expand All @@ -1132,7 +1135,7 @@ func TestBuilder_InitialPostIsPersisted(t *testing.T) {

// Remove the persisted post file and try again
require.NoError(t, os.Remove(filepath.Join(tab.nipostBuilder.DataDir(), postFilename)))
tab.mpost.EXPECT().GenerateProof(gomock.Any(), shared.ZeroChallenge, gomock.Any()).Return(&types.Post{}, &types.PostMetadata{}, nil)
tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostMetadata{}, nil)
require.NoError(t, tab.generateInitialPost(context.Background()))
}

Expand Down
Loading

0 comments on commit 0befd88

Please sign in to comment.