-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add block download progress to metrics UI #2484
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK modulo comments.
src/metrics.cpp
Outdated
double averageSpacing = (targetSpacing + checkpointSpacing) / 2; | ||
int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing); | ||
// Round to nearest ten to reduce noise | ||
netheight = (netheight / 10) * 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not rounding to the nearest 10; it's rounding down to a multiple of 10.
src/metrics.cpp
Outdated
// checkpoint, and use that to estimate the current network height. | ||
auto chainParams = Params(); | ||
auto checkpointData = chainParams.Checkpoints(); | ||
int medianHeight = height - 5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use CBlockIndex::nMedianTimeSpan / 2
instead of 5.
92bea1d
to
4d9c9e0
Compare
@daira comments addressed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK. I'm not sure what our testing policy is for changes that obviously only affect non-essential output; do we need to test this @nathan-at-least ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requested change: unit tests of arithmetic.
src/metrics.cpp
Outdated
int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing); | ||
// Round to nearest ten to reduce noise | ||
netheight = ((netheight + 5) / 10) * 10; | ||
int downloadPercent = height * 100 / netheight; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imagine there were some bug in the arithmetic. Could we factor out the "sensor" code (which reads from blockchain state, ex IsInitialBlockDownload()
and chainParams.Checkpoints
, arithmetic functional code, and display code, and then unittest at least the arithmetic functional code?
Then if there were an arithmetic bug, that would imply either we missed a test specification, or the specification was buggy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@str4d will write a unit test for this.
4d9c9e0
to
047aec1
Compare
Refactored the code and added unit tests. I force-pushed to squash this into the existing commit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ut(ACK+cov)
src/metrics.cpp
Outdated
// We average the target spacing with the observed spacing to the last | ||
// checkpoint, and use that to estimate the current network height. | ||
int medianHeight = height - CBlockIndex::nMedianTimeSpan / 2; | ||
double checkpointSpacing = (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what conditions could this potentially divide by zero?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, can checkpointSpacing
become negative in pathological cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double division-by-zero is well-defined (for IEEE arithmetic) to produce infinity or -infinity. Dividing a double by an infinity gives zero.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provided we have floating point non-stop mode enabled (via feholdexcept or fesetexceptflag). I assumed we did because we use infinities in the fee handling code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest avoiding the issue by using:
double checkpointSpacing = max(1.0d, (double (tipmediantime - timeLastCheckpoint)) / max(1.0d, double (medianHeight - heightLastCheckpoint)));
(and adding tests that exercise the clamping).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ebfull raises a good point. I have addressed this in a different way: while the current height is <= the last checkpoint, estimate the checkpoint spacing using the interval [genesis, lastCheckpoint]
instead of [lastCheckpoint, tip]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK.
There are some pathological cases and I'm not sure if they are reachable.
If not, an improvement would be to add precondition assertions to guard against undefined behavior (if that is indeed C++ divide by zero behavior). Otherwise test cases for them and error recovery would be good. I don't see either of those as requirements for merging this.
src/metrics.cpp
Outdated
// We average the target spacing with the observed spacing to the last | ||
// checkpoint, and use that to estimate the current network height. | ||
int medianHeight = height - CBlockIndex::nMedianTimeSpan / 2; | ||
double checkpointSpacing = (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, can checkpointSpacing
become negative in pathological cases?
src/metrics.cpp
Outdated
int medianHeight = height - CBlockIndex::nMedianTimeSpan / 2; | ||
double checkpointSpacing = (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint); | ||
double averageSpacing = (targetSpacing + checkpointSpacing) / 2; | ||
int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what conditions could averageSpacing == 0
? Three cases to consider:
targetSpacing == checkpointSpacing == 0
- One is negative (which seem unexpected).
- The other is negative.
src/metrics.cpp
Outdated
Checkpoints::GetTotalBlocksEstimate(checkpointData), | ||
checkpointData.nTimeLastCheckpoint, | ||
chainParams.GetConsensus().nPowTargetSpacing); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally like factoring out the "I/O" into this outer function. What's your opinion @str4d?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you clarify what you mean? If you mean pulling the stdio calls from the parent into here, I would like to point out that having them in their current function makes aligning the UI significantly easier, as all the common calls are together (in this case, inside printStats()
).
src/metrics.cpp
Outdated
height, tipmediantime, | ||
Checkpoints::GetTotalBlocksEstimate(checkpointData), | ||
checkpointData.nTimeLastCheckpoint, | ||
chainParams.GetConsensus().nPowTargetSpacing); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answering my edge-case questions above:
nPowTargetSpacing
is defined in one place as anint64_t
and is our target block time and it would be quite unlikely we wouldn't notice changing this to negative.- I haven't determined what the pathological conditions for
checkpointData.nTimeLastCheckpoint
orCheckpoints::GetTotalBlockEstimate()
would be.
I suspect the worst case behavior for those pathological conditions would be just incorrect display, although it sounds like division by 0 can be undefined behavior.
Note that we're behind schedule on the release and this is the last feature PR. It's in danger of getting kicked out if the edge case issues are not resolved today (Friday). |
Corrections are to the median block times, which were generated by subtracting CBlockIndex::nMedianTimeSpan / 2 from the block height and then multiplying by the target spacing. GetMedianTimePast() takes an array sorted by std::sort() and returns element CBlockIndex::nMedianTimeSpan / 2, meaning that if CBlockIndex::nMedianTimeSpan is odd (which it is), there is an out-by-one error in the subtraction.
ut(ACK+cov) |
@zkbot r+ |
📌 Commit 92bfde0 has been approved by |
Add block download progress to metrics UI
No description provided.