-
Notifications
You must be signed in to change notification settings - Fork 784
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
Block: add methods to calculate difficulty of a consecutive header/block #929
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
Looks great! Should we update the usage of |
Yes, good point @ryanio, I will alter the tests so that we do not use mock headers anymore. |
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.
lgtm!
/**
* Returns the canonical difficulty of any consecutive new header, given the timestamp of the consecutive block and (optionally) the header number and the common
* @param timestamp - The `BN` timestamp of the consecutive header which we should calculate the difficulty for
* @param number - The `BN` header number of the consecutive header. Defaults to the current headers' number + 1
* @param common - The `Common` to use: defaults to the current headers' Common
*/
public getConsecutiveCanonicalDifficulty(timestamp: BN, number?: BN, common?: Common): BN {
const blockTs = timestamp.clone()
const { timestamp: parentTs, difficulty: parentDif } = this
common = common || this._common
let num = number?.clone() || this.number.addn(1)
const hardfork = common.hardfork() || common.activeHardfork(num.toNumber())
const minimumDifficulty = new BN(common.paramByHardfork('pow', 'minimumDifficulty', hardfork))
const offset = parentDif.div(
new BN(common.paramByHardfork('pow', 'difficultyBoundDivisor', hardfork))
) For some strange reasons GitHub doesn't let me post on the code directly right now, so I'll just copy over here. TBH I am still a bit confused here on the changes. Does the "difficulty of any consecutive new header" mean that this will also give the difficulty e.g. 5 headers in advance? If so, can we have a test for this? If not, why do we need const hardfork = common.hardfork() || common.activeHardfork(num.toNumber()) This line doesn't seem correct to me since * @param block - The block to get the canonical difficulty for This has been left in the |
Hi @holgerd77, thanks for these comments. I agree that this const hardfork = common.hardfork() || common.activeHardfork(num.toNumber()) Note that originally, we called into _getHardfork(), which is the same code as above. By the type signature of I will update the docs when I rebase this one. |
Actually upon inspecting this Common code it seems that the type signature of Will need to investigate this one a bit more. Looks like this is feature (?) is not tested thoroughly. |
I gave the initial argumentation from the opening post a re-read and TBH I am not really convinced by this whole construction. If the whole problem is the now-existing immutability of the header parameters, wouldn't it be cleaner to directly trigger difficulty calculation in the constructor, e.g. by adding a I think this whole combination of |
@jochem-brouwer Side note on the |
Hi @holgerd77 thanks for these suggestions. I agree with your concerns and upon some more thought the current approach might not be the best approach. In practice in your feature where we let the constructor calculate the difficulty would only make sense in I'd have to check if this would lead to any problems in the tests but I think this is possible. It does mean that we allow the RE: the I will change this so we will only support this in the constructor, which indeed makes more sense! |
Maybe pass in a |
411658b
to
7423290
Compare
Hi @holgerd77, I rolled back this PR and 🍒 -picked one commit from the original PR (c672b07) and instead wrote your approach. This is much simpler - thanks so much for this suggestion! I have instead named this parameter |
tx/vm/block: docs: fix spelling
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.
Oh yeah, this really makes it a lot cleaner, think this was worth the exchange! 😄
Thanks @jochem-brouwer for the update on this, will merge.
@@ -411,7 +416,7 @@ export class BlockHeader { | |||
|
|||
if (height) { | |||
const dif = height.sub(header.number) | |||
if (!(dif.cmpn(8) === -1 && dif.cmpn(1) === 1)) { | |||
if (!(dif.ltn(8) && dif.gtn(1))) { |
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.
Yeah, that's nice to have these comparisons replaced, for me this BN.js
cmp
function remained pretty unreadable over the time I am dealing with it.
* header will be used to calculate the difficulty for this block and the calculated | ||
* difficulty takes precedence over a provided static `difficulty` value. | ||
*/ | ||
calcDifficultyFromHeader?: BlockHeader |
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.
If a
BlockHeader
is given, then this header is used to calculate the difficulty upon creating the Block Header.
This was to prone yet for misunderstanding, have updated the comment with an additional commit. The double Block Header
reference was too confusing - one refering to the header provided and one to the header created.
Some general note: I think the usage of "this" in these kind of option comments often don't work, since it is always a bit misleading in the sense that it becomes not 100% clear if "this" refers to "this" option provided or to "this" instance created, I now stumbled upon this (haha 😄 ) a couple of times. Think it works better to in doubt be a bit more redundant and e.g. repeat "the header provided" instead of using "this header".
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.
Ah yes I'm somewhat used to write this
in these descriptions, will have to self-review those sometimes 👍
@@ -157,4 +157,73 @@ tape('[Block]: block functions', function (t) { | |||
}, 'should not throw on DAO HF block with correct extra data') | |||
st.end() | |||
}) | |||
|
|||
t.test( | |||
'should set canonical difficulty if I provide a calcDifficultyFromHeader header', |
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 think it should rather be avoided to write test descriptions out of the self perspective 😄 , won't let this be a block though of course, just some note.
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.
Ah yes you are right 😅 Will consider this too.
Cherry-picked from #895
It is (recently) not allowed anymore to edit params like
difficulty
in Header. In order to currently set the (right) difficulty in header (i.e. the canonical difficulty) then one has to create a mock Header and then callcanonicalDifficulty
on this mock Header. Then, one can create a newHeader
with the difficulty as returned by thiscanonicalDifficulty
call.It doesn't make a lot of sense to create a mock header. We want to "just set it to the correct value".
This PR:
calcDifficultyFromHeader
as aBlockOption
. If this is defined, then thisHeader
will be used to calculate the difficulty; any existing difficulty will be overwritten to this new, correct, value. Suggestion by @holgerd77 👍blockchain
to use this new method.canonicalDifficulty
method a bit more readable by instead using the correspondinggt
/lt
methods ofBN
instead of usingcmp
. Suggestion by @ryanio 👍