polkadot_test_client/
block_builder.rs1use crate::Client;
18use codec::{Decode, Encode};
19use polkadot_primitives::{Block, InherentData as ParachainsInherentData};
20use polkadot_test_runtime::UncheckedExtrinsic;
21use polkadot_test_service::GetLastTimestamp;
22use sc_block_builder::{BlockBuilder, BlockBuilderBuilder};
23use sp_api::ProvideRuntimeApi;
24use sp_consensus_babe::{
25 digests::{PreDigest, SecondaryPlainPreDigest},
26 BABE_ENGINE_ID,
27};
28use sp_runtime::{traits::Block as BlockT, Digest, DigestItem};
29use sp_state_machine::BasicExternalities;
30
31pub trait InitPolkadotBlockBuilder {
33 fn init_polkadot_block_builder(&self) -> sc_block_builder::BlockBuilder<Block, Client>;
38
39 fn init_polkadot_block_builder_at(
44 &self,
45 hash: <Block as BlockT>::Hash,
46 ) -> sc_block_builder::BlockBuilder<Block, Client>;
47}
48
49impl InitPolkadotBlockBuilder for Client {
50 fn init_polkadot_block_builder(&self) -> BlockBuilder<Block, Client> {
51 let chain_info = self.chain_info();
52 self.init_polkadot_block_builder_at(chain_info.best_hash)
53 }
54
55 fn init_polkadot_block_builder_at(
56 &self,
57 hash: <Block as BlockT>::Hash,
58 ) -> BlockBuilder<Block, Client> {
59 let last_timestamp =
60 self.runtime_api().get_last_timestamp(hash).expect("Get last timestamp");
61
62 let minimum_period = BasicExternalities::new_empty()
65 .execute_with(|| polkadot_test_runtime::MinimumPeriod::get());
66
67 let timestamp = if last_timestamp == 0 {
68 std::time::SystemTime::now()
69 .duration_since(std::time::SystemTime::UNIX_EPOCH)
70 .expect("Time is always after UNIX_EPOCH; qed")
71 .as_millis() as u64
72 } else {
73 last_timestamp + minimum_period
74 };
75
76 let slot_duration = BasicExternalities::new_empty()
79 .execute_with(|| polkadot_test_runtime::SlotDuration::get());
80
81 let slot = (timestamp / slot_duration).into();
82
83 let digest = Digest {
84 logs: vec![DigestItem::PreRuntime(
85 BABE_ENGINE_ID,
86 PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: 42 })
87 .encode(),
88 )],
89 };
90
91 let mut block_builder = BlockBuilderBuilder::new(self)
92 .on_parent_block(hash)
93 .fetch_parent_block_number(&self)
94 .expect("Fetches parent block number")
95 .with_inherent_digests(digest)
96 .build()
97 .expect("Creates new block builder for test runtime");
98
99 let mut inherent_data = sp_inherents::InherentData::new();
100
101 inherent_data
102 .put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
103 .expect("Put timestamp inherent data");
104
105 let parent_header = self
106 .header(hash)
107 .expect("Get the parent block header")
108 .expect("The target block header must exist");
109
110 let parachains_inherent_data = ParachainsInherentData {
111 bitfields: Vec::new(),
112 backed_candidates: Vec::new(),
113 disputes: Vec::new(),
114 parent_header,
115 };
116
117 inherent_data
118 .put_data(
119 polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER,
120 ¶chains_inherent_data,
121 )
122 .expect("Put parachains inherent data");
123
124 let inherents = block_builder.create_inherents(inherent_data).expect("Creates inherents");
125
126 inherents
127 .into_iter()
128 .for_each(|ext| block_builder.push(ext).expect("Pushes inherent"));
129
130 block_builder
131 }
132}
133
134pub trait BlockBuilderExt {
136 fn push_polkadot_extrinsic(
144 &mut self,
145 ext: UncheckedExtrinsic,
146 ) -> Result<(), sp_blockchain::Error>;
147}
148
149impl BlockBuilderExt for BlockBuilder<'_, Block, Client> {
150 fn push_polkadot_extrinsic(
151 &mut self,
152 ext: UncheckedExtrinsic,
153 ) -> Result<(), sp_blockchain::Error> {
154 let encoded = ext.encode();
155 self.push(
156 Decode::decode(&mut &encoded[..]).expect(
157 "The runtime specific extrinsic always decodes to an opaque extrinsic; qed",
158 ),
159 )
160 }
161}