@@ -679,10 +679,15 @@ func (h *HandlerV2) validatePost(
679
679
if err == nil {
680
680
return nil
681
681
}
682
- errInvalid := & verifying.ErrInvalidIndex {}
683
- if ! errors .As (err , & errInvalid ) {
682
+ errInvalidIdx := & verifying.ErrInvalidIndex {}
683
+ if ! errors .As (err , & errInvalidIdx ) {
684
684
return fmt .Errorf ("validating post for ID %s: %w" , nodeID .ShortString (), err )
685
685
}
686
+ h .logger .Debug ("ATX with invalid post index" ,
687
+ log .ZContext (ctx ),
688
+ zap .Stringer ("atx_id" , atx .ID ()),
689
+ zap .Int ("index" , errInvalidIdx .Index ),
690
+ )
686
691
687
692
// check if post contains at least one valid label
688
693
validIdx := 0
@@ -715,7 +720,7 @@ func (h *HandlerV2) validatePost(
715
720
commitment ,
716
721
nodeID ,
717
722
nipostIndex ,
718
- uint32 (errInvalid .Index ),
723
+ uint32 (errInvalidIdx .Index ),
719
724
uint32 (validIdx ),
720
725
)
721
726
if err != nil {
@@ -724,40 +729,35 @@ func (h *HandlerV2) validatePost(
724
729
if err := h .malPublisher .Publish (ctx , nodeID , proof ); err != nil {
725
730
return fmt .Errorf ("publishing malfeasance proof for invalid post: %w" , err )
726
731
}
727
- return fmt .Errorf ("invalid post for ID %s: %w" , nodeID .ShortString (), errInvalid )
732
+ return fmt .Errorf ("invalid post for ID %s: %w" , nodeID .ShortString (), errInvalidIdx )
728
733
}
729
734
730
- func (h * HandlerV2 ) checkMalicious (ctx context.Context , tx sql.Transaction , atx * activationTx ) (bool , error ) {
731
- malicious , err := malfeasance .IsMalicious (tx , atx .SmesherID )
732
- if err != nil {
733
- return malicious , fmt .Errorf ("checking if node is malicious: %w" , err )
734
- }
735
- if malicious {
736
- return true , nil
737
- }
738
-
739
- malicious , err = h .checkDoubleMarry (ctx , tx , atx )
735
+ func (h * HandlerV2 ) checkMalicious (
736
+ ctx context.Context ,
737
+ tx sql.Transaction ,
738
+ watx * activationTx ,
739
+ ) (wire.Proof , types.NodeID , error ) {
740
+ proof , nodeID , err := h .checkDoubleMarry (ctx , tx , watx )
740
741
if err != nil {
741
- return malicious , fmt .Errorf ("checking double marry: %w" , err )
742
+ return nil , types . EmptyNodeID , fmt .Errorf ("checking double marry: %w" , err )
742
743
}
743
- if malicious {
744
- return true , nil
744
+ if proof != nil {
745
+ return proof , nodeID , nil
745
746
}
746
747
747
- malicious , err = h .checkDoubleMerge (ctx , tx , atx )
748
+ proof , nodeID , err = h .checkDoubleMerge (ctx , tx , watx )
748
749
if err != nil {
749
- return malicious , fmt .Errorf ("checking double merge: %w" , err )
750
+ return nil , types . EmptyNodeID , fmt .Errorf ("checking double merge: %w" , err )
750
751
}
751
- if malicious {
752
- return true , nil
752
+ if proof != nil {
753
+ return proof , nodeID , nil
753
754
}
754
755
755
- malicious , err = h .checkPrevAtx (ctx , tx , atx )
756
+ proof , nodeID , err = h .checkPrevAtx (ctx , tx , watx )
756
757
if err != nil {
757
- return malicious , fmt .Errorf ("checking previous ATX: %w" , err )
758
+ return nil , types . EmptyNodeID , fmt .Errorf ("checking previous ATX: %w" , err )
758
759
}
759
-
760
- return malicious , err
760
+ return proof , nodeID , nil
761
761
}
762
762
763
763
func (h * HandlerV2 ) fetchWireAtx (
@@ -778,11 +778,15 @@ func (h *HandlerV2) fetchWireAtx(
778
778
return atx , nil
779
779
}
780
780
781
- func (h * HandlerV2 ) checkDoubleMarry (ctx context.Context , tx sql.Transaction , atx * activationTx ) (bool , error ) {
781
+ func (h * HandlerV2 ) checkDoubleMarry (
782
+ ctx context.Context ,
783
+ tx sql.Transaction ,
784
+ atx * activationTx ,
785
+ ) (wire.Proof , types.NodeID , error ) {
782
786
for _ , m := range atx .marriages {
783
787
info , err := marriage .FindByNodeID (tx , m .id )
784
788
if err != nil {
785
- return false , fmt .Errorf ("checking if ID is married: %w" , err )
789
+ return nil , types . EmptyNodeID , fmt .Errorf ("checking if ID is married: %w" , err )
786
790
}
787
791
if info .ATX == atx .ID () {
788
792
continue
@@ -795,28 +799,32 @@ func (h *HandlerV2) checkDoubleMarry(ctx context.Context, tx sql.Transaction, at
795
799
zap .Stringer ("atx_id" , info .ATX ),
796
800
)
797
801
case err != nil :
798
- return false , fmt .Errorf ("fetching other ATX: %w" , err )
802
+ return nil , types . EmptyNodeID , fmt .Errorf ("fetching other ATX: %w" , err )
799
803
}
800
804
801
805
proof , err := wire .NewDoubleMarryProof (tx , atx .ActivationTxV2 , otherAtx , m .id )
802
806
if err != nil {
803
- return true , fmt .Errorf ("creating double marry proof: %w" , err )
807
+ return nil , types . EmptyNodeID , fmt .Errorf ("creating double marry proof: %w" , err )
804
808
}
805
- return true , h . malPublisher . Publish ( ctx , m .id , proof )
809
+ return proof , m .id , nil
806
810
}
807
- return false , nil
811
+ return nil , types . EmptyNodeID , nil
808
812
}
809
813
810
- func (h * HandlerV2 ) checkDoubleMerge (ctx context.Context , tx sql.Transaction , atx * activationTx ) (bool , error ) {
814
+ func (h * HandlerV2 ) checkDoubleMerge (
815
+ ctx context.Context ,
816
+ tx sql.Transaction ,
817
+ atx * activationTx ,
818
+ ) (wire.Proof , types.NodeID , error ) {
811
819
if atx .MarriageATX == nil {
812
- return false , nil
820
+ return nil , types . EmptyNodeID , nil
813
821
}
814
822
ids , err := atxs .MergeConflict (tx , * atx .MarriageATX , atx .PublishEpoch )
815
823
switch {
816
824
case errors .Is (err , sql .ErrNotFound ):
817
- return false , nil
825
+ return nil , types . EmptyNodeID , nil
818
826
case err != nil :
819
- return false , fmt .Errorf ("searching for ATXs with the same marriage ATX: %w" , err )
827
+ return nil , types . EmptyNodeID , fmt .Errorf ("searching for ATXs with the same marriage ATX: %w" , err )
820
828
}
821
829
otherIndex := slices .IndexFunc (ids , func (id types.ATXID ) bool { return id != atx .ID () })
822
830
other := ids [otherIndex ]
@@ -836,7 +844,7 @@ func (h *HandlerV2) checkDoubleMerge(ctx context.Context, tx sql.Transaction, at
836
844
// see https://github.com/spacemeshos/go-spacemesh/issues/6434
837
845
otherAtx , err := h .fetchWireAtx (ctx , tx , other )
838
846
if err != nil {
839
- return false , fmt .Errorf ("fetching other ATX: %w" , err )
847
+ return nil , types . EmptyNodeID , fmt .Errorf ("fetching other ATX: %w" , err )
840
848
}
841
849
842
850
// TODO(mafa): checkpoints need to include all marriage ATXs in full to be able to create malfeasance proofs
@@ -845,16 +853,20 @@ func (h *HandlerV2) checkDoubleMerge(ctx context.Context, tx sql.Transaction, at
845
853
// see https://github.com/spacemeshos/go-spacemesh/issues/6435
846
854
proof , err := wire .NewDoubleMergeProof (tx , atx .ActivationTxV2 , otherAtx )
847
855
if err != nil {
848
- return true , fmt .Errorf ("creating double merge proof: %w" , err )
856
+ return nil , types . EmptyNodeID , fmt .Errorf ("creating double merge proof: %w" , err )
849
857
}
850
- return true , h . malPublisher . Publish ( ctx , atx .ActivationTxV2 .SmesherID , proof )
858
+ return proof , atx .ActivationTxV2 .SmesherID , nil
851
859
}
852
860
853
- func (h * HandlerV2 ) checkPrevAtx (ctx context.Context , tx sql.Transaction , atx * activationTx ) (bool , error ) {
861
+ func (h * HandlerV2 ) checkPrevAtx (
862
+ ctx context.Context ,
863
+ tx sql.Transaction ,
864
+ atx * activationTx ,
865
+ ) (wire.Proof , types.NodeID , error ) {
854
866
for id , data := range atx .ids {
855
867
expectedPrevID , err := atxs .PrevIDByNodeID (tx , id , atx .PublishEpoch )
856
868
if err != nil && ! errors .Is (err , sql .ErrNotFound ) {
857
- return false , fmt .Errorf ("get last atx by node id: %w" , err )
869
+ return nil , types . EmptyNodeID , fmt .Errorf ("get last atx by node id: %w" , err )
858
870
}
859
871
if expectedPrevID == data .previous {
860
872
continue
@@ -871,7 +883,7 @@ func (h *HandlerV2) checkPrevAtx(ctx context.Context, tx sql.Transaction, atx *a
871
883
case errors .Is (err , sql .ErrNotFound ):
872
884
continue
873
885
case err != nil :
874
- return true , fmt .Errorf ("checking for previous ATX collision: %w" , err )
886
+ return nil , types . EmptyNodeID , fmt .Errorf ("checking for previous ATX collision: %w" , err )
875
887
}
876
888
877
889
var wireAtxV1 * wire.ActivationTxV1
@@ -882,7 +894,7 @@ func (h *HandlerV2) checkPrevAtx(ctx context.Context, tx sql.Transaction, atx *a
882
894
var blob sql.Blob
883
895
v , err := atxs .LoadBlob (ctx , tx , collision .Bytes (), & blob )
884
896
if err != nil {
885
- return true , fmt .Errorf ("get atx blob %s: %w" , id .ShortString (), err )
897
+ return nil , types . EmptyNodeID , fmt .Errorf ("get atx blob %s: %w" , id .ShortString (), err )
886
898
}
887
899
switch v {
888
900
case types .AtxV1 :
@@ -903,9 +915,9 @@ func (h *HandlerV2) checkPrevAtx(ctx context.Context, tx sql.Transaction, atx *a
903
915
)
904
916
proof , err := wire .NewInvalidPrevAtxProofV2 (tx , atx .ActivationTxV2 , wireAtx , id )
905
917
if err != nil {
906
- return true , fmt .Errorf ("creating invalid previous ATX proof: %w" , err )
918
+ return nil , types . EmptyNodeID , fmt .Errorf ("creating invalid previous ATX proof: %w" , err )
907
919
}
908
- return true , h . malPublisher . Publish ( ctx , id , proof )
920
+ return proof , id , nil
909
921
default :
910
922
h .logger .Fatal ("Failed to create invalid previous ATX proof: unknown ATX version" ,
911
923
zap .Stringer ("atx_id" , collision ),
@@ -921,16 +933,19 @@ func (h *HandlerV2) checkPrevAtx(ctx context.Context, tx sql.Transaction, atx *a
921
933
)
922
934
proof , err := wire .NewInvalidPrevAtxProofV1 (tx , atx .ActivationTxV2 , wireAtxV1 , id )
923
935
if err != nil {
924
- return true , fmt .Errorf ("creating invalid previous ATX proof: %w" , err )
936
+ return nil , types . EmptyNodeID , fmt .Errorf ("creating invalid previous ATX proof: %w" , err )
925
937
}
926
- return true , h . malPublisher . Publish ( ctx , id , proof )
938
+ return proof , id , nil
927
939
}
928
- return false , nil
940
+ return nil , types . EmptyNodeID , nil
929
941
}
930
942
931
943
// Store an ATX in the DB.
932
944
func (h * HandlerV2 ) storeAtx (ctx context.Context , atx * types.ActivationTx , watx * activationTx ) error {
933
945
republishProof := false
946
+ malicious := false
947
+ var proof wire.Proof
948
+ var nodeID types.NodeID
934
949
if err := h .cdb .WithTxImmediate (ctx , func (tx sql.Transaction ) error {
935
950
if len (watx .marriages ) != 0 {
936
951
newMarriageID , err := marriage .NewID (tx )
@@ -942,7 +957,6 @@ func (h *HandlerV2) storeAtx(ctx context.Context, atx *types.ActivationTx, watx
942
957
ATX : atx .ID (),
943
958
Target : atx .SmesherID ,
944
959
}
945
- malicious := false
946
960
marriageIDs := make (map [marriage.ID ]struct {}, 1 )
947
961
marriageIDs [newMarriageID ] = struct {}{}
948
962
for i , m := range watx .marriages {
@@ -1009,34 +1023,44 @@ func (h *HandlerV2) storeAtx(ctx context.Context, atx *types.ActivationTx, watx
1009
1023
return fmt .Errorf ("setting atx units for ID %s: %w" , id , err )
1010
1024
}
1011
1025
}
1012
- return nil
1013
- }); err != nil {
1014
- return fmt .Errorf ("store atx: %w" , err )
1015
- }
1016
1026
1017
- malicious := false
1018
- err := h .cdb .WithTxImmediate (ctx , func (tx sql.Transaction ) error {
1027
+ if malicious || republishProof {
1028
+ return nil
1029
+ }
1030
+
1019
1031
// malfeasance check happens after storing the ATX because storing updates the marriage set
1020
1032
// that is needed for the malfeasance proof
1021
1033
//
1022
1034
// TODO(mafa): don't store own ATX if it would mark the node as malicious
1023
1035
// this probably needs to be done by validating and storing own ATXs eagerly and skipping validation in
1024
1036
// the gossip handler (not sync!)
1025
- if republishProof {
1026
- malicious = true
1027
- return h .malPublisher .Regossip (ctx , atx .SmesherID )
1028
- }
1029
-
1030
- var err error
1031
- malicious , err = h .checkMalicious (ctx , tx , watx )
1037
+ proof , nodeID , err = h .checkMalicious (ctx , tx , watx )
1032
1038
return err
1033
- })
1034
- if err != nil {
1035
- return fmt .Errorf ("check malicious: %w" , err )
1039
+ }); err != nil {
1040
+ return fmt .Errorf ("store atx: %w" , err )
1041
+ }
1042
+
1043
+ switch {
1044
+ case republishProof : // marriage set of known malicious smesher has changed, force re-gossip of proof
1045
+ if err := h .malPublisher .Regossip (ctx , watx .SmesherID ); err != nil {
1046
+ h .logger .Error ("failed to regossip malfeasance proof" ,
1047
+ zap .Stringer ("atx_id" , watx .ID ()),
1048
+ zap .Stringer ("smesher_id" , watx .SmesherID ),
1049
+ zap .Error (err ),
1050
+ )
1051
+ }
1052
+ case proof != nil : // new malfeasance proof for identity created, publish proof (gossip is decided by publisher)
1053
+ if err := h .malPublisher .Publish (ctx , nodeID , proof ); err != nil {
1054
+ h .logger .Error ("failed to publish malfeasance proof" ,
1055
+ zap .Stringer ("atx_id" , watx .ID ()),
1056
+ zap .Stringer ("smesher_id" , watx .SmesherID ),
1057
+ zap .Error (err ),
1058
+ )
1059
+ }
1036
1060
}
1037
1061
1038
1062
h .beacon .OnAtx (atx )
1039
- if added := h .atxsdata .AddFromAtx (atx , malicious ); added != nil {
1063
+ if added := h .atxsdata .AddFromAtx (atx , malicious || proof != nil ); added != nil {
1040
1064
h .tortoise .OnAtx (atx .TargetEpoch (), atx .ID (), added )
1041
1065
}
1042
1066
0 commit comments