Skip to content

state: add an 'IsTimely' method to implement the 'timely' check for proposer-based timestamps#7170

Merged
williambanfield merged 10 commits intowb/proposer-based-timestampsfrom
wb/is-timely
Nov 9, 2021
Merged

state: add an 'IsTimely' method to implement the 'timely' check for proposer-based timestamps#7170
williambanfield merged 10 commits intowb/proposer-based-timestampsfrom
wb/is-timely

Conversation

@williambanfield
Copy link
Contributor

@williambanfield williambanfield commented Oct 27, 2021

This pull requests implements the 'timely' as outlined in the proposer-based timestamps specification.

For a proposed block timestamp to be considered timely, it must satisfy the following inequality:

proposedBlockTime < validatorLocalTime + Precision + MsgDelay && proposedBlockTime > validatorLocaltime - Precision.

Where Precision and MsgDelay are system parameters where Precision bounds the acceptable clock drift between any two correct process and MsgDelay bounds the acceptable delay for full transmitting a message between any two processes.

part of #6942

@williambanfield williambanfield changed the base branch from master to wb/proposer-based-timestamps October 27, 2021 14:27
state/state.go Outdated
//
// For more information on the meaning of 'timely', see the proposer-based timestamp specification:
// https://github.com/tendermint/spec/tree/master/spec/consensus/proposer-based-timestamp
func IsTimely(bt time.Time, lt time.Time, precision time.Duration, msgDelay time.Duration) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way that this can be attached as a method to an existing type?

Alternately, seems like there should be a POD type to wrap up these arguments, as "function which takes two time.Time and two time.Duration" would be very easy to flip one or both of the pairs of arguments in a way that would be difficult to notice at the call site.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good call. I believe this could be a method attached to the proposals themselves (if we first check IsTimely and then that the proposal time matches the received block time). To avoid confusion between precision and msgDelay it may be better to take the new TimeParams (or whatever it's called) from ConsensusParams as an argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved this to be a method on the block (since that will be what timely is checked against) and moved the method to take in the timestamp params instead. I also added a mechansim for defining a local time source, that this method will take as an argument, but perhaps that is overkill and a time.Time would suffice instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the new method, but this code is still there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

types/block.go Outdated
//
// For more information on the meaning of 'timely', see the proposer-based timestamp specification:
// https://github.com/tendermint/spec/tree/master/spec/consensus/proposer-based-timestamp
func (b *Block) IsTimely(clock tmtime.Source, p TimestampParams) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we measure timeliness when we receive the proposal or when we receive the block. I thought it was based on the proposal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a discussion with @josef-widder and @cason, I determined that it's acceptable to use the propose message. This has the benefit of using a message with a constant size, meaning block size will not affect MSGDELAY.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of the implementation, this also seems easier. If a Proposal is not timely, when it is received and processed at first by the consensus implementation, there is no point in "asking for" and receiving the corresponding BlockParts. In addition, if the timely call is made for the block, when in the implementation will it be called? This is relevant, as different calls to timely may return true and the false, depending on when they are invoked.

@williambanfield williambanfield added the S:automerge Automatically merge PR when requirements pass label Nov 1, 2021
}

// TimestampParams influence the validity of block timestamps.
type TimestampParams struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add a default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set some basics and will follow up in #7202

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These would be Synchronous or Timing parameters, wouldn't them?

@williambanfield williambanfield merged commit 0d2a5de into wb/proposer-based-timestamps Nov 9, 2021
@williambanfield williambanfield deleted the wb/is-timely branch November 9, 2021 20:23
Copy link

@cason cason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me is not clear whether the corner cases are defined or tested properly. I also think that the main isTimely method could be easier to read, by using Before() and After() and Add() and Sub() time methods.

// https://github.com/tendermint/tendermint/issues/7202
return TimestampParams{
Precision: 2 * time.Second,
Accuracy: 500 * time.Millisecond,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observe that if Accuracy = 0.5ms, two clocks might differ by at most Precision = 1ms.

// configured Precision and MsgDelay parameters.
// Specifically, a proposed block timestamp is considered timely if it is satisfies the following inequalities:
//
// proposedBlockTime > validatorLocaltime - Precision && proposedBlockTime < validatorLocalTime + Precision + MsgDelay.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proposedBlockTime > validatorLocaltime - Precision

Are you sure that this is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lt := clock.Now()
lhs := lt.Add(-tp.Precision)
rhs := lt.Add(tp.Precision).Add(tp.MsgDelay)
if lhs.Before(p.Timestamp) && p.Timestamp.Before(rhs) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just a detail, but I would prefer having something like "a.After(b) and a.Before(c)" for more clarity.

{
// Checking that the following inequality evaluates to true:
// 1 - 2 < 0 < 1 + 2 + 1
name: "basic timely",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the "basic" case, meaning the most common, is:

  • The proposal timestamp is "for sure" in the past, so: proposalTime + Precision < localTime - Precision
  • The receiving time of the proposal is "fore sure" within the acceptable window, so: localTime + Precision < proposalTime + msgDelay - Precision

{
// Checking that the following inequality evaluates to false:
// 3 - 2 < 0 < 3 + 2 + 1
name: "local time too large",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, is not the local time that is large, but the Proposal took too long to be received.

{
// Checking that the following inequality evaluates to false:
// 0 - 2 < 2 < 2 + 1
name: "proposal time too large",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a more clear name would be: "proposal timestamp in the future"

proposalTime: genesisTime,
localTime: genesisTime.Add(1 * time.Nanosecond),
precision: time.Nanosecond * 2,
msgDelay: time.Nanosecond,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect msgDelay >> Precision.

@williambanfield
Copy link
Contributor Author

For me is not clear whether the corner cases are defined or tested properly. I also think that the main isTimely method could be easier to read, by using Before() and After() and Add() and Sub() time methods.

.Sub produces a time.Duration, whereas what we need is a time.Time. Add produces a time.Time, another sort of annoying difference in similarly named functions.

williambanfield added a commit that referenced this pull request Nov 24, 2021
…roposer-based timestamps (#7170)

* state: add an IsTimely function to implement the check for timely in proposer-based timestamps

* move time checks into block.go and add time source mechanism

* timestamp params comment

* add todo related to pbts spec and timestamp params

* remove old istimely

* switch to using built in before function

* lint++

* wip

* move into proposal and create a default set of params

* defer using default cons params for now
williambanfield added a commit that referenced this pull request Jan 15, 2022
…roposer-based timestamps (#7170)

* state: add an IsTimely function to implement the check for timely in proposer-based timestamps

* move time checks into block.go and add time source mechanism

* timestamp params comment

* add todo related to pbts spec and timestamp params

* remove old istimely

* switch to using built in before function

* lint++

* wip

* move into proposal and create a default set of params

* defer using default cons params for now
@williambanfield williambanfield restored the wb/is-timely branch September 9, 2022 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S:automerge Automatically merge PR when requirements pass

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants