github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/model/timeout.go (about)

     1  package model
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/onflow/crypto"
     8  	"github.com/rs/zerolog"
     9  
    10  	"github.com/onflow/flow-go/model/flow"
    11  )
    12  
    13  // TimerInfo represents a local timeout for a view, and indicates the Pacemaker has not yet
    14  // observed evidence to transition to the next view (QC or TC). When a timeout occurs for
    15  // the first time in a view, we will broadcast a TimeoutObject and continue waiting for evidence
    16  // to enter the next view, but we will no longer submit a vote for this view. A timeout may occur
    17  // multiple times for the same round, which is an indication
    18  // to re-broadcast our TimeoutObject for the view, to ensure liveness.
    19  type TimerInfo struct {
    20  	// View is round at which timer was created.
    21  	View uint64
    22  	// StartTime represents time of entering the view.
    23  	StartTime time.Time
    24  	// Duration is how long we waited before timing out the view.
    25  	// It does not include subsequent timeouts (ie. all timeout events emitted for the same
    26  	// view will have the same Duration).
    27  	Duration time.Duration
    28  }
    29  
    30  // NewViewEvent indicates that a new view has started. While it has the same
    31  // data model as `TimerInfo`, their semantics are different (hence we use
    32  // different types): `TimerInfo` represents a continuous time interval. In
    33  // contrast, NewViewEvent marks the specific point in time, when the timer
    34  // is started.
    35  type NewViewEvent TimerInfo
    36  
    37  // TimeoutObject represents intent of replica to leave its current view with a timeout. This concept is very similar to
    38  // HotStuff vote. Valid TimeoutObject is signed by staking key.
    39  type TimeoutObject struct {
    40  	// View is the view number which is replica is timing out
    41  	View uint64
    42  	// NewestQC is the newest QC (by view) known to the creator of this TimeoutObject
    43  	NewestQC *flow.QuorumCertificate
    44  	// LastViewTC is the timeout certificate for previous view if NewestQC.View != View - 1, else nil
    45  	LastViewTC *flow.TimeoutCertificate
    46  	// SignerID is the identifier of replica that has signed this TimeoutObject
    47  	// SignerID must be the origin ID from networking layer, which cryptographically
    48  	//  authenticates the message's sender.
    49  	SignerID flow.Identifier
    50  	// SigData is a BLS signature created by staking key signing View + NewestQC.View
    51  	// This signature is further aggregated in TimeoutCertificate.
    52  	SigData crypto.Signature
    53  	// TimeoutTick is the number of times the `timeout.Controller` has (re-)emitted the
    54  	// timeout for this view. When the timer for the view's original duration expires, a `TimeoutObject`
    55  	// with `TimeoutTick = 0` is broadcast. Subsequently, `timeout.Controller` re-broadcasts the
    56  	// `TimeoutObject` periodically  based on some internal heuristic. Each time we attempt a re-broadcast,
    57  	// the `TimeoutTick` is incremented. Incrementing the field prevents de-duplicated within the network layer,
    58  	// which in turn guarantees quick delivery of the `TimeoutObject` after GST and facilitates recovery.
    59  	// This field is not part of timeout object ID. Thereby, two timeouts are identical if only they differ
    60  	// by their TimeoutTick value.
    61  	TimeoutTick uint64
    62  }
    63  
    64  // ID returns the TimeoutObject's identifier
    65  func (t *TimeoutObject) ID() flow.Identifier {
    66  	body := struct {
    67  		View         uint64
    68  		NewestQCID   flow.Identifier
    69  		LastViewTCID flow.Identifier
    70  		SignerID     flow.Identifier
    71  		SigData      crypto.Signature
    72  	}{
    73  		View:         t.View,
    74  		NewestQCID:   t.NewestQC.ID(),
    75  		LastViewTCID: t.LastViewTC.ID(),
    76  		SignerID:     t.SignerID,
    77  		SigData:      t.SigData,
    78  	}
    79  	return flow.MakeID(body)
    80  }
    81  
    82  func (t *TimeoutObject) String() string {
    83  	return fmt.Sprintf(
    84  		"View: %d, HighestQC.View: %d, LastViewTC: %v, TimeoutTick: %d",
    85  		t.View,
    86  		t.NewestQC.View,
    87  		t.LastViewTC,
    88  		t.TimeoutTick,
    89  	)
    90  }
    91  
    92  // LogContext returns a `zerolog.Contex` including the most important properties of the TC:
    93  //   - view number that this TC is for
    94  //   - view and ID of the block that the included QC points to
    95  //   - number of times a re-broadcast of this timeout was attempted
    96  //   - [optional] if the TC also includes a TC for the prior view, i.e. `LastViewTC` ≠ nil:
    97  //     the new of `LastViewTC` and the view that `LastViewTC.NewestQC` is for
    98  func (t *TimeoutObject) LogContext(logger zerolog.Logger) zerolog.Context {
    99  	logContext := logger.With().
   100  		Uint64("timeout_newest_qc_view", t.NewestQC.View).
   101  		Hex("timeout_newest_qc_block_id", t.NewestQC.BlockID[:]).
   102  		Uint64("timeout_view", t.View).
   103  		Uint64("timeout_tick", t.TimeoutTick)
   104  
   105  	if t.LastViewTC != nil {
   106  		logContext.
   107  			Uint64("last_view_tc_view", t.LastViewTC.View).
   108  			Uint64("last_view_tc_newest_qc_view", t.LastViewTC.NewestQC.View)
   109  	}
   110  	return logContext
   111  }