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 }