github.com/koko1123/flow-go-1@v0.29.6/module/epochs/epoch_lookup.go (about)

     1  package epochs
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/koko1123/flow-go-1/state/protocol"
     8  )
     9  
    10  // EpochLookup implements the EpochLookup interface using protocol state to
    11  // match views to epochs.
    12  type EpochLookup struct {
    13  	state protocol.State
    14  }
    15  
    16  // NewEpochLookup instantiates a new EpochLookup
    17  func NewEpochLookup(state protocol.State) *EpochLookup {
    18  	return &EpochLookup{
    19  		state: state,
    20  	}
    21  }
    22  
    23  // EpochForView returns the counter of the epoch that the view belongs to.
    24  // The protocol.State#Epochs object exposes previous, current, and next epochs,
    25  // which should be all we need. In general, we can't guarantee that a node will
    26  // have access to epoch data beyond these three, so it is safe to throw an error
    27  // for a query that doesn't fit within the view bounds of these three epochs
    28  // (even if the node does happen to have that stored in the underlying storage)
    29  // -- these queries indicate a bug in the querier.
    30  func (l *EpochLookup) EpochForView(view uint64) (epochCounter uint64, err error) {
    31  	epochs := l.state.Final().Epochs()
    32  	previous := epochs.Previous()
    33  	current := epochs.Current()
    34  	next := epochs.Next()
    35  
    36  	for _, epoch := range []protocol.Epoch{previous, current, next} {
    37  		counter, err := epoch.Counter()
    38  		if errors.Is(err, protocol.ErrNoPreviousEpoch) {
    39  			continue
    40  		}
    41  		if err != nil {
    42  			return 0, err
    43  		}
    44  
    45  		firstView, err := epoch.FirstView()
    46  		if err != nil {
    47  			return 0, err
    48  		}
    49  		finalView, err := epoch.FinalView()
    50  		if err != nil {
    51  			return 0, err
    52  		}
    53  		if firstView <= view && view <= finalView {
    54  			return counter, nil
    55  		}
    56  	}
    57  
    58  	return 0, fmt.Errorf("couldn't get epoch for view %d", view)
    59  }
    60  
    61  // EpochForViewWithFallback returns the counter of the epoch that the input
    62  // view belongs to, with the same rules as EpochForView, except that this
    63  // function will return the last committed epoch counter in perpetuity in the
    64  // case that any epoch preparation. For example, if we are in epoch 10, and
    65  // reach the final view of epoch 10 before epoch 11 has finished being setup,
    66  // this function will return 10 even after the final view of epoch 10.
    67  func (l *EpochLookup) EpochForViewWithFallback(view uint64) (uint64, error) {
    68  
    69  	epochs := l.state.Final().Epochs()
    70  	current := epochs.Current()
    71  	next := epochs.Next()
    72  
    73  	// TMP: EMERGENCY EPOCH CHAIN CONTINUATION [EECC]
    74  	//
    75  	// If the given view is within the bounds of the next epoch, and the epoch
    76  	// has not been set up or committed, we pretend that we are still in the
    77  	// current epoch and return that epoch's counter.
    78  	//
    79  	// This is used to determine which Random Beacon key we will use to sign and
    80  	// verify blocks and votes. The failure case we are avoiding here is if the
    81  	// DKG for next epoch failed and there is no Random Beacon key for that epoch,
    82  	// or if the next epoch failed for any other reason. In either case we will
    83  	// continue using the last valid Random Beacon key until the next spork.
    84  	//
    85  	currentFinalView, err := current.FinalView()
    86  	if err != nil {
    87  		return 0, err
    88  	}
    89  	if view > currentFinalView {
    90  		_, err := next.DKG() // either of the following errors indicates that we have transitioned into EECC
    91  		if errors.Is(err, protocol.ErrEpochNotCommitted) || errors.Is(err, protocol.ErrNextEpochNotSetup) {
    92  			return current.Counter()
    93  		}
    94  		if err != nil {
    95  			return 0, fmt.Errorf("unexpected error in EECC logic while retrieving DKG data: %w", err)
    96  		}
    97  	}
    98  
    99  	// HAPPY PATH logic
   100  	return l.EpochForView(view)
   101  }