github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/slashing/consumer.go (about)

     1  package slashing
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/onflow/flow-go/model/flow"
     9  	"github.com/onflow/flow-go/module"
    10  	"github.com/onflow/flow-go/network"
    11  	"github.com/onflow/flow-go/network/alsp"
    12  	"github.com/onflow/flow-go/utils/logging"
    13  )
    14  
    15  const (
    16  	unknown = "unknown"
    17  )
    18  
    19  // Consumer is a struct that logs a message for any slashable offenses.
    20  // This struct will be updated in the future when slashing is implemented.
    21  type Consumer struct {
    22  	log                       zerolog.Logger
    23  	metrics                   module.NetworkSecurityMetrics
    24  	misbehaviorReportConsumer network.MisbehaviorReportConsumer
    25  }
    26  
    27  // NewSlashingViolationsConsumer returns a new Consumer.
    28  func NewSlashingViolationsConsumer(log zerolog.Logger, metrics module.NetworkSecurityMetrics, misbehaviorReportConsumer network.MisbehaviorReportConsumer) *Consumer {
    29  	return &Consumer{
    30  		log:                       log.With().Str("module", "network_slashing_consumer").Logger(),
    31  		metrics:                   metrics,
    32  		misbehaviorReportConsumer: misbehaviorReportConsumer,
    33  	}
    34  }
    35  
    36  // logOffense logs the slashing violation with details.
    37  func (c *Consumer) logOffense(misbehavior network.Misbehavior, violation *network.Violation) {
    38  	// if violation fails before the message is decoded the violation.MsgType will be unknown
    39  	if len(violation.MsgType) == 0 {
    40  		violation.MsgType = unknown
    41  	}
    42  
    43  	// if violation fails for an unknown peer violation.Identity will be nil
    44  	role := unknown
    45  	nodeID := flow.ZeroID
    46  	if violation.Identity != nil {
    47  		role = violation.Identity.Role.String()
    48  		nodeID = violation.Identity.NodeID
    49  	}
    50  
    51  	e := c.log.Error().
    52  		Str("peer_id", violation.PeerID).
    53  		Str("misbehavior", misbehavior.String()).
    54  		Str("message_type", violation.MsgType).
    55  		Str("channel", violation.Channel.String()).
    56  		Str("protocol", violation.Protocol.String()).
    57  		Bool(logging.KeySuspicious, true).
    58  		Str("role", role).
    59  		Hex("sender_id", logging.ID(nodeID))
    60  
    61  	e.Msg(fmt.Sprintf("potential slashable offense: %s", violation.Err))
    62  
    63  	// capture unauthorized message count metric
    64  	c.metrics.OnUnauthorizedMessage(role, violation.MsgType, violation.Channel.String(), misbehavior.String())
    65  }
    66  
    67  // reportMisbehavior reports the slashing violation to the alsp misbehavior report manager. When violation identity
    68  // is nil this indicates the misbehavior occurred either on a public network and the identity of the sender is unknown
    69  // we can skip reporting the misbehavior.
    70  // Args:
    71  // - misbehavior: the network misbehavior.
    72  // - violation: the slashing violation.
    73  // Any error encountered while creating the misbehavior report is considered irrecoverable and will result in a fatal log.
    74  func (c *Consumer) reportMisbehavior(misbehavior network.Misbehavior, violation *network.Violation) {
    75  	if violation.Identity == nil {
    76  		c.log.Debug().
    77  			Bool(logging.KeySuspicious, true).
    78  			Str("peerID", violation.PeerID).
    79  			Msg("violation identity unknown (or public) skipping misbehavior reporting")
    80  		c.metrics.OnViolationReportSkipped()
    81  		return
    82  	}
    83  	report, err := alsp.NewMisbehaviorReport(violation.Identity.NodeID, misbehavior)
    84  	if err != nil {
    85  		// failing to create the misbehavior report is unlikely. If an error is encountered while
    86  		// creating the misbehavior report it indicates a bug and processing can not proceed.
    87  		c.log.Fatal().
    88  			Err(err).
    89  			Str("peerID", violation.PeerID).
    90  			Msg("failed to create misbehavior report")
    91  	}
    92  	c.misbehaviorReportConsumer.ReportMisbehaviorOnChannel(violation.Channel, report)
    93  }
    94  
    95  // OnUnAuthorizedSenderError logs an error for unauthorized sender error and reports a misbehavior to alsp misbehavior report manager.
    96  func (c *Consumer) OnUnAuthorizedSenderError(violation *network.Violation) {
    97  	c.logOffense(alsp.UnAuthorizedSender, violation)
    98  	c.reportMisbehavior(alsp.UnAuthorizedSender, violation)
    99  }
   100  
   101  // OnUnknownMsgTypeError logs an error for unknown message type error and reports a misbehavior to alsp misbehavior report manager.
   102  func (c *Consumer) OnUnknownMsgTypeError(violation *network.Violation) {
   103  	c.logOffense(alsp.UnknownMsgType, violation)
   104  	c.reportMisbehavior(alsp.UnknownMsgType, violation)
   105  }
   106  
   107  // OnInvalidMsgError logs an error for messages that contained payloads that could not
   108  // be unmarshalled into the message type denoted by message code byte and reports a misbehavior to alsp misbehavior report manager.
   109  func (c *Consumer) OnInvalidMsgError(violation *network.Violation) {
   110  	c.logOffense(alsp.InvalidMessage, violation)
   111  	c.reportMisbehavior(alsp.InvalidMessage, violation)
   112  }
   113  
   114  // OnSenderEjectedError logs an error for sender ejected error and reports a misbehavior to alsp misbehavior report manager.
   115  func (c *Consumer) OnSenderEjectedError(violation *network.Violation) {
   116  	c.logOffense(alsp.SenderEjected, violation)
   117  	c.reportMisbehavior(alsp.SenderEjected, violation)
   118  }
   119  
   120  // OnUnauthorizedUnicastOnChannel logs an error for messages unauthorized to be sent via unicast and reports a misbehavior to alsp misbehavior report manager.
   121  func (c *Consumer) OnUnauthorizedUnicastOnChannel(violation *network.Violation) {
   122  	c.logOffense(alsp.UnauthorizedUnicastOnChannel, violation)
   123  	c.reportMisbehavior(alsp.UnauthorizedUnicastOnChannel, violation)
   124  }
   125  
   126  // OnUnauthorizedPublishOnChannel logs an error for messages unauthorized to be sent via pubsub.
   127  func (c *Consumer) OnUnauthorizedPublishOnChannel(violation *network.Violation) {
   128  	c.logOffense(alsp.UnauthorizedPublishOnChannel, violation)
   129  	c.reportMisbehavior(alsp.UnauthorizedPublishOnChannel, violation)
   130  }
   131  
   132  // OnUnexpectedError logs an error for unexpected errors. This indicates message validation
   133  // has failed for an unknown reason and could potentially be n slashable offense and reports a misbehavior to alsp misbehavior report manager.
   134  func (c *Consumer) OnUnexpectedError(violation *network.Violation) {
   135  	c.logOffense(alsp.UnExpectedValidationError, violation)
   136  	c.reportMisbehavior(alsp.UnExpectedValidationError, violation)
   137  }