From 210f2ecd5f6626e72b630925b07690e8058d7c06 Mon Sep 17 00:00:00 2001 From: kimmy lin <30611210+countvonzero@users.noreply.github.com> Date: Fri, 11 Aug 2023 00:16:02 +0200 Subject: [PATCH] verify atx syntactic correctness before fetching deps --- activation/activation.go | 2 +- activation/handler.go | 184 ++++++++++---------- activation/handler_test.go | 313 +++++++++++++++++++++------------- activation/interface.go | 6 +- activation/mocks.go | 24 +-- activation/nipost.go | 1 - activation/nipost_test.go | 24 ++- activation/validation.go | 35 +--- activation/validation_test.go | 119 ++----------- checkpoint/recovery_test.go | 8 +- node/node.go | 1 - 11 files changed, 333 insertions(+), 384 deletions(-) diff --git a/activation/activation.go b/activation/activation.go index 908d981453e..cfa1efb3f53 100644 --- a/activation/activation.go +++ b/activation/activation.go @@ -342,7 +342,7 @@ func (b *Builder) verifyInitialPost(ctx context.Context, post *types.Post, metad if err != nil { b.log.With().Panic("failed to fetch commitment ATX ID.", log.Err(err)) } - err = b.validator.Post(ctx, types.EpochID(0), b.nodeID, commitmentAtxId, post, metadata, b.postSetupProvider.LastOpts().NumUnits) + err = b.validator.Post(ctx, b.nodeID, commitmentAtxId, post, metadata, b.postSetupProvider.LastOpts().NumUnits) switch { case errors.Is(err, context.Canceled): // If the context was canceled, we don't want to emit or log errors just propagate the cancellation signal. diff --git a/activation/handler.go b/activation/handler.go index 5c334b23a35..ae4487d80b1 100644 --- a/activation/handler.go +++ b/activation/handler.go @@ -43,7 +43,6 @@ type Handler struct { edVerifier *signing.EdVerifier clock layerClock publisher pubsub.Publisher - layersPerEpoch uint32 tickSize uint64 goldenATXID types.ATXID nipostValidator nipostValidator @@ -63,7 +62,6 @@ func NewHandler( c layerClock, pub pubsub.Publisher, fetcher system.Fetcher, - layersPerEpoch uint32, tickSize uint64, goldenATXID types.ATXID, nipostValidator nipostValidator, @@ -77,7 +75,6 @@ func NewHandler( edVerifier: edVerifier, clock: c, publisher: pub, - layersPerEpoch: layersPerEpoch, tickSize: tickSize, goldenATXID: goldenATXID, nipostValidator: nipostValidator, @@ -165,47 +162,84 @@ func (h *Handler) ProcessAtx(ctx context.Context, atx *types.VerifiedActivationT return nil } -// SyntacticallyValidateAtx ensures the following conditions apply, otherwise it returns an error. -// -// - The PublishEpoch is less than or equal to the current epoch + 1. -// - If the sequence number is non-zero: PrevATX points to a syntactically valid ATX whose sequence number is one less -// than the current ATXs sequence number. -// - If the sequence number is zero: PrevATX is empty. -// - Positioning ATX points to a syntactically valid ATX. -// - NIPost challenge is a hash of the serialization of the following fields: -// NodeID, SequenceNumber, PrevATXID, LayerID, StartTick, PositioningATX. -// - The NIPost is valid. -// - ATX LayerID is NIPostLayerTime or less after the PositioningATX LayerID. -// - The ATX view of the previous epoch contains ActiveSetSize activations. -func (h *Handler) SyntacticallyValidateAtx(ctx context.Context, atx *types.ActivationTx) (*types.VerifiedActivationTx, error) { +func (h *Handler) SyntacticallyValidate(ctx context.Context, atx *types.ActivationTx) error { + if atx.NIPost == nil { + return fmt.Errorf("nil nipst for atx %s", atx.ShortString()) + } + current := h.clock.CurrentLayer().GetEpoch() + if atx.PublishEpoch > current+1 { + return fmt.Errorf("atx publish epoch is too far in the future: %d > %d", atx.PublishEpoch, current+1) + } + if atx.PositioningATX == types.EmptyATXID { + return fmt.Errorf("empty positioning atx") + } + + switch { + case atx.PrevATXID == types.EmptyATXID: + if atx.InitialPost == nil { + return fmt.Errorf("no prev atx declared, but initial post is not included") + } + if atx.InnerActivationTx.NodeID == nil { + return fmt.Errorf("no prev atx declared, but node id is missing") + } + if atx.VRFNonce == nil { + return fmt.Errorf("no prev atx declared, but vrf nonce is missing") + } + if atx.CommitmentATX == nil { + return fmt.Errorf("no prev atx declared, but commitment atx is missing") + } + if *atx.CommitmentATX == types.EmptyATXID { + return fmt.Errorf("empty commitment atx") + } + if atx.Sequence != 0 { + return fmt.Errorf("no prev atx declared, but sequence number not zero") + } + + // Use the NIPost's Post metadata, while overriding the challenge to a zero challenge, + // as expected from the initial Post. + initialPostMetadata := *atx.NIPost.PostMetadata + initialPostMetadata.Challenge = shared.ZeroChallenge + if err := h.nipostValidator.Post(ctx, atx.SmesherID, *atx.CommitmentATX, atx.InitialPost, &initialPostMetadata, atx.NumUnits); err != nil { + return fmt.Errorf("invalid initial post: %w", err) + } + if err := h.nipostValidator.VRFNonce(atx.SmesherID, *atx.CommitmentATX, atx.VRFNonce, &initialPostMetadata, atx.NumUnits); err != nil { + return fmt.Errorf("invalid vrf nonce: %w", err) + } + default: + if atx.InnerActivationTx.NodeID != nil { + return fmt.Errorf("prev atx declared, but node id is included") + } + if atx.InitialPost != nil { + return fmt.Errorf("prev atx declared, but initial post is included") + } + if atx.CommitmentATX != nil { + return fmt.Errorf("rpev atx declared, but commitment atx is included") + } + } + return nil +} + +func (h *Handler) SyntacticallyValidateDeps(ctx context.Context, atx *types.ActivationTx) (*types.VerifiedActivationTx, error) { var ( commitmentATX *types.ATXID err error ) - - current := h.clock.CurrentLayer() - if atx.PublishEpoch > current.GetEpoch()+1 { - return nil, fmt.Errorf("atx publish epoch is too far in the future: %d > %d", atx.PublishEpoch, current.GetEpoch()+1) - } - if atx.PrevATXID == types.EmptyATXID { if err := h.validateInitialAtx(ctx, atx); err != nil { return nil, err } - commitmentATX = atx.CommitmentATX // validateInitialAtx checks that commitmentATX is not nil and references an existing valid ATX + commitmentATX = atx.CommitmentATX } else { commitmentATX, err = h.getCommitmentAtx(atx) if err != nil { return nil, fmt.Errorf("commitment atx for %s not found: %w", atx.SmesherID, err) } - - err = h.validateNonInitialAtx(ctx, atx, *commitmentATX) - if err != nil { + if err := h.validateNonInitialAtx(ctx, atx, *commitmentATX); err != nil { return nil, err } } - if err := h.nipostValidator.PositioningAtx(&atx.PositioningATX, h.cdb, h.goldenATXID, atx.PublishEpoch, h.layersPerEpoch); err != nil { + if err := h.nipostValidator.PositioningAtx(&atx.PositioningATX, h.cdb, h.goldenATXID, atx.PublishEpoch); err != nil { return nil, err } @@ -218,7 +252,7 @@ func (h *Handler) SyntacticallyValidateAtx(ctx context.Context, atx *types.Activ expectedChallengeHash := atx.NIPostChallenge.Hash() h.log.WithContext(ctx).With().Info("validating nipost", log.String("expected_challenge_hash", expectedChallengeHash.String()), atx.ID()) - leaves, err := h.nipostValidator.NIPost(ctx, atx.PublishEpoch, atx.SmesherID, *commitmentATX, atx.NIPost, expectedChallengeHash, atx.NumUnits) + leaves, err := h.nipostValidator.NIPost(ctx, atx.SmesherID, *commitmentATX, atx.NIPost, expectedChallengeHash, atx.NumUnits) if err != nil { return nil, fmt.Errorf("invalid nipost: %w", err) } @@ -227,44 +261,14 @@ func (h *Handler) SyntacticallyValidateAtx(ctx context.Context, atx *types.Activ } func (h *Handler) validateInitialAtx(ctx context.Context, atx *types.ActivationTx) error { - if atx.InitialPost == nil { - return fmt.Errorf("no prevATX declared, but initial Post is not included") - } - - if atx.InnerActivationTx.NodeID == nil { - return fmt.Errorf("no prevATX declared, but NodeID is missing") - } - if err := h.nipostValidator.InitialNIPostChallenge(&atx.NIPostChallenge, h.cdb, h.goldenATXID); err != nil { return err } - - // Use the NIPost's Post metadata, while overriding the challenge to a zero challenge, - // as expected from the initial Post. - initialPostMetadata := *atx.NIPost.PostMetadata - initialPostMetadata.Challenge = shared.ZeroChallenge - - if err := h.nipostValidator.Post(ctx, atx.PublishEpoch, atx.SmesherID, *atx.CommitmentATX, atx.InitialPost, &initialPostMetadata, atx.NumUnits); err != nil { - return fmt.Errorf("invalid initial Post: %w", err) - } - - if atx.VRFNonce == nil { - return fmt.Errorf("no prevATX declared, but VRFNonce is missing") - } - - if err := h.nipostValidator.VRFNonce(atx.SmesherID, *atx.CommitmentATX, atx.VRFNonce, &initialPostMetadata, atx.NumUnits); err != nil { - return fmt.Errorf("invalid VRFNonce: %w", err) - } - atx.SetEffectiveNumUnits(atx.NumUnits) return nil } func (h *Handler) validateNonInitialAtx(ctx context.Context, atx *types.ActivationTx, commitmentATX types.ATXID) error { - if atx.InnerActivationTx.NodeID != nil { - return fmt.Errorf("prevATX declared, but NodeID is included") - } - if err := h.nipostValidator.NIPostChallenge(&atx.NIPostChallenge, h.cdb, atx.SmesherID); err != nil { return err } @@ -276,7 +280,7 @@ func (h *Handler) validateNonInitialAtx(ctx context.Context, atx *types.Activati nonce := atx.VRFNonce if atx.NumUnits > prevAtx.NumUnits && nonce == nil { - h.log.WithContext(ctx).With().Info("PoST size increased without new VRF Nonce, re-validating current nonce", + h.log.WithContext(ctx).With().Info("post size increased without new vrf Nonce, re-validating current nonce", atx.ID(), log.Stringer("smesher", atx.SmesherID), ) @@ -291,14 +295,10 @@ func (h *Handler) validateNonInitialAtx(ctx context.Context, atx *types.Activati if nonce != nil { err = h.nipostValidator.VRFNonce(atx.SmesherID, commitmentATX, nonce, atx.NIPost.PostMetadata, atx.NumUnits) if err != nil { - return fmt.Errorf("invalid VRFNonce: %w", err) + return fmt.Errorf("invalid vrf nonce: %w", err) } } - if atx.InitialPost != nil { - return fmt.Errorf("prevATX declared, but initial Post is included") - } - if prevAtx.NumUnits < atx.NumUnits { atx.SetEffectiveNumUnits(prevAtx.NumUnits) } else { @@ -330,7 +330,7 @@ func (h *Handler) ContextuallyValidateAtx(atx *types.VerifiedActivationTx) error if err == nil && atx.PrevATXID == types.EmptyATXID { // no previous atx declared, but already seen at least one atx from node - return fmt.Errorf("no prevATX reported, but other atx with same nodeID (%v) found: %v", atx.SmesherID, lastAtx.ShortString()) + return fmt.Errorf("no prev atx reported, but other atx with same node id (%v) found: %v", atx.SmesherID, lastAtx.ShortString()) } if err == nil && atx.PrevATXID != lastAtx { @@ -391,7 +391,7 @@ func (h *Handler) storeAtx(ctx context.Context, atx *types.VerifiedActivationTx) } encoded, err := codec.Encode(proof) if err != nil { - h.log.With().Panic("failed to encode MalfeasanceProof", log.Err(err)) + h.log.With().Panic("failed to encode malfeasance proof", log.Err(err)) } if err := identities.SetMalicious(dbtx, atx.SmesherID, encoded, time.Now()); err != nil { return fmt.Errorf("add malfeasance proof: %w", err) @@ -438,7 +438,7 @@ func (h *Handler) storeAtx(ctx context.Context, atx *types.VerifiedActivationTx) } encodedProof, err := codec.Encode(&gossip) if err != nil { - h.log.With().Fatal("failed to encode MalfeasanceGossip", log.Err(err)) + h.log.With().Fatal("failed to encode malfeasance gossip", log.Err(err)) } if err = h.publisher.Publish(ctx, pubsub.MalfeasanceProof, encodedProof); err != nil { h.log.With().Error("failed to broadcast malfeasance proof", log.Err(err)) @@ -517,63 +517,54 @@ func (h *Handler) handleAtx(ctx context.Context, expHash types.Hash32, peer p2p. return fmt.Errorf("failed to verify atx signature: %w", errMalformedData) } - logger := h.log.WithContext(ctx).WithFields(atx.ID()) existing, _ := h.cdb.GetAtxHeader(atx.ID()) if existing != nil { - logger.With().Debug("received known atx") return fmt.Errorf("%w atx %s", errKnownAtx, atx.ID()) } - if atx.NIPost == nil { - return fmt.Errorf("nil nipst in gossip for atx %s", atx.ShortString()) + if err := h.SyntacticallyValidate(ctx, &atx); err != nil { + return err } h.registerHashes(&atx, peer) - if err := h.fetcher.GetPoetProof(ctx, atx.GetPoetProofRef()); err != nil { - return fmt.Errorf("received atx (%v) with syntactically invalid or missing poet proof (%x): %w", - atx.ShortString(), atx.GetPoetProofRef().ShortString(), err, - ) - } - - if err := h.FetchAtxReferences(ctx, &atx); err != nil { - return fmt.Errorf("received atx (%v) with missing references of prev or pos id %v, %v: %w", - atx.ID().ShortString(), atx.PrevATXID.ShortString(), atx.PositioningATX.ShortString(), err, - ) + if err := h.FetchReferences(ctx, &atx); err != nil { + return err } - vAtx, err := h.SyntacticallyValidateAtx(ctx, &atx) + vAtx, err := h.SyntacticallyValidateDeps(ctx, &atx) if err != nil { - return fmt.Errorf("received syntactically invalid atx %v: %w", atx.ShortString(), err) + return fmt.Errorf("atx %v syntatically invalid based on deps: %w", atx.ShortString(), err) } if expHash != (types.Hash32{}) && vAtx.ID().Hash32() != expHash { return fmt.Errorf("%w: atx want %s, got %s", errWrongHash, expHash.ShortString(), vAtx.ID().Hash32().ShortString()) } - err = h.ProcessAtx(ctx, vAtx) - if err != nil { + if err := h.ProcessAtx(ctx, vAtx); err != nil { return fmt.Errorf("cannot process atx %v: %w", atx.ShortString(), err) } events.ReportNewActivation(vAtx) - logger.With().Info("new atx", log.Inline(vAtx), log.Int("size", len(msg))) + h.log.WithContext(ctx).With().Info("new atx", log.Inline(vAtx), log.Int("size", len(msg))) return nil } -// FetchAtxReferences fetches referenced ATXs from peers if they are not found in db. -func (h *Handler) FetchAtxReferences(ctx context.Context, atx *types.ActivationTx) error { - logger := h.log.WithContext(ctx) +// FetchReferences fetches referenced ATXs from peers if they are not found in db. +func (h *Handler) FetchReferences(ctx context.Context, atx *types.ActivationTx) error { + if err := h.fetcher.GetPoetProof(ctx, atx.GetPoetProofRef()); err != nil { + return fmt.Errorf("atx (%s) missing poet proof (%s): %w", + atx.ShortString(), atx.GetPoetProofRef().ShortString(), err, + ) + } + atxIDs := make(map[types.ATXID]struct{}, 3) if atx.PositioningATX != types.EmptyATXID && atx.PositioningATX != h.goldenATXID { - logger.With().Debug("fetching pos atx", atx.PositioningATX, atx.ID()) atxIDs[atx.PositioningATX] = struct{}{} } if atx.PrevATXID != types.EmptyATXID { - logger.With().Debug("fetching prev atx", atx.PrevATXID, atx.ID()) atxIDs[atx.PrevATXID] = struct{}{} } if atx.CommitmentATX != nil && *atx.CommitmentATX != h.goldenATXID { - logger.With().Debug("fetching commitment atx", *atx.CommitmentATX, atx.ID()) atxIDs[*atx.CommitmentATX] = struct{}{} } @@ -582,8 +573,13 @@ func (h *Handler) FetchAtxReferences(ctx context.Context, atx *types.ActivationT } if err := h.fetcher.GetAtxs(ctx, maps.Keys(atxIDs)); err != nil { - return fmt.Errorf("fetch referenced atxs: %w", err) + dbg := fmt.Sprintf("prev %v pos %v commit %v", atx.PrevATXID, atx.PositioningATX, atx.CommitmentATX) + return fmt.Errorf("fetch referenced atxs (%s): %w", dbg, err) } - logger.With().Debug("done fetching references for atx", atx.ID()) + + h.log.WithContext(ctx).With().Debug("done fetching references for atx", + atx.ID(), + log.Int("num fetched", len(atxIDs)), + ) return nil } diff --git a/activation/handler_test.go b/activation/handler_test.go index be9d261c13a..6ee52e207ac 100644 --- a/activation/handler_test.go +++ b/activation/handler_test.go @@ -101,7 +101,7 @@ func newTestHandler(tb testing.TB, goldenATXID types.ATXID) *testHandler { mbeacon := NewMockAtxReceiver(ctrl) mtortoise := mocks.NewMockTortoise(ctrl) - atxHdlr := NewHandler(cdb, verifier, mclock, mpub, mockFetch, types.GetLayersPerEpoch(), 1, goldenATXID, mValidator, mbeacon, mtortoise, lg, PoetConfig{}) + atxHdlr := NewHandler(cdb, verifier, mclock, mpub, mockFetch, 1, goldenATXID, mValidator, mbeacon, mtortoise, lg, PoetConfig{}) return &testHandler{ Handler: atxHdlr, @@ -217,11 +217,11 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + _, err = atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.NoError(t, err) }) @@ -239,12 +239,13 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + _, err = atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.NoError(t, err) }) @@ -260,11 +261,11 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - vAtx, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + vAtx, err := atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.NoError(t, err) require.Equal(t, uint32(90), vAtx.NumUnits) require.Equal(t, uint32(90), vAtx.EffectiveNumUnits()) @@ -282,12 +283,12 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - vAtx, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + vAtx, err := atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.NoError(t, err) require.Equal(t, uint32(110), vAtx.NumUnits) require.Equal(t, uint32(100), vAtx.EffectiveNumUnits()) @@ -305,11 +306,11 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("invalid VRF")) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.ErrorContains(t, err, "invalid VRFNonce") + _, err = atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) + require.ErrorContains(t, err, "invalid vrf nonce") }) t.Run("valid initial atx", func(t *testing.T) { @@ -333,13 +334,13 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) + atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + _, err = atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.NoError(t, err) }) @@ -355,7 +356,7 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + err := atxHdlr.SyntacticallyValidate(context.Background(), atx) require.ErrorContains(t, err, "atx publish epoch is too far in the future") }) @@ -370,9 +371,9 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("nipost error")) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + _, err = atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.EqualError(t, err, "nipost error") }) @@ -387,10 +388,10 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("bad positioning atx")) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("bad positioning atx")) + _, err := atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.EqualError(t, err, "bad positioning atx") }) @@ -408,11 +409,16 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { } atx.InnerActivationTx.NodeID = new(types.NodeID) *atx.InnerActivationTx.NodeID = sig.NodeID() + vrfNonce := types.VRFPostIndex(11) + atx.VRFNonce = &vrfNonce + atx.SmesherID = sig.NodeID() atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) + atxHdlr.mValidator.EXPECT().Post(gomock.Any(), sig.NodeID(), cATX, atx.InitialPost, gomock.Any(), atx.NumUnits) + atxHdlr.mValidator.EXPECT().VRFNonce(sig.NodeID(), cATX, &vrfNonce, gomock.Any(), atx.NumUnits) + require.NoError(t, atxHdlr.SyntacticallyValidate(context.Background(), atx)) atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("bad initial nipost")) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + _, err := atxHdlr.SyntacticallyValidateDeps(context.Background(), atx) require.EqualError(t, err, "bad initial nipost") }) @@ -431,33 +437,27 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.ErrorContains(t, err, "NodeID is missing") + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) + require.ErrorContains(t, err, "node id is missing") }) t.Run("missing VRF nonce in initial atx", func(t *testing.T) { t.Parallel() - atxHdlr := newTestHandler(t, goldenATXID) - ctxID := posAtx.ID() - challenge := newChallenge(0, types.EmptyATXID, posAtx.ID(), currentLayer.GetEpoch(), &ctxID) - atx := newAtx(t, sig, challenge, &types.NIPost{}, 100, types.GenerateAddress([]byte("aaaa"))) + cATX := posAtx.ID() + challenge := newChallenge(0, types.EmptyATXID, posAtx.ID(), currentLayer.GetEpoch(), &cATX) + atx := newAtx(t, sig, challenge, npst, 100, types.GenerateAddress([]byte("aaaa"))) atx.InitialPost = &types.Post{ Nonce: 0, Indices: make([]byte, 10), } - atx.InnerActivationTx.NodeID = new(types.NodeID) - *atx.InnerActivationTx.NodeID = sig.NodeID() - atx.NIPost = newNIPostWithChallenge(t, atx.NIPostChallenge.Hash(), poetRef) - require.NoError(t, SignAndFinalizeAtx(sig, atx)) + nodeID := sig.NodeID() + atx.InnerActivationTx.NodeID = &nodeID atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.ErrorContains(t, err, "VRFNonce is missing") + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) + require.ErrorContains(t, err, "vrf nonce is missing") }) t.Run("invalid VRF nonce in initial atx", func(t *testing.T) { @@ -480,11 +480,10 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("invalid VRF nonce")) atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("invalid VRF nonce")) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) require.ErrorContains(t, err, "invalid VRF nonce") }) @@ -499,8 +498,8 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.EqualError(t, err, "no prevATX declared, but initial Post is not included") + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) + require.EqualError(t, err, "no prev atx declared, but initial post is not included") }) t.Run("prevAtx not declared but validation of initial post fails", func(t *testing.T) { @@ -521,10 +520,9 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { *atx.InnerActivationTx.NodeID = sig.NodeID() atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("failed post validation")) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) + err := atxHdlr.SyntacticallyValidate(context.Background(), atx) require.ErrorContains(t, err, "failed post validation") }) @@ -543,10 +541,9 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { require.NoError(t, SignAndFinalizeAtx(sig, atx)) atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.EqualError(t, err, "prevATX declared, but initial Post is included") + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) + require.EqualError(t, err, "prev atx declared, but initial post is included") }) t.Run("prevAtx declared but NodeID is included", func(t *testing.T) { @@ -564,8 +561,8 @@ func TestHandler_SyntacticallyValidateAtx(t *testing.T) { atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer) - _, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - require.EqualError(t, err, "prevATX declared, but NodeID is included") + err = atxHdlr.SyntacticallyValidate(context.Background(), atx) + require.EqualError(t, err, "prev atx declared, but node id is included") }) } @@ -763,61 +760,6 @@ func TestHandler_ProcessAtxStoresNewVRFNonce(t *testing.T) { require.Equal(t, nonce2, got) } -func BenchmarkActivationDb_SyntacticallyValidateAtx(b *testing.B) { - r := require.New(b) - - goldenATXID := types.ATXID{2, 3, 4} - atxHdlr := newTestHandler(b, goldenATXID) - - currentLayer := types.LayerID(1012) - atxHdlr.mclock.EXPECT().CurrentLayer().Return(currentLayer).AnyTimes() - atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(1), nil).AnyTimes() - atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - atxHdlr.mValidator.EXPECT().VRFNonce(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - - sig, err := signing.NewEdSigner() - r.NoError(err) - - coinbase := types.GenerateAddress([]byte("c012ba5e")) - var atxList []*types.VerifiedActivationTx - for i := 0; i < 300; i++ { - atxList = append(atxList, newActivationTx(b, sig, 0, types.EmptyATXID, types.EmptyATXID, &goldenATXID, types.LayerID(1).GetEpoch(), 0, 100, coinbase, 100, &types.NIPost{})) - } - - poetRef := []byte{0x12, 0x21} - for _, atx := range atxList { - atx.NIPost = newNIPostWithChallenge(b, atx.NIPostChallenge.Hash(), poetRef) - } - - challenge := newChallenge(0, types.EmptyATXID, goldenATXID, currentLayer.GetEpoch(), &goldenATXID) - npst := newNIPostWithChallenge(b, challenge.Hash(), poetRef) - prevAtx := newActivationTx(b, sig, 0, types.EmptyATXID, goldenATXID, &goldenATXID, currentLayer.GetEpoch()-1, 0, 100, coinbase, 100, npst) - r.NoError(atxs.Add(atxHdlr.cdb, prevAtx)) - - challenge = newChallenge(1, prevAtx.ID(), prevAtx.ID(), currentLayer.GetEpoch()+1, nil) - atx := newAtx(b, sig, challenge, &types.NIPost{}, 100, coinbase) - nonce := types.VRFPostIndex(1) - atx.VRFNonce = &nonce - atx.NIPost = newNIPostWithChallenge(b, atx.NIPostChallenge.Hash(), poetRef) - require.NoError(b, SignAndFinalizeAtx(sig, atx)) - - start := time.Now() - _, err = atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - b.Logf("\nSyntactic validation took %v\n", time.Since(start)) - r.NoError(err) - - start = time.Now() - vAtx, err := atxHdlr.SyntacticallyValidateAtx(context.Background(), atx) - b.Logf("\nSecond syntactic validation took %v\n", time.Since(start)) - r.NoError(err) - - start = time.Now() - err = atxHdlr.ContextuallyValidateAtx(vAtx) - b.Logf("\nContextual validation took %v\n\n", time.Since(start)) - r.NoError(err) -} - func BenchmarkNewActivationDb(b *testing.B) { r := require.New(b) @@ -934,6 +876,97 @@ func TestHandler_AwaitAtx(t *testing.T) { r.Len(atxHdlr.atxChannels, 0) // last unsubscribe clears the channel } +func TestHandler_HandleGossipAtx(t *testing.T) { + goldenATXID := types.ATXID{2, 3, 4} + atxHdlr := newTestHandler(t, goldenATXID) + + sig1, err := signing.NewEdSigner() + require.NoError(t, err) + nodeID1 := sig1.NodeID() + nipost := newNIPostWithChallenge(t, types.HexToHash32("0x3333"), []byte{0xba, 0xbe}) + vrfNonce := types.VRFPostIndex(12345) + first := &types.ActivationTx{ + InnerActivationTx: types.InnerActivationTx{ + NIPostChallenge: types.NIPostChallenge{ + PublishEpoch: 1, + Sequence: 0, + PrevATXID: types.EmptyATXID, + PositioningATX: goldenATXID, + CommitmentATX: &goldenATXID, + InitialPost: nipost.Post, + }, + Coinbase: types.Address{2, 3, 4}, + NumUnits: 2, + NIPost: nipost, + NodeID: &nodeID1, + VRFNonce: &vrfNonce, + }, + SmesherID: nodeID1, + } + first.Signature = sig1.Sign(signing.ATX, first.SignedBytes()) + first.SetEffectiveNumUnits(first.NumUnits) + first.SetReceived(time.Now()) + _, err = first.Verify(0, 2) + require.NoError(t, err) + + second := &types.ActivationTx{ + InnerActivationTx: types.InnerActivationTx{ + NIPostChallenge: types.NIPostChallenge{ + PublishEpoch: 2, + Sequence: 1, + PrevATXID: first.ID(), + PositioningATX: first.ID(), + }, + Coinbase: types.Address{2, 3, 4}, + NumUnits: 2, + NIPost: nipost, + }, + SmesherID: nodeID1, + } + second.Signature = sig1.Sign(signing.ATX, second.SignedBytes()) + secondData, err := codec.Encode(second) + require.NoError(t, err) + + atxHdlr.mclock.EXPECT().CurrentLayer().Return(second.PublishEpoch.FirstLayer()) + atxHdlr.mclock.EXPECT().LayerToTime(gomock.Any()).Return(time.Now()) + atxHdlr.mockFetch.EXPECT().RegisterPeerHashes(gomock.Any(), gomock.Any()) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), second.GetPoetProofRef()).Return(errors.New("woof")) + err = atxHdlr.HandleGossipAtx(context.Background(), "", secondData) + require.Error(t, err) + require.ErrorContains(t, err, "missing poet proof") + + atxHdlr.mclock.EXPECT().CurrentLayer().Return(second.PublishEpoch.FirstLayer()) + atxHdlr.mclock.EXPECT().LayerToTime(gomock.Any()).Return(time.Now()) + atxHdlr.mockFetch.EXPECT().RegisterPeerHashes(gomock.Any(), gomock.Any()) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), second.GetPoetProofRef()) + atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, ids []types.ATXID) error { + require.ElementsMatch(t, []types.ATXID{first.ID()}, ids) + data, err := codec.Encode(first) + require.NoError(t, err) + atxHdlr.mclock.EXPECT().CurrentLayer().Return(first.PublishEpoch.FirstLayer()) + atxHdlr.mclock.EXPECT().LayerToTime(gomock.Any()).Return(time.Now()) + atxHdlr.mValidator.EXPECT().Post(gomock.Any(), nodeID1, goldenATXID, first.InitialPost, gomock.Any(), first.NumUnits) + atxHdlr.mValidator.EXPECT().VRFNonce(nodeID1, goldenATXID, &vrfNonce, gomock.Any(), first.NumUnits) + atxHdlr.mockFetch.EXPECT().RegisterPeerHashes(gomock.Any(), gomock.Any()) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), first.GetPoetProofRef()) + atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(&first.NIPostChallenge, gomock.Any(), goldenATXID) + atxHdlr.mValidator.EXPECT().PositioningAtx(&goldenATXID, gomock.Any(), goldenATXID, first.PublishEpoch) + atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), nodeID1, goldenATXID, second.NIPost, gomock.Any(), second.NumUnits) + atxHdlr.mbeacon.EXPECT().OnAtx(gomock.Any()) + atxHdlr.mtortoise.EXPECT().OnAtx(gomock.Any()) + require.NoError(t, atxHdlr.HandleGossipAtx(context.Background(), "", data)) + return nil + }, + ) + atxHdlr.mValidator.EXPECT().NIPostChallenge(&second.NIPostChallenge, gomock.Any(), nodeID1) + atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), nodeID1, goldenATXID, second.NIPost, gomock.Any(), second.NumUnits) + atxHdlr.mValidator.EXPECT().PositioningAtx(&second.PositioningATX, gomock.Any(), goldenATXID, second.PublishEpoch) + atxHdlr.mbeacon.EXPECT().OnAtx(gomock.Any()) + atxHdlr.mtortoise.EXPECT().OnAtx(gomock.Any()) + require.NoError(t, atxHdlr.HandleGossipAtx(context.Background(), "", secondData)) +} + func TestHandler_HandleSyncedAtx(t *testing.T) { // Arrange goldenATXID := types.ATXID{2, 3, 4} @@ -953,7 +986,7 @@ func TestHandler_HandleSyncedAtx(t *testing.T) { require.NoError(t, err) atxHdlr.mclock.EXPECT().LayerToTime(gomock.Any()).Return(time.Now()) - require.EqualError(t, atxHdlr.HandleSyncedAtx(context.Background(), atx.ID().Hash32(), p2p.NoPeer, buf), fmt.Sprintf("nil nipst in gossip for atx %v", atx.ID())) + require.EqualError(t, atxHdlr.HandleSyncedAtx(context.Background(), atx.ID().Hash32(), p2p.NoPeer, buf), fmt.Sprintf("nil nipst for atx %v", atx.ID())) }) t.Run("known atx is ignored by handleAtxData", func(t *testing.T) { @@ -1035,7 +1068,7 @@ func BenchmarkGetAtxHeaderWithConcurrentProcessAtx(b *testing.B) { } // Check that we're not trying to sync an ATX that references the golden ATX or an empty ATX (i.e. not adding it to the sync queue). -func TestHandler_FetchAtxReferences(t *testing.T) { +func TestHandler_FetchReferences(t *testing.T) { goldenATXID := types.ATXID{2, 3, 4} sig, err := signing.NewEdSigner() @@ -1054,8 +1087,9 @@ func TestHandler_FetchAtxReferences(t *testing.T) { nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), gomock.InAnyOrder([]types.ATXID{atx.PositioningATX, atx.PrevATXID})).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("valid prev ATX and golden pos ATX", func(t *testing.T) { @@ -1067,8 +1101,9 @@ func TestHandler_FetchAtxReferences(t *testing.T) { nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), []types.ATXID{atx.PrevATXID}).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("valid prev ATX and empty pos ATX", func(t *testing.T) { @@ -1080,8 +1115,9 @@ func TestHandler_FetchAtxReferences(t *testing.T) { nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), []types.ATXID{atx.PrevATXID}).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("empty prev ATX, valid pos ATX and valid commitment ATX", func(t *testing.T) { @@ -1094,8 +1130,9 @@ func TestHandler_FetchAtxReferences(t *testing.T) { atx := newAtx(t, sig, challenge, nipost, 2, coinbase) atx.CommitmentATX = &commitATX + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), gomock.InAnyOrder([]types.ATXID{atx.PositioningATX, *atx.CommitmentATX})).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("empty prev ATX, valid pos ATX and golden commitment ATX", func(t *testing.T) { @@ -1108,8 +1145,9 @@ func TestHandler_FetchAtxReferences(t *testing.T) { atx := newAtx(t, sig, challenge, nipost, 2, coinbase) atx.CommitmentATX = &goldenATXID + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), []types.ATXID{atx.PositioningATX}).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("empty prev ATX, empty pos ATX", func(t *testing.T) { @@ -1121,7 +1159,8 @@ func TestHandler_FetchAtxReferences(t *testing.T) { nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) atx := newAtx(t, sig, challenge, nipost, 2, coinbase) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) }) t.Run("same prev and pos ATX", func(t *testing.T) { @@ -1133,8 +1172,36 @@ func TestHandler_FetchAtxReferences(t *testing.T) { nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), []types.ATXID{atx.PrevATXID}).Return(nil) - require.NoError(t, atxHdlr.FetchAtxReferences(context.Background(), atx)) + require.NoError(t, atxHdlr.FetchReferences(context.Background(), atx)) + }) + + t.Run("no poet proofs", func(t *testing.T) { + t.Parallel() + atxHdlr := newTestHandler(t, goldenATXID) + + coinbase := types.Address{2, 4, 5} + challenge := newChallenge(1, types.EmptyATXID, types.EmptyATXID, types.LayerID(22).GetEpoch(), nil) + nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) + atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()).Return(errors.New("pooh")) + require.Error(t, atxHdlr.FetchReferences(context.Background(), atx)) + }) + + t.Run("no atxs", func(t *testing.T) { + t.Parallel() + atxHdlr := newTestHandler(t, goldenATXID) + + coinbase := types.Address{2, 4, 5} + challenge := newChallenge(1, prevATX, prevATX, types.LayerID(22).GetEpoch(), nil) + nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666")) + atx := newAtx(t, sig, challenge, nipost, 2, coinbase) + + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) + atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), []types.ATXID{atx.PrevATXID}).Return(errors.New("pooh")) + require.Error(t, atxHdlr.FetchReferences(context.Background(), atx)) }) } @@ -1188,7 +1255,7 @@ func TestHandler_AtxWeight(t *testing.T) { atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(leaves, nil) atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mbeacon.EXPECT().OnAtx(gomock.Any()) atxHdlr.mtortoise.EXPECT().OnAtx(gomock.Any()) require.NoError(t, atxHdlr.HandleSyncedAtx(context.Background(), atx1.ID().Hash32(), peer, buf)) @@ -1231,7 +1298,7 @@ func TestHandler_AtxWeight(t *testing.T) { atxHdlr.mockFetch.EXPECT().GetAtxs(gomock.Any(), gomock.Any()) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(leaves, nil) atxHdlr.mValidator.EXPECT().NIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) atxHdlr.mbeacon.EXPECT().OnAtx(gomock.Any()) atxHdlr.mtortoise.EXPECT().OnAtx(gomock.Any()) require.NoError(t, atxHdlr.HandleSyncedAtx(context.Background(), atx2.ID().Hash32(), peer, buf)) @@ -1286,7 +1353,7 @@ func TestHandler_WrongHash(t *testing.T) { atxHdlr.mValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(uint64(111), nil) atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + atxHdlr.mValidator.EXPECT().PositioningAtx(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) err = atxHdlr.HandleSyncedAtx(context.Background(), types.RandomHash(), peer, buf) require.ErrorIs(t, err, errWrongHash) require.ErrorIs(t, err, pubsub.ErrValidationReject) diff --git a/activation/interface.go b/activation/interface.go index 9718a791d1d..833f74dc72c 100644 --- a/activation/interface.go +++ b/activation/interface.go @@ -25,14 +25,14 @@ type PostVerifier interface { type nipostValidator interface { InitialNIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, goldenATXID types.ATXID) error NIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, nodeID types.NodeID) error - NIPost(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, atxId types.ATXID, NIPost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) + NIPost(ctx context.Context, nodeId types.NodeID, atxId types.ATXID, NIPost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) NumUnits(cfg *PostConfig, numUnits uint32) error - Post(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, atxId types.ATXID, Post *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error + Post(ctx context.Context, nodeId types.NodeID, atxId types.ATXID, Post *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error PostMetadata(cfg *PostConfig, metadata *types.PostMetadata) error VRFNonce(nodeId types.NodeID, commitmentAtxId types.ATXID, vrfNonce *types.VRFPostIndex, PostMetadata *types.PostMetadata, numUnits uint32) error - PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID, layersPerEpoch uint32) error + PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID) error } type layerClock interface { diff --git a/activation/mocks.go b/activation/mocks.go index 098fb8e20c4..c63201893a7 100644 --- a/activation/mocks.go +++ b/activation/mocks.go @@ -145,9 +145,9 @@ func (mr *MocknipostValidatorMockRecorder) InitialNIPostChallenge(challenge, atx } // NIPost mocks base method. -func (m *MocknipostValidator) NIPost(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, atxId types.ATXID, NIPost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) { +func (m *MocknipostValidator) NIPost(ctx context.Context, nodeId types.NodeID, atxId types.ATXID, NIPost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) { m.ctrl.T.Helper() - varargs := []interface{}{ctx, publishEpoch, nodeId, atxId, NIPost, expectedChallenge, numUnits} + varargs := []interface{}{ctx, nodeId, atxId, NIPost, expectedChallenge, numUnits} for _, a := range opts { varargs = append(varargs, a) } @@ -158,9 +158,9 @@ func (m *MocknipostValidator) NIPost(ctx context.Context, publishEpoch types.Epo } // NIPost indicates an expected call of NIPost. -func (mr *MocknipostValidatorMockRecorder) NIPost(ctx, publishEpoch, nodeId, atxId, NIPost, expectedChallenge, numUnits interface{}, opts ...interface{}) *gomock.Call { +func (mr *MocknipostValidatorMockRecorder) NIPost(ctx, nodeId, atxId, NIPost, expectedChallenge, numUnits interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, publishEpoch, nodeId, atxId, NIPost, expectedChallenge, numUnits}, opts...) + varargs := append([]interface{}{ctx, nodeId, atxId, NIPost, expectedChallenge, numUnits}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NIPost", reflect.TypeOf((*MocknipostValidator)(nil).NIPost), varargs...) } @@ -193,23 +193,23 @@ func (mr *MocknipostValidatorMockRecorder) NumUnits(cfg, numUnits interface{}) * } // PositioningAtx mocks base method. -func (m *MocknipostValidator) PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID, layersPerEpoch uint32) error { +func (m *MocknipostValidator) PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PositioningAtx", id, atxs, goldenATXID, pubepoch, layersPerEpoch) + ret := m.ctrl.Call(m, "PositioningAtx", id, atxs, goldenATXID, pubepoch) ret0, _ := ret[0].(error) return ret0 } // PositioningAtx indicates an expected call of PositioningAtx. -func (mr *MocknipostValidatorMockRecorder) PositioningAtx(id, atxs, goldenATXID, pubepoch, layersPerEpoch interface{}) *gomock.Call { +func (mr *MocknipostValidatorMockRecorder) PositioningAtx(id, atxs, goldenATXID, pubepoch interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PositioningAtx", reflect.TypeOf((*MocknipostValidator)(nil).PositioningAtx), id, atxs, goldenATXID, pubepoch, layersPerEpoch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PositioningAtx", reflect.TypeOf((*MocknipostValidator)(nil).PositioningAtx), id, atxs, goldenATXID, pubepoch) } // Post mocks base method. -func (m *MocknipostValidator) Post(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, atxId types.ATXID, Post *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error { +func (m *MocknipostValidator) Post(ctx context.Context, nodeId types.NodeID, atxId types.ATXID, Post *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error { m.ctrl.T.Helper() - varargs := []interface{}{ctx, publishEpoch, nodeId, atxId, Post, PostMetadata, numUnits} + varargs := []interface{}{ctx, nodeId, atxId, Post, PostMetadata, numUnits} for _, a := range opts { varargs = append(varargs, a) } @@ -219,9 +219,9 @@ func (m *MocknipostValidator) Post(ctx context.Context, publishEpoch types.Epoch } // Post indicates an expected call of Post. -func (mr *MocknipostValidatorMockRecorder) Post(ctx, publishEpoch, nodeId, atxId, Post, PostMetadata, numUnits interface{}, opts ...interface{}) *gomock.Call { +func (mr *MocknipostValidatorMockRecorder) Post(ctx, nodeId, atxId, Post, PostMetadata, numUnits interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, publishEpoch, nodeId, atxId, Post, PostMetadata, numUnits}, opts...) + varargs := append([]interface{}{ctx, nodeId, atxId, Post, PostMetadata, numUnits}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Post", reflect.TypeOf((*MocknipostValidator)(nil).Post), varargs...) } diff --git a/activation/nipost.go b/activation/nipost.go index ce27462afd9..da25f56cc6a 100644 --- a/activation/nipost.go +++ b/activation/nipost.go @@ -287,7 +287,6 @@ func (nb *NIPostBuilder) BuildNIPost(ctx context.Context, challenge *types.NIPos } if err := nb.validator.Post( postCtx, - challenge.PublishEpoch, nb.nodeID, commitmentAtxId, proof, diff --git a/activation/nipost_test.go b/activation/nipost_test.go index 2fe7b234d5a..e28ffa2f6c7 100644 --- a/activation/nipost_test.go +++ b/activation/nipost_test.go @@ -57,7 +57,7 @@ func TestNIPostBuilderWithMocks(t *testing.T) { postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) nipostValidator := NewMocknipostValidator(ctrl) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil) poetProvider := defaultPoetServiceMock(t, []byte("poet")) poetProvider.EXPECT().Proof(gomock.Any(), "").Return(&types.PoetProofMessage{ @@ -109,7 +109,7 @@ func TestPostSetup(t *testing.T) { mclock := defaultLayerClockMock(t) nipostValidator := NewMocknipostValidator(gomock.NewController(t)) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( postProvider.id, @@ -154,7 +154,6 @@ func TestNIPostBuilderWithClients(t *testing.T) { nipost := buildNIPost(t, postProvider, challenge, poetDb, v) _, err = v.NIPost( context.Background(), - challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, @@ -258,7 +257,7 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) { mclock := defaultLayerClockMock(t) nipostValidator := NewMocknipostValidator(ctrl) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( postProvider.id, @@ -293,7 +292,6 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) { v := NewValidator(poetDb, postProvider.cfg, logger, verifier) _, err = v.NIPost( context.Background(), - challenge.PublishEpoch, postProvider.id, postProvider.goldenATXID, nipost, @@ -361,8 +359,8 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { ) req.NoError(err) - postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) nipost, err := nb.BuildNIPost(context.Background(), &challenge) req.NoError(err) req.NotNil(nipost) @@ -412,7 +410,7 @@ func TestNIPostBuilder_BuildNIPost(t *testing.T) { ) req.NoError(err) postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), 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) @@ -420,8 +418,8 @@ 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()).Times(1) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + postProvider.EXPECT().GenerateProof(gomock.Any(), gomock.Any(), gomock.Any()) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) nipost, err = nb.BuildNIPost(context.Background(), &challenge3) req.NoError(err) req.NotNil(nipost) @@ -481,7 +479,7 @@ func TestNIPostBuilder_ManyPoETs_SubmittingChallenge_DeadlineReached(t *testing. }, nil }, ) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, postProvider, @@ -557,7 +555,7 @@ func TestNIPostBuilder_ManyPoETs_AllFinished(t *testing.T) { }, nil }, ) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, postProvider, @@ -955,7 +953,7 @@ func TestNIPoSTBuilder_Continues_After_Interrupted(t *testing.T) { }, ) nipostValidator := NewMocknipostValidator(ctrl) - nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) + nipostValidator.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) nb, err := NewNIPostBuilder( types.NodeID{1}, postProvider, diff --git a/activation/validation.go b/activation/validation.go index fb58f283128..3db0be69aa0 100644 --- a/activation/validation.go +++ b/activation/validation.go @@ -54,7 +54,7 @@ func NewValidator(poetDb poetDbAPI, cfg PostConfig, log log.Log, postVerifier Po // Some of the Post metadata fields validation values is ought to eventually be derived from // consensus instead of local configuration. If so, their validation should be removed to contextual validation, // while still syntactically-validate them here according to locally configured min/max values. -func (v *Validator) NIPost(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, commitmentAtxId types.ATXID, nipost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) { +func (v *Validator) NIPost(ctx context.Context, nodeId types.NodeID, commitmentAtxId types.ATXID, nipost *types.NIPost, expectedChallenge types.Hash32, numUnits uint32, opts ...verifying.OptionFunc) (uint64, error) { if err := v.NumUnits(&v.cfg, numUnits); err != nil { return 0, err } @@ -63,8 +63,8 @@ func (v *Validator) NIPost(ctx context.Context, publishEpoch types.EpochID, node return 0, err } - if err := v.Post(ctx, publishEpoch, nodeId, commitmentAtxId, nipost.Post, nipost.PostMetadata, numUnits, opts...); err != nil { - return 0, fmt.Errorf("invalid Post: %w", err) + if err := v.Post(ctx, nodeId, commitmentAtxId, nipost.Post, nipost.PostMetadata, numUnits, opts...); err != nil { + return 0, fmt.Errorf("invalid Post: %v", err) } var ref types.PoetProofRef @@ -113,7 +113,7 @@ func validateMerkleProof(leaf []byte, proof *types.MerkleProof, expectedRoot []b // Post validates a Proof of Space-Time (PoST). It returns nil if validation passed or an error indicating why // validation failed. -func (v *Validator) Post(ctx context.Context, publishEpoch types.EpochID, nodeId types.NodeID, commitmentAtxId types.ATXID, PoST *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error { +func (v *Validator) Post(ctx context.Context, nodeId types.NodeID, commitmentAtxId types.ATXID, PoST *types.Post, PostMetadata *types.PostMetadata, numUnits uint32, opts ...verifying.OptionFunc) error { p := (*shared.Proof)(PoST) m := &shared.ProofMetadata{ @@ -146,7 +146,7 @@ func (*Validator) NumUnits(cfg *PostConfig, numUnits uint32) error { } func (*Validator) PostMetadata(cfg *PostConfig, metadata *types.PostMetadata) error { - if metadata.LabelsPerUnit < uint64(cfg.LabelsPerUnit) { + if metadata.LabelsPerUnit < cfg.LabelsPerUnit { return fmt.Errorf("invalid `LabelsPerUnit`; expected: >=%d, given: %d", cfg.LabelsPerUnit, metadata.LabelsPerUnit) } return nil @@ -170,17 +170,9 @@ func (*Validator) VRFNonce(nodeId types.NodeID, commitmentAtxId types.ATXID, vrf return nil } -func (*Validator) InitialNIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, goldenATXID types.ATXID) error { - if challenge.Sequence != 0 { - return fmt.Errorf("no prevATX declared, but sequence number not zero") - } - - if challenge.InitialPost == nil { - return fmt.Errorf("no prevATX declared, but initial Post is not included in challenge") - } - +func (v *Validator) InitialNIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, goldenATXID types.ATXID) error { if challenge.CommitmentATX == nil { - return fmt.Errorf("no prevATX declared, but commitmentATX is missing") + v.log.Panic("commitment atx is nil") } if *challenge.CommitmentATX != goldenATXID { @@ -218,21 +210,12 @@ func (*Validator) NIPostChallenge(challenge *types.NIPostChallenge, atxs atxProv if prevATX.Sequence+1 != challenge.Sequence { return fmt.Errorf("sequence number is not one more than prev sequence number") } - - if challenge.InitialPost != nil { - return fmt.Errorf("prevATX declared, but initial Post is included in challenge") - } - - if challenge.CommitmentATX != nil { - return fmt.Errorf("prevATX declared, but commitmentATX is included") - } - return nil } -func (*Validator) PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID, layersPerEpoch uint32) error { +func (v *Validator) PositioningAtx(id *types.ATXID, atxs atxProvider, goldenATXID types.ATXID, pubepoch types.EpochID) error { if *id == types.EmptyATXID { - return fmt.Errorf("empty positioning atx") + v.log.Panic("empty positioning atx") } if *id == goldenATXID { return nil diff --git a/activation/validation_test.go b/activation/validation_test.go index 76ce3bc178c..f0c5ee59276 100644 --- a/activation/validation_test.go +++ b/activation/validation_test.go @@ -126,38 +126,6 @@ func Test_Validation_InitialNIPostChallenge(t *testing.T) { require.NoError(t, err) }) - t.Run("sequence number is not zero", func(t *testing.T) { - t.Parallel() - - challenge := &types.NIPostChallenge{ - Sequence: 1, - } - err := v.InitialNIPostChallenge(challenge, nil, goldenATXID) - require.EqualError(t, err, "no prevATX declared, but sequence number not zero") - }) - - t.Run("missing initial post", func(t *testing.T) { - t.Parallel() - posAtxId := types.ATXID{1, 2, 3} - - challenge := newChallenge(0, types.EmptyATXID, posAtxId, types.LayerID(2).GetEpoch(), &goldenATXID) - - err := v.InitialNIPostChallenge(&challenge, nil, goldenATXID) - require.EqualError(t, err, "no prevATX declared, but initial Post is not included in challenge") - }) - - t.Run("missing commitment atx", func(t *testing.T) { - t.Parallel() - - posAtxId := types.ATXID{1, 2, 3} - - challenge := newChallenge(0, types.EmptyATXID, posAtxId, types.LayerID(2).GetEpoch(), nil) - challenge.InitialPost = &types.Post{} - - err := v.InitialNIPostChallenge(&challenge, nil, goldenATXID) - require.EqualError(t, err, "no prevATX declared, but commitmentATX is missing") - }) - t.Run("commitment atx from wrong pub layer", func(t *testing.T) { t.Parallel() @@ -302,54 +270,6 @@ func Test_Validation_NIPostChallenge(t *testing.T) { err := v.NIPostChallenge(&challenge, atxProvider, nodeId) require.EqualError(t, err, "sequence number is not one more than prev sequence number") }) - - t.Run("challenge contains initial post", func(t *testing.T) { - t.Parallel() - - nodeId := types.RandomNodeID() - - prevAtxId := types.ATXID{3, 2, 1} - posAtxId := types.ATXID{1, 2, 3} - - challenge := newChallenge(10, prevAtxId, posAtxId, 2, nil) - challenge.InitialPost = &types.Post{} - - atxProvider := NewMockatxProvider(ctrl) - atxProvider.EXPECT().GetAtxHeader(prevAtxId).Return(&types.ActivationTxHeader{ - NIPostChallenge: types.NIPostChallenge{ - PublishEpoch: 1, - Sequence: 9, - }, - NodeID: nodeId, - }, nil) - - err := v.NIPostChallenge(&challenge, atxProvider, nodeId) - require.EqualError(t, err, "prevATX declared, but initial Post is included in challenge") - }) - - t.Run("challenge contains commitment atx", func(t *testing.T) { - t.Parallel() - - nodeId := types.RandomNodeID() - - prevAtxId := types.ATXID{3, 2, 1} - posAtxId := types.ATXID{1, 2, 3} - - challenge := newChallenge(10, prevAtxId, posAtxId, 2, nil) - challenge.CommitmentATX = &types.ATXID{9, 9, 9} - - atxProvider := NewMockatxProvider(ctrl) - atxProvider.EXPECT().GetAtxHeader(prevAtxId).Return(&types.ActivationTxHeader{ - NIPostChallenge: types.NIPostChallenge{ - PublishEpoch: 1, - Sequence: 9, - }, - NodeID: nodeId, - }, nil) - - err := v.NIPostChallenge(&challenge, atxProvider, nodeId) - require.EqualError(t, err, "prevATX declared, but commitmentATX is included") - }) } func Test_Validation_Post(t *testing.T) { @@ -369,10 +289,10 @@ func Test_Validation_Post(t *testing.T) { meta := types.PostMetadata{} postVerifier.EXPECT().Verify(gomock.Any(), (*shared.Proof)(&post), gomock.Any(), gomock.Any()).Return(nil) - require.NoError(t, v.Post(context.Background(), types.EpochID(0), types.EmptyNodeID, types.RandomATXID(), &post, &meta, 1)) + require.NoError(t, v.Post(context.Background(), types.EmptyNodeID, types.RandomATXID(), &post, &meta, 1)) postVerifier.EXPECT().Verify(gomock.Any(), (*shared.Proof)(&post), gomock.Any(), gomock.Any()).Return(errors.New("invalid")) - require.Error(t, v.Post(context.Background(), types.EpochID(0), types.EmptyNodeID, types.RandomATXID(), &post, &meta, 1)) + require.Error(t, v.Post(context.Background(), types.EmptyNodeID, types.RandomATXID(), &post, &meta, 1)) } func Test_Validation_PositioningAtx(t *testing.T) { @@ -402,7 +322,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { }, }, nil) - err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 2, layersPerEpochBig) + err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 2) require.NoError(t, err) }) @@ -413,7 +333,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { atxProvider := NewMockatxProvider(ctrl) - err := v.PositioningAtx(&goldenAtxId, atxProvider, goldenAtxId, types.LayerID(1012).GetEpoch(), layersPerEpochBig) + err := v.PositioningAtx(&goldenAtxId, atxProvider, goldenAtxId, types.LayerID(1012).GetEpoch()) require.NoError(t, err) }) @@ -424,21 +344,10 @@ func Test_Validation_PositioningAtx(t *testing.T) { atxProvider := NewMockatxProvider(ctrl) - err := v.PositioningAtx(&goldenAtxId, atxProvider, goldenAtxId, 5, layersPerEpochBig) + err := v.PositioningAtx(&goldenAtxId, atxProvider, goldenAtxId, 5) require.NoError(t, err) }) - t.Run("fail at empty positioning atx", func(t *testing.T) { - t.Parallel() - - goldenAtxId := types.ATXID{9, 9, 9} - - atxProvider := NewMockatxProvider(ctrl) - - err := v.PositioningAtx(&types.EmptyATXID, atxProvider, goldenAtxId, types.LayerID(1012).GetEpoch(), layersPerEpochBig) - require.EqualError(t, err, "empty positioning atx") - }) - t.Run("fail when posAtx is not found", func(t *testing.T) { t.Parallel() @@ -448,7 +357,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { atxProvider := NewMockatxProvider(ctrl) atxProvider.EXPECT().GetAtxHeader(posAtxId).Return(nil, errors.New("db error")) - err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, types.LayerID(1012).GetEpoch(), layersPerEpochBig) + err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, types.LayerID(1012).GetEpoch()) require.ErrorIs(t, err, &ErrAtxNotFound{Id: posAtxId}) require.ErrorContains(t, err, "db error") }) @@ -467,7 +376,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { }, }, nil) - err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 3, layersPerEpochBig) + err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 3) require.EqualError(t, err, "positioning atx epoch (5) must be before 3") }) @@ -485,7 +394,7 @@ func Test_Validation_PositioningAtx(t *testing.T) { }, }, nil) - err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 10, layersPerEpochBig) + err := v.PositioningAtx(&posAtxId, atxProvider, goldenAtxId, 10) require.NoError(t, err) }) } @@ -582,33 +491,33 @@ func TestValidator_Validate(t *testing.T) { opts := []verifying.OptionFunc{verifying.WithLabelScryptParams(postProvider.opts.Scrypt)} - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) r.NoError(err) - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, types.BytesToHash([]byte("lerner")), postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, types.BytesToHash([]byte("lerner")), postProvider.opts.NumUnits, opts...) r.Contains(err.Error(), "invalid membership proof") newNIPost := *nipost newNIPost.Post = &types.Post{} - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, &newNIPost, challengeHash, postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, &newNIPost, challengeHash, postProvider.opts.NumUnits, opts...) r.Contains(err.Error(), "invalid Post") newPostCfg := postProvider.cfg newPostCfg.MinNumUnits = postProvider.opts.NumUnits + 1 v = NewValidator(poetDb, newPostCfg, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) 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, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) 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, logtest.New(t).WithName("validator"), nil) - _, err = v.NIPost(context.Background(), challenge.PublishEpoch, postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) + _, err = v.NIPost(context.Background(), postProvider.id, postProvider.commitmentAtxId, nipost, challengeHash, postProvider.opts.NumUnits, opts...) r.EqualError(err, fmt.Sprintf("invalid `LabelsPerUnit`; expected: >=%d, given: %d", newPostCfg.LabelsPerUnit, nipost.PostMetadata.LabelsPerUnit)) } diff --git a/checkpoint/recovery_test.go b/checkpoint/recovery_test.go index 00ab7aba3e0..12b0367c003 100644 --- a/checkpoint/recovery_test.go +++ b/checkpoint/recovery_test.go @@ -217,7 +217,6 @@ func TestRecover_SameRecoveryInfo(t *testing.T) { func validateAndPreserveData(tb testing.TB, db *sql.Database, deps []*types.VerifiedActivationTx, proofs []*types.PoetProofMessage) { lg := logtest.New(tb) - layersPerEpoch := uint32(3) edVerifier, err := signing.NewEdVerifier() require.NoError(tb, err) poetDb := activation.NewPoetDb(db, lg) @@ -234,7 +233,6 @@ func validateAndPreserveData(tb testing.TB, db *sql.Database, deps []*types.Veri mclock, nil, mfetch, - layersPerEpoch, 10, goldenAtx, mvalidator, @@ -253,13 +251,13 @@ func validateAndPreserveData(tb testing.TB, db *sql.Database, deps []*types.Veri mfetch.EXPECT().GetPoetProof(gomock.Any(), vatx.GetPoetProofRef()) if vatx.InitialPost != nil { mvalidator.EXPECT().InitialNIPostChallenge(&vatx.ActivationTx.NIPostChallenge, gomock.Any(), goldenAtx).AnyTimes() - mvalidator.EXPECT().Post(gomock.Any(), vatx.PublishEpoch, vatx.SmesherID, *vatx.CommitmentATX, vatx.InitialPost, gomock.Any(), vatx.NumUnits) + mvalidator.EXPECT().Post(gomock.Any(), vatx.SmesherID, *vatx.CommitmentATX, vatx.InitialPost, gomock.Any(), vatx.NumUnits) mvalidator.EXPECT().VRFNonce(vatx.SmesherID, *vatx.CommitmentATX, vatx.VRFNonce, gomock.Any(), vatx.NumUnits) } else { mvalidator.EXPECT().NIPostChallenge(&vatx.ActivationTx.NIPostChallenge, cdb, vatx.SmesherID) } - mvalidator.EXPECT().PositioningAtx(&vatx.PositioningATX, cdb, goldenAtx, vatx.PublishEpoch, layersPerEpoch) - mvalidator.EXPECT().NIPost(gomock.Any(), vatx.PublishEpoch, vatx.SmesherID, gomock.Any(), vatx.NIPost, gomock.Any(), vatx.NumUnits).Return(uint64(1111111), nil) + mvalidator.EXPECT().PositioningAtx(&vatx.PositioningATX, cdb, goldenAtx, vatx.PublishEpoch) + mvalidator.EXPECT().NIPost(gomock.Any(), vatx.SmesherID, gomock.Any(), vatx.NIPost, gomock.Any(), vatx.NumUnits).Return(uint64(1111111), nil) mreceiver.EXPECT().OnAtx(gomock.Any()) mtrtl.EXPECT().OnAtx(gomock.Any()) require.NoError(tb, atxHandler.HandleSyncedAtx(context.Background(), vatx.ID().Hash32(), "self", encoded)) diff --git a/node/node.go b/node/node.go index 18d890a1ee6..1232668fab8 100644 --- a/node/node.go +++ b/node/node.go @@ -652,7 +652,6 @@ func (app *App) initServices(ctx context.Context) error { app.clock, app.host, fetcherWrapped, - layersPerEpoch, app.Config.TickSize, goldenATXID, validator,