feat: Fast upgrades: upgrade payload section in blocks - #11655
frankdavid wants to merge 21 commits into
Conversation
First step of the Phase-2 rolling-reboot consensus protocol, which adds the data types and the artifact mechanism. * Add `UpgradePermitAction` (`Request` / `Authorize` / `Return`). `UpgradePermitAuthorizationRequest` is the signed content, `UpgradePermitAuthorizationShare` is the gossiped artifact. * Add the in-memory `UpgradePermitAuthPoolImpl` which is modeled after other pools. * Add the `ic-consensus-upgrade` crate with `UpgradePermitAuthPoolManager`. It signs shares for requests in finalized blocks and validates gossiped shares. * Register the new proto file with the generator and add `UpgradePermitAuthorizationRequest` (signing) and `UpgradePermitAuthorizationShare` (pool-ID hashing) domain separators.
Add the upgrade section to block payloads and wire it into the payload builder infrastructure (with a placeholder builder for now). - Add `upgrade_payload_bytes` to the `Block` proto and upgrade to `BatchPayload`/`BatchMessages` - Add an `Upgrade` section to `BatchPayloadSectionBuilder` - Add the `ic-consensus-upgrade` crate with a placeholder `UpgradePayloadBuilder`
|
✅ No security or compliance issues detected. Reviewed everything up to 5324358. Security OverviewDetected Code Changes
|
alin-at-dfinity
left a comment
There was a problem hiding this comment.
The change overall LGTM, but I'll leave it to Leo or Pierugo to approve, particularly since I'm not sure what the changed hashes in the crypto_hash_stability tests imply.
| assert_eq!( | ||
| hex::encode(hash.get_ref().0.as_slice()), | ||
| "764535296841f3db421a928cfadff3460be406d0182da64034eee623a9a97e99", | ||
| "c20a87578beb94df369dabfefc30c0d47d170c75d68236aae3b16335c0f21c4a", |
There was a problem hiding this comment.
@pierugo-dfinity, @eichhorl, is this (and the similar hash changes below) OK? Does it require any other changes / staged rollout / whatever?
The comment on mod crypto_hash_stability simply says "hashes [...] must remain constant across code changes".
There was a problem hiding this comment.
It's a red herring. As Leo mentioned, the better alternative would be to use a summary block for building the CUP instead of a data block here and below.
There was a problem hiding this comment.
Moved to summary block
There was a problem hiding this comment.
Do you want to split the block and use summary for CUP tests and Data for others (only block_proposal_stability atm)?
There was a problem hiding this comment.
I think it's fine for now (a proposal for a summary block is just as legitimate). If that's not too much of a burden, maybe you could rename fn test_block to fn test_summary_block such that it's clearer for next time (we're already modifying the surrounding code).
| logger: ReplicaLogger, | ||
| ) -> Self { | ||
| let section_builder = vec![ | ||
| BatchPayloadSectionBuilder::Upgrade(upgrade_payload_builder), |
There was a problem hiding this comment.
Why put it first when it is last everywhere else?
There was a problem hiding this comment.
Just for test stability. Otherwise the test would need more changes. The section_builder order should not matter for behavior but if you prefer a particular order, I can change it (and then also change the tests accordingly.)
There was a problem hiding this comment.
I think it is cleaner to keep it last here as well, if the plumbing is expected when adding a new section (which is rare) and isn't too demanding.
| // TODO: implement proper validation | ||
| UpgradePayload::deserialize(payload) | ||
| .map(|_| ()) | ||
| .map_err(|e| { | ||
| ValidationError::InvalidArtifact(InvalidPayloadReason::InvalidUpgradePayload( | ||
| InvalidUpgradePayloadReason::DecodeFailed(format!("{e:?}")), | ||
| )) | ||
| }) |
There was a problem hiding this comment.
Shouldn't we actually validate that the payload is empty? Otherwise a malicious node could fill that section.
There was a problem hiding this comment.
Execution doesn't care about it, so it wouldn't really matter, right? The next PR is bringing the real logic, so unless you can think of a way how this could be abused, I'd just leave it for now.
There was a problem hiding this comment.
I suppose the idea is that a malicious block maker could fill the upgrade payload with garbage, slowing down the subnet (this up to 4 MB payload would have to be gossiped to everyone for no good reason).
OTOH, this is only a temporary situation, until we actually start putting useful content in the payload.
There was a problem hiding this comment.
fill the upgrade payload with garbage, slowing down the subnet
Yes exactly. I think it's best to always keep the builder and the validator in sync. And rejecting obvious malicious behaviour like here.
| assert_eq!( | ||
| hex::encode(hash.get_ref().0.as_slice()), | ||
| "764535296841f3db421a928cfadff3460be406d0182da64034eee623a9a97e99", | ||
| "c20a87578beb94df369dabfefc30c0d47d170c75d68236aae3b16335c0f21c4a", |
There was a problem hiding this comment.
It's a red herring. As Leo mentioned, the better alternative would be to use a summary block for building the CUP instead of a data block here and below.
Co-authored-by: Pierugo Pace <pierugo.pace@dfinity.org>
…st-upgrades-block-payload
…rades-block-payload # Conflicts: # rs/types/types/src/crypto/hash/tests.rs
Add the upgrade section to block payloads and wire it into the payload builder infrastructure (with a placeholder builder for now).
upgrade_payload_bytesto theBlockproto and upgrade toBatchPayload/BatchMessagesUpgradesection toBatchPayloadSectionBuilderic-consensus-upgradecrate with a placeholderUpgradePayloadBuilder