diff --git a/activation/activation.go b/activation/activation.go index 6065b1b927b..96a842436d8 100644 --- a/activation/activation.go +++ b/activation/activation.go @@ -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" @@ -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 @@ -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() @@ -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) diff --git a/activation/activation_test.go b/activation/activation_test.go index e0ce677ccec..e8d7e0b349c 100644 --- a/activation/activation_test.go +++ b/activation/activation_test.go @@ -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 { @@ -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), @@ -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() @@ -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)) @@ -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() @@ -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 @@ -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 @@ -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) @@ -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) @@ -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) @@ -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())) } diff --git a/activation/interface.go b/activation/interface.go index 310c43c4bf6..da320fe59a4 100644 --- a/activation/interface.go +++ b/activation/interface.go @@ -5,7 +5,6 @@ import ( "io" "time" - "github.com/spacemeshos/post/proving" "github.com/spacemeshos/post/shared" "github.com/spacemeshos/post/verifying" @@ -56,20 +55,26 @@ type atxProvider interface { } // PostSetupProvider defines the functionality required for Post setup. +// 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 { - Status() *PostSetupStatus - Providers() ([]PostSetupProvider, error) - Benchmark(p PostSetupProvider) (int, error) PrepareInitializer(ctx context.Context, opts PostSetupOpts) error StartSession(context context.Context) error Reset() error - GenerateProof(ctx context.Context, challenge []byte, options ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error) CommitmentAtx() (types.ATXID, error) VRFNonce() (*types.VRFPostIndex, error) LastOpts() *PostSetupOpts Config() PostConfig } +// nipostClient is a temporary interface for the NIPostBuilder. +// it is implemented by the PostSetupManager but will eventually merge with the PoSTClient. +type nipostClient interface { + Status() *PostSetupStatus + CommitmentAtx() (types.ATXID, error) + LastOpts() *PostSetupOpts +} + // SmeshingProvider defines the functionality required for the node's Smesher API. type SmeshingProvider interface { Smeshing() bool diff --git a/activation/mocks.go b/activation/mocks.go index 1e2d0415840..482f145fa97 100644 --- a/activation/mocks.go +++ b/activation/mocks.go @@ -14,7 +14,6 @@ import ( time "time" types "github.com/spacemeshos/go-spacemesh/common/types" - proving "github.com/spacemeshos/post/proving" shared "github.com/spacemeshos/post/shared" verifying "github.com/spacemeshos/post/verifying" gomock "go.uber.org/mock/gomock" @@ -930,45 +929,6 @@ func (m *MockpostSetupProvider) EXPECT() *MockpostSetupProviderMockRecorder { return m.recorder } -// Benchmark mocks base method. -func (m *MockpostSetupProvider) Benchmark(p PostSetupProvider) (int, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Benchmark", p) - ret0, _ := ret[0].(int) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Benchmark indicates an expected call of Benchmark. -func (mr *MockpostSetupProviderMockRecorder) Benchmark(p any) *postSetupProviderBenchmarkCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Benchmark", reflect.TypeOf((*MockpostSetupProvider)(nil).Benchmark), p) - return &postSetupProviderBenchmarkCall{Call: call} -} - -// postSetupProviderBenchmarkCall wrap *gomock.Call -type postSetupProviderBenchmarkCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *postSetupProviderBenchmarkCall) Return(arg0 int, arg1 error) *postSetupProviderBenchmarkCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *postSetupProviderBenchmarkCall) Do(f func(PostSetupProvider) (int, error)) *postSetupProviderBenchmarkCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *postSetupProviderBenchmarkCall) DoAndReturn(f func(PostSetupProvider) (int, error)) *postSetupProviderBenchmarkCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - // CommitmentAtx mocks base method. func (m *MockpostSetupProvider) CommitmentAtx() (types.ATXID, error) { m.ctrl.T.Helper() @@ -1046,51 +1006,6 @@ func (c *postSetupProviderConfigCall) DoAndReturn(f func() PostConfig) *postSetu return c } -// GenerateProof mocks base method. -func (m *MockpostSetupProvider) GenerateProof(ctx context.Context, challenge []byte, options ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error) { - m.ctrl.T.Helper() - varargs := []any{ctx, challenge} - for _, a := range options { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GenerateProof", varargs...) - ret0, _ := ret[0].(*types.Post) - ret1, _ := ret[1].(*types.PostMetadata) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GenerateProof indicates an expected call of GenerateProof. -func (mr *MockpostSetupProviderMockRecorder) GenerateProof(ctx, challenge any, options ...any) *postSetupProviderGenerateProofCall { - mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, challenge}, options...) - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateProof", reflect.TypeOf((*MockpostSetupProvider)(nil).GenerateProof), varargs...) - return &postSetupProviderGenerateProofCall{Call: call} -} - -// postSetupProviderGenerateProofCall wrap *gomock.Call -type postSetupProviderGenerateProofCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *postSetupProviderGenerateProofCall) Return(arg0 *types.Post, arg1 *types.PostMetadata, arg2 error) *postSetupProviderGenerateProofCall { - c.Call = c.Call.Return(arg0, arg1, arg2) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *postSetupProviderGenerateProofCall) Do(f func(context.Context, []byte, ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error)) *postSetupProviderGenerateProofCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *postSetupProviderGenerateProofCall) DoAndReturn(f func(context.Context, []byte, ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error)) *postSetupProviderGenerateProofCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - // LastOpts mocks base method. func (m *MockpostSetupProvider) LastOpts() *PostSetupOpts { m.ctrl.T.Helper() @@ -1167,45 +1082,6 @@ func (c *postSetupProviderPrepareInitializerCall) DoAndReturn(f func(context.Con return c } -// Providers mocks base method. -func (m *MockpostSetupProvider) Providers() ([]PostSetupProvider, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Providers") - ret0, _ := ret[0].([]PostSetupProvider) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Providers indicates an expected call of Providers. -func (mr *MockpostSetupProviderMockRecorder) Providers() *postSetupProviderProvidersCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Providers", reflect.TypeOf((*MockpostSetupProvider)(nil).Providers)) - return &postSetupProviderProvidersCall{Call: call} -} - -// postSetupProviderProvidersCall wrap *gomock.Call -type postSetupProviderProvidersCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *postSetupProviderProvidersCall) Return(arg0 []PostSetupProvider, arg1 error) *postSetupProviderProvidersCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *postSetupProviderProvidersCall) Do(f func() ([]PostSetupProvider, error)) *postSetupProviderProvidersCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *postSetupProviderProvidersCall) DoAndReturn(f func() ([]PostSetupProvider, error)) *postSetupProviderProvidersCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - // Reset mocks base method. func (m *MockpostSetupProvider) Reset() error { m.ctrl.T.Helper() @@ -1282,79 +1158,179 @@ func (c *postSetupProviderStartSessionCall) DoAndReturn(f func(context.Context) return c } -// Status mocks base method. -func (m *MockpostSetupProvider) Status() *PostSetupStatus { +// VRFNonce mocks base method. +func (m *MockpostSetupProvider) VRFNonce() (*types.VRFPostIndex, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Status") - ret0, _ := ret[0].(*PostSetupStatus) - return ret0 + ret := m.ctrl.Call(m, "VRFNonce") + ret0, _ := ret[0].(*types.VRFPostIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// Status indicates an expected call of Status. -func (mr *MockpostSetupProviderMockRecorder) Status() *postSetupProviderStatusCall { +// VRFNonce indicates an expected call of VRFNonce. +func (mr *MockpostSetupProviderMockRecorder) VRFNonce() *postSetupProviderVRFNonceCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockpostSetupProvider)(nil).Status)) - return &postSetupProviderStatusCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VRFNonce", reflect.TypeOf((*MockpostSetupProvider)(nil).VRFNonce)) + return &postSetupProviderVRFNonceCall{Call: call} } -// postSetupProviderStatusCall wrap *gomock.Call -type postSetupProviderStatusCall struct { +// postSetupProviderVRFNonceCall wrap *gomock.Call +type postSetupProviderVRFNonceCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *postSetupProviderStatusCall) Return(arg0 *PostSetupStatus) *postSetupProviderStatusCall { - c.Call = c.Call.Return(arg0) +func (c *postSetupProviderVRFNonceCall) Return(arg0 *types.VRFPostIndex, arg1 error) *postSetupProviderVRFNonceCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *postSetupProviderStatusCall) Do(f func() *PostSetupStatus) *postSetupProviderStatusCall { +func (c *postSetupProviderVRFNonceCall) Do(f func() (*types.VRFPostIndex, error)) *postSetupProviderVRFNonceCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *postSetupProviderStatusCall) DoAndReturn(f func() *PostSetupStatus) *postSetupProviderStatusCall { +func (c *postSetupProviderVRFNonceCall) DoAndReturn(f func() (*types.VRFPostIndex, error)) *postSetupProviderVRFNonceCall { c.Call = c.Call.DoAndReturn(f) return c } -// VRFNonce mocks base method. -func (m *MockpostSetupProvider) VRFNonce() (*types.VRFPostIndex, error) { +// MocknipostClient is a mock of nipostClient interface. +type MocknipostClient struct { + ctrl *gomock.Controller + recorder *MocknipostClientMockRecorder +} + +// MocknipostClientMockRecorder is the mock recorder for MocknipostClient. +type MocknipostClientMockRecorder struct { + mock *MocknipostClient +} + +// NewMocknipostClient creates a new mock instance. +func NewMocknipostClient(ctrl *gomock.Controller) *MocknipostClient { + mock := &MocknipostClient{ctrl: ctrl} + mock.recorder = &MocknipostClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MocknipostClient) EXPECT() *MocknipostClientMockRecorder { + return m.recorder +} + +// CommitmentAtx mocks base method. +func (m *MocknipostClient) CommitmentAtx() (types.ATXID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VRFNonce") - ret0, _ := ret[0].(*types.VRFPostIndex) + ret := m.ctrl.Call(m, "CommitmentAtx") + ret0, _ := ret[0].(types.ATXID) ret1, _ := ret[1].(error) return ret0, ret1 } -// VRFNonce indicates an expected call of VRFNonce. -func (mr *MockpostSetupProviderMockRecorder) VRFNonce() *postSetupProviderVRFNonceCall { +// CommitmentAtx indicates an expected call of CommitmentAtx. +func (mr *MocknipostClientMockRecorder) CommitmentAtx() *nipostClientCommitmentAtxCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VRFNonce", reflect.TypeOf((*MockpostSetupProvider)(nil).VRFNonce)) - return &postSetupProviderVRFNonceCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitmentAtx", reflect.TypeOf((*MocknipostClient)(nil).CommitmentAtx)) + return &nipostClientCommitmentAtxCall{Call: call} } -// postSetupProviderVRFNonceCall wrap *gomock.Call -type postSetupProviderVRFNonceCall struct { +// nipostClientCommitmentAtxCall wrap *gomock.Call +type nipostClientCommitmentAtxCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *postSetupProviderVRFNonceCall) Return(arg0 *types.VRFPostIndex, arg1 error) *postSetupProviderVRFNonceCall { +func (c *nipostClientCommitmentAtxCall) Return(arg0 types.ATXID, arg1 error) *nipostClientCommitmentAtxCall { c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *postSetupProviderVRFNonceCall) Do(f func() (*types.VRFPostIndex, error)) *postSetupProviderVRFNonceCall { +func (c *nipostClientCommitmentAtxCall) Do(f func() (types.ATXID, error)) *nipostClientCommitmentAtxCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *postSetupProviderVRFNonceCall) DoAndReturn(f func() (*types.VRFPostIndex, error)) *postSetupProviderVRFNonceCall { +func (c *nipostClientCommitmentAtxCall) DoAndReturn(f func() (types.ATXID, error)) *nipostClientCommitmentAtxCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// LastOpts mocks base method. +func (m *MocknipostClient) LastOpts() *PostSetupOpts { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LastOpts") + ret0, _ := ret[0].(*PostSetupOpts) + return ret0 +} + +// LastOpts indicates an expected call of LastOpts. +func (mr *MocknipostClientMockRecorder) LastOpts() *nipostClientLastOptsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastOpts", reflect.TypeOf((*MocknipostClient)(nil).LastOpts)) + return &nipostClientLastOptsCall{Call: call} +} + +// nipostClientLastOptsCall wrap *gomock.Call +type nipostClientLastOptsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *nipostClientLastOptsCall) Return(arg0 *PostSetupOpts) *nipostClientLastOptsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *nipostClientLastOptsCall) Do(f func() *PostSetupOpts) *nipostClientLastOptsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *nipostClientLastOptsCall) DoAndReturn(f func() *PostSetupOpts) *nipostClientLastOptsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Status mocks base method. +func (m *MocknipostClient) Status() *PostSetupStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Status") + ret0, _ := ret[0].(*PostSetupStatus) + return ret0 +} + +// Status indicates an expected call of Status. +func (mr *MocknipostClientMockRecorder) Status() *nipostClientStatusCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MocknipostClient)(nil).Status)) + return &nipostClientStatusCall{Call: call} +} + +// nipostClientStatusCall wrap *gomock.Call +type nipostClientStatusCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *nipostClientStatusCall) Return(arg0 *PostSetupStatus) *nipostClientStatusCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *nipostClientStatusCall) Do(f func() *PostSetupStatus) *nipostClientStatusCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *nipostClientStatusCall) DoAndReturn(f func() *PostSetupStatus) *nipostClientStatusCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/activation/nipost.go b/activation/nipost.go index 7cb5147b1ec..37a3d4d37c3 100644 --- a/activation/nipost.go +++ b/activation/nipost.go @@ -8,11 +8,11 @@ import ( "fmt" "math/rand" "slices" + "sync" "time" "github.com/spacemeshos/merkle-tree" "github.com/spacemeshos/poet/shared" - "github.com/spacemeshos/post/proving" "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/activation/metrics" @@ -83,17 +83,20 @@ func (nb *NIPostBuilder) persistState() { // NIPostBuilder holds the required state and dependencies to create Non-Interactive Proofs of Space-Time (NIPost). type NIPostBuilder struct { - nodeID types.NodeID - dataDir string - postSetupProvider postSetupProvider - poetProvers map[string]PoetProvingServiceClient - poetDB poetDbAPI - state *types.NIPostBuilderState - log log.Log - signer *signing.EdSigner - layerClock layerClock - poetCfg PoetConfig - validator nipostValidator + nodeID types.NodeID + dataDir string + nipostClient nipostClient + poetProvers map[string]PoetProvingServiceClient + poetDB poetDbAPI + state *types.NIPostBuilderState + log log.Log + signer *signing.EdSigner + layerClock layerClock + poetCfg PoetConfig + validator nipostValidator + + postMux sync.Mutex + postClient PostClient } type NIPostBuilderOption func(*NIPostBuilder) @@ -122,7 +125,7 @@ type poetDbAPI interface { // NewNIPostBuilder returns a NIPostBuilder. func NewNIPostBuilder( nodeID types.NodeID, - postSetupProvider postSetupProvider, + nipostClient nipostClient, poetDB poetDbAPI, poetServers []string, dataDir string, @@ -142,16 +145,16 @@ func NewNIPostBuilder( } b := &NIPostBuilder{ - nodeID: nodeID, - postSetupProvider: postSetupProvider, - poetProvers: poetClients, - poetDB: poetDB, - state: &types.NIPostBuilderState{NIPost: &types.NIPost{}}, - dataDir: dataDir, - log: lg, - signer: signer, - poetCfg: poetCfg, - layerClock: layerClock, + nodeID: nodeID, + nipostClient: nipostClient, + poetProvers: poetClients, + poetDB: poetDB, + state: &types.NIPostBuilderState{NIPost: &types.NIPost{}}, + dataDir: dataDir, + log: lg, + signer: signer, + poetCfg: poetCfg, + layerClock: layerClock, } for _, opt := range opts { @@ -164,6 +167,41 @@ func (nb *NIPostBuilder) DataDir() string { return nb.dataDir } +func (nb *NIPostBuilder) Connected(client PostClient) { + nb.postMux.Lock() + defer nb.postMux.Unlock() + + if nb.postClient != nil { + nb.log.With().Error("post service already connected") + return + } + + nb.postClient = client +} + +func (nb *NIPostBuilder) Disconnected(client PostClient) { + nb.postMux.Lock() + defer nb.postMux.Unlock() + + if nb.postClient != client { + nb.log.With().Debug("post service not connected") + return + } + + nb.postClient = nil +} + +func (nb *NIPostBuilder) proof(ctx context.Context, challenge []byte) (*types.Post, *types.PostMetadata, error) { + nb.postMux.Lock() + defer nb.postMux.Unlock() + + if nb.postClient == nil { + return nil, nil, errors.New("post service not connected") + } + + return nb.postClient.Proof(ctx, challenge) +} + // UpdatePoETProvers updates poetProver reference. It should not be executed concurrently with BuildNIPoST. func (nb *NIPostBuilder) UpdatePoETProvers(poetProvers []PoetProvingServiceClient) { // TODO(mafa): this seems incorrect - this makes it impossible for the node to fetch a submitted challenge @@ -221,7 +259,7 @@ func (nb *NIPostBuilder) BuildNIPost(ctx context.Context, challenge *types.NIPos challengeHash := challenge.Hash() nb.loadState(challengeHash) - if s := nb.postSetupProvider.Status(); s.State != PostSetupStateComplete { + if s := nb.nipostClient.Status(); s.State != PostSetupStateComplete { return nil, errors.New("post setup not complete") } @@ -284,12 +322,12 @@ func (nb *NIPostBuilder) BuildNIPost(ctx context.Context, challenge *types.NIPos startTime := time.Now() events.EmitPostStart(nb.state.PoetProofRef[:]) - proof, proofMetadata, err := nb.postSetupProvider.GenerateProof(postCtx, nb.state.PoetProofRef[:], proving.WithPowCreator(nb.nodeID.Bytes())) + proof, proofMetadata, err := nb.proof(postCtx, nb.state.PoetProofRef[:]) if err != nil { events.EmitPostFailure() return nil, fmt.Errorf("failed to generate Post: %w", err) } - commitmentAtxId, err := nb.postSetupProvider.CommitmentAtx() + commitmentAtxId, err := nb.nipostClient.CommitmentAtx() if err != nil { return nil, fmt.Errorf("failed to get commitment ATX: %w", err) } @@ -299,7 +337,7 @@ func (nb *NIPostBuilder) BuildNIPost(ctx context.Context, challenge *types.NIPos commitmentAtxId, proof, proofMetadata, - nb.postSetupProvider.LastOpts().NumUnits, + nb.nipostClient.LastOpts().NumUnits, ); err != nil { events.EmitInvalidPostProof() return nil, fmt.Errorf("failed to verify Post: %w", err) diff --git a/activation/nipost_integration_test.go.bak b/activation/nipost_integration_test.go.bak new file mode 100644 index 00000000000..00ff706b5cb --- /dev/null +++ b/activation/nipost_integration_test.go.bak @@ -0,0 +1,315 @@ +package activation_test + +import ( + "context" + "errors" + "os" + "testing" + "time" + + "github.com/spacemeshos/poet/logging" + "github.com/spacemeshos/post/config" + "github.com/spacemeshos/post/initialization" + "github.com/stretchr/testify/require" + "github.com/zeebo/assert" + "go.uber.org/mock/gomock" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest" + "golang.org/x/sync/errgroup" + + "github.com/spacemeshos/go-spacemesh/activation" + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/datastore" + "github.com/spacemeshos/go-spacemesh/log/logtest" + "github.com/spacemeshos/go-spacemesh/signing" + "github.com/spacemeshos/go-spacemesh/sql" +) + +const ( + layersPerEpoch = 10 + layerDuration = time.Second + postGenesisEpoch types.EpochID = 2 +) + +func TestMain(m *testing.M) { + types.SetLayersPerEpoch(layersPerEpoch) + res := m.Run() + os.Exit(res) +} + +func initPost(tb testing.TB, log *zap.Logger, dir string) { + tb.Helper() + + cfg := activation.DefaultPostConfig() + + sig, err := signing.NewEdSigner() + require.NoError(tb, err) + id := sig.NodeID() + + opts := activation.DefaultPostSetupOpts() + opts.DataDir = dir + opts.ProviderID.SetInt64(int64(initialization.CPUProviderID())) + opts.Scrypt.N = 2 // Speedup initialization in tests. + + goldenATXID := types.ATXID{2, 3, 4} + + cdb := datastore.NewCachedDB(sql.InMemory(), logtest.New(tb)) + provingOpts := activation.DefaultPostProvingOpts() + provingOpts.Flags = config.RecommendedPowFlags() + mgr, err := activation.NewPostSetupManager(id, cfg, log.Named("manager"), cdb, goldenATXID, provingOpts) + require.NoError(tb, err) + + ctx, cancel := context.WithCancel(context.Background()) + tb.Cleanup(cancel) + + var eg errgroup.Group + lastStatus := &activation.PostSetupStatus{} + eg.Go(func() error { + timer := time.NewTicker(50 * time.Millisecond) + defer timer.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + status := mgr.Status() + require.GreaterOrEqual(tb, status.NumLabelsWritten, lastStatus.NumLabelsWritten) + + if status.NumLabelsWritten == uint64(opts.NumUnits)*cfg.LabelsPerUnit { + return nil + } + require.Equal(tb, activation.PostSetupStateInProgress, status.State) + } + } + }) + + // Create data. + require.NoError(tb, mgr.PrepareInitializer(context.Background(), opts)) + require.NoError(tb, mgr.StartSession(context.Background())) + require.NoError(tb, eg.Wait()) + require.Equal(tb, activation.PostSetupStateComplete, mgr.Status().State) +} + +func spawnPoet(tb testing.TB, opts ...HTTPPoetOpt) *HTTPPoetTestHarness { + tb.Helper() + ctx, cancel := context.WithCancel(logging.NewContext(context.Background(), zaptest.NewLogger(tb))) + + poetProver, err := NewHTTPPoetTestHarness(ctx, tb.TempDir(), opts...) + require.NoError(tb, err) + require.NotNil(tb, poetProver) + + var eg errgroup.Group + tb.Cleanup(func() { + cancel() + eg.Wait() + }) + eg.Go(func() error { + err := poetProver.Service.Start(ctx) + return errors.Join(err, poetProver.Service.Close()) + }) + + return poetProver +} + +// TODO(mafa): start post service with supervisor. +func buildNIPost(tb testing.TB, postProvider *testPostManager, nipostChallenge types.NIPostChallenge, poetDb poetDbAPI, validator nipostValidator) *types.NIPost { + require.NoError(tb, postProvider.PrepareInitializer(context.Background(), postProvider.opts)) + require.NoError(tb, postProvider.StartSession(context.Background())) + mclock := activation.NewMocklayerClock(gomock.NewController(tb)) + mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( + func(got types.LayerID) time.Time { + // time.Now() ~= currentLayer + genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) + return genesis.Add(layerDuration * time.Duration(got)) + }, + ) + + epoch := layersPerEpoch * layerDuration + poetCfg := activation.PoetConfig{ + PhaseShift: epoch / 2, + CycleGap: epoch / 5, + GracePeriod: epoch / 5, + RequestTimeout: epoch / 5, + RequestRetryDelay: epoch / 50, + MaxRequestRetries: 10, + } + + poetProver := spawnPoet(tb, WithGenesis(time.Now()), WithEpochDuration(epoch), WithPhaseShift(poetCfg.PhaseShift), WithCycleGap(poetCfg.CycleGap)) + + signer, err := signing.NewEdSigner() + require.NoError(tb, err) + nb, err := activation.NewNIPostBuilder( + postProvider.id, + postProvider, + poetDb, + []string{poetProver.RestURL().String()}, + tb.TempDir(), + logtest.New(tb, zapcore.DebugLevel), + signer, + poetCfg, + mclock, + activation.WithNipostValidator(validator), + ) + require.NoError(tb, err) + nipost, err := nb.BuildNIPost(context.Background(), &nipostChallenge) + require.NoError(tb, err) + return nipost +} + +func TestNIPostBuilderWithClients(t *testing.T) { + challenge := types.NIPostChallenge{ + PublishEpoch: postGenesisEpoch + 2, + } + poetDb := activation.NewPoetDb(sql.InMemory(), logtest.New(t).WithName("poetDb")) + postCfg := activation.DefaultPostConfig() + postCfg.PowDifficulty[0] = 1 + postProvider := newTestPostManager(t, withPostConfig(postCfg)) + verifier, err := activation.NewPostVerifier(postProvider.Config(), zaptest.NewLogger(t).Named("verifier")) + require.NoError(t, err) + defer verifier.Close() + + v := activation.NewValidator(poetDb, postProvider.Config(), postProvider.opts.Scrypt, verifier) + nipost := buildNIPost(t, postProvider, challenge, poetDb, v) + _, err = v.NIPost( + context.Background(), + postProvider.id, + postProvider.commitmentAtxId, + nipost, + challenge.Hash(), + postProvider.opts.NumUnits, + ) + require.NoError(t, err) +} + +func TestNIPostBuilder_Close(t *testing.T) { + t.Parallel() + r := require.New(t) + + ctrl := gomock.NewController(t) + nipostClient := activation.NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&activation.PostSetupStatus{State: activation.PostSetupStateComplete}) + poetProver := spawnPoet(t, WithGenesis(time.Now()), WithEpochDuration(time.Second)) + poetDb := activation.NewMockpoetDbAPI(ctrl) + challenge := types.NIPostChallenge{ + PublishEpoch: postGenesisEpoch + 2, + } + mclock := activation.NewMocklayerClock(gomock.NewController(t)) + mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( + func(got types.LayerID) time.Time { + // time.Now() ~= currentLayer + genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) + return genesis.Add(layerDuration * time.Duration(got)) + }, + ) + + sig, err := signing.NewEdSigner() + r.NoError(err) + nb, err := activation.NewNIPostBuilder( + types.NodeID{1}, + nipostClient, + poetDb, + []string{poetProver.RestURL().String()}, + t.TempDir(), + logtest.New(t), + sig, + activation.PoetConfig{}, + mclock, + ) + r.NoError(err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + nipost, err := nb.BuildNIPost(ctx, &challenge) + r.ErrorIs(err, context.Canceled) + r.Nil(nipost) +} + +func TestNewNIPostBuilderNotInitialized(t *testing.T) { + r := require.New(t) + + challenge := types.NIPostChallenge{ + PublishEpoch: postGenesisEpoch + 2, + } + challengeHash := challenge.Hash() + + postProvider := newTestPostManager(t) + + epoch := layersPerEpoch * layerDuration + poetCfg := activation.PoetConfig{ + PhaseShift: epoch / 5, + CycleGap: epoch / 10, + GracePeriod: epoch / 10, + RequestTimeout: epoch / 10, + RequestRetryDelay: epoch / 100, + MaxRequestRetries: 10, + } + + poetClient := activation.NewMockPoetProvingServiceClient(gomock.NewController(t)) + poetClient.EXPECT().Submit(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.PoetRound{}, nil) + poetClient.EXPECT().PoetServiceID(gomock.Any()).Return(types.PoetServiceID{ServiceID: []byte("poet")}, nil) + poetClient.EXPECT().PowParams(gomock.Any()).Return(&activation.PoetPowParams{}, nil) + poetClient.EXPECT().Address().Return("http://localhost:9999") + poetClient.EXPECT().Proof(gomock.Any(), "").Return(&types.PoetProofMessage{ + PoetProof: types.PoetProof{}, + }, []types.Member{types.Member(challenge.Hash())}, nil) + + ctrl := gomock.NewController(t) + poetDb := activation.NewMockpoetDbAPI(ctrl) + poetDb.EXPECT().GetProof(gomock.Any()).Return( + &types.PoetProof{}, &challengeHash, nil, + ) + poetDb.EXPECT().ValidateAndStore(gomock.Any(), gomock.Any()).Return(nil) + mclock := activation.NewMocklayerClock(gomock.NewController(t)) + mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( + func(got types.LayerID) time.Time { + // time.Now() ~= currentLayer + genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) + return genesis.Add(layerDuration * time.Duration(got)) + }, + ) + + nipostValidator := activation.NewMocknipostValidator(ctrl) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + + nb, err := activation.NewNIPostBuilder( + postProvider.id, + postProvider, + poetDb, + []string{}, + t.TempDir(), + logtest.New(t), + postProvider.signer, + poetCfg, + mclock, + activation.WithNipostValidator(nipostValidator), + withPoetClients([]activation.PoetProvingServiceClient{poetProvider}), + ) + require.NoError(t, err) + + nipost, err := nb.BuildNIPost(context.Background(), &challenge) + r.EqualError(err, "post setup not complete") + r.Nil(nipost) + + r.NoError(postProvider.PrepareInitializer(context.Background(), postProvider.opts)) + r.NoError(postProvider.StartSession(context.Background())) + + nipost, err = nb.BuildNIPost(context.Background(), &challenge) + r.NoError(err) + r.NotNil(nipost) + + verifier, err := activation.NewPostVerifier(postProvider.cfg, zaptest.NewLogger(t).Named("verifier")) + r.NoError(err) + t.Cleanup(func() { assert.NoError(t, verifier.Close()) }) + v := activation.NewValidator(poetDb, postProvider.cfg, postProvider.opts.Scrypt, verifier) + _, err = v.NIPost( + context.Background(), + postProvider.id, + postProvider.goldenATXID, + nipost, + challenge.Hash(), + postProvider.opts.NumUnits, + ) + r.NoError(err) +} diff --git a/activation/nipost_test.go b/activation/nipost_test.go index 21963ad0119..b9ff36204aa 100644 --- a/activation/nipost_test.go +++ b/activation/nipost_test.go @@ -8,19 +8,14 @@ import ( "time" "github.com/spacemeshos/go-scale/tester" - "github.com/spacemeshos/poet/logging" - "github.com/spacemeshos/post/proving" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "go.uber.org/zap/zapcore" - "go.uber.org/zap/zaptest" - "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/log/logtest" "github.com/spacemeshos/go-spacemesh/signing" - "github.com/spacemeshos/go-spacemesh/sql" ) func defaultPoetServiceMock(tb testing.TB, id []byte, address string) *MockPoetProvingServiceClient { @@ -53,11 +48,13 @@ func TestNIPostBuilderWithMocks(t *testing.T) { } ctrl := gomock.NewController(t) - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() + + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Times(1) nipostValidator := NewMocknipostValidator(ctrl) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil) @@ -75,7 +72,7 @@ func TestNIPostBuilderWithMocks(t *testing.T) { require.NoError(t, err) nb, err := NewNIPostBuilder( types.NodeID{1}, - postProvider, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -87,6 +84,8 @@ func TestNIPostBuilderWithMocks(t *testing.T) { withPoetClients([]PoetProvingServiceClient{poetProvider}), ) require.NoError(t, err) + nb.Connected(postClient) + nipost, err := nb.BuildNIPost(context.Background(), &challenge) require.NoError(t, err) require.NotNil(t, nipost) @@ -106,13 +105,17 @@ func TestPostSetup(t *testing.T) { PoetProof: types.PoetProof{}, }, []types.Member{types.Member(challenge.Hash())}, nil) - poetDb := NewMockpoetDbAPI(gomock.NewController(t)) + ctrl := gomock.NewController(t) + poetDb := NewMockpoetDbAPI(ctrl) poetDb.EXPECT().ValidateAndStore(gomock.Any(), gomock.Any()).Return(nil) mclock := defaultLayerClockMock(t) - nipostValidator := NewMocknipostValidator(gomock.NewController(t)) + nipostValidator := NewMocknipostValidator(ctrl) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Times(1) + nb, err := NewNIPostBuilder( postProvider.id, postProvider, @@ -127,6 +130,7 @@ func TestPostSetup(t *testing.T) { withPoetClients([]PoetProvingServiceClient{poetProvider}), ) r.NoError(err) + nb.Connected(postClient) r.NoError(postProvider.PrepareInitializer(context.Background(), postProvider.opts)) r.NoError(postProvider.StartSession(context.Background())) @@ -137,172 +141,6 @@ func TestPostSetup(t *testing.T) { r.NotNil(nipost) } -func TestNIPostBuilderWithClients(t *testing.T) { - challenge := types.NIPostChallenge{ - PublishEpoch: postGenesisEpoch + 2, - } - poetDb := NewPoetDb(sql.InMemory(), logtest.New(t).WithName("poetDb")) - postCfg := DefaultPostConfig() - postCfg.PowDifficulty[0] = 1 - postProvider := newTestPostManager(t, withPostConfig(postCfg)) - logger := logtest.New(t).WithName("validator") - verifier, err := NewPostVerifier(postProvider.Config(), logger) - require.NoError(t, err) - defer verifier.Close() - - v := NewValidator(poetDb, postProvider.Config(), postProvider.opts.Scrypt, logger, verifier) - nipost := buildNIPost(t, postProvider, challenge, poetDb, v) - _, err = v.NIPost( - context.Background(), - postProvider.id, - postProvider.commitmentAtxId, - nipost, - challenge.Hash(), - postProvider.opts.NumUnits, - ) - require.NoError(t, err) -} - -func spawnPoet(tb testing.TB, opts ...HTTPPoetOpt) *HTTPPoetTestHarness { - tb.Helper() - ctx, cancel := context.WithCancel(logging.NewContext(context.Background(), zaptest.NewLogger(tb))) - - poetProver, err := NewHTTPPoetTestHarness(ctx, tb.TempDir(), opts...) - require.NoError(tb, err) - require.NotNil(tb, poetProver) - - var eg errgroup.Group - tb.Cleanup(func() { - cancel() - eg.Wait() - }) - eg.Go(func() error { - err := poetProver.Service.Start(ctx) - return errors.Join(err, poetProver.Service.Close()) - }) - - return poetProver -} - -func buildNIPost(tb testing.TB, postProvider *testPostManager, nipostChallenge types.NIPostChallenge, poetDb poetDbAPI, validator nipostValidator) *types.NIPost { - require.NoError(tb, postProvider.PrepareInitializer(context.Background(), postProvider.opts)) - require.NoError(tb, postProvider.StartSession(context.Background())) - mclock := defaultLayerClockMock(tb) - - epoch := layersPerEpoch * layerDuration - poetCfg := PoetConfig{ - PhaseShift: epoch / 2, - CycleGap: epoch / 5, - GracePeriod: epoch / 5, - RequestTimeout: epoch / 5, - RequestRetryDelay: epoch / 50, - MaxRequestRetries: 10, - } - - poetProver := spawnPoet(tb, WithGenesis(time.Now()), WithEpochDuration(epoch), WithPhaseShift(poetCfg.PhaseShift), WithCycleGap(poetCfg.CycleGap)) - - signer, err := signing.NewEdSigner() - require.NoError(tb, err) - nb, err := NewNIPostBuilder( - postProvider.id, - postProvider, - poetDb, - []string{poetProver.RestURL().String()}, - tb.TempDir(), - logtest.New(tb, zapcore.DebugLevel), - signer, - poetCfg, - mclock, - WithNipostValidator(validator), - ) - require.NoError(tb, err) - nipost, err := nb.BuildNIPost(context.Background(), &nipostChallenge) - require.NoError(tb, err) - return nipost -} - -func TestNewNIPostBuilderNotInitialized(t *testing.T) { - if testing.Short() { - t.Skip() - } - - r := require.New(t) - - challenge := types.NIPostChallenge{ - PublishEpoch: postGenesisEpoch + 2, - } - challengeHash := challenge.Hash() - - postProvider := newTestPostManager(t) - - epoch := layersPerEpoch * layerDuration - poetCfg := PoetConfig{ - PhaseShift: epoch / 5, - CycleGap: epoch / 10, - GracePeriod: epoch / 10, - RequestTimeout: epoch / 10, - RequestRetryDelay: epoch / 100, - MaxRequestRetries: 10, - } - - poetProvider := defaultPoetServiceMock(t, []byte("poet"), "http://localhost:9999") - poetProvider.EXPECT().Proof(gomock.Any(), "").Return(&types.PoetProofMessage{ - PoetProof: types.PoetProof{}, - }, []types.Member{types.Member(challenge.Hash())}, nil) - - ctrl := gomock.NewController(t) - poetDb := NewMockpoetDbAPI(ctrl) - poetDb.EXPECT().GetProof(gomock.Any()).Return( - &types.PoetProof{}, &challengeHash, nil, - ) - poetDb.EXPECT().ValidateAndStore(gomock.Any(), gomock.Any()).Return(nil) - mclock := defaultLayerClockMock(t) - - nipostValidator := NewMocknipostValidator(ctrl) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) - - nb, err := NewNIPostBuilder( - postProvider.id, - postProvider, - poetDb, - []string{}, - t.TempDir(), - logtest.New(t), - postProvider.signer, - poetCfg, - mclock, - WithNipostValidator(nipostValidator), - withPoetClients([]PoetProvingServiceClient{poetProvider}), - ) - require.NoError(t, err) - - nipost, err := nb.BuildNIPost(context.Background(), &challenge) - r.EqualError(err, "post setup not complete") - r.Nil(nipost) - - r.NoError(postProvider.PrepareInitializer(context.Background(), postProvider.opts)) - r.NoError(postProvider.StartSession(context.Background())) - - nipost, err = nb.BuildNIPost(context.Background(), &challenge) - r.NoError(err) - r.NotNil(nipost) - - logger := logtest.New(t).WithName("validator") - verifier, err := NewPostVerifier(postProvider.cfg, logger) - r.NoError(err) - defer verifier.Close() - v := NewValidator(poetDb, postProvider.cfg, postProvider.opts.Scrypt, logger, verifier) - _, err = v.NIPost( - context.Background(), - postProvider.id, - postProvider.goldenATXID, - nipost, - challenge.Hash(), - postProvider.opts.NumUnits, - ) - r.NoError(err) -} - func TestNIPostBuilder_BuildNIPost(t *testing.T) { t.Parallel() req := require.New(t) @@ -310,10 +148,10 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { ctrl := gomock.NewController(t) nipostValidator := NewMocknipostValidator(ctrl) - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}).AnyTimes() - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}).AnyTimes() + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() challenge := types.NIPostChallenge{ PublishEpoch: postGenesisEpoch + 2, @@ -347,7 +185,7 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { nodeID := types.NodeID{1} nb, err := NewNIPostBuilder( nodeID, - postProvider, + nipostClient, poetDb, []string{}, dir, @@ -360,7 +198,10 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { ) req.NoError(err) - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Times(1) + nb.Connected(postClient) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) nipost, err := nb.BuildNIPost(context.Background(), &challenge) req.NoError(err) @@ -374,7 +215,7 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { req.NoError(err) nb, err = NewNIPostBuilder( nodeID, - postProvider, + nipostClient, poetDb, []string{}, dir, @@ -385,7 +226,9 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { withPoetClients([]PoetProvingServiceClient{poetProver}), ) req.NoError(err) - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, fmt.Errorf("error")).Times(1) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Return(nil, nil, fmt.Errorf("error")).Times(1) + nb.Connected(postClient) + // check that proof ref is not called again nipost, err = nb.BuildNIPost(context.Background(), &challenge2) req.Nil(nipost) @@ -398,7 +241,7 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { req.NoError(err) nb, err = NewNIPostBuilder( nodeID, - postProvider, + nipostClient, poetDb, []string{}, dir, @@ -410,8 +253,10 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { withPoetClients([]PoetProvingServiceClient{poetProver}), ) req.NoError(err) - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Times(1) + nb.Connected(postClient) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + // check that proof ref is not called again nipost, err = nb.BuildNIPost(context.Background(), &challenge2) req.NoError(err) @@ -419,7 +264,7 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { // test state not loading if other challenge provided poetDb.EXPECT().ValidateAndStore(gomock.Any(), gomock.Any()).Return(nil) - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).Times(1) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) nipost, err = nb.BuildNIPost(context.Background(), &challenge3) req.NoError(err) @@ -471,12 +316,14 @@ func TestNIPostBuilder_ManyPoETs_SubmittingChallenge_DeadlineReached(t *testing. poetCfg := PoetConfig{ PhaseShift: layerDuration * layersPerEpoch / 2, } - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( - func(ctx context.Context, challenge []byte, _ ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error) { + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() + + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).DoAndReturn( + func(ctx context.Context, challenge []byte) (*types.Post, *types.PostMetadata, error) { return &types.Post{}, &types.PostMetadata{ Challenge: challenge, }, nil @@ -485,7 +332,7 @@ func TestNIPostBuilder_ManyPoETs_SubmittingChallenge_DeadlineReached(t *testing. nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, - postProvider, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -499,6 +346,7 @@ func TestNIPostBuilder_ManyPoETs_SubmittingChallenge_DeadlineReached(t *testing. req.NoError(err) // Act + nb.Connected(postClient) nipost, err := nb.BuildNIPost(context.Background(), &challenge) req.NoError(err) @@ -547,21 +395,24 @@ func TestNIPostBuilder_ManyPoETs_AllFinished(t *testing.T) { sig, err := signing.NewEdSigner() req.NoError(err) - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( - func(_ context.Context, challenge []byte, _ ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error) { + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() + + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).DoAndReturn( + func(ctx context.Context, challenge []byte) (*types.Post, *types.PostMetadata, error) { return &types.Post{}, &types.PostMetadata{ Challenge: challenge, }, nil }, ) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, - postProvider, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -573,6 +424,7 @@ func TestNIPostBuilder_ManyPoETs_AllFinished(t *testing.T) { withPoetClients(poets), ) req.NoError(err) + nb.Connected(postClient) // Act nipost, err := nb.BuildNIPost(context.Background(), &challenge) @@ -583,42 +435,6 @@ func TestNIPostBuilder_ManyPoETs_AllFinished(t *testing.T) { req.EqualValues(ref[:], nipost.PostMetadata.Challenge) } -func TestNIPostBuilder_Close(t *testing.T) { - t.Parallel() - r := require.New(t) - - ctrl := gomock.NewController(t) - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) - poetProver := spawnPoet(t, WithGenesis(time.Now()), WithEpochDuration(time.Second)) - poetDb := NewMockpoetDbAPI(ctrl) - challenge := types.NIPostChallenge{ - PublishEpoch: postGenesisEpoch + 2, - } - mclock := defaultLayerClockMock(t) - - sig, err := signing.NewEdSigner() - r.NoError(err) - nb, err := NewNIPostBuilder( - types.NodeID{1}, - postProvider, - poetDb, - []string{poetProver.RestURL().String()}, - t.TempDir(), - logtest.New(t), - sig, - PoetConfig{}, - mclock, - ) - r.NoError(err) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - nipost, err := nb.BuildNIPost(ctx, &challenge) - r.ErrorIs(err, context.Canceled) - r.Nil(nipost) -} - func TestNIPSTBuilder_PoetUnstable(t *testing.T) { t.Parallel() challenge := types.NIPostChallenge{ @@ -637,15 +453,15 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { ctrl := gomock.NewController(t) poetDb := NewMockpoetDbAPI(ctrl) mclock := defaultLayerClockMock(t) - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().PoetServiceID(gomock.Any()).AnyTimes().Return(types.PoetServiceID{}, errors.New("test")) poetProver.EXPECT().Address().Return("http://localhost:9999") nb, err := NewNIPostBuilder( nodeID, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -665,8 +481,8 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { ctrl := gomock.NewController(t) poetDb := NewMockpoetDbAPI(ctrl) mclock := defaultLayerClockMock(t) - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().PoetServiceID(gomock.Any()).AnyTimes().Return(types.PoetServiceID{ServiceID: []byte{}}, nil) poetProver.EXPECT().Submit(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("test")) @@ -675,7 +491,7 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { nb, err := NewNIPostBuilder( nodeID, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -696,8 +512,8 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { ctrl := gomock.NewController(t) poetDb := NewMockpoetDbAPI(ctrl) mclock := defaultLayerClockMock(t) - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().PoetServiceID(gomock.Any()).AnyTimes().Return(types.PoetServiceID{ServiceID: []byte{}}, nil) poetProver.EXPECT().Submit(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( @@ -711,7 +527,7 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { nb, err := NewNIPostBuilder( nodeID, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -731,14 +547,14 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { ctrl := gomock.NewController(t) poetDb := NewMockpoetDbAPI(ctrl) mclock := defaultLayerClockMock(t) - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) poetProver := defaultPoetServiceMock(t, []byte("poet"), "http://localhost:9999") poetProver.EXPECT().Proof(gomock.Any(), "").Return(nil, nil, errors.New("failed")) nb, err := NewNIPostBuilder( nodeID, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -759,14 +575,14 @@ func TestNIPSTBuilder_PoetUnstable(t *testing.T) { poetDb := NewMockpoetDbAPI(ctrl) poetDb.EXPECT().ValidateAndStore(gomock.Any(), gomock.Any()).Return(nil) mclock := defaultLayerClockMock(t) - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) poetProver := defaultPoetServiceMock(t, []byte("poet"), "http://localhost:9999") poetProver.EXPECT().Proof(gomock.Any(), "").Return(&types.PoetProofMessage{PoetProof: types.PoetProof{}}, []types.Member{}, nil) nb, err := NewNIPostBuilder( nodeID, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -801,8 +617,8 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { mclock := NewMocklayerClock(ctrl) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().Address().Return("http://localhost:9999") - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn( func(got types.LayerID) time.Time { return genesis.Add(layerDuration * time.Duration(got)) @@ -810,7 +626,7 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { nb, err := NewNIPostBuilder( types.NodeID{1}, - postProver, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -834,8 +650,8 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { mclock := NewMocklayerClock(ctrl) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().Address().Return("http://localhost:9999") - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn( func(got types.LayerID) time.Time { return genesis.Add(layerDuration * time.Duration(got)) @@ -844,7 +660,7 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { dir := t.TempDir() nb, err := NewNIPostBuilder( types.NodeID{1}, - postProver, + nipostClient, poetDb, []string{}, dir, @@ -873,8 +689,8 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { mclock := NewMocklayerClock(ctrl) poetProver := NewMockPoetProvingServiceClient(ctrl) poetProver.EXPECT().Address().Return("http://localhost:9999") - postProver := NewMockpostSetupProvider(ctrl) - postProver.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn( func(got types.LayerID) time.Time { return genesis.Add(layerDuration * time.Duration(got)) @@ -883,7 +699,7 @@ func TestNIPoSTBuilder_StaleChallenge(t *testing.T) { dir := t.TempDir() nb, err := NewNIPostBuilder( types.NodeID{1}, - postProver, + nipostClient, poetDb, []string{}, dir, @@ -950,22 +766,25 @@ func TestNIPoSTBuilder_Continues_After_Interrupted(t *testing.T) { poetCfg := PoetConfig{ PhaseShift: layerDuration * layersPerEpoch / 2, } - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}).Times(2) - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( - func(ctx context.Context, challenge []byte, _ ...proving.OptionFunc) (*types.Post, *types.PostMetadata, error) { + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}).Times(2) + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() + + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()).DoAndReturn( + func(ctx context.Context, challenge []byte) (*types.Post, *types.PostMetadata, error) { return &types.Post{}, &types.PostMetadata{ Challenge: challenge, }, nil }, ) + nipostValidator := NewMocknipostValidator(ctrl) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, - postProvider, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -977,6 +796,7 @@ func TestNIPoSTBuilder_Continues_After_Interrupted(t *testing.T) { withPoetClients([]PoetProvingServiceClient{poet}), ) req.NoError(err) + nb.Connected(postClient) // Act nipost, err := nb.BuildNIPost(buildCtx, &challenge) @@ -1067,11 +887,10 @@ func TestNIPostBuilder_Mainnet_PoetRound3_Workaround(t *testing.T) { } ctrl := gomock.NewController(t) - postProvider := NewMockpostSetupProvider(ctrl) - postProvider.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) - postProvider.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() - postProvider.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + nipostClient := NewMocknipostClient(ctrl) + nipostClient.EXPECT().Status().Return(&PostSetupStatus{State: PostSetupStateComplete}) + nipostClient.EXPECT().CommitmentAtx().Return(types.EmptyATXID, nil).AnyTimes() + nipostClient.EXPECT().LastOpts().Return(&PostSetupOpts{}).AnyTimes() nipostValidator := NewMocknipostValidator(ctrl) nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil) @@ -1118,6 +937,9 @@ func TestNIPostBuilder_Mainnet_PoetRound3_Workaround(t *testing.T) { }, ) + postClient := NewMockPostClient(ctrl) + postClient.EXPECT().Proof(gomock.Any(), gomock.Any()) + sig, err := signing.NewEdSigner() require.NoError(t, err) poetCfg := PoetConfig{ @@ -1125,7 +947,7 @@ func TestNIPostBuilder_Mainnet_PoetRound3_Workaround(t *testing.T) { } nb, err := NewNIPostBuilder( types.NodeID{1}, - postProvider, + nipostClient, poetDb, []string{}, t.TempDir(), @@ -1137,6 +959,8 @@ func TestNIPostBuilder_Mainnet_PoetRound3_Workaround(t *testing.T) { withPoetClients(poets), ) require.NoError(t, err) + nb.Connected(postClient) + nipost, err := nb.BuildNIPost(context.Background(), &challenge) require.NoError(t, err) require.NotNil(t, nipost) diff --git a/activation/poet_integration_test.go b/activation/poet_integration_test.go new file mode 100644 index 00000000000..9d8376c285f --- /dev/null +++ b/activation/poet_integration_test.go @@ -0,0 +1,135 @@ +package activation_test + +import ( + "bytes" + "context" + "errors" + "net/url" + "testing" + "time" + + "github.com/spacemeshos/poet/server" + "github.com/spacemeshos/poet/shared" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + "golang.org/x/sync/errgroup" + + "github.com/spacemeshos/go-spacemesh/activation" + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/signing" +) + +// HTTPPoetTestHarness utilizes a local self-contained poet server instance +// targeted by an HTTP client. It is intended to be used in tests only. +type HTTPPoetTestHarness struct { + Service *server.Server +} + +func (h *HTTPPoetTestHarness) RestURL() *url.URL { + return &url.URL{ + Scheme: "http", + Host: h.Service.GrpcRestProxyAddr().String(), + } +} + +type HTTPPoetOpt func(*server.Config) + +func WithGenesis(genesis time.Time) HTTPPoetOpt { + return func(cfg *server.Config) { + cfg.Genesis = server.Genesis(genesis) + } +} + +func WithEpochDuration(epoch time.Duration) HTTPPoetOpt { + return func(cfg *server.Config) { + cfg.Round.EpochDuration = epoch + } +} + +func WithPhaseShift(phase time.Duration) HTTPPoetOpt { + return func(cfg *server.Config) { + cfg.Round.PhaseShift = phase + } +} + +func WithCycleGap(gap time.Duration) HTTPPoetOpt { + return func(cfg *server.Config) { + cfg.Round.CycleGap = gap + } +} + +// NewHTTPPoetTestHarness returns a new instance of HTTPPoetHarness. +func NewHTTPPoetTestHarness(ctx context.Context, poetdir string, opts ...HTTPPoetOpt) (*HTTPPoetTestHarness, error) { + cfg := server.DefaultConfig() + cfg.PoetDir = poetdir + cfg.RawRESTListener = "localhost:0" + cfg.RawRPCListener = "localhost:0" + + for _, opt := range opts { + opt(cfg) + } + + server.SetupConfig(cfg) + + poet, err := server.New(ctx, *cfg) + if err != nil { + return nil, err + } + + return &HTTPPoetTestHarness{ + Service: poet, + }, nil +} + +func TestHTTPPoet(t *testing.T) { + if testing.Short() { + t.Skip() + } + t.Parallel() + r := require.New(t) + + var eg errgroup.Group + + poetDir := t.TempDir() + t.Cleanup(func() { r.NoError(eg.Wait()) }) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + c, err := NewHTTPPoetTestHarness(ctx, poetDir) + r.NoError(err) + r.NotNil(c) + + eg.Go(func() error { + err := c.Service.Start(ctx) + return errors.Join(err, c.Service.Close()) + }) + + client, err := activation.NewHTTPPoetClient(c.RestURL().String(), activation.DefaultPoetConfig(), activation.WithLogger(zaptest.NewLogger(t))) + require.NoError(t, err) + + resp, err := client.PowParams(context.Background()) + r.NoError(err) + + signer, err := signing.NewEdSigner(signing.WithPrefix([]byte("prefix"))) + require.NoError(t, err) + ch := types.RandomHash() + + nonce, err := shared.FindSubmitPowNonce( + context.Background(), + resp.Challenge, + ch.Bytes(), + signer.NodeID().Bytes(), + uint(resp.Difficulty), + ) + r.NoError(err) + + signature := signer.Sign(signing.POET, ch.Bytes()) + prefix := bytes.Join([][]byte{signer.Prefix(), {byte(signing.POET)}}, nil) + + poetRound, err := client.Submit(context.Background(), prefix, ch.Bytes(), signature, signer.NodeID(), activation.PoetPoW{ + Nonce: nonce, + Params: *resp, + }) + r.NoError(err) + r.NotNil(poetRound) +} diff --git a/activation/poet_test.go b/activation/poet_test.go index ec83604d360..00bdca983a5 100644 --- a/activation/poet_test.go +++ b/activation/poet_test.go @@ -1,75 +1,15 @@ package activation import ( - "bytes" "context" "errors" "net/http" "net/url" "testing" - "github.com/spacemeshos/poet/shared" "github.com/stretchr/testify/require" - "go.uber.org/zap/zaptest" - "golang.org/x/sync/errgroup" - - "github.com/spacemeshos/go-spacemesh/common/types" - "github.com/spacemeshos/go-spacemesh/signing" ) -func TestHTTPPoet(t *testing.T) { - if testing.Short() { - t.Skip() - } - t.Parallel() - r := require.New(t) - - var eg errgroup.Group - - poetDir := t.TempDir() - t.Cleanup(func() { r.NoError(eg.Wait()) }) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - c, err := NewHTTPPoetTestHarness(ctx, poetDir) - r.NoError(err) - r.NotNil(c) - - eg.Go(func() error { - err := c.Service.Start(ctx) - return errors.Join(err, c.Service.Close()) - }) - - client, err := NewHTTPPoetClient(c.RestURL().String(), DefaultPoetConfig(), WithLogger(zaptest.NewLogger(t))) - require.NoError(t, err) - - resp, err := client.PowParams(context.Background()) - r.NoError(err) - - signer, err := signing.NewEdSigner(signing.WithPrefix([]byte("prefix"))) - require.NoError(t, err) - ch := types.RandomHash() - - nonce, err := shared.FindSubmitPowNonce( - context.Background(), - resp.Challenge, - ch.Bytes(), - signer.NodeID().Bytes(), - uint(resp.Difficulty), - ) - r.NoError(err) - - signature := signer.Sign(signing.POET, ch.Bytes()) - prefix := bytes.Join([][]byte{signer.Prefix(), {byte(signing.POET)}}, nil) - - poetRound, err := client.Submit(context.Background(), prefix, ch.Bytes(), signature, signer.NodeID(), PoetPoW{ - Nonce: nonce, - Params: *resp, - }) - r.NoError(err) - r.NotNil(poetRound) -} - func TestCheckRetry(t *testing.T) { t.Parallel() t.Run("doesn't retry on context cancellation.", func(t *testing.T) { diff --git a/activation/poet_test_harness.go b/activation/poet_test_harness.go deleted file mode 100644 index 1351c37ab03..00000000000 --- a/activation/poet_test_harness.go +++ /dev/null @@ -1,71 +0,0 @@ -package activation - -import ( - "context" - "net/url" - "time" - - "github.com/spacemeshos/poet/server" -) - -// HTTPPoetTestHarness utilizes a local self-contained poet server instance -// targeted by an HTTP client. It is intended to be used in tests only. -type HTTPPoetTestHarness struct { - Service *server.Server -} - -func (h *HTTPPoetTestHarness) RestURL() *url.URL { - return &url.URL{ - Scheme: "http", - Host: h.Service.GrpcRestProxyAddr().String(), - } -} - -type HTTPPoetOpt func(*server.Config) - -func WithGenesis(genesis time.Time) HTTPPoetOpt { - return func(cfg *server.Config) { - cfg.Genesis = server.Genesis(genesis) - } -} - -func WithEpochDuration(epoch time.Duration) HTTPPoetOpt { - return func(cfg *server.Config) { - cfg.Round.EpochDuration = epoch - } -} - -func WithPhaseShift(phase time.Duration) HTTPPoetOpt { - return func(cfg *server.Config) { - cfg.Round.PhaseShift = phase - } -} - -func WithCycleGap(gap time.Duration) HTTPPoetOpt { - return func(cfg *server.Config) { - cfg.Round.CycleGap = gap - } -} - -// NewHTTPPoetTestHarness returns a new instance of HTTPPoetHarness. -func NewHTTPPoetTestHarness(ctx context.Context, poetdir string, opts ...HTTPPoetOpt) (*HTTPPoetTestHarness, error) { - cfg := server.DefaultConfig() - cfg.PoetDir = poetdir - cfg.RawRESTListener = "localhost:0" - cfg.RawRPCListener = "localhost:0" - - for _, opt := range opts { - opt(cfg) - } - - server.SetupConfig(cfg) - - poet, err := server.New(ctx, *cfg) - if err != nil { - return nil, err - } - - return &HTTPPoetTestHarness{ - Service: poet, - }, nil -} diff --git a/activation/post.go b/activation/post.go index ebf3dbb3956..22a03531023 100644 --- a/activation/post.go +++ b/activation/post.go @@ -2,7 +2,6 @@ package activation import ( "context" - "encoding/hex" "errors" "fmt" "runtime" @@ -48,35 +47,6 @@ func (c PostConfig) ToConfig() config.Config { } } -type PowDifficulty [32]byte - -func (d PowDifficulty) String() string { - return fmt.Sprintf("%X", d[:]) -} - -// Set implements pflag.Value.Set. -func (f *PowDifficulty) Set(value string) error { - return f.UnmarshalText([]byte(value)) -} - -// Type implements pflag.Value.Type. -func (PowDifficulty) Type() string { - return "PowDifficulty" -} - -func (d *PowDifficulty) UnmarshalText(text []byte) error { - decodedLen := hex.DecodedLen(len(text)) - if decodedLen != 32 { - return fmt.Errorf("expected 32 bytes, got %d", decodedLen) - } - var dst [32]byte - if _, err := hex.Decode(dst[:], text); err != nil { - return err - } - *d = PowDifficulty(dst) - return nil -} - // PostSetupOpts are the options used to initiate a Post setup data creation session, // either via the public smesher API, or on node launch (via cmd args). type PostSetupOpts struct { diff --git a/activation/post_supervisor.go b/activation/post_supervisor.go index ac0e8f0ba44..f20393b95f2 100644 --- a/activation/post_supervisor.go +++ b/activation/post_supervisor.go @@ -7,6 +7,7 @@ import ( "io" "os/exec" "path/filepath" + "strconv" "strings" "sync/atomic" @@ -46,12 +47,18 @@ func MainnetPostServiceConfig() PostSupervisorConfig { type PostSupervisorConfig struct { PostServiceCmd string `mapstructure:"post-opts-post-service"` - DataDir string `mapstructure:"post-opts-datadir"` - NodeAddress string `mapstructure:"post-opts-node-address"` - PowDifficulty PowDifficulty `mapstructure:"post-opts-pow-difficulty"` - PostServiceMode string `mapstructure:"post-opts-post-service-mode"` + DataDir string `mapstructure:"post-opts-datadir"` + NodeAddress string `mapstructure:"post-opts-node-address"` + PostServiceMode string `mapstructure:"post-opts-post-service-mode"` - N string `mapstructure:"post-opts-n"` + PowDifficulty PowDifficulty `mapstructure:"post-opts-pow-difficulty"` + K1 uint32 `mapstructure:"post-opts-k1"` + K2 uint32 `mapstructure:"post-opts-k2"` + K3 uint32 `mapstructure:"post-opts-k3"` + + N uint `mapstructure:"post-opts-n"` + R uint `mapstructure:"post-opts-r"` + P uint `mapstructure:"post-opts-p"` } // PostSupervisor manages a local post service. @@ -113,8 +120,23 @@ func (ps *PostSupervisor) runCmd(ctx context.Context, opts PostSupervisorConfig) "--pow-difficulty", opts.PowDifficulty.String(), "--randomx-mode", opts.PostServiceMode, } - if opts.N != "" { - args = append(args, "-n", opts.N) + if opts.K1 != 0 { + args = append(args, "--k1", strconv.FormatUint(uint64(opts.K1), 10)) + } + if opts.K2 != 0 { + args = append(args, "--k2", strconv.FormatUint(uint64(opts.K2), 10)) + } + if opts.K3 != 0 { + args = append(args, "--k3", strconv.FormatUint(uint64(opts.K3), 10)) + } + if opts.N != 0 { + args = append(args, "-n", strconv.FormatUint(uint64(opts.N), 10)) + } + if opts.R != 0 { + args = append(args, "-r", strconv.FormatUint(uint64(opts.R), 10)) + } + if opts.P != 0 { + args = append(args, "-p", strconv.FormatUint(uint64(opts.P), 10)) } cmd := exec.CommandContext( diff --git a/activation/post_test.go b/activation/post_test.go index ae43a02dece..605c82fc322 100644 --- a/activation/post_test.go +++ b/activation/post_test.go @@ -10,7 +10,6 @@ import ( "github.com/spacemeshos/post/config" "github.com/spacemeshos/post/initialization" "github.com/spacemeshos/post/shared" - "github.com/spacemeshos/post/verifying" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" "golang.org/x/sync/errgroup" @@ -39,14 +38,15 @@ func TestPostSetupManager(t *testing.T) { for { select { case <-ctx.Done(): - return ctx.Err() + return nil case <-timer.C: status := mgr.Status() req.GreaterOrEqual(status.NumLabelsWritten, lastStatus.NumLabelsWritten) - if status.NumLabelsWritten < uint64(mgr.opts.NumUnits)*mgr.cfg.LabelsPerUnit { - req.Equal(PostSetupStateInProgress, status.State) + if status.NumLabelsWritten == uint64(mgr.opts.NumUnits)*mgr.cfg.LabelsPerUnit { + return nil } + req.Equal(PostSetupStateInProgress, status.State) } } }) @@ -55,7 +55,7 @@ func TestPostSetupManager(t *testing.T) { req.NoError(mgr.PrepareInitializer(context.Background(), mgr.opts)) req.NoError(mgr.StartSession(context.Background())) cancel() - _ = eg.Wait() + require.NoError(t, eg.Wait()) req.Equal(PostSetupStateComplete, mgr.Status().State) @@ -220,53 +220,6 @@ func TestPostSetupManager_InitialStatus(t *testing.T) { req.Zero(status.NumLabelsWritten) } -func TestPostSetupManager_GenerateProof(t *testing.T) { - req := require.New(t) - ch := make([]byte, 32) - - mgr := newTestPostManager(t) - - // Attempt to generate proof. - _, _, err := mgr.GenerateProof(context.Background(), ch) - req.EqualError(err, errNotComplete.Error()) - - // Create data. - req.NoError(mgr.PrepareInitializer(context.Background(), mgr.opts)) - req.NoError(mgr.StartSession(context.Background())) - - // Generate proof. - p, m, err := mgr.GenerateProof(context.Background(), ch) - req.NoError(err) - - // Verify the proof - verifier, err := verifying.NewProofVerifier() - req.NoError(err) - defer verifier.Close() - err = verifier.Verify(&shared.Proof{ - Nonce: p.Nonce, - Indices: p.Indices, - Pow: p.Pow, - }, &shared.ProofMetadata{ - NodeId: mgr.id.Bytes(), - CommitmentAtxId: mgr.goldenATXID.Bytes(), - Challenge: ch, - NumUnits: mgr.opts.NumUnits, - LabelsPerUnit: m.LabelsPerUnit, - }, - config.DefaultConfig(), - logtest.New(t).WithName("verifying").Zap(), - verifying.WithLabelScryptParams(mgr.opts.Scrypt), - ) - req.NoError(err) - - // Re-instantiate `PostSetupManager`. - mgr = newTestPostManager(t) - - // Attempt to generate proof. - _, _, err = mgr.GenerateProof(context.Background(), ch) - req.ErrorIs(err, errNotComplete) -} - func TestPostSetupManager_VRFNonce(t *testing.T) { req := require.New(t) @@ -455,28 +408,10 @@ type testPostManager struct { cdb *datastore.CachedDB } -type newPostSetupMgrOptions struct { - cfg PostConfig -} - -type newPostSetupMgrOptionFunc func(*newPostSetupMgrOptions) - -func withPostConfig(cfg PostConfig) newPostSetupMgrOptionFunc { - return func(o *newPostSetupMgrOptions) { - o.cfg = cfg - } -} - -func newTestPostManager(tb testing.TB, o ...newPostSetupMgrOptionFunc) *testPostManager { +// TODO(mafa): start post service with supervisor. +func newTestPostManager(tb testing.TB) *testPostManager { tb.Helper() - options := newPostSetupMgrOptions{ - cfg: DefaultPostConfig(), - } - for _, opt := range o { - opt(&options) - } - sig, err := signing.NewEdSigner() require.NoError(tb, err) id := sig.NodeID() @@ -491,7 +426,7 @@ func newTestPostManager(tb testing.TB, o ...newPostSetupMgrOptionFunc) *testPost cdb := datastore.NewCachedDB(sql.InMemory(), logtest.New(tb)) provingOpts := DefaultPostProvingOpts() provingOpts.Flags = config.RecommendedPowFlags() - mgr, err := NewPostSetupManager(id, options.cfg, zaptest.NewLogger(tb), cdb, goldenATXID, provingOpts) + mgr, err := NewPostSetupManager(id, DefaultPostConfig(), zaptest.NewLogger(tb), cdb, goldenATXID, provingOpts) require.NoError(tb, err) return &testPostManager{ diff --git a/activation/post_types.go b/activation/post_types.go new file mode 100644 index 00000000000..b81dadd66db --- /dev/null +++ b/activation/post_types.go @@ -0,0 +1,35 @@ +package activation + +import ( + "encoding/hex" + "fmt" +) + +type PowDifficulty [32]byte + +func (d PowDifficulty) String() string { + return fmt.Sprintf("%X", d[:]) +} + +// Set implements pflag.Value.Set. +func (f *PowDifficulty) Set(value string) error { + return f.UnmarshalText([]byte(value)) +} + +// Type implements pflag.Value.Type. +func (PowDifficulty) Type() string { + return "PowDifficulty" +} + +func (d *PowDifficulty) UnmarshalText(text []byte) error { + decodedLen := hex.DecodedLen(len(text)) + if decodedLen != 32 { + return fmt.Errorf("expected 32 bytes, got %d", decodedLen) + } + var dst [32]byte + if _, err := hex.Decode(dst[:], text); err != nil { + return err + } + *d = PowDifficulty(dst) + return nil +} diff --git a/activation/post_verifier.go b/activation/post_verifier.go index 765830065a7..2fb9ed10a77 100644 --- a/activation/post_verifier.go +++ b/activation/post_verifier.go @@ -7,6 +7,7 @@ import ( "github.com/spacemeshos/post/config" "github.com/spacemeshos/post/shared" "github.com/spacemeshos/post/verifying" + "go.uber.org/zap" "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/common/types" @@ -37,17 +38,17 @@ type postVerifierWorker struct { type postVerifier struct { *verifying.ProofVerifier - logger log.Log + logger *zap.Logger cfg config.Config } func (v *postVerifier) Verify(ctx context.Context, p *shared.Proof, m *shared.ProofMetadata, opts ...verifying.OptionFunc) error { - v.logger.WithContext(ctx).With().Debug("verifying post", log.FieldNamed("proof_node_id", types.BytesToNodeID(m.NodeId))) - return v.ProofVerifier.Verify(p, m, v.cfg, v.logger.Zap(), opts...) + v.logger.Debug("verifying post", zap.Stringer("proof_node_id", types.BytesToNodeID(m.NodeId))) + return v.ProofVerifier.Verify(p, m, v.cfg, v.logger, opts...) } // NewPostVerifier creates a new post verifier. -func NewPostVerifier(cfg PostConfig, logger log.Log, opts ...verifying.OptionFunc) (PostVerifier, error) { +func NewPostVerifier(cfg PostConfig, logger *zap.Logger, opts ...verifying.OptionFunc) (PostVerifier, error) { verifier, err := verifying.NewProofVerifier(opts...) if err != nil { return nil, err diff --git a/activation/post_verifier_test.go b/activation/post_verifier_test.go index 6c12d3d8934..2abad47d1a0 100644 --- a/activation/post_verifier_test.go +++ b/activation/post_verifier_test.go @@ -9,11 +9,11 @@ import ( "github.com/spacemeshos/post/shared" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "go.uber.org/zap/zaptest" "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/activation" "github.com/spacemeshos/go-spacemesh/log" - "github.com/spacemeshos/go-spacemesh/log/logtest" ) func TestOffloadingPostVerifier(t *testing.T) { @@ -41,7 +41,7 @@ func TestOffloadingPostVerifier(t *testing.T) { } func TestPostVerifierDetectsInvalidProof(t *testing.T) { - verifier, err := activation.NewPostVerifier(activation.PostConfig{}, logtest.New(t)) + verifier, err := activation.NewPostVerifier(activation.PostConfig{}, zaptest.NewLogger(t)) require.NoError(t, err) defer verifier.Close() require.Error(t, verifier.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{})) diff --git a/activation/validation.go b/activation/validation.go index 4b8b82852d1..8274bcae15d 100644 --- a/activation/validation.go +++ b/activation/validation.go @@ -15,7 +15,6 @@ import ( "github.com/spacemeshos/go-spacemesh/activation/metrics" "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/common/util" - "github.com/spacemeshos/go-spacemesh/log" ) type ErrAtxNotFound struct { @@ -42,13 +41,12 @@ type Validator struct { poetDb poetDbAPI cfg PostConfig scrypt config.ScryptParams - log log.Log postVerifier PostVerifier } // NewValidator returns a new NIPost validator. -func NewValidator(poetDb poetDbAPI, cfg PostConfig, scrypt config.ScryptParams, log log.Log, postVerifier PostVerifier) *Validator { - return &Validator{poetDb, cfg, scrypt, log, postVerifier} +func NewValidator(poetDb poetDbAPI, cfg PostConfig, scrypt config.ScryptParams, postVerifier PostVerifier) *Validator { + return &Validator{poetDb, cfg, scrypt, postVerifier} } // NIPost validates a NIPost, given a node id and expected challenge. It returns an error if the NIPost is invalid. diff --git a/activation/validation_integration_test.go.bak b/activation/validation_integration_test.go.bak new file mode 100644 index 00000000000..030b24049aa --- /dev/null +++ b/activation/validation_integration_test.go.bak @@ -0,0 +1,64 @@ +package activation_test + +import ( + "context" + "fmt" + "testing" + + "github.com/spacemeshos/go-spacemesh/activation" + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/log/logtest" + "github.com/spacemeshos/go-spacemesh/sql" + "go.uber.org/zap/zaptest" + + "github.com/stretchr/testify/require" +) + +func TestValidator_Validate(t *testing.T) { + r := require.New(t) + + challenge := types.NIPostChallenge{ + PublishEpoch: postGenesisEpoch + 2, + } + challengeHash := challenge.Hash() + poetDb := activation.NewPoetDb(sql.InMemory(), logtest.New(t).WithName("poetDb")) + + log := zaptest.NewLogger(t) + postProvider := newTestPostManager(t) + verifier, err := activation.NewPostVerifier(postProvider.cfg, log.Named("verifier")) + r.NoError(err) + defer verifier.Close() + + v := activation.NewValidator(poetDb, postProvider.cfg, postProvider.opts.Scrypt, verifier) + + nipost := buildNIPost(t, postProvider, challenge, poetDb, v) + + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) + r.NoError(err) + + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, types.BytesToHash([]byte("lerner")), postProvider.opts.NumUnits) + r.Contains(err.Error(), "invalid membership proof") + + newNIPost := *nipost + newNIPost.Post = &types.Post{} + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, &newNIPost, challengeHash, postProvider.opts.NumUnits) + r.Contains(err.Error(), "invalid Post") + + newPostCfg := postProvider.cfg + newPostCfg.MinNumUnits = postProvider.opts.NumUnits + 1 + v = activation.NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, nil) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) + r.EqualError(err, fmt.Sprintf("invalid `numUnits`; expected: >=%d, given: %d", newPostCfg.MinNumUnits, postProvider.opts.NumUnits)) + + newPostCfg = postProvider.cfg + newPostCfg.MaxNumUnits = postProvider.opts.NumUnits - 1 + v = activation.NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, nil) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) + r.EqualError(err, fmt.Sprintf("invalid `numUnits`; expected: <=%d, given: %d", newPostCfg.MaxNumUnits, postProvider.opts.NumUnits)) + + newPostCfg = postProvider.cfg + newPostCfg.LabelsPerUnit = nipost.PostMetadata.LabelsPerUnit + 1 + v = activation.NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, nil) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) + r.EqualError(err, fmt.Sprintf("invalid `LabelsPerUnit`; expected: >=%d, given: %d", newPostCfg.LabelsPerUnit, nipost.PostMetadata.LabelsPerUnit)) +} diff --git a/activation/validation_test.go b/activation/validation_test.go index 226562f733e..abeb785acd3 100644 --- a/activation/validation_test.go +++ b/activation/validation_test.go @@ -13,8 +13,6 @@ import ( "go.uber.org/mock/gomock" "github.com/spacemeshos/go-spacemesh/common/types" - "github.com/spacemeshos/go-spacemesh/log/logtest" - "github.com/spacemeshos/go-spacemesh/sql" ) func Test_Validation_VRFNonce(t *testing.T) { @@ -48,7 +46,7 @@ func Test_Validation_VRFNonce(t *testing.T) { nonce := (*types.VRFPostIndex)(init.Nonce()) - v := NewValidator(poetDbAPI, postCfg, initOpts.Scrypt, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, initOpts.Scrypt, nil) // Act & Assert t.Run("valid vrf nonce", func(t *testing.T) { @@ -89,7 +87,7 @@ func Test_Validation_InitialNIPostChallenge(t *testing.T) { postCfg := DefaultPostConfig() goldenATXID := types.ATXID{2, 3, 4} - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, nil) // Act & Assert t.Run("valid initial nipost challenge passes", func(t *testing.T) { @@ -157,7 +155,7 @@ func Test_Validation_NIPostChallenge(t *testing.T) { poetDbAPI := NewMockpoetDbAPI(ctrl) postCfg := DefaultPostConfig() - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, nil) // Act & Assert t.Run("valid nipost challenge passes", func(t *testing.T) { @@ -283,7 +281,7 @@ func Test_Validation_Post(t *testing.T) { postCfg := DefaultPostConfig() postVerifier := NewMockPostVerifier(ctrl) - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), postVerifier) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, postVerifier) post := types.Post{} meta := types.PostMetadata{} @@ -305,7 +303,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { poetDbAPI := NewMockpoetDbAPI(ctrl) postCfg := DefaultPostConfig() - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, nil) // Act & Assert t.Run("valid nipost challenge passes", func(t *testing.T) { @@ -409,7 +407,7 @@ func Test_Validate_NumUnits(t *testing.T) { poetDbAPI := NewMockpoetDbAPI(ctrl) postCfg := DefaultPostConfig() - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, nil) // Act & Assert t.Run("valid number of num units passes", func(t *testing.T) { @@ -443,7 +441,7 @@ func Test_Validate_PostMetadata(t *testing.T) { poetDbAPI := NewMockpoetDbAPI(ctrl) postCfg := DefaultPostConfig() - v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, logtest.New(t).WithName("validator"), nil) + v := NewValidator(poetDbAPI, postCfg, config.ScryptParams{}, nil) // Act & Assert t.Run("valid post metadata", func(t *testing.T) { @@ -469,55 +467,6 @@ func Test_Validate_PostMetadata(t *testing.T) { }) } -func TestValidator_Validate(t *testing.T) { - r := require.New(t) - - challenge := types.NIPostChallenge{ - PublishEpoch: postGenesisEpoch + 2, - } - challengeHash := challenge.Hash() - poetDb := NewPoetDb(sql.InMemory(), logtest.New(t).WithName("poetDb")) - - logger := logtest.New(t).WithName("validator") - postProvider := newTestPostManager(t) - verifier, err := NewPostVerifier(postProvider.cfg, logger) - r.NoError(err) - defer verifier.Close() - - v := NewValidator(poetDb, postProvider.cfg, postProvider.opts.Scrypt, logger, verifier) - - nipost := buildNIPost(t, postProvider, challenge, poetDb, v) - - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) - r.NoError(err) - - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, types.BytesToHash([]byte("lerner")), postProvider.opts.NumUnits) - r.Contains(err.Error(), "invalid membership proof") - - newNIPost := *nipost - newNIPost.Post = &types.Post{} - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, &newNIPost, challengeHash, postProvider.opts.NumUnits) - r.Contains(err.Error(), "invalid Post") - - newPostCfg := postProvider.cfg - newPostCfg.MinNumUnits = postProvider.opts.NumUnits + 1 - v = NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) - r.EqualError(err, fmt.Sprintf("invalid `numUnits`; expected: >=%d, given: %d", newPostCfg.MinNumUnits, postProvider.opts.NumUnits)) - - newPostCfg = postProvider.cfg - newPostCfg.MaxNumUnits = postProvider.opts.NumUnits - 1 - v = NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) - r.EqualError(err, fmt.Sprintf("invalid `numUnits`; expected: <=%d, given: %d", newPostCfg.MaxNumUnits, postProvider.opts.NumUnits)) - - newPostCfg = postProvider.cfg - newPostCfg.LabelsPerUnit = nipost.PostMetadata.LabelsPerUnit + 1 - v = NewValidator(poetDb, newPostCfg, postProvider.opts.Scrypt, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits) - r.EqualError(err, fmt.Sprintf("invalid `LabelsPerUnit`; expected: >=%d, given: %d", newPostCfg.LabelsPerUnit, nipost.PostMetadata.LabelsPerUnit)) -} - func TestValidateMerkleProof(t *testing.T) { challenge := types.CalcHash32([]byte("challenge")) diff --git a/api/grpcserver/post_client.go b/api/grpcserver/post_client.go index a69b7686534..1c35da90654 100644 --- a/api/grpcserver/post_client.go +++ b/api/grpcserver/post_client.go @@ -41,15 +41,17 @@ func (pc *postClient) Proof(ctx context.Context, challenge []byte) (*types.Post, resp: resp, } - select { - case <-pc.closed: - return nil, nil, fmt.Errorf("post client closed") - case <-ctx.Done(): - return nil, nil, ctx.Err() - case pc.con <- cmd: - } - for { + // send command + select { + case <-pc.closed: + return nil, nil, fmt.Errorf("post client closed") + case <-ctx.Done(): + return nil, nil, ctx.Err() + case pc.con <- cmd: + } + + // receive response select { case <-pc.closed: return nil, nil, fmt.Errorf("post client closed") @@ -67,6 +69,7 @@ func (pc *postClient) Proof(ctx context.Context, challenge []byte) (*types.Post, case <-ctx.Done(): return nil, nil, ctx.Err() case <-time.After(2 * time.Second): // TODO(mafa): make polling interval configurable + continue } } diff --git a/api/grpcserver/post_service_test.go b/api/grpcserver/post_service_test.go index b648540dd04..6c0061ac70b 100644 --- a/api/grpcserver/post_service_test.go +++ b/api/grpcserver/post_service_test.go @@ -89,7 +89,7 @@ func launchPostSupervisor(tb testing.TB, log *zap.Logger, cfg Config, postDir st NodeAddress: fmt.Sprintf("http://%s", cfg.PublicListener), PowDifficulty: activation.DefaultPostConfig().PowDifficulty, PostServiceMode: "light", - N: "2", + N: 2, } ps, err := activation.NewPostSupervisor(log, opts) diff --git a/api/grpcserver/smesher_service_test.go b/api/grpcserver/smesher_service_test.go index 3de923770c6..87423be59d8 100644 --- a/api/grpcserver/smesher_service_test.go +++ b/api/grpcserver/smesher_service_test.go @@ -19,7 +19,7 @@ import ( func TestPostConfig(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) @@ -45,7 +45,7 @@ func TestPostConfig(t *testing.T) { func TestStartSmeshingPassesCorrectSmeshingOpts(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) @@ -79,7 +79,7 @@ func TestStartSmeshingPassesCorrectSmeshingOpts(t *testing.T) { func TestSmesherService_PostSetupProviders(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) @@ -120,7 +120,7 @@ func TestSmesherService_PostSetupProviders(t *testing.T) { func TestSmesherService_PostSetupStatus(t *testing.T) { t.Run("completed", func(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) @@ -138,7 +138,7 @@ func TestSmesherService_PostSetupStatus(t *testing.T) { t.Run("completed with last Opts", func(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) @@ -169,7 +169,7 @@ func TestSmesherService_PostSetupStatus(t *testing.T) { t.Run("in progress", func(t *testing.T) { ctrl := gomock.NewController(t) - postSetupProvider := activation.NewMockpostSetupProvider(ctrl) + postSetupProvider := grpcserver.NewMockpostSetupProvider(ctrl) smeshingProvider := activation.NewMockSmeshingProvider(ctrl) svc := grpcserver.NewSmesherService(postSetupProvider, smeshingProvider, time.Second, activation.DefaultPostSetupOpts()) diff --git a/common/types/activation.go b/common/types/activation.go index fb2ffc9d878..dc9d43b9aeb 100644 --- a/common/types/activation.go +++ b/common/types/activation.go @@ -16,6 +16,12 @@ import ( //go:generate scalegen +// BytesToATXID is a helper to copy buffer into a ATXID. +func BytesToATXID(buf []byte) (id ATXID) { + copy(id[:], buf) + return id +} + // ATXID is a 32-bit hash used to identify an activation transaction. type ATXID Hash32 diff --git a/common/types/nodeid.go b/common/types/nodeid.go index ff46b00f9c7..ef9bc6f401e 100644 --- a/common/types/nodeid.go +++ b/common/types/nodeid.go @@ -9,7 +9,7 @@ import ( "github.com/spacemeshos/go-spacemesh/log" ) -// BytesToNodeID is a helper to copy buffer into NodeID struct. +// BytesToNodeID is a helper to copy buffer into a NodeID. func BytesToNodeID(buf []byte) (id NodeID) { copy(id[:], buf) return id diff --git a/config/config.go b/config/config.go index f9829bdc1ef..f2b0a028c89 100644 --- a/config/config.go +++ b/config/config.go @@ -137,7 +137,7 @@ type SmeshingConfig struct { Start bool `mapstructure:"smeshing-start"` CoinbaseAccount string `mapstructure:"smeshing-coinbase"` Opts activation.PostSetupOpts `mapstructure:"smeshing-opts"` - ProvingOpts activation.PostProvingOpts `mapstructure:"smeshing-proving-opts"` + ProvingOpts activation.PostProvingOpts `mapstructure:"smeshing-proving-opts"` // TODO(mafa): remove? VerifyingOpts activation.PostProofVerifyingOpts `mapstructure:"smeshing-verifying-opts"` } diff --git a/config/mainnet.go b/config/mainnet.go index 34b814727da..09e13acf113 100644 --- a/config/mainnet.go +++ b/config/mainnet.go @@ -144,12 +144,13 @@ func MainnetConfig() Config { DataDir: os.TempDir(), Interval: 30 * time.Second, }, - P2P: p2pconfig, - API: grpcserver.DefaultConfig(), - TIME: timeConfig.DefaultConfig(), - SMESHING: smeshing, - FETCH: fetch.DefaultConfig(), - LOGGING: logging, + P2P: p2pconfig, + API: grpcserver.DefaultConfig(), + TIME: timeConfig.DefaultConfig(), + SMESHING: smeshing, + POSTService: activation.MainnetPostServiceConfig(), + FETCH: fetch.DefaultConfig(), + LOGGING: logging, Sync: syncer.Config{ Interval: time.Minute, EpochEndFraction: 0.8, diff --git a/config/presets/fastnet.go b/config/presets/fastnet.go index 6e5e4f37a1a..d6471f347b2 100644 --- a/config/presets/fastnet.go +++ b/config/presets/fastnet.go @@ -97,5 +97,10 @@ func fastnet() config.Config { conf.POET.RequestRetryDelay = 1 * time.Second conf.POET.MaxRequestRetries = 3 + conf.POSTService.N = conf.SMESHING.Opts.Scrypt.N + + conf.POSTService.K1 = conf.POST.K1 + conf.POSTService.K2 = conf.POST.K2 + conf.POSTService.K3 = conf.POST.K3 return conf } diff --git a/config/presets/standalone.go b/config/presets/standalone.go index 50e0810072c..5cd209c01ef 100644 --- a/config/presets/standalone.go +++ b/config/presets/standalone.go @@ -1,6 +1,7 @@ package presets import ( + "fmt" "math/big" "os" "path/filepath" @@ -88,6 +89,11 @@ func standalone() config.Config { conf.API.PublicListener = "0.0.0.0:10092" conf.API.PrivateListener = "0.0.0.0:10093" - conf.POSTService.NodeAddress = "http://0.0.0.0:10093" + conf.POSTService.NodeAddress = fmt.Sprintf("http://%s", conf.API.PrivateListener) + conf.POSTService.DataDir = conf.SMESHING.Opts.DataDir + + conf.POSTService.K1 = conf.POST.K1 + conf.POSTService.K2 = conf.POST.K2 + conf.POSTService.K3 = conf.POST.K3 return conf } diff --git a/node/node.go b/node/node.go index f36b404a3a2..6db1842fa32 100644 --- a/node/node.go +++ b/node/node.go @@ -336,6 +336,7 @@ type App struct { certifier *blocks.Certifier postSetupMgr *activation.PostSetupManager atxBuilder *activation.Builder + nipostBuilder *activation.NIPostBuilder atxHandler *activation.Handler txHandler *txs.TxHandler validator *activation.Validator @@ -350,7 +351,7 @@ type App struct { updater *bootstrap.Updater poetDb *activation.PoetDb postVerifier *activation.OffloadingPostVerifier - postService *activation.PostSupervisor + postSupervisor *activation.PostSupervisor preserve *checkpoint.PreservedData errCh chan error @@ -553,7 +554,7 @@ func (app *App) initServices(ctx context.Context) error { nipostValidatorLogger := app.addLogger(NipostValidatorLogger, lg) postVerifiers := make([]activation.PostVerifier, 0, app.Config.SMESHING.VerifyingOpts.Workers) lg.Debug("creating post verifier") - verifier, err := activation.NewPostVerifier(app.Config.POST, nipostValidatorLogger, verifying.WithPowFlags(app.Config.SMESHING.VerifyingOpts.Flags)) + verifier, err := activation.NewPostVerifier(app.Config.POST, nipostValidatorLogger.Zap(), verifying.WithPowFlags(app.Config.SMESHING.VerifyingOpts.Flags)) lg.With().Debug("created post verifier", log.Err(err)) if err != nil { return err @@ -564,13 +565,13 @@ func (app *App) initServices(ctx context.Context) error { app.postVerifier = activation.NewOffloadingPostVerifier(postVerifiers, nipostValidatorLogger) if app.Config.POSTService.PostServiceCmd != "" { - app.postService, err = activation.NewPostSupervisor(app.log.Zap(), app.Config.POSTService) + app.postSupervisor, err = activation.NewPostSupervisor(app.log.Zap(), app.Config.POSTService) if err != nil { return fmt.Errorf("start post service: %w", err) } } - validator := activation.NewValidator(poetDb, app.Config.POST, app.Config.SMESHING.Opts.Scrypt, nipostValidatorLogger, app.postVerifier) + validator := activation.NewValidator(poetDb, app.Config.POST, app.Config.SMESHING.Opts.Scrypt, app.postVerifier) app.validator = validator cfg := vm.DefaultConfig() @@ -942,6 +943,7 @@ func (app *App) initServices(ctx context.Context) error { app.syncer = newSyncer app.svm = state app.atxBuilder = atxBuilder + app.nipostBuilder = nipostBuilder app.postSetupMgr = postSetupMgr app.atxHandler = atxHandler app.poetDb = poetDb @@ -1093,7 +1095,7 @@ func (app *App) initService(ctx context.Context, svc grpcserver.Service) (grpcse case grpcserver.Smesher: return grpcserver.NewSmesherService(app.postSetupMgr, app.atxBuilder, app.Config.API.SmesherStreamInterval, app.Config.SMESHING.Opts), nil case grpcserver.Post: - return grpcserver.NewPostService(app.log.Zap()), nil + return grpcserver.NewPostService(app.log.Zap(), app.nipostBuilder, app.atxBuilder), nil case grpcserver.Transaction: return grpcserver.NewTransactionService(app.db, app.host, app.mesh, app.conState, app.syncer, app.txHandler), nil case grpcserver.Activation: @@ -1245,8 +1247,8 @@ func (app *App) stopServices(ctx context.Context) { app.syncer.Close() } - if app.postService != nil { - if err := app.postService.Close(); err != nil { + if app.postSupervisor != nil { + if err := app.postSupervisor.Close(); err != nil { app.log.With().Error("error stopping local post service", log.Err(err)) } } diff --git a/node/node_test.go b/node/node_test.go index 6a80f401095..4499959c952 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -420,6 +420,15 @@ func TestSpacemeshApp_NodeService(t *testing.T) { app.Config = getTestDefaultConfig(t) app.Config.SMESHING.CoinbaseAccount = types.GenerateAddress([]byte{1}).String() app.Config.SMESHING.Opts.DataDir = t.TempDir() + app.Config.SMESHING.Opts.Scrypt.N = 2 + + path, err := exec.Command("go", "env", "GOMOD").Output() + if err != nil { + panic(err) + } + app.Config.POSTService.PostServiceCmd = filepath.Join(filepath.Dir(string(path)), "build", "service") + app.Config.POSTService.DataDir = app.Config.SMESHING.Opts.DataDir + app.Config.POSTService.N = app.Config.SMESHING.Opts.Scrypt.N edSgn, err := signing.NewEdSigner() require.NoError(t, err) @@ -1089,18 +1098,22 @@ func TestAdminEvents(t *testing.T) { require.NoError(t, err) cfg.DataDirParent = t.TempDir() cfg.FileLock = filepath.Join(cfg.DataDirParent, "LOCK") - cfg.SMESHING.Opts.DataDir = t.TempDir() + cfg.SMESHING.Opts.DataDir = cfg.DataDirParent + cfg.SMESHING.Opts.Scrypt.N = 2 path, err := exec.Command("go", "env", "GOMOD").Output() if err != nil { panic(err) } cfg.POSTService.PostServiceCmd = filepath.Join(filepath.Dir(string(path)), "build", "service") + cfg.POSTService.DataDir = cfg.SMESHING.Opts.DataDir + cfg.POSTService.N = cfg.SMESHING.Opts.Scrypt.N cfg.Genesis.GenesisTime = time.Now().Add(5 * time.Second).Format(time.RFC3339) types.SetLayersPerEpoch(cfg.LayersPerEpoch) - app := New(WithConfig(&cfg), WithLog(logtest.New(t))) + logger := logtest.New(t, zapcore.DebugLevel) + app := New(WithConfig(&cfg), WithLog(logger)) signer, err := app.LoadOrCreateEdSigner() require.NoError(t, err) app.edSgn = signer // https://github.com/spacemeshos/go-spacemesh/issues/4653 @@ -1118,7 +1131,7 @@ func TestAdminEvents(t *testing.T) { }) t.Cleanup(func() { eg.Wait() }) - grpcCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + grpcCtx, cancel := context.WithTimeout(ctx, 20*time.Second) defer cancel() conn, err := grpc.DialContext( grpcCtx,