Skip to content

Commit

Permalink
Implement malfeasance2 info method for GRPC API (#6566)
Browse files Browse the repository at this point in the history
## Motivation

Followup for #6557. Now malfeasance2 proofs are actually fetched from the DB and metadata for them returned.
  • Loading branch information
fasmat committed Jan 3, 2025
1 parent 988dd4a commit 65296dd
Show file tree
Hide file tree
Showing 43 changed files with 1,260 additions and 176 deletions.
2 changes: 1 addition & 1 deletion activation/e2e/nipost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func launchPostSupervisor(
provingOpts := activation.DefaultPostProvingOpts()
provingOpts.RandomXMode = activation.PostRandomXModeLight

builder := activation.NewMockAtxBuilder(gomock.NewController(tb))
builder := activation.NewMockatxBuilder(gomock.NewController(tb))
builder.EXPECT().Register(gomock.Any())
ps := activation.NewPostSupervisor(log, postCfg, provingOpts, mgr, builder)
require.NoError(tb, ps.Start(cmdCfg, postOpts, sig))
Expand Down
31 changes: 2 additions & 29 deletions activation/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import (
"github.com/spacemeshos/go-spacemesh/p2p"
"github.com/spacemeshos/go-spacemesh/p2p/pubsub"
"github.com/spacemeshos/go-spacemesh/signing"
"github.com/spacemeshos/go-spacemesh/sql"
"github.com/spacemeshos/go-spacemesh/sql/atxs"
"github.com/spacemeshos/go-spacemesh/system"
)

Expand Down Expand Up @@ -128,7 +126,7 @@ func NewHandler(
beacon: beacon,
tortoise: tortoise,
malPublisher: legacyMalPublisher,
malPublisher2: &MalfeasancePublisher{}, // TODO(mafa): pass real publisher when available
malPublisher2: &MalfeasanceHandlerV2{}, // TODO(mafa): pass real publisher when available
signers: make(map[types.NodeID]*signing.EdSigner),
},

Expand All @@ -145,7 +143,7 @@ func NewHandler(
fetcher: fetcher,
beacon: beacon,
tortoise: tortoise,
malPublisher: &MalfeasancePublisher{}, // TODO(mafa): pass real publisher when available
malPublisher: &MalfeasanceHandlerV2{}, // TODO(mafa): pass real publisher when available
},
}

Expand Down Expand Up @@ -292,28 +290,3 @@ func (h *Handler) handleAtx(ctx context.Context, expHash types.Hash32, peer p2p.
h.inProgress.Forget(key)
return err
}

// Obtain the atxSignature of the given ATX.
func atxSignature(ctx context.Context, db sql.Executor, id types.ATXID) (types.EdSignature, error) {
var blob sql.Blob
v, err := atxs.LoadBlob(ctx, db, id.Bytes(), &blob)
if err != nil {
return types.EmptyEdSignature, err
}

if len(blob.Bytes) == 0 {
// An empty blob indicates a golden ATX (after a checkpoint-recovery).
return types.EmptyEdSignature, fmt.Errorf("can't get signature for a golden (checkpointed) ATX: %s", id)
}

// TODO: implement for ATX V2
switch v {
case types.AtxV1:
var atx wire.ActivationTxV1
if err := codec.Decode(blob.Bytes, &atx); err != nil {
return types.EmptyEdSignature, fmt.Errorf("decoding atx v1: %w", err)
}
return atx.Signature, nil
}
return types.EmptyEdSignature, fmt.Errorf("unsupported ATX version: %v", v)
}
28 changes: 26 additions & 2 deletions activation/handler_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,8 @@ func (h *HandlerV1) storeAtx(ctx context.Context, atx *types.ActivationTx, watx
return fmt.Errorf("store atx: %w", err)
}

added := h.cacheAtx(ctx, atx, malicious)
h.beacon.OnAtx(atx)
if added != nil {
if added := h.cacheAtx(ctx, atx, malicious); added != nil {
h.tortoise.OnAtx(atx.TargetEpoch(), atx.ID(), added)
}

Expand Down Expand Up @@ -631,3 +630,28 @@ func collectAtxDeps(goldenAtxId types.ATXID, atx *wire.ActivationTxV1) (types.Ha

return types.BytesToHash(atx.NIPost.PostMetadata.Challenge), maps.Keys(filtered)
}

// Obtain the signature of the given ATX.
func atxSignature(ctx context.Context, db sql.Executor, id types.ATXID) (types.EdSignature, error) {
var blob sql.Blob
v, err := atxs.LoadBlob(ctx, db, id.Bytes(), &blob)
if err != nil {
return types.EmptyEdSignature, err
}

if len(blob.Bytes) == 0 {
// An empty blob indicates a golden ATX (after a checkpoint-recovery).
return types.EmptyEdSignature, fmt.Errorf("can't get signature for a golden (checkpointed) ATX: %s", id)
}

switch v {
case types.AtxV1:
var atx wire.ActivationTxV1
if err := codec.Decode(blob.Bytes, &atx); err != nil {
return types.EmptyEdSignature, fmt.Errorf("decoding atx v1: %w", err)
}
return atx.Signature, nil
default: // only needed for V1 ATXs
return types.EmptyEdSignature, fmt.Errorf("unsupported ATX version: %v", v)
}
}
2 changes: 1 addition & 1 deletion activation/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ var (
ErrPostClientNotConnected = errors.New("post service not registered")
)

type AtxBuilder interface {
type atxBuilder interface {
Register(sig *signing.EdSigner)
}

Expand Down
34 changes: 31 additions & 3 deletions activation/malfeasance2.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,43 @@ 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"
)

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

func (p *MalfeasancePublisher) Publish(ctx context.Context, id types.NodeID, proof wire.Proof) error {
func NewMalfeasanceHandlerV2() *MalfeasanceHandlerV2 {
return &MalfeasanceHandlerV2{}
}

func (mh *MalfeasanceHandlerV2) decodeProof(data []byte) (wire.Proof, error) {
var atxProof wire.ATXProof
if err := codec.Decode(data, &atxProof); err != nil {
return nil, err
}

proof, err := atxProof.Decode()
if err != nil {
return nil, err
}
return proof, nil
}

func (mh *MalfeasanceHandlerV2) Info(data []byte) (map[string]string, error) {
proof, err := mh.decodeProof(data)
if err != nil {
return nil, fmt.Errorf("decoding ATX malfeasance proof: %w", err)
}
info := proof.Info()
info["type"] = proof.String()
return info, nil
}

func (p *MalfeasanceHandlerV2) Publish(ctx context.Context, id types.NodeID, proof wire.Proof) error {
// TODO(mafa): implement me
return nil
}
91 changes: 91 additions & 0 deletions activation/malfeasance2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package activation

import (
"testing"

"github.com/stretchr/testify/require"

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

type testMalHandler struct {
*MalfeasanceHandlerV2
}

func newTestMalHandler(tb testing.TB) *testMalHandler {
handler := NewMalfeasanceHandlerV2()

return &testMalHandler{
MalfeasanceHandlerV2: handler,
}
}

func TestHandler_Info(t *testing.T) {
t.Parallel()

t.Run("decode proof error", func(t *testing.T) {
t.Parallel()
th := newTestMalHandler(t)

info, err := th.Info([]byte("invalid proof"))
require.Error(t, err)
require.Contains(t, err.Error(), "decoding ATX malfeasance proof")
require.Nil(t, info)
})

tt := []struct {
name string
proofType wire.ProofType
proof wire.Proof
}{
{
name: "double marry proof",
proofType: wire.DoubleMarry,
proof: &wire.ProofDoubleMarry{},
},
{
name: "double merge proof",
proofType: wire.DoubleMerge,
proof: &wire.ProofDoubleMerge{},
},
{
name: "invalid post",
proofType: wire.InvalidPost,
proof: &wire.ProofInvalidPost{},
},
{
name: "invalid prev atx v1",
proofType: wire.InvalidPreviousV1,
proof: &wire.ProofInvalidPrevAtxV1{},
},
{
name: "invalid prev atx v2",
proofType: wire.InvalidPreviousV2,
proof: &wire.ProofInvalidPrevAtxV2{},
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
th := newTestMalHandler(t)

atxProof := &wire.ATXProof{
Version: wire.ProofVersion(1),

ProofType: tc.proofType,
Proof: codec.MustEncode(tc.proof),
}
data, err := codec.Encode(atxProof)
require.NoError(t, err)

expectedInfo := tc.proof.Info()
expectedInfo["type"] = tc.proof.String()

info, err := th.Info(data)
require.NoError(t, err)
require.Equal(t, expectedInfo, info)
})
}
}
40 changes: 20 additions & 20 deletions activation/mocks.go

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

4 changes: 2 additions & 2 deletions activation/post_supervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type PostSupervisor struct {
provingOpts PostProvingOpts

postSetupProvider postSetupProvider
atxBuilder AtxBuilder
atxBuilder atxBuilder

pid atomic.Int64 // pid of the running post service, only for tests.

Expand All @@ -85,7 +85,7 @@ func NewPostSupervisor(
postCfg PostConfig,
provingOpts PostProvingOpts,
postSetupProvider postSetupProvider,
atxBuilder AtxBuilder,
atxBuilder atxBuilder,
) *PostSupervisor {
return &PostSupervisor{
logger: logger,
Expand Down
Loading

0 comments on commit 65296dd

Please sign in to comment.