Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Introduce upgrade go-ahead and upgrade restriction signals #3371

Merged
merged 9 commits into from
Aug 3, 2021
64 changes: 63 additions & 1 deletion primitives/src/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,41 @@ pub mod well_known_keys {
.collect()
})
}
}

/// The signal that indicates whether the parachain should go-ahead with the proposed validation
/// code upgrade.
///
/// The storage entry stores a value of `UpgradeGoAhead` type.
pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec<u8> {
let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];

para_id.using_encoded(|para_id: &[u8]| {
prefix.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}

/// The signal that indicates whether the parachain is disallowed to signal an upgrade at this
/// relay-parent.
///
/// The storage entry stores a value of `UpgradeRestriction` type.
pub fn upgrade_restriction_signal(para_id: Id) -> Vec<u8> {
let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];

para_id.using_encoded(|para_id: &[u8]| {
prefix.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
}

/// Unique identifier for the Parachains Inherent
pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
Expand Down Expand Up @@ -1012,6 +1045,35 @@ pub struct AbridgedHrmpChannel {
pub mqc_head: Option<Hash>,
}

/// A possible upgrade restriction that prevents a parachain from performing an upgrade.
#[derive(Encode, Decode, PartialEq, RuntimeDebug)]
pub enum UpgradeRestriction {
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
/// There is an upgrade restriction and there are no details about its specifics nor how long
/// it could last.
Present,
}

/// A struct that the relay-chain communicates to a parachain indicating what course of action the
/// parachain should take in the coordinated parachain validation code upgrade process.
///
/// This data type appears in the last step of the upgrade process. After the parachain observes it
/// and reacts to it the upgrade process concludes.
#[derive(Encode, Decode, PartialEq, RuntimeDebug)]
pub enum UpgradeGoAhead {
/// Abort the upgrade process. There is something wrong with the validation code previously
/// submitted by the parachain. This variant can also be used to prevent upgrades by the governance
/// should an emergency emerge.
///
/// The expected reaction on this variant is that the parachain will admit this message and
/// remove all the data about the pending upgrade. Depending on the nature of the problem (to
/// be examined offchain for now), it can try to send another validation code or just retry later.
Abort,
/// Apply the pending code change. The parablock that is built on a relay-parent that is descendant
/// of the relay-parent where the parachain observed this signal must use the upgraded validation
/// code.
GoAhead,
}

/// Consensus engine id for polkadot v1 consensus engine.
pub const POLKADOT_ENGINE_ID: runtime_primitives::ConsensusEngineId = *b"POL1";

Expand Down
2 changes: 1 addition & 1 deletion roadmap/implementers-guide/src/runtime/inclusion.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. create a corresponding entry in the `PendingAvailabilityCommitments` with the commitments.
1. Return a `Vec<CoreIndex>` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex.
* `enact_candidate(relay_parent_number: BlockNumber, CommittedCandidateReceipt)`:
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number + config.validationl_upgrade_delay)`.
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number, config)`.
> TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it.
1. Reward all backing validators of each candidate, contained within the `backers` field.
1. call `Ump::receive_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments).
Expand Down
38 changes: 35 additions & 3 deletions roadmap/implementers-guide/src/runtime/paras.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,35 @@ PastCodePruning: Vec<(ParaId, BlockNumber)>;
FutureCodeUpgrades: map ParaId => Option<BlockNumber>;
/// The actual future code of a para.
FutureCodeHash: map ParaId => Option<ValidationCodeHash>;
/// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade procedure.
///
/// This value is abscent when there are no upgrades scheduled or during the time the relay chain
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
/// performs the checks. It is set at the first relay-chain block when the corresponding parachain
/// can switch its upgrade function. As soon as the parachain's block is included, the value
/// gets reset to `None`.
///
/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
/// the format will require migration of parachains.
UpgradeGoAheadSignal: map hasher(twox_64_concat) ParaId => Option<UpgradeGoAhead>;
/// This is used by the relay-chain to communicate that there are restrictions for performing
/// an upgrade for this parachain.
///
/// This may be a because the parachain waits for the upgrade cooldown to expire. Another
/// potential use case is when we want to perform some maintanance (such as storage migration)
/// we could restrict upgrades to make the process simpler.
///
/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
/// the format will require migration of parachains.
UpgradeRestrictionSignal: map hasher(twox_64_concat) ParaId => Option<UpgradeRestriction>;
/// The list of parachains that are awaiting for their upgrade restriction to cooldown.
///
/// Ordered ascending by block number.
UpgradeCooldowns: Vec<(ParaId, T::BlockNumber)>;
/// The list of upcoming code upgrades. Each item is a pair of which para performs a code
/// upgrade and at which relay-chain block it is expected at.
///
/// Ordered ascending by block number.
UpcomingUpgrades: Vec<(ParaId, T::BlockNumber)>;
/// The actions to perform during the start of a specific session index.
ActionsQueue: map SessionIndex => Vec<ParaId>;
/// Upcoming paras instantiation arguments.
Expand Down Expand Up @@ -171,6 +200,9 @@ CodeByHash: map ValidationCodeHash => Option<ValidationCode>

1. Do pruning based on all entries in `PastCodePruning` with `BlockNumber <= now`. Update the
corresponding `PastCodeMeta` and `PastCode` accordingly.
1. Toggle the upgrade related signals
1. Collect all `(para_id, expected_at)` from `UpcomingUpgrades` where `expected_at <= now` and prune them. For each para pruned set `UpgradeGoAheadSignal` to `GoAhead`.
1. Collect all `(para_id, next_possible_upgrade_at)` from `UpgradeCooldowns` where `next_possible_upgrade_at <= now` and prune them. For each para prunned set `UpgradeRestrictionSignal` to `Present`.

## Routines

Expand All @@ -179,12 +211,12 @@ CodeByHash: map ValidationCodeHash => Option<ValidationCode>
* `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up after the next full session.
* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread to be upgraded to a parachain.
* `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded to a parathread.
* `schedule_code_upgrade(ParaId, CurrentCode, expected_at: BlockNumber)`: Schedule a future code
* `schedule_code_upgrade(ParaId, CurrentCode, relay_parent: BlockNumber, HostConfiguration)`: Schedule a future code
upgrade of the given parachain, to be applied after inclusion of a block of the same parachain
executed in the context of a relay-chain block with number >= `expected_at`.
executed in the context of a relay-chain block with number >= `relay_parent + config.validation_upgrade_delay`. If the upgrade is scheduled `UpgradeRestrictionSignal` is set and it will remain set until `relay_parent + config.validation_upgrade_frequency`.
* `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head,
where the new head was executed in the context of a relay-chain block with given number. This will
apply pending code upgrades based on the block number provided.
apply pending code upgrades based on the block number provided. If an upgrade took place it will clear the `UpgradeGoAheadSignal`.
* `validation_code_at(ParaId, at: BlockNumber, assume_intermediate: Option<BlockNumber>)`: Fetches
the validation code to be used when validating a block in the context of the given relay-chain
height. A second block number parameter may be used to tell the lookup to proceed as if an
Expand Down
21 changes: 14 additions & 7 deletions runtime/parachains/src/inclusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,8 @@ impl<T: Config> Module<T> {
weight += <paras::Pallet<T>>::schedule_code_upgrade(
receipt.descriptor.para_id,
new_code,
relay_parent_number + config.validation_upgrade_delay,
relay_parent_number,
&config,
);
}

Expand Down Expand Up @@ -2038,13 +2039,19 @@ mod tests {
BackingKind::Threshold,
));

Paras::schedule_code_upgrade(
chain_a,
vec![1, 2, 3, 4].into(),
10,
);
{
let cfg = Configuration::config();
let expected_at = 10 + cfg.validation_upgrade_delay;
assert_eq!(expected_at, 10);
Paras::schedule_code_upgrade(
chain_a,
vec![1, 2, 3, 4].into(),
expected_at,
&cfg,
);

assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(10));
assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(expected_at));
}

assert_eq!(
Inclusion::process_candidates(
Expand Down
Loading