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

[Merged by Bors] - Add invalid post malfeasance #6308

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
64aadb5
Add invalid post malfeasance
fasmat Aug 29, 2024
5d4742f
make generate
fasmat Aug 29, 2024
aba0dbf
Continue validation of proof
fasmat Oct 28, 2024
a7e2b3b
Add missing string for enum
fasmat Oct 30, 2024
5ae98bd
Refactor proof interface
fasmat Oct 30, 2024
83fb450
Continue implementing invalid post proof
fasmat Oct 30, 2024
1f514d8
Adjust proof interface to pass Context
fasmat Oct 30, 2024
7b8a890
WiP
fasmat Oct 30, 2024
c14e9f7
WiP Invalid Post Proof
fasmat Oct 31, 2024
8dceaf6
Refactor proof generation
fasmat Oct 31, 2024
096f93e
More refactoring
fasmat Oct 31, 2024
c9dd294
Continued refactoring
fasmat Oct 31, 2024
92c6f62
Code deduplication
fasmat Oct 31, 2024
bc17ddf
Cleanup
fasmat Nov 1, 2024
ce59ff9
Add todos for later
fasmat Nov 1, 2024
00fbeff
WiP
fasmat Nov 1, 2024
c5b5e44
Finish implementation of proof
fasmat Nov 1, 2024
382bed6
WiP Adding tests
fasmat Nov 1, 2024
9866631
Generalize MarriageProof for Malfeasance Proofs
fasmat Nov 2, 2024
2339333
Make positive test pass
fasmat Nov 2, 2024
7170bd6
Working happy path for merged and solo ATX
fasmat Nov 2, 2024
a2f690d
Move shared proofs to their own file
fasmat Nov 2, 2024
ebda15f
More testcases
fasmat Nov 2, 2024
a3de4da
Fix typos
fasmat Nov 4, 2024
0989153
Add remaining tests
fasmat Nov 4, 2024
312dd2e
Add test to handler v2
fasmat Nov 4, 2024
434a7b1
Add missing tests
fasmat Nov 4, 2024
4bc8b97
Remove obsolete method
fasmat Nov 4, 2024
4b5a81f
Cleanup
fasmat Nov 4, 2024
beba431
Cleanup
fasmat Nov 4, 2024
2e16199
Simplify check
fasmat Nov 5, 2024
cb7ccaa
Update merkle-tree library
fasmat Nov 6, 2024
03607bc
Update TODO
fasmat Nov 6, 2024
1334924
Update TODOs
fasmat Nov 6, 2024
33ef67e
Fix failing test
fasmat Nov 6, 2024
3425c11
Update old smesher image for system tests
fasmat Nov 6, 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
2 changes: 1 addition & 1 deletion activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ func (b *Builder) createAtx(
PositioningATX: challenge.PositioningATX,
Coinbase: b.Coinbase(),
VRFNonce: (uint64)(nipostState.VRFNonce),
NiPosts: []wire.NiPostsV2{
NIPosts: []wire.NIPostV2{
{
Membership: wire.MerkleProofV2{
Nodes: nipostState.Membership.Nodes,
Expand Down
2 changes: 1 addition & 1 deletion activation/certifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@
if err := codec.Decode(blob.Bytes, &atx); err != nil {
return nil, nil, fmt.Errorf("decoding ATX blob: %w", err)
}
return wire.PostFromWireV1(&atx.NiPosts[0].Posts[0].Post), atx.NiPosts[0].Challenge[:], nil
return wire.PostFromWireV1(&atx.NIPosts[0].Posts[0].Post), atx.NIPosts[0].Challenge[:], nil

Check warning on line 347 in activation/certifier.go

View check run for this annotation

Codecov / codecov/patch

activation/certifier.go#L347

Added line #L347 was not covered by tests
}
panic("unsupported ATX version")
}
8 changes: 4 additions & 4 deletions activation/e2e/atx_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func createInitialAtx(
Post: *wire.PostToWireV1(initial),
},
VRFNonce: uint64(nipost.VRFNonce),
NiPosts: []wire.NiPostsV2{
NIPosts: []wire.NIPostV2{
{
Membership: wire.MerkleProofV2{
Nodes: nipost.Membership.Nodes,
Expand All @@ -121,7 +121,7 @@ func createSoloAtx(publish types.EpochID, prev, pos types.ATXID, nipost *nipost.
PreviousATXs: []types.ATXID{prev},
PositioningATX: pos,
VRFNonce: uint64(nipost.VRFNonce),
NiPosts: []wire.NiPostsV2{
NIPosts: []wire.NIPostV2{
{
Membership: wire.MerkleProofV2{
Nodes: nipost.Membership.Nodes,
Expand Down Expand Up @@ -152,7 +152,7 @@ func createMerged(
PreviousATXs: previous,
MarriageATX: &marriage,
PositioningATX: positioning,
NiPosts: []wire.NiPostsV2{
NIPosts: []wire.NIPostV2{
{
Membership: membership,
Challenge: types.Hash32(niposts[0].PostMetadata.Challenge),
Expand All @@ -163,7 +163,7 @@ func createMerged(
for i, nipost := range niposts {
idx := slices.IndexFunc(previous, func(a types.ATXID) bool { return a == nipost.previous })
require.NotEqual(tb, -1, idx)
atx.NiPosts[0].Posts = append(atx.NiPosts[0].Posts, wire.SubPostV2{
atx.NIPosts[0].Posts = append(atx.NIPosts[0].Posts, wire.SubPostV2{
MarriageIndex: uint32(i),
PrevATXIndex: uint32(idx),
MembershipLeafIndex: nipost.Membership.LeafIndex,
Expand Down
3 changes: 3 additions & 0 deletions activation/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func toAtx(tb testing.TB, watx *wire.ActivationTxV1) *types.ActivationTx {
}

type handlerMocks struct {
ctrl *gomock.Controller
goldenATXID types.ATXID

mclock *MocklayerClock
Expand Down Expand Up @@ -184,6 +185,8 @@ func (h *handlerMocks) expectAtxV1(atx *wire.ActivationTxV1, nodeId types.NodeID
func newTestHandlerMocks(tb testing.TB, golden types.ATXID) handlerMocks {
ctrl := gomock.NewController(tb)
return handlerMocks{
ctrl: ctrl,

goldenATXID: golden,
mclock: NewMocklayerClock(ctrl),
mpub: pubsubmocks.NewMockPublisher(ctrl),
Expand Down
82 changes: 58 additions & 24 deletions activation/handler_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@
}

if atx.MarriageATX == nil {
if len(atx.NiPosts) != 1 {
if len(atx.NIPosts) != 1 {
return errors.New("solo atx must have one nipost")
}
if len(atx.NiPosts[0].Posts) != 1 {
if len(atx.NIPosts[0].Posts) != 1 {
return errors.New("solo atx must have one post")
}
if atx.NiPosts[0].Posts[0].PrevATXIndex != 0 {
if atx.NIPosts[0].Posts[0].PrevATXIndex != 0 {
return errors.New("solo atx post must have prevATXIndex 0")
}
}
Expand All @@ -204,7 +204,7 @@
return errors.New("initial atx must not have previous atxs")
}

numUnits := atx.NiPosts[0].Posts[0].NumUnits
numUnits := atx.NIPosts[0].Posts[0].NumUnits
if err := h.nipostValidator.VRFNonceV2(
atx.SmesherID, atx.Initial.CommitmentATX, atx.VRFNonce, numUnits,
); err != nil {
Expand Down Expand Up @@ -309,7 +309,7 @@
}

poetRefs := make(map[types.Hash32]struct{})
for _, nipost := range atx.NiPosts {
for _, nipost := range atx.NIPosts {
poetRefs[nipost.Challenge] = struct{}{}
}

Expand Down Expand Up @@ -495,7 +495,7 @@

func (h *HandlerV2) verifyIncludedIDsUniqueness(atx *wire.ActivationTxV2) error {
seen := make(map[uint32]struct{})
for _, niposts := range atx.NiPosts {
for _, niposts := range atx.NIPosts {
for _, post := range niposts.Posts {
if _, ok := seen[post.MarriageIndex]; ok {
return fmt.Errorf("ID present twice (duplicated marriage index): %d", post.MarriageIndex)
Expand Down Expand Up @@ -540,8 +540,8 @@
}

// validate previous ATXs
nipostSizes := make(nipostSizes, len(atx.NiPosts))
for i, niposts := range atx.NiPosts {
nipostSizes := make(nipostSizes, len(atx.NIPosts))
for i, niposts := range atx.NIPosts {
nipostSizes[i] = new(nipostSize)
for _, post := range niposts.Posts {
if post.MarriageIndex >= uint32(len(equivocationSet)) {
Expand All @@ -563,7 +563,7 @@
}

// validate poet membership proofs
for i, niposts := range atx.NiPosts {
for i, niposts := range atx.NIPosts {
// verify PoET memberships in a single go
indexedChallenges := make(map[uint64][]byte)

Expand Down Expand Up @@ -608,7 +608,7 @@

// validate all niposts
var smesherCommitment *types.ATXID
for _, niposts := range atx.NiPosts {
for idx, niposts := range atx.NIPosts {
for _, post := range niposts.Posts {
id := equivocationSet[post.MarriageIndex]
var commitment types.ATXID
Expand All @@ -632,24 +632,18 @@
id,
commitment,
wire.PostFromWireV1(&post.Post),
niposts.Challenge[:],
niposts.Challenge.Bytes(),
post.NumUnits,
PostSubset([]byte(h.local)),
)
invalidIdx := &verifying.ErrInvalidIndex{}
if errors.As(err, invalidIdx) {
h.logger.Debug(
"ATX with invalid post index",
zap.Stringer("id", atx.ID()),
zap.Int("index", invalidIdx.Index),
)
// TODO(mafa): finish proof
var proof wire.Proof
if err := h.malPublisher.Publish(ctx, id, proof); err != nil {
return nil, fmt.Errorf("publishing malfeasance proof for invalid post: %w", err)
switch {
case errors.As(err, invalidIdx):
if err := h.publishInvalidPostProof(ctx, atx, id, idx, uint32(invalidIdx.Index)); err != nil {
return nil, fmt.Errorf("publishing invalid post proof: %w", err)

Check warning on line 643 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L643

Added line #L643 was not covered by tests
}
}
if err != nil {
return nil, fmt.Errorf("invalid post for ID %s: %w", id.ShortString(), err)
case err != nil:
return nil, fmt.Errorf("validating post for ID %s: %w", id.ShortString(), err)
}
result.ids[id] = idData{
Expand All @@ -674,6 +668,45 @@
return &result, nil
}

func (h *HandlerV2) publishInvalidPostProof(
ctx context.Context,
atx *wire.ActivationTxV2,
nodeID types.NodeID,
nipostIndex int,
invalidPostIndex uint32,
) error {
initialAtx := atx
if initialAtx.Initial == nil {
initialID, err := atxs.GetFirstIDByNodeID(h.cdb, nodeID)
if err != nil {
return fmt.Errorf("fetch initial ATX for ID %s: %w", nodeID.ShortString(), err)
}

Check warning on line 683 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L682-L683

Added lines #L682 - L683 were not covered by tests

// TODO(mafa): implement for v1 initial ATXs: https://github.com/spacemeshos/go-spacemesh/issues/6433
initialAtx, err = h.fetchWireAtx(ctx, h.cdb, initialID)
if err != nil {
return fmt.Errorf("fetch initial ATX blob for ID %s: %w", nodeID.ShortString(), err)
}

Check warning on line 689 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L688-L689

Added lines #L688 - L689 were not covered by tests
}

// TODO(mafa): checkpoints need to include all initial ATXs in full to be able to create this malfeasance proof:
//
// see https://github.com/spacemeshos/go-spacemesh/issues/6436
//
// TODO(mafa): checkpoints need to include all marriage ATXs in full to be able to create malfeasance proofs
// like this one (but also others)
//
// see https://github.com/spacemeshos/go-spacemesh/issues/6435
proof, err := wire.NewInvalidPostProof(h.cdb, atx, initialAtx, nodeID, nipostIndex, invalidPostIndex)
if err != nil {
return fmt.Errorf("creating invalid post proof: %w", err)
}

Check warning on line 703 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L702-L703

Added lines #L702 - L703 were not covered by tests
if err := h.malPublisher.Publish(ctx, nodeID, proof); err != nil {
return fmt.Errorf("publishing malfeasance proof for invalid post: %w", err)
}

Check warning on line 706 in activation/handler_v2.go

View check run for this annotation

Codecov / codecov/patch

activation/handler_v2.go#L705-L706

Added lines #L705 - L706 were not covered by tests
return nil
}

func (h *HandlerV2) checkMalicious(ctx context.Context, tx sql.Transaction, atx *activationTx) (bool, error) {
malicious, err := malfeasance.IsMalicious(tx, atx.SmesherID)
if err != nil {
Expand Down Expand Up @@ -717,7 +750,7 @@

func (h *HandlerV2) fetchWireAtx(
ctx context.Context,
tx sql.Transaction,
tx sql.Executor,
id types.ATXID,
) (*wire.ActivationTxV2, error) {
var blob sql.Blob
Expand Down Expand Up @@ -808,6 +841,7 @@
zap.Stringer("smesher_id", atx.SmesherID),
)

// TODO(mafa): finish proof
var proof wire.Proof
return true, h.malPublisher.Publish(ctx, atx.SmesherID, proof)
}
Expand Down
Loading
Loading