From 7c1dd95e50cd80ce9f1c1aea1e542131995795e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 2 Mar 2021 08:26:43 +0100 Subject: [PATCH] contracts: Use unstable sort for topics (#8232) * contracts: Use unstable sort for topics * Add warning about non-determinism --- substrate/frame/contracts/src/wasm/runtime.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index c383fdcc2a..7fde24d204 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -294,24 +294,6 @@ fn already_charged(_: u32) -> Option { None } -/// Finds duplicates in a given vector. -/// -/// This function has complexity of O(n log n) and no additional memory is required, although -/// the order of items is not preserved. -fn has_duplicates>(items: &mut Vec) -> bool { - // Sort the vector - items.sort_by(|a, b| { - Ord::cmp(a.as_ref(), b.as_ref()) - }); - // And then find any two consecutive equal elements. - items.windows(2).any(|w| { - match w { - &[ref a, ref b] => a == b, - _ => false, - } - }) -} - /// Can only be used for one call. pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, @@ -1295,6 +1277,22 @@ define_env!(Env, , // - data_ptr - a pointer to a raw data buffer which will saved along the event. // - data_len - the length of the data buffer. seal_deposit_event(ctx, topics_ptr: u32, topics_len: u32, data_ptr: u32, data_len: u32) => { + + fn has_duplicates(items: &mut Vec) -> bool { + // # Warning + // + // Unstable sorts are non-deterministic across architectures. The usage here is OK + // because we are rejecting duplicates which removes the non determinism. + items.sort_unstable(); + // Find any two consecutive equal elements. + items.windows(2).any(|w| { + match &w { + &[a, b] => a == b, + _ => false, + } + }) + } + let num_topic = topics_len .checked_div(sp_std::mem::size_of::>() as u32) .ok_or_else(|| "Zero sized topics are not allowed")?; @@ -1317,6 +1315,8 @@ define_env!(Env, , } // Check for duplicate topics. If there are any, then trap. + // Complexity O(n * log(n)) and no additional allocations. + // This also sorts the topics. if has_duplicates(&mut topics) { Err(Error::::DuplicateTopics)?; }