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
multi: Introduce AssumeValid. #2839
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.
I haven't reviewed the tests yet, but I spotted an issue I wanted to call out in the mean time.
705fb08
to
3a877c5
Compare
As I'm going through the readme and the code, I noticed that you seem to be using "AssumeValid Hash" and "AssumeValid Node" interchangeably. For instance, in the comment above:
Did you do this intentionally, and I'm just misunderstanding? Otherwise, I think it makes more sense to say that you specify "AssumeValid Hash" or an "AssumeValid Block", and if a node is broadcasting either of those things, then I suppose you can call it an "AssumeValid Node." |
It's because the term node is overloaded. It refers to both the peer (network node) as well as the internal nodes ( So, the hash is what you specify as the config option. The node (aka block / It would probably be clearer to those less familiar with the code to refer to them as blocks whenever they're being referencing in the same context as network nodes/peers. EDIT: As for the specific text in question, I agree that it would probably read better as:
|
// | ||
// Block 00000000000000001251efb83ad1a5c71351b50fe9195f009cf0bf5a7cd99d52 | ||
// Height: 606000 | ||
AssumeValid: *newHashFromStr("00000000000000001251efb83ad1a5c71351b50fe9195f009cf0bf5a7cd99d52"), |
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.
Confirming this hash:
$ dcrctl getblockhash 606000
00000000000000001251efb83ad1a5c71351b50fe9195f009cf0bf5a7cd99d52
// | ||
// Block 00000000d64ceb1a686315ed56235e9a6838e3a22e9ec9bd92c2e04c09e0778b | ||
// Height: 807905 | ||
AssumeValid: *newHashFromStr("00000000d64ceb1a686315ed56235e9a6838e3a22e9ec9bd92c2e04c09e0778b"), |
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.
Confirming this hash as well:
$ dcrctl --testnet getblockhash 807905
00000000d64ceb1a686315ed56235e9a6838e3a22e9ec9bd92c2e04c09e0778b
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 test coverage looks great overall. Do you think it's worth adding one for the clamping on a side chain case identified during the review to prevent any possible regressions in that regard?
3a877c5
to
3b3fcda
Compare
Yep, I was thinking the same. I added a test for this and validated that the test will fail if the fix is reverted. |
@matthawkins90 Thanks for pointing out that the terminology was a bit confusing. As @davecgh noted, the term "node" is overloaded, and when used in place of "block", it is referring to the internal struct I've updated to use "block" rather than "node" for the cases that are not directly referring to a variable of the |
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.
In addition to the code review, I also tested this as follows:
- Added prints for chosen flags and script execution policy to manually inspect the results
- Ran
mainnet
andtestnet
, andsimnet
with the default values - Ran
mainnet
andtestnet
, andsimnet
with various custom values, including 0 to disable - Forced clamping, both on the main chain and side chain via
simnet
- Triggered reorgs of varying complexity via
simnet
Thanks for the explanation! Yup, sorry, I wasn't aware of the |
3b3fcda
to
7b624b7
Compare
This introduces an AssumeValid parameter that is the hash of a block that has been externally verified to be valid. In a subsequent commit, it will be used to allow several validation checks to be skipped for blocks that are both an ancestor of the assumed valid block and an ancestor of the best header. Note that the AssumeValid block hash that is specified for mainnet and testnet is for the same block that was used for MinKnownChainWork. Using the same block for both of these slightly simplifies the process for external verification of the values when they are updated periodically with new releases.
This adds an assumeValid field to BlockChain and sets it based on the AssumeValid chain parameter.
This adds tracking of the assumed valid node to BlockChain. The assumed valid node will be used in place of checkpoints to set the BFFastAdd flag in a subsequent commit.
This updates BlockChain to set the BFFastAdd flag if a block is both an ancestor of the assumed valid block and an ancestor of the best header. A helper function isAssumeValidAncestor is introduced that determines whether the provided node is both an ancestor of the assumed valid node and an ancestor of the best header. False is returned when the assume valid node has not been discovered or when assume valid is disabled. The assumed valid node is clamped back as needed to ensure that it is at least 2 weeks worth of blocks behind the best header. This protects against malicious actors trying to play games by tricking users into using an assumed valid hash near the tip.
This updates block validation to not run scripts if a block is both an ancestor of the assumed valid block and an ancestor of the best header.
This updates block validation to not run scripts if bulk import mode is enabled. Bulk import mode is only enabled when importing blocks that are already known to be valid.
This adds tests that validate that it is correctly determined whether or not a node is an ancestor of an assumed valid node under a variety of conditions.
This adds an assumevalid config option which allows for specifying a hash of an assumed valid block or disabling assume valid. The usage is as follows: * (flag not specified): defaults to the hard-coded value in source * --assumevalid=0: disable AssumeValid * --assumevalid=[blockhash]: set AssumeValid to the specified block hash
7b624b7
to
288b106
Compare
This introduces an
AssumeValid
parameter and configuration option. It is broken down into several commits to ease the review process.Motivation: Checkpoints vs AssumeValid
Prior to this PR,
Checkpoints
were being used for two distinct purposes:This PR introduces a new parameter,
AssumeValid
, to control when validation checks can be skipped rather than continuing to useCheckpoints
for this purpose.The separation of
Checkpoints
andAssumeValid
provides a few benefits:AssumeValid
hash that is closer to tipCheckpoints
since rejecting forks before a certain point affects consensusThe
--assumevalid
config optionSince the
AssumeValid
hash can be closer to tip, this PR adds the ability to set it without a code change via an--assumevalid
option. It can be specified as follows:--assumevalid=0
: disableAssumeValid
--assumevalid=[blockhash]
: setAssumeValid
to the specified block hashSpecifying an
AssumeValid
hash closer to tip allows for faster syncing. This is useful since the hard-codedAssumeValid
block becomes deeper in the chain (and therefore more validation needs to be done post theAssumeValid
block) the longer a particular release build is out.As noted in the implementation,
AssumeValid
is clamped back as needed to ensure that it is at least 2 weeks worth of blocks behind the best header. This protects against malicious actors trying to play games by tricking users into using an assumed valid hash near the tip.