From 6688e2dbe683196ead46254e0c10544da9519451 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 20 Dec 2023 18:05:15 +0200 Subject: [PATCH 1/5] wip --- sips/dynamic_qbft_timeout.md | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 sips/dynamic_qbft_timeout.md diff --git a/sips/dynamic_qbft_timeout.md b/sips/dynamic_qbft_timeout.md new file mode 100644 index 0000000..eaf835c --- /dev/null +++ b/sips/dynamic_qbft_timeout.md @@ -0,0 +1,84 @@ +| Author | Title | Category | Status | +| -------------- | --------------------- | -------- | -------- | +| Gal Rogozinski | QBFT timeout | Core | approved | + + +**Summary** +Changes to the constant timeouts we defined in SIP#6 that should improve performance. + +**Rational** +Currently for all duties, we have a `quickTimeout` of 2 seconds before sending a `RoundChange` message and a `slowTimeout` of 2 minutes starting from the 8th round.The timer starts when the QBFT instance starts. This approach has 2 issues: + +1. Duties that require a pre-consensus stage may start their instances at different times, causing some nodes to timeout sooner than others. This will result in a greater probability of a failed first round. +2. Different duties have different timing assumptions, which may cause some duties to execute earlier than others. + + + +**Beacon Duty Timing Assumptions** +The Beacon chain has some timing assumptions regarding duty execution for maximizing rewards. + +| Duty | Timing Assumption | Dependency | Description | +| -------------- | ----------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- | +| Proposal | < 4 Sec | --- | Attestations wait 4 seconds for a block | +| Attester | < 4 Sec | Proposal | Attestations wait 4 seconds for a block then need to be propogated within 4 seconds for aggregators to pick them up | +| Aggregator | < 4 Sec | Attester | Aggregators start aggregating within 8 seconds from slot start and need to propogate within 4 seconds | +| Sync Committee | < 4 sec | Proposal | Sync Committee wait 4 seconds for a block | +| Contribution | < 4 sec | Sync Committee | Contributions wait 8 seconds from the slot start | + + + +**Specification** + +```go +var ( + quickTimeoutThreshold = Round(8) + quickTimeout = 2 * time.Second + slowTimeout = 2 * time.Minute +) + + +// Timeout returns the number of seconds until next timeout for a given round. +// When we have the proposal duty we immediately call it. +func Timeout(r Round) time.Duration { + if r <= quickTimeoutThreshold { + return quickTimeout + } + return slowTimeout +} + +// Called for all beacon duties other than proposals +func RoundTimeout(r Round, baseDuration Duration) Time { + if r == Round.FirstRound { + return baseDuration + quickTimeout + } else { + return Timeout(r) + } +} +``` + +*Proposals* + +No changes from SIP#6. + +```go +func ProposalTimeout(r Round) + return Timeout(r) +``` + +*Attestations/Sync Committees* + +Once the slot starts, wait 4 seconds for a block to be produced then start the timer according to the same rules as defined in SIP#6. + +```go +func AttestationOrSyncCommitteeTimeout(r Round) + return RoundTimeout(r, 4) +``` + +*Aggregator/Contribution* + +Once the slot starts, wait 8 seconds for a block to be produced then start the timer according to the same rules as defined in SIP#6. + +```go +func AggregationOrContribuitionTimeout(r Round) + return RoundTimeout(r, 4) +``` \ No newline at end of file From 7331058ed2dbd6018be4dca35b268b40ae78cac7 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Mon, 25 Dec 2023 12:46:11 +0200 Subject: [PATCH 2/5] dynamic qbft timeout --- sips/dynamic_qbft_timeout.md | 61 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/sips/dynamic_qbft_timeout.md b/sips/dynamic_qbft_timeout.md index eaf835c..471474d 100644 --- a/sips/dynamic_qbft_timeout.md +++ b/sips/dynamic_qbft_timeout.md @@ -4,7 +4,7 @@ **Summary** -Changes to the constant timeouts we defined in SIP#6 that should improve performance. +Changes to the constant timeouts we defined in [SIP#6](https://github.com/bloxapp/SIPs/blob/main/sips/constant_qbft_timeout.md) that should improve performance. **Rational** Currently for all duties, we have a `quickTimeout` of 2 seconds before sending a `RoundChange` message and a `slowTimeout` of 2 minutes starting from the 8th round.The timer starts when the QBFT instance starts. This approach has 2 issues: @@ -27,7 +27,9 @@ The Beacon chain has some timing assumptions regarding duty execution for maximi -**Specification** +**Specification** + +From the slot start time after `baseDuration` delay wait 2 seconds before emitting a `RoundChange` message until the 8th round (inclusive). Afterwards, wait 2 minutes. ```go var ( @@ -36,49 +38,48 @@ var ( slowTimeout = 2 * time.Minute ) - -// Timeout returns the number of seconds until next timeout for a given round. -// When we have the proposal duty we immediately call it. -func Timeout(r Round) time.Duration { - if r <= quickTimeoutThreshold { - return quickTimeout - } - return slowTimeout -} - +// RoundTimeout returns the time in which we should send a RC message // Called for all beacon duties other than proposals -func RoundTimeout(r Round, baseDuration Duration) Time { - if r == Round.FirstRound { - return baseDuration + quickTimeout - } else { - return Timeout(r) - } +func RoundTimeout(r Round, dutyStartTime Time, baseDuration Duration) Time { + // Calculate additional timeout based on round + var additionalTimeout time.Duration + if round <= quickTimeoutThreshold { + additionalTimeout = time.Duration(int(round)) * slowTimeout + } else { + quickPortion := time.Duration(quickTimeoutThreshold) * quickTimeout + slowPortion := time.Duration(int(round-quickTimeoutThreshold)) * slowTimeout + additionalTimeout = quickPortion + slowPortion + } + + // Combine base duration and additional timeout + timeoutDuration := baseDuration + additionalTimeout + + // Get the start time of the duty + dutyStartTime := t.beaconNetwork.GetSlotStartTime(phase0.Slot(height)) + + // Calculate the time until the duty should start plus the timeout duration + return time.Until(dutyStartTime.Add(timeoutDuration)) } ``` *Proposals* -No changes from SIP#6. - -```go -func ProposalTimeout(r Round) - return Timeout(r) -``` +No changes from [SIP#6](https://github.com/bloxapp/SIPs/blob/main/sips/constant_qbft_timeout.md). Doesn't rely on the slot/duty start time. *Attestations/Sync Committees* -Once the slot starts, wait 4 seconds for a block to be produced then start the timer according to the same rules as defined in SIP#6. +Once the slot starts, wait 4 seconds for a block to be produced then start the timer according to the new rules. ```go -func AttestationOrSyncCommitteeTimeout(r Round) - return RoundTimeout(r, 4) +func AttestationOrSyncCommitteeTimeout(r Round, dutyStartTime Time) Time + return RoundTimeout(r, dutyStarTime, 4) ``` *Aggregator/Contribution* -Once the slot starts, wait 8 seconds for a block to be produced then start the timer according to the same rules as defined in SIP#6. +Once the slot starts, wait 8 seconds for a block to be produced then start the timer according to the new rules ```go -func AggregationOrContribuitionTimeout(r Round) - return RoundTimeout(r, 4) +func AggregationOrContribuitionTimeout(r Round, dutyStartTime Time) Time + return RoundTimeout(r, dutyStartTime 8) ``` \ No newline at end of file From 9e2f23e2699b848e2b6952959d454ba24774da34 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Mon, 25 Dec 2023 12:52:27 +0200 Subject: [PATCH 3/5] add comma --- sips/dynamic_qbft_timeout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/dynamic_qbft_timeout.md b/sips/dynamic_qbft_timeout.md index 471474d..b62fa64 100644 --- a/sips/dynamic_qbft_timeout.md +++ b/sips/dynamic_qbft_timeout.md @@ -81,5 +81,5 @@ Once the slot starts, wait 8 seconds for a block to be produced then start the t ```go func AggregationOrContribuitionTimeout(r Round, dutyStartTime Time) Time - return RoundTimeout(r, dutyStartTime 8) + return RoundTimeout(r, dutyStartTime, 8) ``` \ No newline at end of file From 9adab9768400a73fedf50d70c5e9bda619cfcabe Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 23 Jan 2024 11:44:39 +0200 Subject: [PATCH 4/5] don't use Time --- sips/dynamic_qbft_timeout.md | 45 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/sips/dynamic_qbft_timeout.md b/sips/dynamic_qbft_timeout.md index b62fa64..1fe2fd8 100644 --- a/sips/dynamic_qbft_timeout.md +++ b/sips/dynamic_qbft_timeout.md @@ -33,32 +33,33 @@ From the slot start time after `baseDuration` delay wait 2 seconds before emitti ```go var ( - quickTimeoutThreshold = Round(8) - quickTimeout = 2 * time.Second - slowTimeout = 2 * time.Minute + // quickTimeoutThreshold is the round after which the timeout duration increases to 2 minutes + quickTimeoutThreshold = Round(8) + // quickTimeout is the timeout in seconds for the first 8 rounds + quickTimeout int64 = 2 // 2 seconds + // slowTimeout is the timeout in seconds for rounds after the first 8 + slowTimeout int64 = 120 // 2 minutes ) -// RoundTimeout returns the time in which we should send a RC message +// RoundTimeout returns the unix epoch time (seconds) in which we should send a RC message // Called for all beacon duties other than proposals -func RoundTimeout(r Round, dutyStartTime Time, baseDuration Duration) Time { - // Calculate additional timeout based on round - var additionalTimeout time.Duration - if round <= quickTimeoutThreshold { - additionalTimeout = time.Duration(int(round)) * slowTimeout - } else { - quickPortion := time.Duration(quickTimeoutThreshold) * quickTimeout - slowPortion := time.Duration(int(round-quickTimeoutThreshold)) * slowTimeout - additionalTimeout = quickPortion + slowPortion +func RoundTimeout(round Round, height Height, baseDuration int64, network types.BeaconNetwork) int64 { + // Calculate additional timeout in seconds based on round + var additionalTimeout int64 + additionalTimeout = int64(min(round, quickTimeoutThreshold)) * quickTimeout + if round > quickTimeoutThreshold { + slowPortion := int64(round-quickTimeoutThreshold) * slowTimeout + additionalTimeout += slowPortion } // Combine base duration and additional timeout timeoutDuration := baseDuration + additionalTimeout - // Get the start time of the duty - dutyStartTime := t.beaconNetwork.GetSlotStartTime(phase0.Slot(height)) + // Get the unix epoch start time of the duty seconds + dutyStartTime := network.EstimatedTimeAtSlot(phase0.Slot(height)) // Calculate the time until the duty should start plus the timeout duration - return time.Until(dutyStartTime.Add(timeoutDuration)) + return dutyStartTime + timeoutDuration } ``` @@ -71,8 +72,10 @@ No changes from [SIP#6](https://github.com/bloxapp/SIPs/blob/main/sips/constant_ Once the slot starts, wait 4 seconds for a block to be produced then start the timer according to the new rules. ```go -func AttestationOrSyncCommitteeTimeout(r Round, dutyStartTime Time) Time - return RoundTimeout(r, dutyStarTime, 4) +// AttestationOrSyncCommitteeTimeout returns the unix epoch time (seconds) in which we should send a RC message +func AttestationOrSyncCommitteeTimeout(round Round, height Height, network types.BeaconNetwork) int64 { + return RoundTimeout(round, height, 4, network) +} ``` *Aggregator/Contribution* @@ -80,6 +83,8 @@ func AttestationOrSyncCommitteeTimeout(r Round, dutyStartTime Time) Time Once the slot starts, wait 8 seconds for a block to be produced then start the timer according to the new rules ```go -func AggregationOrContribuitionTimeout(r Round, dutyStartTime Time) Time - return RoundTimeout(r, dutyStartTime, 8) +// AggregationOrContributionTimeout returns the unix epoch time (seconds) in which we should send a RC message +func AggregationOrContributionTimeout(r Round, height Height, network types.BeaconNetwork) int64 { + return RoundTimeout(r, height, 8, network) +} ``` \ No newline at end of file From f07c1754cee590f41364a2249beaba9082da5ce8 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Sun, 24 Mar 2024 13:38:54 +0200 Subject: [PATCH 5/5] lower timeout threshold to 6 --- sips/dynamic_qbft_timeout.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sips/dynamic_qbft_timeout.md b/sips/dynamic_qbft_timeout.md index 1fe2fd8..3b06001 100644 --- a/sips/dynamic_qbft_timeout.md +++ b/sips/dynamic_qbft_timeout.md @@ -29,15 +29,15 @@ The Beacon chain has some timing assumptions regarding duty execution for maximi **Specification** -From the slot start time after `baseDuration` delay wait 2 seconds before emitting a `RoundChange` message until the 8th round (inclusive). Afterwards, wait 2 minutes. +From the slot start time after `baseDuration` delay wait 2 seconds before emitting a `RoundChange` message until the 6th round (inclusive). Afterwards, wait 2 minutes. ```go var ( // quickTimeoutThreshold is the round after which the timeout duration increases to 2 minutes - quickTimeoutThreshold = Round(8) - // quickTimeout is the timeout in seconds for the first 8 rounds + quickTimeoutThreshold = Round(6) + // quickTimeout is the timeout in seconds for the first 6 rounds quickTimeout int64 = 2 // 2 seconds - // slowTimeout is the timeout in seconds for rounds after the first 8 + // slowTimeout is the timeout in seconds for rounds after the first 6 slowTimeout int64 = 120 // 2 minutes )