Skip to content

Commit f6e7385

Browse files
paritytech-release-backport-bot[bot]bkchrEgorPopelyaevgithub-actions[bot]
authored
[stable2509] Backport #10280 (#10295)
Backport #10280 into `stable2509` from bkchr. See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. <!-- # To be used by other automation, do not modify: original-pr-number: #${pull_number} --> --------- Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Egor_P <[email protected]> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 6217936 commit f6e7385

File tree

5 files changed

+105
-5
lines changed

5 files changed

+105
-5
lines changed

cumulus/pallets/parachain-system/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ pub mod pallet {
579579
// TODO: This is more than zero, but will need benchmarking to figure out what.
580580
let mut total_weight = Weight::zero();
581581

582-
// NOTE: the inherent data is expected to be unique, even if this block is built
582+
// NOTE: the inherent data is expected to be unique, even if this block is build
583583
// in the context of the same relay parent as the previous one. In particular,
584584
// the inherent shouldn't contain messages that were already processed by any of the
585585
// ancestors.
@@ -637,7 +637,7 @@ pub mod pallet {
637637
),
638638
);
639639

640-
// initialization logic: we know that this runs exactly once every block,
640+
// Initialization logic: we know that this runs exactly once every block,
641641
// which means we can put the initialization logic here to remove the
642642
// sequencing problem.
643643
let upgrade_go_ahead_signal = relay_state_proof

cumulus/pallets/parachain-system/src/validate_block/implementation.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use frame_support::{
3434
use polkadot_parachain_primitives::primitives::{
3535
HeadData, RelayChainBlockNumber, ValidationResult,
3636
};
37-
use sp_core::storage::{ChildInfo, StateVersion};
37+
use sp_core::storage::{well_known_keys, ChildInfo, StateVersion};
3838
use sp_externalities::{set_and_run_with_externalities, Externalities};
3939
use sp_io::{hashing::blake2_128, KillStorageResult};
4040
use sp_runtime::traits::{
@@ -269,6 +269,10 @@ where
269269
},
270270
);
271271

272+
if overlay.storage(well_known_keys::CODE).is_some() && num_blocks > 1 {
273+
panic!("When applying a runtime upgrade, only one block per PoV is allowed. Received {num_blocks}.")
274+
}
275+
272276
run_with_externalities_and_recorder::<B, _, _>(
273277
&backend,
274278
&mut Default::default(),

cumulus/pallets/parachain-system/src/validate_block/tests.rs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616

1717
use crate::{validate_block::MemoryOptimizedValidationParams, *};
1818
use codec::{Decode, DecodeAll, Encode};
19-
use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
19+
use cumulus_primitives_core::{relay_chain, ParachainBlockData, PersistedValidationData};
2020
use cumulus_test_client::{
2121
generate_extrinsic, generate_extrinsic_with_pair,
2222
runtime::{
23-
self as test_runtime, Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY,
23+
self as test_runtime, Block, Hash, Header, SudoCall, SystemCall, TestPalletCall,
24+
UncheckedExtrinsic, WASM_BINARY,
2425
},
2526
seal_block, transfer, BlockData, BlockOrigin, BuildParachainBlockData, Client,
2627
DefaultTestClientBuilderExt, HeadData, InitBlockBuilder,
@@ -692,3 +693,89 @@ fn ensure_we_only_like_blockchains() {
692693
.contains("Not a valid chain of blocks :("));
693694
}
694695
}
696+
697+
#[test]
698+
fn rejects_multiple_blocks_per_pov_when_applying_runtime_upgrade() {
699+
sp_tracing::try_init_simple();
700+
701+
if env::var("RUN_TEST").is_ok() {
702+
let (client, genesis_head) = create_elastic_scaling_test_client();
703+
704+
let code = test_runtime::elastic_scaling_500ms::WASM_BINARY
705+
.expect("You need to build the WASM binaries to run the tests!")
706+
.to_vec();
707+
let code_len = code.len() as u32;
708+
709+
let mut proof_builder =
710+
RelayStateSproofBuilder { current_slot: 1.into(), ..Default::default() };
711+
proof_builder.host_config.max_code_size = code_len * 2;
712+
713+
// Build the block that send the runtime upgrade.
714+
let TestBlockData { block: initial_block_data, .. } = build_block_with_witness(
715+
&client,
716+
vec![generate_extrinsic_with_pair(
717+
&client,
718+
Alice.into(),
719+
SudoCall::sudo {
720+
call: Box::new(SystemCall::set_code_without_checks { code }.into()),
721+
},
722+
Some(0),
723+
)],
724+
genesis_head.clone(),
725+
proof_builder,
726+
Vec::new(),
727+
);
728+
729+
let initial_block = initial_block_data.blocks()[0].clone();
730+
let (mut header, extrinsics) = initial_block.clone().deconstruct();
731+
let seal = header.digest.pop().unwrap();
732+
733+
let mut import = BlockImportParams::new(BlockOrigin::Own, header.clone());
734+
import.body = Some(extrinsics);
735+
import.post_digests.push(seal);
736+
import.fork_choice = Some(ForkChoiceStrategy::Custom(true));
737+
738+
futures::executor::block_on(BlockImport::import_block(&client, import)).unwrap();
739+
let initial_block_header = initial_block.header().clone();
740+
741+
let mut proof_builder = RelayStateSproofBuilder {
742+
current_slot: 2.into(),
743+
upgrade_go_ahead: Some(relay_chain::UpgradeGoAhead::GoAhead),
744+
..Default::default()
745+
};
746+
proof_builder.host_config.max_code_size = code_len * 2;
747+
748+
// 2. Build a PoV that consists of multiple blocks.
749+
let TestBlockData { block: pov_block_data, validation_data: pov_validation_data } =
750+
build_multiple_blocks_with_witness(
751+
&client,
752+
initial_block_header.clone(), // Start building PoV from the initial block's header
753+
proof_builder,
754+
4,
755+
|_| Vec::new(),
756+
);
757+
758+
// 3. Validate the PoV.
759+
call_validate_block_elastic_scaling(
760+
initial_block_header, // The parent is the head of the initial block before the PoV
761+
pov_block_data,
762+
pov_validation_data.relay_parent_storage_root,
763+
)
764+
.unwrap_err();
765+
} else {
766+
let output = Command::new(env::current_exe().unwrap())
767+
.args([
768+
"rejects_multiple_blocks_per_pov_when_applying_runtime_upgrade",
769+
"--",
770+
"--nocapture",
771+
])
772+
.env("RUN_TEST", "1")
773+
.output()
774+
.expect("Runs the test");
775+
776+
assert!(output.status.success());
777+
778+
assert!(dbg!(String::from_utf8(output.stderr).unwrap())
779+
.contains("only one block per PoV is allowed"));
780+
}
781+
}

cumulus/test/runtime/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub use frame_support::{
9494
},
9595
StorageValue,
9696
};
97+
pub use frame_system::Call as SystemCall;
9798
use frame_system::{
9899
limits::{BlockLength, BlockWeights},
99100
EnsureRoot,

prdoc/pr_10280.prdoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
title: Accept only one block in `validate_block` when upgrading a runtime
2+
doc:
3+
- audience: Node Dev
4+
description: |-
5+
As the validation is running the entire time using the same validation code, we can not accept any other blocks after a runtime upgrade was applied.
6+
crates:
7+
- name: cumulus-pallet-parachain-system
8+
bump: patch

0 commit comments

Comments
 (0)