-
Notifications
You must be signed in to change notification settings - Fork 180
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
[Util/Admin] Creating protocol snapshot from checkpoint file #5604
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5604 +/- ##
==========================================
- Coverage 55.65% 55.61% -0.04%
==========================================
Files 1037 1042 +5
Lines 101377 101957 +580
==========================================
+ Hits 56424 56708 +284
- Misses 40613 40897 +284
- Partials 4340 4352 +12
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
07164e1
to
6a0c386
Compare
6a0c386
to
1e77fdc
Compare
if !ok { | ||
return nil, fmt.Errorf("could not parse blocks-to-skip: %v", data) | ||
} |
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 suppose the validator should do this validation.
cmd/util/common/checkpoint.go
Outdated
return nil, 0, flow.DummyStateCommitment, fmt.Errorf("could not find finalized height for sealed height %v: %w", sealedHeight, err) | ||
} | ||
|
||
return state.AtHeight(finalizedHeight), sealedHeight, commit, nil |
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 doesn't handle checking that the full sealing segment is included. Is that required for ENs?
validSnapshot, err := b.getValidSnapshot(snapshot, 0, false) |
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.
Looks like the getValidSnapshot
contains some necessary validation to the generated protocol snapshot, such as ensuring the finalized block and sealed block belong to the same epoch.
However, these checks are placed in the access backend (engine/access/rpc/backend_network.go), I think it makes more sense to be placed in a package inside protocol state, so that it can be imported by other packages, such as util / admin.
Any idea why we didn't do that in the first place? @jordanschalm
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.
Most likely the reason is that the protocol state needs to be able to return a snapshot for every incorporated block, which includes snapshots that getValidSnapshot
considers invalid for dynamic bootstrapping.
I'm happy to move the checks into the protocol package and agree that makes sense. It just needs to be differentiated from the existing snapshot API, something like func GetDynamicBootstrapSnapshot(state, referenceSnapshot)
.
// Expected error returns during normal operations: | ||
// * ErrSnapshotPhaseMismatch - snapshot does not contain a valid sealing segment | ||
// All other errors should be treated as exceptions. | ||
func (b *backendNetwork) getValidSnapshot(snapshot protocol.Snapshot, blocksVisited int, findNextValidSnapshot bool) (protocol.Snapshot, error) { |
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.
moved to snapshots.getValidSnapshot
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.
Nice work. Added mainly documentation suggestions.
Main feedback is regarding how we find the snapshot corresponding to a particular state commitment, details in this comment: #5604 (comment).
cmd/util/common/checkpoint.go
Outdated
// the finalized height that seals the given sealed height must be above the sealed height | ||
// so if we iterate through each height, we should eventually find the finalized height |
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 we iterate through each height, we should eventually find the finalized height
This is not true in the general case. For example, suppose we have the following structure:
A <- B <- C <- D[Seal_A,Seal_B]
and suppose we are trying to find the block sealing A
.
Block D
seals A
, however the latest sealed block as of D
is not A
, its B
.
In this kind of scenario, we will never successfully exit this loop. In particular, the way sealing works, no snapshot exists for which Seal_A.StateCommitment
is the sealed commitment.
We could solve this algorithmically by changing the scanning logic. Rather than scanning blocks and exiting when we find a block B
such that Seal_B.StateCommitment
is in our search set, we could exit when we find a block B
such that seals.HighestInFork(B.ID())
(the latest seal as of block B
) is in our search set. Then we could skip the step of translating a sealed height into a finalized height (findFinalizedHeightBySealedHeight
).
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.
Good catch and good idea!
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's simple here that we don't need to implement this function, but I think it could be a useful utility function to know which block finalizes the seal for a given block. We don't have an index for this type of lookup, and the search is currently missing.
The scenario could be: I submitted a transaction A, which is included in block 10, I would like to know which block seals my transaction (seals block 10).
Is there any other scenario that needed this function?
Co-authored-by: Jordan Schalm <jordan@dapperlabs.com>
@@ -20,6 +20,7 @@ import ( | |||
// ErrEOFNotReached for indicating end of file not reached error | |||
var ErrEOFNotReached = errors.New("expect to reach EOF, but actually didn't") | |||
|
|||
// TODO: validate the header file and the sub file that contains the root hashes |
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.
will implement in a separate PR
#5623
Close #5580
This PR creates an admin tool and util command to generate a protocol snapshot from latest checkpoint file.
The generated protocol snapshot file can be used along with the checkpoint file for dynamic bootstrapping an execution node.