Skip to content

Commit 69e5251

Browse files
Kubuxumasih
andauthored
Implement backoff on base decisions (#369)
* Implement backoff on base decisions Signed-off-by: Jakub Sztandera <[email protected]> * Address review Signed-off-by: Jakub Sztandera <[email protected]> * Reduce maximum backoff to 10 minutes * Adjust the base of backoff table with exponent of 1.3 --------- Signed-off-by: Jakub Sztandera <[email protected]> Co-authored-by: Masih H. Derkani <[email protected]>
1 parent f2319a9 commit 69e5251

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

gpbft/chain.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ func (c ECChain) IsZero() bool {
143143
return len(c) == 0
144144
}
145145

146+
func (c ECChain) HasSuffix() bool {
147+
return len(c.Suffix()) != 0
148+
}
149+
146150
// Returns the base tipset.
147151
func (c ECChain) Base() *TipSet {
148152
return &c[0]

gpbft/chain_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func TestECChain(t *testing.T) {
3939
require.Len(t, subject, 1)
4040
require.Equal(t, &wantBase, subject.Base())
4141
require.Equal(t, &wantBase, subject.Head())
42+
require.False(t, subject.HasSuffix())
4243
require.NoError(t, subject.Validate())
4344

4445
wantNext := gpbft.TipSet{Epoch: 1, Key: []byte("lobster"), PowerTable: []byte("pt")}
@@ -48,6 +49,7 @@ func TestECChain(t *testing.T) {
4849
require.Equal(t, &wantBase, subjectExtended.Base())
4950
require.Equal(t, []gpbft.TipSet{wantNext}, subjectExtended.Suffix())
5051
require.Equal(t, &wantNext, subjectExtended.Head())
52+
require.True(t, subjectExtended.HasSuffix())
5153
require.Equal(t, &wantNext, subjectExtended.Prefix(1).Head())
5254
require.True(t, subjectExtended.HasTipset(&wantBase))
5355
require.False(t, subject.HasPrefix(subjectExtended))

host.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func (h *gpbftHost) Time() time.Time {
281281
// The timestamp may be in the past, in which case the alarm will fire as soon as possible
282282
// (but not synchronously).
283283
func (h *gpbftHost) SetAlarm(at time.Time) {
284-
h.log.Infof("set alarm for %v", at)
284+
h.log.Debugf("set alarm for %v", at)
285285
// we cannot reuse the timer because we don't know if it was read or not
286286
h.alertTimer.Stop()
287287
h.alertTimer = time.NewTimer(time.Until(at))
@@ -294,7 +294,8 @@ func (h *gpbftHost) SetAlarm(at time.Time) {
294294
// based on the decision received (which may be in the past).
295295
// E.g. this might be: finalised tipset timestamp + epoch duration + stabilisation delay.
296296
func (h *gpbftHost) ReceiveDecision(decision *gpbft.Justification) time.Time {
297-
h.log.Infof("got decision, finalized head at epoch: %d", decision.Vote.Value.Head().Epoch)
297+
h.log.Infof("got decision at instance %d, finalized head at epoch: %d",
298+
decision.Vote.Instance, decision.Vote.Value.Head().Epoch)
298299
err := h.saveDecision(decision)
299300
if err != nil {
300301
h.log.Errorf("error while saving decision: %+v", err)
@@ -305,7 +306,44 @@ func (h *gpbftHost) ReceiveDecision(decision *gpbft.Justification) time.Time {
305306
return time.Now().Add(h.manifest.ECDelay)
306307
}
307308

308-
return ts.Timestamp().Add(h.manifest.ECDelay)
309+
if decision.Vote.Value.HasSuffix() {
310+
// we decided on something new, use just the ECDelay
311+
return ts.Timestamp().Add(h.manifest.ECDelay)
312+
}
313+
314+
// we decided on base, calculate how much we should back off
315+
// all of this should go into manifest but I think Alfonso dislikes me already :P
316+
const (
317+
minBackoff = 2.
318+
maxBackoff = 20. // 10m with 30s ECDelay
319+
)
320+
// the backoff is defined in multiples of ECDelay starting at the last finalized tipset
321+
// each additional base decision beyond that will incurr the maxBackoff
322+
var backoffTable = []float64{2, 2.3, 2.69, 3.197, 3.8561, 4.71293, 4.71293, 5.826809, 7.2748517, 9.15730721} // 1.3^i+1 backoff, table for more flexibility
323+
//TODO move all the above to manifest
324+
325+
attempts := 0
326+
var backoffMultipler float64
327+
for instance := decision.Vote.Instance - 1; instance > h.manifest.InitialInstance; instance-- {
328+
cert, err := h.client.certStore.Get(h.runningCtx, instance)
329+
if err != nil {
330+
h.log.Errorf("error while getting instance %d from certstore: %+v", instance, err)
331+
break
332+
}
333+
if !cert.ECChain.HasSuffix() {
334+
attempts += 1
335+
}
336+
if attempts < len(backoffTable) {
337+
backoffMultipler += min(backoffTable[attempts], maxBackoff)
338+
} else {
339+
backoffMultipler += maxBackoff
340+
}
341+
}
342+
343+
backoff := time.Duration(float64(h.manifest.ECDelay) * backoffMultipler)
344+
h.log.Infof("backing off for: %v", backoff)
345+
346+
return ts.Timestamp().Add(backoff)
309347
}
310348

311349
func (h *gpbftHost) saveDecision(decision *gpbft.Justification) error {

0 commit comments

Comments
 (0)