-
Notifications
You must be signed in to change notification settings - Fork 677
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
Nakamoto staging blocks #3992
Nakamoto staging blocks #3992
Conversation
…king in sortition db, add epoch30
Codecov Report
@@ Coverage Diff @@
## next #3992 +/- ##
==========================================
- Coverage 0.16% 0.16% -0.01%
==========================================
Files 350 350
Lines 291672 292190 +518
==========================================
Hits 469 469
- Misses 291203 291721 +518
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
/// current chain tip: only recent tenures can receive blocks this | ||
/// way. Otherwise, the `BlockHeaderHash` must have been | ||
/// explicitly confirmed by a block commit. | ||
pub fn expects_blocks_from_tenure( |
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'm having a hard time reconciling the docstring with the code body. The code body returns the latest BlockSnapshot
whose block-signing key hash matches the given public key, if there any such snapshots within the last NAKAMOTO_TENURE_BLOCK_ACCEPTANCE_PERIOD
sortitions. What does this have to do with "expect[ing] to receive unknown blocks?" Also, it seems miners can reuse the same signing key in multiple tenures, so if there were two snapshots from the same miner in this window, this method would not return the earlier one. Is this desired?
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 point. I think this should be a bool instead.
At first, I intended to use this result to figure out the consensus hash that started the miner's tenure. However, for exactly the reason you point out, it cannot do that (because the miner's key could be reused). Instead, I think that the Nakamoto block headers should contain the consensus hash of their tenure. There's other ways to figure out their associated tenure, I'm sure, but it dramatically simplifies things if the block's include it. I know it's a somewhat counter-intuitive change from Stacks 2.0's perspective: in 2.0, a miner cannot know their consensus hash when they produce their block, but because block production happens after their tenure starts in 3.0, they actually do know their consensus hash.
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.
Instead, I think that the Nakamoto block headers should contain the consensus hash of their tenure.
I agree -- we should use this instead of BurnchainHeaderHash
for burn_view
.
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'll do this when working on the coordinator
@@ -77,6 +77,12 @@ impl LeaderKeyRegisterOp { | |||
Some(LeaderKeyRegisterOp::new(&prover_pubk)) | |||
} | |||
|
|||
/// Interpret the first 20 bytes of the key registration's memo field as the Hash160 of | |||
/// of the public key that will sign this miner's nakamoto blocks. | |||
pub fn interpret_nakamoto_signing_key(&self) -> Option<Hash160> { |
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, interesting idea! This should get added to the SIP and design doc. Can you add a quick one-sentence comment in both places so we remember to merge it in? Thanks!
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, this field should probably be explicit in LeaderKeyRegisterOp
as an Option<..>
. The field would be required to be Some(..)
in epoch 3.0, but it's not considered in earlier epochs.
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 there is a little bit of code clarity tradeoff with adding a new field to the struct, and I'm genuinely not sure which would work out more elegantly. If there's a new field in the struct, there's two kind of immediate impacts:
- The db schema of the Sortition DB needs to change and FromRow/ToSql need to handle the new field. The db schema of the burnchain DB doesn't change, but the deserialization of the opcode would need to make sure that it handles the absence of the field correctly. Or the schema of the SortitionDB doesn't change and the FromRow / Insert method handles shuttling the new field via the existing memo column.
- The consensus deserialize/serialize needs to be sure to be compatible. This is pretty straight forward and I'm not worried about its impact.
In light of (1), do you still think there should be a new field for this struct?
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 that in each breaking change, we've required users to spin up from genesis anyway, so introducing a new field which renders the Stacks 2.x chainstate incompatible I think is fine (especially if it simplifies the consensus code).
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 can take this on
@@ -2141,6 +2141,16 @@ impl< | |||
self.inner_handle_new_burnchain_block(&mut HashSet::new()) | |||
} | |||
|
|||
/// Are affirmation maps active during the epoch? |
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 news -- they're going away in Epoch 3.0. There's no longer a need for them because the chain can't fork.
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, I agree. But I think the code may have to stay in place for a while, and the intention here is to have a function that encapsulates the decision on whether an affirmation map check should occur.
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, I meant to say that the check could return false
for epoch 3.0.
pub fn tenure_changed(&self) -> bool { | ||
// TODO: when tenure change txs are implemented, this must be updated | ||
true | ||
pub fn tenure_changed(&self, parent: &StacksBlockId) -> bool { |
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 might make more sense to return the list of TenureChange
transactions here. The tenure can change multiple times in a block, since it has to contain all missing TenureChange
transactions as well.
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 that will be necessary once the TenureChange
transactions are actually getting validated, but right now, all the stacks block processor cares about is whether or not a tenure change occurred.
return ChainstateError::InvalidStacksBlock("Unrecoverable miner public key".into()); | ||
})?; | ||
|
||
if sortdb |
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 this whole if
-block needs to be dropped. A node can accept any block back to the last PoX anchor block, especially while booting up.
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 there needs to be two different acceptance paths for blocks:
- Any block that has been committed to by a leader block commit -- leader block commits still commit to block hashes, but those are not the chain tip. These are used to accept blocks while booting up, catching up to the chain tip.
- The if block in the code above: while operating at the chain tip, the only blocks that should be accepted are ones in recent tenures.
"0c5e890e95e2f92ef36934bc0e5d71a6715974593f7d952b07ee6f959dae3f1c", | ||
"0cd7696c4920ea5bc498ea46ee1df8566e06ea0bc8fd16a1e0ffd292d55f746e", | ||
"84177188b1c02af772d2442b760fd9215b9dfadeed5723504acda2c94b068d15", | ||
"c76d48e971b2ea3c78c476486455090da37df260a41eef355d4e9330faf166c0", |
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 ended up changing these hashes when I was working on the coordinator (since I had to change some of the header structs, which changes the state root hash). That's okay, right?
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, it's fine -- perhaps after factoring the mining routine in the mockamoto node, we should update this test anyways so that its able to figure out its own 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.
Thanks @kantai!
stackslib/src/core/mod.rs
Outdated
@@ -428,6 +432,10 @@ pub static STACKS_EPOCH_2_3_MARKER: u8 = 0x08; | |||
/// *or greater*. | |||
pub static STACKS_EPOCH_2_4_MARKER: u8 = 0x09; | |||
|
|||
/// Stacks 3.0 epoch marker. All block-commits in 2.4 must have a memo bitfield with this value |
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.
/// Stacks 3.0 epoch marker. All block-commits in 2.4 must have a memo bitfield with this value | |
/// Stacks 3.0 epoch marker. All block-commits in 3.0 must have a memo bitfield with this value |
Awesome to see this being reviewed!
If this is not in the SIP already then probably worth adding. The SIPs will be the first place a lot of devs will look for information and can help their understanding of how the code works. |
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! 🚀
Yep -- opened as a PR against the current SIP (stacksgov/sips#158) |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This PR has the initial work for handling nakamoto staging blocks.
Currently, the staging blocks table is part of the same chainstate sqlite db as the old staging blocks table. This simplifies things initially, but part of the nakamoto workstream will be putting that in its own sqlite db.
This extends the
TenureChange
PR with a few more items:It also adds three methods for the staging blocks: getting the next ready block, marking a block as processed, and marking a burn block as processed. Because a block's "burn view" is somewhat independent of the burn block that selected its tenure, this should be tracked separately, so the nakamoto staging blocks table tracks "burn_attachable" and "stacks_attachable".