-
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 validation methods, take 3 #1959
Conversation
@holgerd77 here's my WIP on the block validation methods. |
Correction: all the blockchain tests are passing locally. CI is failing because I haven't addressed the broader monorepo yet and was focused on getting things working between |
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
await this.header.validate(blockchain) | ||
await this.validateUncles(blockchain) | ||
await this.validateData(onlyHeader) | ||
} |
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 I wrote otherwise in the original issue but I guess we really want to keep this combined version (which would also solve a related client-TODO) in a public Blockchain.validateBlock()
method.
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.
The thought being we just want to be able to validate a new block in it's entirety without having to actually put it in the chain?
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 no, my thought was actually only to have an atomic (and also: more convenient) validate()
method (as before) since this already appeared as a use case in client (where you wrote your TODO).
Does this otherwise have any affects on the "put it on the chain or not" question?
Without having had a look into the current state of the code: it would generally be good for these methods if we can call in for a child block (so: the block to be validated) which not necessarily would need to be in the chain and only the parent block being expected to be in the chain.
Does this make sense?
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.
(or even better in the cases where this is possible: both doesn't need to be in the chain, so these would be the cases where a method could even be called in a static context)
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've added a public blockchain.validateBlock
method that wraps up those three validation checks. I don't think we can make it a static method without breaking it into further pieces since some the checks are heavily dependent on the existence of the chain.
674919b
to
a268fb2
Compare
@holgerd77 This PR is now ready for review. I've revised the initial description to reflect the changes made. Thanks @g11tech for helping track down some of the trickier client test failures! |
1273a87
to
9214ce4
Compare
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!
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, looks already pretty great, made some comments and change requests on things like structure, (method) order, naming and visibility of things.
// Block difficulty for in-turn signatures | ||
export const CLIQUE_DIFF_INTURN = BigInt(2) | ||
// Block difficulty for out-of-turn signatures | ||
export const CLIQUE_DIFF_NOTURN = BigInt(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.
Can we change the order of constants and types here (or is it just me who feel that constants would belong to the top?) and then also put all exported constants grouped together first?
|
||
if (header._common.consensusType() === 'pow') { | ||
await this.consensus.validateDifficulty(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 guess we can (and should) remove this PoW check here, to make sure this works in a generic context.
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 one is super tricky I've discovered. Because this.consensus
is the blockchain's current consensus mechanism, this fails on merge transition blocks where the header is now PoS but the blockchain is still PoW (since the blockchain hasn't switched to PoS so blockchain.consensus
is ethashConsensus
. We should skip this check on the merge block because the PoS difficulty check (i.e. PoS blocks must always have difficulty 0) is done in the block constructor via `block._consensusValidation) and it will always fail if you pass in a new header that's a PoS block but the current chain is either still PoA or PoW. I'll check for PoS instead and skip if so.
packages/blockchain/src/index.ts
Outdated
} | ||
// Validate clique difficulty | ||
await this.consensus.validateDifficulty(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.
Now we have this one consensus-related check back in here which is unlucky. Wonder if there is a good place in consensus
we can safely move.
Maybe in the clique.validate()
method as well? 🤔 Might need a double check if the semantic result would be somewhat matching/equivalent.
But we should really target to remove here.
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.
Left some minor comments, look good to me overall.
Thanks for the detailed review! Will address all this cleanup. |
Please don't merge this. I've got to fix the client tests, again. |
337c0a0
to
ddeaa8b
Compare
@acolytec3 thanks a lot for addressing all the feedback, this looks really great! 👍
Yes, I guess we should not throw here.
Maybe I am missing something but there is a There is also a |
The reason I ask the question is we have format level consensus checks in the blockheader constructor that require things like PoA blocks have to have minimum 97 bytes of |
Yes, I guess we want but can you leave it out here and instead open a short issue, since this is not breaking and we can add later (if I am not mistaken). I will merge in #1974 once CI passes. Can you prioritize on bringing this branch up to date then so that we can merge in here as well? I would want to have the big PRs out of the way. ugh. 🙂 Thanks (I am getting a bit stressed 😋). |
c0f3b1f
to
570843e
Compare
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, great work 🎉, will merge.
* | ||
* @param msg Base error message | ||
* @hidden | ||
*/ | ||
protected _errorMsg(msg: string) { | ||
private _errorMsg(msg: string) { |
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.
Small nit here, this should remain protected
to allow for sub-classing.
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.
Got it. Adding this to #1982
@@ -524,7 +389,7 @@ export class Block { | |||
* @param msg Base error message | |||
* @hidden | |||
*/ | |||
protected _errorMsg(msg: string) { | |||
private _errorMsg(msg: string) { |
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.
Same here.
Fixes #1879 and #1889
block.validate
andblockheader.validate
and moves the format/basic consensus checks into helper methods that are called in the respective constructors. These helpers throw if invalid fields are foundblockchain
,validateBlock
andvalidateHeader
that are called when a block is inserted into the chain. All of the checks from the removedvalidate
methods that require a blockchain context are now done in these methods.validateUncles
to `blockchainblockchain
dependency where possible and moved toblockchain
where not