I'm trying to onboard a team to paraID2000 on Rococo, but I'm not being able to do so successfully. The ID was previously being used by another team that attempted to upgrade their chain and bricked it. What I did was to manually delete the futureCodeHash for that previous chain, deregister the paraID, and then re-register it with the new team's information (registar.forceRegister(who, deposit,id,gensis,wasm)). Still, the parachain is not producing blocks and I'm not entirely sure why.

Did I miss any steps in the middle? How can I best debug this?

  • Not an expert on this but I think the parachain id is meant to not use twice. Probably it's just easier to register another parachain if it's just for local testing
    – h4x3rotab
    Mar 25, 2022 at 17:33
  • You can request rococo onboarding of a parachain here: github.com/paritytech/subport/issues/…
    – Squirrel
    Mar 26, 2022 at 16:25

1 Answer 1


It shows what steps should be taken for offboarding a parachain or parathread from the system in the Polkadot codebase here, which includes the following:

  • ◻ Remove the registered parachain id from the head-data storage item <Self as Store>::Heads::remove(&para)
  • ◻ Remove the registered parachain id from the FutureCodeUpgrades storage item <Self as Store>::FutureCodeUpgrades::remove(&para)
  • ◻ Remove the registered parachain id from the UpgradeGoAheadSignal storage item <Self as Store>::UpgradeGoAheadSignal::remove(&para)
  • ◻ Remove the registered parachain id from the UpgradeRestrictionSignal storage item <Self as Store>::UpgradeRestrictionSignal::remove(&para)
  • ◻ Decrease the number of references of the validation code and remove it from storage if zero is reached, which involves
    • ☑ Copy the FutureCodeHash for that parachain id and remove it from FutureCodeHash storage
      let removed_future_code_hash = <Self as Store>::FutureCodeHash::take(&para)
    • ◻ If that FutureCodeHash value is not None, then you need to use that copied FutureCodeHash as the ValidationCodeHash (code_hash) in the decrease_code_ref function shown here
      if let Some(removed_future_code_hash) = removed_future_code_hash {
      • ◻ In decrease_code_ref you provide it as an argument to CodeByHashRefs.
        • Obtain its refs storage value, as shown below:
          fn decrease_code_ref(code_hash: &ValidationCodeHash) -> Weight {
              let refs = <Self as Store>::CodeByHashRefs::get(code_hash)
        • If refs == 0 then no further action is required in this step.
        • Else if refs <= 1 then remove that code_hash value from the storage values CodeByHash and CodeByHashRefs as shown below:
          <Self as Store>::CodeByHash::remove(code_hash);
          <Self as Store>::CodeByHashRefs::remove(code_hash);
        • Otherwise you need to insert a value into CodeByHashRefs storage, where the key is that code_hash and the value is refs - 1 as shown below:
          <Self as Store>::CodeByHashRefs::insert(code_hash, refs - 1);
  • ◻ Note the replacement of code for the parachain id, in the context of the current relay-chain block number, and provide the replaced code, which involves:
    • ◻ Copy the CurrentCodeHash for that parachain id and remove it from CurrentCodeHash storage
      let removed_code_hash = <Self as Store>::CurrentCodeHash::take(&para)
    • ◻ If that CurrentCodeHash value is not None, then you need to do the following in the note_past_code function:
      • Use that copied CurrentCodeHash as the ValidationCodeHash (old_code_hash) in the note_past_code function shown here, as shown below:
        if let Some(removed_code_hash) = removed_code_hash {
            Self::note_past_code(para, now, now, removed_code_hash);
      • ◻ In the note_past_code function it shows you have to update the PastCodeMeta for that parachain id, and the current relay-chain block number, which requires updating the upgrade_times property of ParaPastCodeMeta by pushing a new ReplacementTimes { expected_at, activated_at } value where expected_at and activated_at are both the current relay-chain block number.
        <Self as Store>::PastCodeMeta::mutate(&id, |past_meta| {
            past_meta.note_replacement(at, now);
        impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
            // note a replacement has occurred at a given block number.
            pub(crate) fn note_replacement(&mut self, expected_at: N, activated_at: N) {
                self.upgrade_times.push(ReplacementTimes { expected_at, activated_at })
        /// Metadata used to track previous parachain validation code that we keep in
        /// the state.
        pub struct ParaPastCodeMeta<N> {
            upgrade_times: Vec<ReplacementTimes<N>>,
      • ◻ In the note_past_code function, it shows you have to insert the old_code_hash as the new value of a key that is a tuple containing the parachain id and the current relay-chain block number:
        <Self as Store>::PastCodeHash::insert(&(id, at), old_code_hash);
      • ◻ In the note_past_code function, it shows you need to update PastCodePruning storage by finding the index of the current relay-chain block number, and then inserting a new tuple value under that index (id, now), which is the parachain id and the current relay-chain block number
        <Self as Store>::PastCodePruning::mutate(|pruning| {
            let insert_idx =
                pruning.binary_search_by_key(&now, |&(_, b)| b).unwrap_or_else(|idx| idx);
            pruning.insert(insert_idx, (id, now));
        pub(super) type PastCodePruning<T: Config> =
            StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;

It also shows what steps to take to deregister a parachain:

  • ☑ Deregister a parachain as shown in the function here

If you have only manually deleted the FutureCodeHash for the previous parachain id and deregistered the parachan, then it seems you have only finished doing the steps where I have checked the checkboxes above, and hopefully you made a copy of the FutureCodeHash before deleting it, but it appears you still have to do the other offboarding steps that are indicated above with unchecked checkboxes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.