-
Notifications
You must be signed in to change notification settings - Fork 781
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: support uncle validation #935
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
4db67e9
to
12f0dcb
Compare
Ok, actually 2nd last "biggie" I am getting aware. 🙃 Is this intended to go into |
Hi @holgerd77, I have created a seperate PR which handles the requirements for this specific PR: this is #942. The uncle handling logic is rather complex; the actual logic itself depends on changing the current interface of blocks' |
Ok, great, than please rebase #942 as soon as you'll have some time. |
Ah yes good point, will do now. |
e435940
to
cbec91f
Compare
Wrote a massive amount of uncle tests here, which I think are also great because of the educational value. This should cover all rules regarding uncles 😄 I hope the VM tests pass now. |
VM tests fail but this is due to the linter? I haven't touched VM here so the linter should pass? Does maybe ESLint here have a different version or something? @evertonfraga Anyways this is ready for review 👍 😄 |
It would be great if we can get this in the RC release, as this completes the validation logic of Will rebase. |
block: fix validate uncles
block: fix option carry-over bug in uncle headers block: remove comment, add changes to changelog
cbec91f
to
ecb1064
Compare
OK, ready for review again! |
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 seems to be a complex topic which needs to be handled with some care, not sure if this can still make it into the RC release, we'll see.
Have some starter questions.
packages/block/src/block.ts
Outdated
|
||
// validate the header | ||
for (let i = 0; i < uncleHeaders.length; i++) { | ||
const header = uncleHeaders[i] |
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 not a blocker, but I find for (const uncleHeader of uncleHeaders)
more elegant and simple.
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 did all the others without a loop and instead with a map
, don't know why I used a for loop here. Note that for(const x of y)
is something that ESLint does not like (we have ignored that rule). I don't know why ESLint doesn't like that syntax.
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 right, I can't directly use map
because it calls an async
function.
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.
Have rewritten this using map
and Promise.all
, personally, I like it 😄
packages/block/src/block.ts
Outdated
parentHash = parentBlock.header.parentHash | ||
} | ||
|
||
canonicalBlockMap.map((block) => { |
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.
It would be good if these different validation sections in _validateUncleHeaders
get some short comment headers (maybe analogue to the already commented validateUncles
starting section) to structure this a bit and grasp what is going on.
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.
Yes good point, will do this.
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.
Have squashed this logic using some helpers, should be easier to read now 😄
} | ||
}) | ||
|
||
const getBlocks = this.header.number.clone().sub(lowestUncleNumber).addn(1).toNumber() |
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 the lowestUncleNumber
here is e.g. 1 for whatever reason the following loop would go and re-read the whole blockchain. This can't be right I would assume? 🤔
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 am not seeing why this would read the whole blockchain. Please note that in validating the headers, it is checked that the uncle is at most 8 blocks older, so this should put an upper bound of the amount of blocks being read.
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.
Thanks, I wasn't aware of this check in uncle header validation.
Okay, upon re-reading the code after your comments @holgerd77 I think I can simplify this code a bit more by introducing some helper variables. I am using |
Okay, just updated this one, moved some comments around and made the validation logic better readable (I hope) 😄 . Ready for re-review. |
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.
Thanks @jochem-brouwer, this code is now super-clean and really a great read! 👍
One structural suggestion on combining the methods but we can also directly proceed if you don't have time for the change right now and would rather like to go on.
for (const uh of this.uncleHeaders) { | ||
await this._validateUncleHeader(uh, blockchain) | ||
} | ||
await this._validateUncleHeaders(this.uncleHeaders, blockchain) |
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.
On a second look I don't think it makes any sense to keep this double public/private method structure with validateUncles()
and _validateUncleHeaders()
, these double this.uncleHeaders.length
checks (one on > 2, the other on === 0) rather makes this in the current split form more inconsistent, do we want to throw this into one function? 🤔 This double documentation is also a bit "redundancy for nothing" for my taste.
} | ||
}) | ||
|
||
const getBlocks = this.header.number.clone().sub(lowestUncleNumber).addn(1).toNumber() |
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.
Thanks, I wasn't aware of this check in uncle header validation.
// Helper variable: set hash to `true` if uncle hash is included in any canonical block | ||
const includedUncles: { [key: string]: boolean } = {} | ||
|
||
// Due to the header validation check above, we know that `getBlocks` it between 1 and 8 inclusive. |
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.
Super nit-pick: "it" -> "is"
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.
On a second tought: this method combination question is such an internal thing, have added this to the tiny-fixes-issue and will merge here now, so we keep a blank slate for the releases.
Closes #933
This PR fixes the following TODO in
block
: