Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle V2 Malfeasance proofs in V2 ATX handler #6133

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2c6d192
Removed SignedBytes function
fasmat Jul 11, 2024
1ff6265
Add malfeasance to activation package
fasmat Jul 11, 2024
7c2bad6
WiP
fasmat Jul 12, 2024
5e3e216
Add general publisher
fasmat Jul 12, 2024
88a0601
Cleanup
fasmat Jul 12, 2024
c260799
Fix failing tests
fasmat Jul 12, 2024
d6c0157
Update todods
fasmat Jul 13, 2024
d83399f
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Jul 13, 2024
856970a
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Jul 16, 2024
66f946b
Invalid Post WiP
fasmat Jul 16, 2024
3470e7b
Fix typo
fasmat Jul 16, 2024
061a2ab
Fix systest settings
fasmat Jul 24, 2024
5b48b94
Fix tests
fasmat Jul 24, 2024
af75ec3
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Jul 24, 2024
8c6d414
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Jul 30, 2024
fe0943b
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Jul 30, 2024
6566056
Update changelog
fasmat Jul 30, 2024
0c611bc
Fix CHANGELOG.md
fasmat Jul 31, 2024
b5d9b8a
Add code for double marry malfeasance proof
fasmat Jul 31, 2024
ef26d33
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 1, 2024
66c71db
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 3, 2024
07eadb2
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 5, 2024
15c9a4e
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 6, 2024
77ecaf3
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 7, 2024
e93746a
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 8, 2024
f1a83cd
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 12, 2024
614d79a
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 13, 2024
cbab84b
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 14, 2024
219ddf6
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 15, 2024
0f0a8e0
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 17, 2024
fa73750
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 20, 2024
491830a
make generate
fasmat Aug 20, 2024
002dee3
Fix compiler issues
fasmat Aug 20, 2024
b905673
Fix failing test
fasmat Aug 20, 2024
1ae09ec
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 22, 2024
96d48c5
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 23, 2024
0cb82ca
Merge remote-tracking branch 'origin/develop' into malfeasance-v2-fou…
fasmat Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion activation/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func NewHandler(
fetcher: fetcher,
beacon: beacon,
tortoise: tortoise,
malPublisher: &MalfeasancePublisher{},
malPublisher: &ATXMalfeasancePublisher{},
},
}

Expand Down Expand Up @@ -286,6 +286,7 @@ func (h *Handler) handleAtx(
case *wire.ActivationTxV1:
return h.v1.processATX(ctx, peer, atx, receivedTime)
case *wire.ActivationTxV2:
// TODO(mafa): change function signature to not return proofs any more
return (*mwire.MalfeasanceProof)(nil), h.v2.processATX(ctx, peer, atx, receivedTime)
default:
panic("unreachable")
Expand Down
4 changes: 2 additions & 2 deletions activation/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ type handlerMocks struct {
mValidator *MocknipostValidator
mbeacon *MockAtxReceiver
mtortoise *mocks.MockTortoise
mMalPublish *MockmalfeasancePublisher
mMalPublish *MockatxMalfeasancePublisher
}

type testHandler struct {
Expand Down Expand Up @@ -190,7 +190,7 @@ func newTestHandlerMocks(tb testing.TB, golden types.ATXID) handlerMocks {
mValidator: NewMocknipostValidator(ctrl),
mbeacon: NewMockAtxReceiver(ctrl),
mtortoise: mocks.NewMockTortoise(ctrl),
mMalPublish: NewMockmalfeasancePublisher(ctrl),
mMalPublish: NewMockatxMalfeasancePublisher(ctrl),
}
}

Expand Down
12 changes: 7 additions & 5 deletions activation/handler_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
tortoise system.Tortoise
logger *zap.Logger
fetcher system.Fetcher
malPublisher malfeasancePublisher
malPublisher atxMalfeasancePublisher
}

