test_parachain_undying/
lib.rs1#![no_std]
20
21extern crate alloc;
22
23use alloc::vec::Vec;
24use codec::{Decode, Encode};
25use polkadot_parachain_primitives::primitives::UpwardMessages;
26use polkadot_primitives::{
27 ClaimQueueOffset, CoreSelector, UMPSignal, DEFAULT_CLAIM_QUEUE_OFFSET, UMP_SEPARATOR,
28};
29use tiny_keccak::{Hasher as _, Keccak};
30
31#[cfg(not(feature = "std"))]
32mod wasm_validation;
33
34#[cfg(not(feature = "std"))]
35#[global_allocator]
36static ALLOC: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc;
37const LOG_TARGET: &str = "runtime::undying";
38
39#[cfg(feature = "std")]
41include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
42
43fn keccak256(input: &[u8]) -> [u8; 32] {
44 let mut out = [0u8; 32];
45 let mut keccak256 = Keccak::v256();
46 keccak256.update(input);
47 keccak256.finalize(&mut out);
48 out
49}
50
51#[cfg(feature = "std")]
53pub fn wasm_binary_unwrap() -> &'static [u8] {
54 WASM_BINARY.expect(
55 "Development wasm binary is not available. Testing is only \
56 supported with the flag disabled.",
57 )
58}
59
60#[derive(Default, Clone, Hash, Eq, PartialEq, Encode, Decode, Debug)]
62pub struct HeadData {
63 pub number: u64,
65 pub parent_hash: [u8; 32],
67 pub post_state: [u8; 32],
69}
70
71impl HeadData {
72 pub fn hash(&self) -> [u8; 32] {
73 keccak256(&self.encode())
74 }
75}
76
77#[derive(Default, Clone, Encode, Decode, Debug)]
79pub struct GraveyardState {
80 pub index: u64,
82 pub graveyard: Vec<u8>,
86 pub zombies: u64,
91 pub seal: [u8; 32],
93 pub core_selector_number: u8,
95}
96
97#[derive(Default, Clone, Encode, Decode, Debug)]
99pub struct BlockData {
100 pub state: GraveyardState,
102 pub tombstones: u64,
105 pub iterations: u32,
107 pub experimental_send_approved_peer: bool,
109}
110
111pub fn hash_state(state: &GraveyardState) -> [u8; 32] {
112 keccak256(state.encode().as_slice())
113}
114
115pub fn execute_transaction(mut block_data: BlockData) -> GraveyardState {
117 let graveyard_size = block_data.state.graveyard.len();
118
119 for _ in 0..block_data.iterations {
120 for _ in 0..block_data.tombstones {
121 block_data.state.graveyard[block_data.state.index as usize] =
122 block_data.state.graveyard[block_data.state.index as usize].wrapping_add(1);
123
124 block_data.state.index =
125 ((block_data.state.index.saturating_add(1)) as usize % graveyard_size) as u64;
126 }
127 block_data.state.seal = hash_state(&block_data.state);
129 }
130 block_data.state.core_selector_number = block_data.state.core_selector_number.wrapping_add(1);
131
132 block_data.state
133}
134
135#[derive(Debug)]
137pub struct StateMismatch;
138
139pub fn execute(
142 parent_hash: [u8; 32],
143 parent_head: HeadData,
144 block_data: BlockData,
145) -> Result<(HeadData, GraveyardState, UpwardMessages), StateMismatch> {
146 assert_eq!(parent_hash, parent_head.hash());
147
148 if hash_state(&block_data.state) != parent_head.post_state {
149 log::debug!(
150 target: LOG_TARGET,
151 "state has diff vs head: {:?} vs {:?}",
152 hash_state(&block_data.state),
153 parent_head.post_state,
154 );
155 return Err(StateMismatch)
156 }
157
158 let mut upward_messages: UpwardMessages = Default::default();
159 upward_messages.force_push(UMP_SEPARATOR);
160 upward_messages.force_push(
161 UMPSignal::SelectCore(
162 CoreSelector(block_data.state.core_selector_number),
163 ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET),
164 )
165 .encode(),
166 );
167
168 if block_data.experimental_send_approved_peer {
169 upward_messages
170 .force_push(UMPSignal::ApprovedPeer(alloc::vec![1, 2, 3].try_into().unwrap()).encode());
171 }
172
173 let new_state = execute_transaction(block_data.clone());
175
176 Ok((
177 HeadData {
178 number: parent_head.number + 1,
179 parent_hash,
180 post_state: hash_state(&new_state),
181 },
182 new_state,
183 upward_messages,
184 ))
185}