diff --git a/activation/malfeasance.go b/activation/malfeasance.go index 17cae36997..2874a96163 100644 --- a/activation/malfeasance.go +++ b/activation/malfeasance.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "github.com/prometheus/client_golang/prometheus" "github.com/spacemeshos/post/shared" @@ -44,6 +45,19 @@ func NewMalfeasanceHandler( } } +func (mh *MalfeasanceHandler) Info(data wire.ProofData) (map[string]string, error) { + ap, ok := data.(*wire.AtxProof) + if !ok { + return nil, errors.New("wrong message type for multiple ATXs") + } + return map[string]string{ + "atx1": ap.Messages[0].InnerMsg.MsgHash.String(), + "atx2": ap.Messages[1].InnerMsg.MsgHash.String(), + "publish_epoch": strconv.FormatUint(uint64(ap.Messages[0].InnerMsg.PublishEpoch), 10), + "smesher_id": ap.Messages[0].SmesherID.String(), + }, nil +} + func (mh *MalfeasanceHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { ap, ok := data.(*wire.AtxProof) if !ok { @@ -109,6 +123,18 @@ func NewInvalidPostIndexHandler( } } +func (mh *InvalidPostIndexHandler) Info(data wire.ProofData) (map[string]string, error) { + pp, ok := data.(*wire.InvalidPostIndexProof) + if !ok { + return nil, errors.New("wrong message type for invalid post index") + } + return map[string]string{ + "atx": pp.Atx.ID().String(), + "index": strconv.FormatUint(uint64(pp.InvalidIdx), 10), + "smesher_id": pp.Atx.SmesherID.String(), + }, nil +} + func (mh *InvalidPostIndexHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { proof, ok := data.(*wire.InvalidPostIndexProof) if !ok { @@ -174,6 +200,19 @@ func NewInvalidPrevATXHandler( } } +func (mh *InvalidPrevATXHandler) Info(data wire.ProofData) (map[string]string, error) { + pp, ok := data.(*wire.InvalidPrevATXProof) + if !ok { + return nil, errors.New("wrong message type for invalid previous ATX") + } + return map[string]string{ + "atx1": pp.Atx1.ID().String(), + "atx2": pp.Atx2.ID().String(), + "prev_atx": pp.Atx1.PrevATXID.String(), + "smesher_id": pp.Atx1.SmesherID.String(), + }, nil +} + func (mh *InvalidPrevATXHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { proof, ok := data.(*wire.InvalidPrevATXProof) if !ok { diff --git a/api/grpcserver/v2alpha1/malfeasance.go b/api/grpcserver/v2alpha1/malfeasance.go index 46ab6db7d9..45541e1ef7 100644 --- a/api/grpcserver/v2alpha1/malfeasance.go +++ b/api/grpcserver/v2alpha1/malfeasance.go @@ -2,10 +2,12 @@ package v2alpha1 import ( "context" + "strconv" "time" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" spacemeshv2alpha1 "github.com/spacemeshos/api/release/go/spacemesh/v2alpha1" + "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -16,12 +18,31 @@ import ( "github.com/spacemeshos/go-spacemesh/sql/identities" ) -func NewMalfeasanceService(db sql.Executor) *MalfeasanceService { - return &MalfeasanceService{db: db} +const ( + Malfeasance = "malfeasance_v2alpha1" + MalfeasanceStream = "malfeasance_stream_v2alpha1" +) + +type malfeasanceInfo interface { + Info(data []byte) (map[string]string, error) +} + +func NewMalfeasanceService( + db sql.Executor, + logger *zap.Logger, + malfeasanceHandler malfeasanceInfo, +) *MalfeasanceService { + return &MalfeasanceService{ + db: db, + logger: logger, + info: malfeasanceHandler, + } } type MalfeasanceService struct { - db sql.Executor + db sql.Executor + logger *zap.Logger + info malfeasanceInfo } func (s *MalfeasanceService) RegisterService(server *grpc.Server) { @@ -54,15 +75,11 @@ func (s *MalfeasanceService) List( rst := make([]*spacemeshv2alpha1.MalfeasanceProof, 0, request.Limit) if err := identities.IterateMaliciousOps(s.db, ops, func(id types.NodeID, proof []byte, received time.Time) bool { - // TODO (mafa): fetch info about proof from malfeasance service - proofType := uint32(0) - properties := make(map[string]string) - rst = append(rst, &spacemeshv2alpha1.MalfeasanceProof{ - Smesher: id.Bytes(), - Domain: spacemeshv2alpha1.MalfeasanceProof_DOMAIN_UNSPECIFIED, - Type: proofType, - Properties: properties, - }) + result := s.toProof(id, proof) + if result == nil { + return true + } + rst = append(rst, result) return true }); err != nil { return nil, status.Error(codes.Internal, err.Error()) @@ -71,12 +88,59 @@ func (s *MalfeasanceService) List( return &spacemeshv2alpha1.MalfeasanceList{Malfeasances: rst}, nil } -func NewMalfeasanceStreamService(db sql.Executor) *MalfeasanceStreamService { - return &MalfeasanceStreamService{db: db} +func (s *MalfeasanceService) toProof(id types.NodeID, proof []byte) *spacemeshv2alpha1.MalfeasanceProof { + properties, err := s.info.Info(proof) + if err != nil { + s.logger.Debug("failed to get malfeasance info", + zap.String("smesher", id.String()), + zap.Error(err), + ) + return nil + } + domain, err := strconv.ParseUint(properties["domain"], 10, 64) + if err != nil { + s.logger.Debug("failed to parse proof domain", + zap.String("smesher", id.String()), + zap.String("domain", properties["domain"]), + zap.Error(err), + ) + return nil + } + delete(properties, "domain") + proofType, err := strconv.ParseUint(properties["type"], 10, 32) + if err != nil { + s.logger.Debug("failed to parse proof type", + zap.String("smesher", id.String()), + zap.String("type", properties["type"]), + zap.Error(err), + ) + return nil + } + delete(properties, "type") + return &spacemeshv2alpha1.MalfeasanceProof{ + Smesher: id.Bytes(), + Domain: spacemeshv2alpha1.MalfeasanceProof_MalfeasanceDomain(domain), + Type: uint32(proofType), + Properties: properties, + } +} + +func NewMalfeasanceStreamService( + db sql.Executor, + logger *zap.Logger, + malfeasanceHandler malfeasanceInfo, +) *MalfeasanceStreamService { + return &MalfeasanceStreamService{ + db: db, + logger: logger, + info: malfeasanceHandler, + } } type MalfeasanceStreamService struct { - db sql.Executor + db sql.Executor + logger *zap.Logger + info malfeasanceInfo } func (s *MalfeasanceStreamService) RegisterService(server *grpc.Server) { diff --git a/hare3/malfeasance.go b/hare3/malfeasance.go index e71a9c6985..e7128ea3bd 100644 --- a/hare3/malfeasance.go +++ b/hare3/malfeasance.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" @@ -52,6 +53,20 @@ func NewMalfeasanceHandler( return mh } +func (mh *MalfeasanceHandler) Info(data wire.ProofData) (map[string]string, error) { + hp, ok := data.(*wire.HareProof) + if !ok { + return nil, errors.New("wrong message type for hare equivocation") + } + return map[string]string{ + "msg1": hp.Messages[0].InnerMsg.MsgHash.String(), + "msg2": hp.Messages[1].InnerMsg.MsgHash.String(), + "layer": hp.Messages[0].InnerMsg.Layer.String(), + "round": strconv.FormatUint(uint64(hp.Messages[0].InnerMsg.Round), 10), + "smesher_id": hp.Messages[0].SmesherID.String(), + }, nil +} + func (mh *MalfeasanceHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { hp, ok := data.(*wire.HareProof) if !ok { diff --git a/malfeasance/handler.go b/malfeasance/handler.go index 52e12bcedd..9c109814db 100644 --- a/malfeasance/handler.go +++ b/malfeasance/handler.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "slices" + "strconv" "time" "go.uber.org/zap" @@ -92,6 +93,24 @@ func (h *Handler) countInvalidProof(p *wire.MalfeasanceProof) { h.handlers[MalfeasanceType(p.Proof.Type)].ReportInvalidProof(numInvalidProofs) } +func (h *Handler) Info(data []byte) (map[string]string, error) { + var p wire.MalfeasanceProof + if err := codec.Decode(data, &p); err != nil { + return nil, fmt.Errorf("decode malfeasance proof: %w", err) + } + mh, ok := h.handlers[MalfeasanceType(p.Proof.Type)] + if !ok { + return nil, fmt.Errorf("unknown malfeasance type %d", p.Proof.Type) + } + properties, err := mh.Info(p.Proof.Data) + if err != nil { + return nil, fmt.Errorf("malfeasance info: %w", err) + } + properties["domain"] = "0" // for malfeasance V1 there are no domains + properties["type"] = strconv.FormatUint(uint64(p.Proof.Type), 10) + return properties, nil +} + // HandleSyncedMalfeasanceProof is the sync validator for MalfeasanceProof. func (h *Handler) HandleSyncedMalfeasanceProof( ctx context.Context, diff --git a/malfeasance/interface.go b/malfeasance/interface.go index ab6d8bcf6c..3486d5878f 100644 --- a/malfeasance/interface.go +++ b/malfeasance/interface.go @@ -17,6 +17,7 @@ type tortoise interface { type MalfeasanceHandler interface { Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) + Info(data wire.ProofData) (map[string]string, error) ReportProof(vec *prometheus.CounterVec) ReportInvalidProof(vec *prometheus.CounterVec) } diff --git a/malfeasance/mocks.go b/malfeasance/mocks.go index ef1a7c1c86..f123149e61 100644 --- a/malfeasance/mocks.go +++ b/malfeasance/mocks.go @@ -78,165 +78,142 @@ func (c *MocktortoiseOnMalfeasanceCall) DoAndReturn(f func(types.NodeID)) *Mockt return c } -// MockHandlerV1 is a mock of HandlerV1 interface. -type MockHandlerV1 struct { +// MockMalfeasanceHandler is a mock of MalfeasanceHandler interface. +type MockMalfeasanceHandler struct { ctrl *gomock.Controller - recorder *MockHandlerV1MockRecorder + recorder *MockMalfeasanceHandlerMockRecorder } -// MockHandlerV1MockRecorder is the mock recorder for MockHandlerV1. -type MockHandlerV1MockRecorder struct { - mock *MockHandlerV1 +// MockMalfeasanceHandlerMockRecorder is the mock recorder for MockMalfeasanceHandler. +type MockMalfeasanceHandlerMockRecorder struct { + mock *MockMalfeasanceHandler } // NewMockMalfeasanceHandler creates a new mock instance. -func NewMockMalfeasanceHandler(ctrl *gomock.Controller) *MockHandlerV1 { - mock := &MockHandlerV1{ctrl: ctrl} - mock.recorder = &MockHandlerV1MockRecorder{mock} +func NewMockMalfeasanceHandler(ctrl *gomock.Controller) *MockMalfeasanceHandler { + mock := &MockMalfeasanceHandler{ctrl: ctrl} + mock.recorder = &MockMalfeasanceHandlerMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHandlerV1) EXPECT() *MockHandlerV1MockRecorder { +func (m *MockMalfeasanceHandler) EXPECT() *MockMalfeasanceHandlerMockRecorder { return m.recorder } -// ReportInvalidProof mocks base method. -func (m *MockHandlerV1) ReportInvalidProof(vec *prometheus.CounterVec) { +// Info mocks base method. +func (m *MockMalfeasanceHandler) Info(data wire.ProofData) (map[string]string, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "ReportInvalidProof", vec) + ret := m.ctrl.Call(m, "Info", data) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// ReportInvalidProof indicates an expected call of ReportInvalidProof. -func (mr *MockHandlerV1MockRecorder) ReportInvalidProof(vec any) *MockHandlerV1ReportInvalidProofCall { +// Info indicates an expected call of Info. +func (mr *MockMalfeasanceHandlerMockRecorder) Info(data any) *MockMalfeasanceHandlerInfoCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReportInvalidProof", reflect.TypeOf((*MockHandlerV1)(nil).ReportInvalidProof), vec) - return &MockHandlerV1ReportInvalidProofCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockMalfeasanceHandler)(nil).Info), data) + return &MockMalfeasanceHandlerInfoCall{Call: call} } -// MockHandlerV1ReportInvalidProofCall wrap *gomock.Call -type MockHandlerV1ReportInvalidProofCall struct { +// MockMalfeasanceHandlerInfoCall wrap *gomock.Call +type MockMalfeasanceHandlerInfoCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockHandlerV1ReportInvalidProofCall) Return() *MockHandlerV1ReportInvalidProofCall { - c.Call = c.Call.Return() +func (c *MockMalfeasanceHandlerInfoCall) Return(arg0 map[string]string, arg1 error) *MockMalfeasanceHandlerInfoCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockHandlerV1ReportInvalidProofCall) Do(f func(*prometheus.CounterVec)) *MockHandlerV1ReportInvalidProofCall { +func (c *MockMalfeasanceHandlerInfoCall) Do(f func(wire.ProofData) (map[string]string, error)) *MockMalfeasanceHandlerInfoCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockHandlerV1ReportInvalidProofCall) DoAndReturn(f func(*prometheus.CounterVec)) *MockHandlerV1ReportInvalidProofCall { +func (c *MockMalfeasanceHandlerInfoCall) DoAndReturn(f func(wire.ProofData) (map[string]string, error)) *MockMalfeasanceHandlerInfoCall { c.Call = c.Call.DoAndReturn(f) return c } -// ReportProof mocks base method. -func (m *MockHandlerV1) ReportProof(vec *prometheus.CounterVec) { +// ReportInvalidProof mocks base method. +func (m *MockMalfeasanceHandler) ReportInvalidProof(vec *prometheus.CounterVec) { m.ctrl.T.Helper() - m.ctrl.Call(m, "ReportProof", vec) + m.ctrl.Call(m, "ReportInvalidProof", vec) } -// ReportProof indicates an expected call of ReportProof. -func (mr *MockHandlerV1MockRecorder) ReportProof(vec any) *MockHandlerV1ReportProofCall { +// ReportInvalidProof indicates an expected call of ReportInvalidProof. +func (mr *MockMalfeasanceHandlerMockRecorder) ReportInvalidProof(vec any) *MockMalfeasanceHandlerReportInvalidProofCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReportProof", reflect.TypeOf((*MockHandlerV1)(nil).ReportProof), vec) - return &MockHandlerV1ReportProofCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReportInvalidProof", reflect.TypeOf((*MockMalfeasanceHandler)(nil).ReportInvalidProof), vec) + return &MockMalfeasanceHandlerReportInvalidProofCall{Call: call} } -// MockHandlerV1ReportProofCall wrap *gomock.Call -type MockHandlerV1ReportProofCall struct { +// MockMalfeasanceHandlerReportInvalidProofCall wrap *gomock.Call +type MockMalfeasanceHandlerReportInvalidProofCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockHandlerV1ReportProofCall) Return() *MockHandlerV1ReportProofCall { +func (c *MockMalfeasanceHandlerReportInvalidProofCall) Return() *MockMalfeasanceHandlerReportInvalidProofCall { c.Call = c.Call.Return() return c } // Do rewrite *gomock.Call.Do -func (c *MockHandlerV1ReportProofCall) Do(f func(*prometheus.CounterVec)) *MockHandlerV1ReportProofCall { +func (c *MockMalfeasanceHandlerReportInvalidProofCall) Do(f func(*prometheus.CounterVec)) *MockMalfeasanceHandlerReportInvalidProofCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockHandlerV1ReportProofCall) DoAndReturn(f func(*prometheus.CounterVec)) *MockHandlerV1ReportProofCall { +func (c *MockMalfeasanceHandlerReportInvalidProofCall) DoAndReturn(f func(*prometheus.CounterVec)) *MockMalfeasanceHandlerReportInvalidProofCall { c.Call = c.Call.DoAndReturn(f) return c } -// Validate mocks base method. -func (m *MockHandlerV1) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { +// ReportProof mocks base method. +func (m *MockMalfeasanceHandler) ReportProof(vec *prometheus.CounterVec) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Validate", ctx, data) - ret0, _ := ret[0].(types.NodeID) - ret1, _ := ret[1].(error) - return ret0, ret1 + m.ctrl.Call(m, "ReportProof", vec) } -// Validate indicates an expected call of Validate. -func (mr *MockHandlerV1MockRecorder) Validate(ctx, data any) *MockHandlerV1ValidateCall { +// ReportProof indicates an expected call of ReportProof. +func (mr *MockMalfeasanceHandlerMockRecorder) ReportProof(vec any) *MockMalfeasanceHandlerReportProofCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockHandlerV1)(nil).Validate), ctx, data) - return &MockHandlerV1ValidateCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReportProof", reflect.TypeOf((*MockMalfeasanceHandler)(nil).ReportProof), vec) + return &MockMalfeasanceHandlerReportProofCall{Call: call} } -// MockHandlerV1ValidateCall wrap *gomock.Call -type MockHandlerV1ValidateCall struct { +// MockMalfeasanceHandlerReportProofCall wrap *gomock.Call +type MockMalfeasanceHandlerReportProofCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockHandlerV1ValidateCall) Return(arg0 types.NodeID, arg1 error) *MockHandlerV1ValidateCall { - c.Call = c.Call.Return(arg0, arg1) +func (c *MockMalfeasanceHandlerReportProofCall) Return() *MockMalfeasanceHandlerReportProofCall { + c.Call = c.Call.Return() return c } // Do rewrite *gomock.Call.Do -func (c *MockHandlerV1ValidateCall) Do(f func(context.Context, wire.ProofData) (types.NodeID, error)) *MockHandlerV1ValidateCall { +func (c *MockMalfeasanceHandlerReportProofCall) Do(f func(*prometheus.CounterVec)) *MockMalfeasanceHandlerReportProofCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockHandlerV1ValidateCall) DoAndReturn(f func(context.Context, wire.ProofData) (types.NodeID, error)) *MockHandlerV1ValidateCall { +func (c *MockMalfeasanceHandlerReportProofCall) DoAndReturn(f func(*prometheus.CounterVec)) *MockMalfeasanceHandlerReportProofCall { c.Call = c.Call.DoAndReturn(f) return c } -// MockHandlerV2 is a mock of HandlerV2 interface. -type MockHandlerV2 struct { - ctrl *gomock.Controller - recorder *MockHandlerV2MockRecorder -} - -// MockHandlerV2MockRecorder is the mock recorder for MockHandlerV2. -type MockHandlerV2MockRecorder struct { - mock *MockHandlerV2 -} - -// NewMockHandlerV2 creates a new mock instance. -func NewMockHandlerV2(ctrl *gomock.Controller) *MockHandlerV2 { - mock := &MockHandlerV2{ctrl: ctrl} - mock.recorder = &MockHandlerV2MockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockHandlerV2) EXPECT() *MockHandlerV2MockRecorder { - return m.recorder -} - // Validate mocks base method. -func (m *MockHandlerV2) Validate(ctx context.Context, data []byte) (types.NodeID, error) { +func (m *MockMalfeasanceHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Validate", ctx, data) ret0, _ := ret[0].(types.NodeID) @@ -245,31 +222,31 @@ func (m *MockHandlerV2) Validate(ctx context.Context, data []byte) (types.NodeID } // Validate indicates an expected call of Validate. -func (mr *MockHandlerV2MockRecorder) Validate(ctx, data any) *MockHandlerV2ValidateCall { +func (mr *MockMalfeasanceHandlerMockRecorder) Validate(ctx, data any) *MockMalfeasanceHandlerValidateCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockHandlerV2)(nil).Validate), ctx, data) - return &MockHandlerV2ValidateCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockMalfeasanceHandler)(nil).Validate), ctx, data) + return &MockMalfeasanceHandlerValidateCall{Call: call} } -// MockHandlerV2ValidateCall wrap *gomock.Call -type MockHandlerV2ValidateCall struct { +// MockMalfeasanceHandlerValidateCall wrap *gomock.Call +type MockMalfeasanceHandlerValidateCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockHandlerV2ValidateCall) Return(arg0 types.NodeID, arg1 error) *MockHandlerV2ValidateCall { +func (c *MockMalfeasanceHandlerValidateCall) Return(arg0 types.NodeID, arg1 error) *MockMalfeasanceHandlerValidateCall { c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockHandlerV2ValidateCall) Do(f func(context.Context, []byte) (types.NodeID, error)) *MockHandlerV2ValidateCall { +func (c *MockMalfeasanceHandlerValidateCall) Do(f func(context.Context, wire.ProofData) (types.NodeID, error)) *MockMalfeasanceHandlerValidateCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockHandlerV2ValidateCall) DoAndReturn(f func(context.Context, []byte) (types.NodeID, error)) *MockHandlerV2ValidateCall { +func (c *MockMalfeasanceHandlerValidateCall) DoAndReturn(f func(context.Context, wire.ProofData) (types.NodeID, error)) *MockMalfeasanceHandlerValidateCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/mesh/malfeasance.go b/mesh/malfeasance.go index ad3f090e2a..fc074aa221 100644 --- a/mesh/malfeasance.go +++ b/mesh/malfeasance.go @@ -50,6 +50,19 @@ func NewMalfeasanceHandler( return mh } +func (mh *MalfeasanceHandler) Info(data wire.ProofData) (map[string]string, error) { + bp, ok := data.(*wire.BallotProof) + if !ok { + return nil, errors.New("wrong message type for multi ballots") + } + return map[string]string{ + "msg1": bp.Messages[0].InnerMsg.MsgHash.String(), + "msg2": bp.Messages[1].InnerMsg.MsgHash.String(), + "layer": bp.Messages[0].InnerMsg.Layer.String(), + "smesher_id": bp.Messages[0].SmesherID.String(), + }, nil +} + func (mh *MalfeasanceHandler) Validate(ctx context.Context, data wire.ProofData) (types.NodeID, error) { bp, ok := data.(*wire.BallotProof) if !ok { diff --git a/node/node.go b/node/node.go index a583798ef1..da94164090 100644 --- a/node/node.go +++ b/node/node.go @@ -370,52 +370,53 @@ func New(opts ...Option) *App { // App is the cli app singleton. type App struct { *cobra.Command - fileLock *flock.Flock - signers []*signing.EdSigner - Config *config.Config - db sql.StateDatabase - cachedDB *datastore.CachedDB - dbMetrics *dbmetrics.DBMetricsCollector - localDB sql.LocalDatabase - grpcPublicServer *grpcserver.Server - grpcPrivateServer *grpcserver.Server - grpcPostServer *grpcserver.Server - grpcTLSServer *grpcserver.Server - jsonAPIServer *grpcserver.JSONHTTPServer - grpcServices map[grpcserver.Service]grpcserver.ServiceAPI - pprofService *http.Server - profilerService *pyroscope.Profiler - syncer *syncer.Syncer - proposalListener *proposals.Handler - proposalBuilder *miner.ProposalBuilder - mesh *mesh.Mesh - atxsdata *atxsdata.Data - clock *timesync.NodeClock - hare3 *hare3.Hare - hare4 *hare4.Hare - hareResultsChan chan hare4.ConsensusOutput - hOracle *eligibility.Oracle - blockGen *blocks.Generator - certifier *blocks.Certifier - atxBuilder *activation.Builder - nipostBuilder *activation.NIPostBuilder - atxHandler *activation.Handler - txHandler *txs.TxHandler - validator *activation.Validator - edVerifier *signing.EdVerifier - beaconProtocol *beacon.ProtocolDriver - log log.Log - syncLogger log.Log - svm *vm.VM - conState *txs.ConservativeState - fetcher *fetch.Fetch - ptimesync *peersync.Sync - tortoise *tortoise.Tortoise - updater *bootstrap.Updater - poetDb *activation.PoetDb - postVerifier activation.PostVerifier - postSupervisor *activation.PostSupervisor - errCh chan error + fileLock *flock.Flock + signers []*signing.EdSigner + Config *config.Config + db sql.StateDatabase + cachedDB *datastore.CachedDB + dbMetrics *dbmetrics.DBMetricsCollector + localDB sql.LocalDatabase + grpcPublicServer *grpcserver.Server + grpcPrivateServer *grpcserver.Server + grpcPostServer *grpcserver.Server + grpcTLSServer *grpcserver.Server + jsonAPIServer *grpcserver.JSONHTTPServer + grpcServices map[grpcserver.Service]grpcserver.ServiceAPI + pprofService *http.Server + profilerService *pyroscope.Profiler + syncer *syncer.Syncer + proposalListener *proposals.Handler + proposalBuilder *miner.ProposalBuilder + mesh *mesh.Mesh + atxsdata *atxsdata.Data + clock *timesync.NodeClock + hare3 *hare3.Hare + hare4 *hare4.Hare + hareResultsChan chan hare4.ConsensusOutput + hOracle *eligibility.Oracle + blockGen *blocks.Generator + certifier *blocks.Certifier + atxBuilder *activation.Builder + nipostBuilder *activation.NIPostBuilder + atxHandler *activation.Handler + txHandler *txs.TxHandler + validator *activation.Validator + edVerifier *signing.EdVerifier + beaconProtocol *beacon.ProtocolDriver + log log.Log + syncLogger log.Log + svm *vm.VM + conState *txs.ConservativeState + fetcher *fetch.Fetch + ptimesync *peersync.Sync + tortoise *tortoise.Tortoise + updater *bootstrap.Updater + poetDb *activation.PoetDb + postVerifier activation.PostVerifier + postSupervisor *activation.PostSupervisor + malfeasanceHandler *malfeasance.Handler + errCh chan error host *p2p.Host @@ -1143,18 +1144,18 @@ func (app *App) initServices(ctx context.Context) error { for _, s := range app.signers { nodeIDs = append(nodeIDs, s.NodeID()) } - malfeasanceHandler := malfeasance.NewHandler( + app.malfeasanceHandler = malfeasance.NewHandler( app.cachedDB, malfeasanceLogger, app.host.ID(), nodeIDs, trtl, ) - malfeasanceHandler.RegisterHandler(malfeasance.MultipleATXs, activationMH) - malfeasanceHandler.RegisterHandler(malfeasance.MultipleBallots, meshMH) - malfeasanceHandler.RegisterHandler(malfeasance.HareEquivocation, hareMH) - malfeasanceHandler.RegisterHandler(malfeasance.InvalidPostIndex, invalidPostMH) - malfeasanceHandler.RegisterHandler(malfeasance.InvalidPrevATX, invalidPrevMH) + app.malfeasanceHandler.RegisterHandler(malfeasance.MultipleATXs, activationMH) + app.malfeasanceHandler.RegisterHandler(malfeasance.MultipleBallots, meshMH) + app.malfeasanceHandler.RegisterHandler(malfeasance.HareEquivocation, hareMH) + app.malfeasanceHandler.RegisterHandler(malfeasance.InvalidPostIndex, invalidPostMH) + app.malfeasanceHandler.RegisterHandler(malfeasance.InvalidPrevATX, invalidPrevMH) fetcher.SetValidators( fetch.ValidatorFunc( @@ -1199,7 +1200,7 @@ func (app *App) initServices(ctx context.Context) error { ), fetch.ValidatorFunc( pubsub.DropPeerOnSyncValidationReject( - malfeasanceHandler.HandleSyncedMalfeasanceProof, + app.malfeasanceHandler.HandleSyncedMalfeasanceProof, app.host, lg.Zap(), ), @@ -1260,7 +1261,7 @@ func (app *App) initServices(ctx context.Context) error { ) app.host.Register( pubsub.MalfeasanceProof, - pubsub.ChainGossipHandler(atxSyncHandler, malfeasanceHandler.HandleMalfeasanceProof), + pubsub.ChainGossipHandler(atxSyncHandler, app.malfeasanceHandler.HandleMalfeasanceProof), ) app.proposalBuilder = proposalBuilder @@ -1558,10 +1559,27 @@ func (app *App) grpcService(svc grpcserver.Service, lg log.Log) (grpcserver.Serv service := v2alpha1.NewRewardStreamService(app.db) app.grpcServices[svc] = service return service, nil + case v2alpha1.Malfeasance: + service := v2alpha1.NewMalfeasanceService( + app.db, + app.addLogger(MalfeasanceLogger, lg).Zap(), + app.malfeasanceHandler, + ) + app.grpcServices[svc] = service + return service, nil + case v2alpha1.MalfeasanceStream: + service := v2alpha1.NewMalfeasanceStreamService( + app.db, + app.addLogger(MalfeasanceLogger, lg).Zap(), + app.malfeasanceHandler, + ) + app.grpcServices[svc] = service + return service, nil case v2alpha1.Network: service := v2alpha1.NewNetworkService( app.clock.GenesisTime(), - app.Config) + app.Config, + ) app.grpcServices[svc] = service return service, nil case v2alpha1.Node: