substrate_test_runtime/
extrinsic.rs1use crate::{
21 substrate_test_pallet::pallet::Call as PalletCall, AccountId, Balance, BalancesCall,
22 CheckSubstrateCall, Extrinsic, Nonce, Pair, RuntimeCall, SignedPayload, TransferData,
23};
24use codec::Encode;
25use frame_metadata_hash_extension::CheckMetadataHash;
26use frame_system::{CheckNonce, CheckWeight};
27use sp_core::crypto::Pair as TraitPair;
28use sp_keyring::Sr25519Keyring;
29use sp_runtime::{
30 generic::Preamble, traits::TransactionExtension, transaction_validity::TransactionPriority,
31 Perbill,
32};
33
34#[derive(Clone)]
36pub struct Transfer {
37 pub from: Pair,
39 pub to: AccountId,
41 pub amount: Balance,
43 pub nonce: u64,
45}
46
47impl Transfer {
48 pub fn into_unchecked_extrinsic(self) -> Extrinsic {
50 ExtrinsicBuilder::new_transfer(self).build()
51 }
52}
53
54impl Default for TransferData {
55 fn default() -> Self {
56 Self {
57 from: Sr25519Keyring::Alice.into(),
58 to: Sr25519Keyring::Bob.into(),
59 amount: 0,
60 nonce: 0,
61 }
62 }
63}
64
65impl TryFrom<&Extrinsic> for TransferData {
67 type Error = ();
68 fn try_from(uxt: &Extrinsic) -> Result<Self, Self::Error> {
69 match uxt {
70 Extrinsic {
71 function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }),
72 preamble: Preamble::Signed(from, _, ((CheckNonce(nonce), ..), ..)),
73 ..
74 } => Ok(TransferData { from: *from, to: *dest, amount: *value, nonce: *nonce }),
75 Extrinsic {
76 function: RuntimeCall::SubstrateTest(PalletCall::bench_call { transfer }),
77 preamble: Preamble::Bare(_),
78 ..
79 } => Ok(transfer.clone()),
80 _ => Err(()),
81 }
82 }
83}
84
85pub struct ExtrinsicBuilder {
87 function: RuntimeCall,
88 signer: Option<Pair>,
89 nonce: Option<Nonce>,
90 metadata_hash: Option<[u8; 32]>,
91}
92
93impl ExtrinsicBuilder {
94 pub fn new(function: impl Into<RuntimeCall>) -> Self {
96 Self {
97 function: function.into(),
98 signer: Some(Sr25519Keyring::Alice.pair()),
99 nonce: None,
100 metadata_hash: None,
101 }
102 }
103
104 pub fn new_unsigned(function: impl Into<RuntimeCall>) -> Self {
106 Self { function: function.into(), signer: None, nonce: None, metadata_hash: None }
107 }
108
109 pub fn new_bench_call(transfer: TransferData) -> Self {
111 Self::new_unsigned(PalletCall::bench_call { transfer })
112 }
113
114 pub fn new_transfer(transfer: Transfer) -> Self {
117 Self {
118 nonce: Some(transfer.nonce),
119 signer: Some(transfer.from.clone()),
120 metadata_hash: None,
121 ..Self::new(BalancesCall::transfer_allow_death {
122 dest: transfer.to,
123 value: transfer.amount,
124 })
125 }
126 }
127
128 pub fn new_include_data(data: Vec<u8>) -> Self {
130 Self::new(PalletCall::include_data { data })
131 }
132
133 pub fn new_storage_change(key: Vec<u8>, value: Option<Vec<u8>>) -> Self {
136 Self::new_unsigned(PalletCall::storage_change { key, value })
137 }
138
139 pub fn new_offchain_index_set(key: Vec<u8>, value: Vec<u8>) -> Self {
141 Self::new(PalletCall::offchain_index_set { key, value })
142 }
143
144 pub fn new_offchain_index_clear(key: Vec<u8>) -> Self {
146 Self::new(PalletCall::offchain_index_clear { key })
147 }
148
149 pub fn new_indexed_call(data: Vec<u8>) -> Self {
151 Self::new(PalletCall::indexed_call { data })
152 }
153
154 pub fn new_deposit_log_digest_item(log: sp_runtime::generic::DigestItem) -> Self {
156 Self::new_unsigned(PalletCall::deposit_log_digest_item { log })
157 }
158
159 pub fn new_fill_block(ratio: Perbill) -> Self {
161 Self::new(PalletCall::fill_block { ratio })
162 }
163
164 pub fn new_call_do_not_propagate() -> Self {
166 Self::new(PalletCall::call_do_not_propagate {})
167 }
168
169 pub fn new_call_with_priority(priority: TransactionPriority) -> Self {
171 Self::new(PalletCall::call_with_priority { priority })
172 }
173
174 pub fn new_read(count: u32) -> Self {
176 Self::new_unsigned(PalletCall::read { count })
177 }
178
179 pub fn new_read_and_panic(count: u32) -> Self {
181 Self::new_unsigned(PalletCall::read_and_panic { count })
182 }
183
184 pub fn unsigned(mut self) -> Self {
186 self.signer = None;
187 self
188 }
189
190 pub fn nonce(mut self, nonce: Nonce) -> Self {
192 self.nonce = Some(nonce);
193 self
194 }
195
196 pub fn signer(mut self, signer: Pair) -> Self {
198 self.signer = Some(signer);
199 self
200 }
201
202 pub fn metadata_hash(mut self, metadata_hash: [u8; 32]) -> Self {
204 self.metadata_hash = Some(metadata_hash);
205 self
206 }
207
208 pub fn build(self) -> Extrinsic {
210 if let Some(signer) = self.signer {
211 let tx_ext = (
212 (CheckNonce::from(self.nonce.unwrap_or(0)), CheckWeight::new()),
213 CheckSubstrateCall {},
214 self.metadata_hash
215 .map(CheckMetadataHash::new_with_custom_hash)
216 .unwrap_or_else(|| CheckMetadataHash::new(false)),
217 frame_system::WeightReclaim::new(),
218 );
219 let raw_payload = SignedPayload::from_raw(
220 self.function.clone(),
221 tx_ext.clone(),
222 tx_ext.implicit().unwrap(),
223 );
224 let signature = raw_payload.using_encoded(|e| signer.sign(e));
225
226 Extrinsic::new_signed(self.function, signer.public(), signature, tx_ext)
227 } else {
228 Extrinsic::new_bare(self.function)
229 }
230 }
231}