func (h *HandlerV2) processATX(
Expand Down Expand Up @@ -528,8 +528,9 @@
return nil, fmt.Errorf("fetching previous atx: %w", err)
}
if prevAtx.PublishEpoch >= atx.PublishEpoch {
err := fmt.Errorf("previous atx is too new (%d >= %d) (%s) ", prevAtx.PublishEpoch, atx.PublishEpoch, prev)
return nil, err
return nil, fmt.Errorf("previous atx (%s) is too new (%d >= %d)",
prev, prevAtx.PublishEpoch, atx.PublishEpoch,
)
}
previousAtxs[i] = prevAtx
}
Expand All @@ -545,8 +546,9 @@
nipostSizes[i] = new(nipostSize)
for _, post := range niposts.Posts {
if post.MarriageIndex >= uint32(len(equivocationSet)) {
err := fmt.Errorf("marriage index out of bounds: %d > %d", post.MarriageIndex, len(equivocationSet)-1)
return nil, err
return nil, fmt.Errorf("marriage index out of bounds: %d > %d",
post.MarriageIndex, len(equivocationSet)-1,
)

Check warning on line 551 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L549-L551

Added lines #L549 - L551 were not covered by tests
}

id := equivocationSet[post.MarriageIndex]
Expand Down
6 changes: 2 additions & 4 deletions activation/handler_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package activation
import (
"context"
"errors"
"fmt"
"math"
"slices"
"testing"
Expand All @@ -17,7 +18,6 @@ import (

"github.com/spacemeshos/go-spacemesh/activation/wire"
"github.com/spacemeshos/go-spacemesh/atxsdata"
"github.com/spacemeshos/go-spacemesh/codec"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/datastore"
"github.com/spacemeshos/go-spacemesh/fetch"
Expand Down Expand Up @@ -1509,7 +1509,7 @@ func TestHandlerV2_SyntacticallyValidateDeps(t *testing.T) {
atx.Sign(sig)

_, err := atxHandler.syntacticallyValidateDeps(context.Background(), atx)
require.ErrorContains(t, err, "previous atx is too new")
require.ErrorContains(t, err, fmt.Sprintf("previous atx (%s) is too new", prev.ID()))
})
t.Run("previous ATX by different smesher", func(t *testing.T) {
atxHandler := newV2TestHandler(t, golden)
Expand Down Expand Up @@ -1719,8 +1719,6 @@ func Test_Marriages(t *testing.T) {
nId, err := malProof.Valid(atxHandler.edVerifier)
require.NoError(t, err)
require.Equal(t, sig.NodeID(), nId)
b := codec.MustEncode(malProof)
_ = b
return nil
})
err = atxHandler.processATX(context.Background(), "", atx2, time.Now())
Expand Down
8 changes: 6 additions & 2 deletions activation/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,22 @@ type syncer interface {
RegisterForATXSynced() <-chan struct{}
}

// malfeasancePublisher is an interface for publishing malfeasance proofs.
// atxMalfeasancePublisher is an interface for publishing malfeasance proofs.
// This interface is used to publish proofs in V2.
//
// The provider of that interface ensures that only valid proofs are published (invalid ones return an error).
// Proofs against an identity that is managed by the node will also return an error and will not be gossiped.
//
// Additionally the publisher will only gossip proofs when the node is in sync, otherwise it will only store them.
// and mark the associated identity as malfeasant.
type malfeasancePublisher interface {
type atxMalfeasancePublisher interface {
Publish(ctx context.Context, id types.NodeID, proof wire.Proof) error
}

type malfeasancePublisher interface {
Publish(ctx context.Context, id types.NodeID, proof []byte) error
}

type atxProvider interface {
GetAtx(id types.ATXID) (*types.ActivationTx, error)
}
Expand Down
16 changes: 0 additions & 16 deletions activation/malfeasance2.go

This file was deleted.

130 changes: 130 additions & 0 deletions activation/malfeasance2_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package activation

import (
"context"
"fmt"

"github.com/spacemeshos/go-spacemesh/activation/wire"
"github.com/spacemeshos/go-spacemesh/codec"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/datastore"
"github.com/spacemeshos/go-spacemesh/signing"
"github.com/spacemeshos/go-spacemesh/system"
)

type MalfeasanceHandlerV2 struct {
syncer syncer
clock layerClock
publisher malfeasancePublisher
cdb *datastore.CachedDB
tortoise system.Tortoise
edVerifier *signing.EdVerifier
}

func NewMalfeasanceHandlerV2(
syncer syncer,
layerClock layerClock,
malPublisher malfeasancePublisher,
cdb *datastore.CachedDB,
tortoise system.Tortoise,
edVerifier *signing.EdVerifier,
) *MalfeasanceHandlerV2 {
return &MalfeasanceHandlerV2{
syncer: syncer,
clock: layerClock,
publisher: malPublisher, // TODO(mafa): implement malfeasancePublisher in `malfeasance` package
cdb: cdb,
tortoise: tortoise,
edVerifier: edVerifier,

Check warning on line 38 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L31-L38

Added lines #L31 - L38 were not covered by tests
}
}

// TODO(mafa): call this validate in the handler for publish/gossip.
// TODO(mafa): extend this validate to return nil if `peer` == self.
func (mh *MalfeasanceHandlerV2) Validate(ctx context.Context, data []byte) ([]types.NodeID, error) {
var decoded wire.ATXProof
if err := codec.Decode(data, &decoded); err != nil {
return nil, fmt.Errorf("decoding ATX malfeasance proof: %w", err)

Check warning on line 47 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L44-L47

Added lines #L44 - L47 were not covered by tests
}

var proof wire.Proof
switch decoded.ProofType {
case wire.DoublePublish:
p := &wire.ProofDoublePublish{}
if err := codec.Decode(decoded.Proof, p); err != nil {
return nil, fmt.Errorf("decoding ATX double publish proof: %w", err)

Check warning on line 55 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L50-L55

Added lines #L50 - L55 were not covered by tests
}
proof = p
case wire.DoubleMarry:
p := &wire.ProofDoubleMarry{}
if err := codec.Decode(decoded.Proof, p); err != nil {
return nil, fmt.Errorf("decoding ATX double marry proof: %w", err)

Check warning on line 61 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L57-L61

Added lines #L57 - L61 were not covered by tests
}
proof = p
case wire.InvalidPost:
p := &wire.ProofInvalidPost{}
if err := codec.Decode(decoded.Proof, p); err != nil {
return nil, fmt.Errorf("decoding ATX invalid post proof: %w", err)

Check warning on line 67 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L63-L67

Added lines #L63 - L67 were not covered by tests
}
default:
return nil, fmt.Errorf("unknown ATX malfeasance proof type: %d", decoded.ProofType)

Check warning on line 70 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L69-L70

Added lines #L69 - L70 were not covered by tests
}

id, err := proof.Valid(mh.edVerifier)
if err != nil {
return nil, fmt.Errorf("validating ATX malfeasance proof: %w", err)

Check warning on line 75 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L73-L75

Added lines #L73 - L75 were not covered by tests
}

// TODO(mafa): do this in the general handler
// validIDs := make([]types.NodeID, 0, len(decoded.Certificates)+1)
// validIDs = append(validIDs, id) // id has already been proven to be malfeasant

// // check certificates provided with the proof
// // TODO(mafa): only works if the main identity becomes malfeasant - try different approach with merkle proofs
// for _, cert := range decoded.Certificates {
// if id != cert.Target {
// continue
// }
// if !mh.edVerifier.Verify(signing.MARRIAGE, cert.Target, cert.ID.Bytes(), cert.Signature) {
// continue
// }
// validIDs = append(validIDs, cert.ID)
// }
// return validIDs, nil
return []types.NodeID{id}, nil

Check warning on line 94 in activation/malfeasance2_handler.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_handler.go#L94

Added line #L94 was not covered by tests
}

// TODO(mafa): this roughly how the general publisher looks like
//
// func Publish(ctx context.Context, smesherID types.NodeID, data []byte) error {
// // Combine IDs from the present equivocation set for atx.SmesherID and IDs in atx.Marriages.
// set, err := identities.EquivocationSet(mh.cdb, nodeID)
// if err != nil {
// return fmt.Errorf("getting equivocation set: %w", err)
// }
// for _, id := range set {
// if err := identities.SetMalicious(mh.cdb, id, encoded, time.Now()); err != nil {
// return fmt.Errorf("adding malfeasance proof: %w", err)
// }

// mh.cdb.CacheMalfeasanceProof(id, proof)
// mh.tortoise.OnMalfeasance(id)
// }

// if !mh.syncer.ListenToATXGossip() {
// // we are not gossiping proofs when we are not listening to ATX gossip
// return nil
// }

// gossip := mwire.MalfeasanceProofV2{
// Layer: mh.clock.CurrentLayer(),
// ProofType: mwire.InvalidActivation,
// Proof: data,
// }

// if err := mh.publisher.Publish(ctx, pubsub.MalfeasanceProof, codec.MustEncode(&gossip)); err != nil {
// mh.logger.Error("failed to broadcast malfeasance proof", zap.Error(err))
// return fmt.Errorf("broadcast atx malfeasance proof: %w", err)
// }
// return nil
// }
16 changes: 16 additions & 0 deletions activation/malfeasance2_publisher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package activation

import (
"context"

"github.com/spacemeshos/go-spacemesh/activation/wire"
"github.com/spacemeshos/go-spacemesh/common/types"
)

// ATXMalfeasancePublisher is the publisher for ATX proofs.
type ATXMalfeasancePublisher struct{}

func (p *ATXMalfeasancePublisher) Publish(ctx context.Context, id types.NodeID, proof wire.Proof) error {

Check warning on line 13 in activation/malfeasance2_publisher.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_publisher.go#L13

Added line #L13 was not covered by tests
// TODO(mafa): implement me
return nil

Check warning on line 15 in activation/malfeasance2_publisher.go

View check run for this annotation

Codecov / codecov/patch

activation/malfeasance2_publisher.go#L15

Added line #L15 was not covered by tests
}
File renamed without changes.
67 changes: 64 additions & 3 deletions activation/mocks.go

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

4 changes: 1 addition & 3 deletions activation/post_verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ func TestPostVerifierPrioritization(t *testing.T) {
verifier := NewMockPostVerifier(gomock.NewController(t))
v := newOffloadingPostVerifier(verifier, 2, zaptest.NewLogger(t), nodeID)

verifier.EXPECT().
Verify(gomock.Any(), gomock.Any(), &shared.ProofMetadata{NodeId: nodeID.Bytes()}, gomock.Any()).
Return(nil)
verifier.EXPECT().Verify(gomock.Any(), gomock.Any(), &shared.ProofMetadata{NodeId: nodeID.Bytes()}, gomock.Any())

err := v.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{NodeId: nodeID.Bytes()})
require.NoError(t, err)
Expand Down
Loading
Loading