[FRAME] Make MQ pallet re-entrancy safe (#2356)

Closes https://github.com/paritytech/polkadot-sdk/issues/2319

Changes:
- Ensure that only `enqueue_message(s)` is callable from within the
message processor. This prevents messed up storage that can currently
happen when the pallet is called into recursively.
- Use `H256` instead of `[u8; 32]` for clearer API.

## Details

The re-entracy check is done with the `environmental` crate by adding a
`with_service_mutex(f)` function that runs the closure exclusively. This
works since the MQ pallet is not instantiable.

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
This commit is contained in:
Oliver Tale-Yazdi
2023-12-07 17:48:13 +01:00
committed by GitHub
parent 95c3ee10bc
commit 7e7fe99047
11 changed files with 478 additions and 79 deletions
+29 -1
View File
@@ -108,7 +108,10 @@ impl MockedWeightInfo {
impl crate::weights::WeightInfo for MockedWeightInfo {
fn reap_page() -> Weight {
WeightForCall::get().get("reap_page").copied().unwrap_or_default()
WeightForCall::get()
.get("reap_page")
.copied()
.unwrap_or(DefaultWeightForCall::get())
}
fn execute_overweight_page_updated() -> Weight {
WeightForCall::get()
@@ -207,6 +210,10 @@ impl ProcessMessage for RecordingMessageProcessor {
let required = Weight::from_parts(weight, weight);
if meter.try_consume(required).is_ok() {
if let Some(p) = message.strip_prefix(&b"callback="[..]) {
let s = String::from_utf8(p.to_vec()).expect("Need valid UTF8");
Callback::get()(&origin, s.parse().expect("Expected an u32"));
}
let mut m = MessagesProcessed::get();
m.push((message.to_vec(), origin));
MessagesProcessed::set(m);
@@ -217,6 +224,10 @@ impl ProcessMessage for RecordingMessageProcessor {
}
}
parameter_types! {
pub static Callback: Box<fn (&MessageOrigin, u32)> = Box::new(|_, _| {});
}
/// Processed a mocked message. Messages that end with `badformat`, `corrupt`, `unsupported` or
/// `yield` will fail with an error respectively.
fn processing_message(msg: &[u8], origin: &MessageOrigin) -> Result<(), ProcessMessageError> {
@@ -264,6 +275,10 @@ impl ProcessMessage for CountingMessageProcessor {
let required = Weight::from_parts(1, 1);
if meter.try_consume(required).is_ok() {
if let Some(p) = message.strip_prefix(&b"callback="[..]) {
let s = String::from_utf8(p.to_vec()).expect("Need valid UTF8");
Callback::get()(&origin, s.parse().expect("Expected an u32"));
}
NumMessagesProcessed::set(NumMessagesProcessed::get() + 1);
Ok(true)
} else {
@@ -372,3 +387,16 @@ pub fn num_overweight_enqueued_events() -> u32 {
pub fn fp(pages: u32, count: u64, size: u64) -> QueueFootprint {
QueueFootprint { storage: Footprint { count, size }, pages }
}
/// A random seed that can be overwritten with `MQ_SEED`.
pub fn gen_seed() -> u64 {
use rand::Rng;
let seed = if let Ok(seed) = std::env::var("MQ_SEED") {
seed.parse().expect("Need valid u64 as MQ_SEED env variable")
} else {
rand::thread_rng().gen::<u64>()
};
println!("Using seed: {}", seed);
seed
}