Unverified Commit 3b7bc013 authored by Sergey Pepyakin's avatar Sergey Pepyakin Committed by GitHub
Browse files

Introduce upgrade go-ahead and upgrade restriction signals (#3371)

* Introduce upgrade goahead and upgrade restriction signals

* Explicit encoding indicies for exposed enums

* typo: abscent -> absent

* Prune cooldowns as well

* Please hunspell
parent 28823045
Pipeline #150979 passed with stages
in 42 minutes and 49 seconds
......@@ -182,6 +182,42 @@ 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
......@@ -1035,6 +1071,38 @@ 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 {
/// There is an upgrade restriction and there are no details about its specifics nor how long
/// it could last.
#[codec(index = 0)]
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.
#[codec(index = 0)]
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.
#[codec(index = 1)]
GoAhead,
}
/// Consensus engine id for polkadot v1 consensus engine.
pub const POLKADOT_ENGINE_ID: runtime_primitives::ConsensusEngineId = *b"POL1";
......
......@@ -45,7 +45,7 @@ PendingAvailabilityCommitments: map ParaId => CandidateCommitments;
All failed checks should lead to an unrecoverable error making the block invalid.
* `process_bitfields(expected_bits, Bitfields, core_lookup: Fn(CoreIndex) -> Option<ParaId>)`:
1. check that there is at most 1 bitfield per validator and that the number of bits in each bitfield is equal to expected_bits.
1. check that there is at most 1 bitfield per validator and that the number of bits in each bitfield is equal to `expected_bits`.
1. check that there are no duplicates
1. check all validator signatures.
1. apply each bit of bitfield to the corresponding pending candidate. looking up parathread cores using the `core_lookup`. Disregard bitfields that have a `1` bit for any free cores.
......@@ -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).
......
......@@ -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 absent when there are no upgrades scheduled or during the time the relay chain
/// 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.
......@@ -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 pruned set `UpgradeRestrictionSignal` to `Present`.
## Routines
......@@ -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
......
......@@ -701,7 +701,8 @@ impl<T: Config> Pallet<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,
);
}
......@@ -2120,9 +2121,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!(
ParaInclusion::process_candidates(
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment