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 } => Ok(TransferData { from: *from, to: *dest, amount: *value, nonce: *nonce }),
74 Extrinsic {
75 function: RuntimeCall::SubstrateTest(PalletCall::bench_call { transfer }),
76 preamble: Preamble::Bare(_),
77 } => Ok(transfer.clone()),
78 _ => Err(()),
79 }
80 }
81}
82
83pub struct ExtrinsicBuilder {
85 function: RuntimeCall,
86 signer: Option<Pair>,
87 nonce: Option<Nonce>,
88 metadata_hash: Option<[u8; 32]>,
89}
90
91impl ExtrinsicBuilder {
92 pub fn new(function: impl Into<RuntimeCall>) -> Self {
94 Self {
95 function: function.into(),
96 signer: Some(Sr25519Keyring::Alice.pair()),
97 nonce: None,
98 metadata_hash: None,
99 }
100 }
101
102 pub fn new_unsigned(function: impl Into<RuntimeCall>) -> Self {
104 Self { function: function.into(), signer: None, nonce: None, metadata_hash: None }
105 }
106
107 pub fn new_bench_call(transfer: TransferData) -> Self {
109 Self::new_unsigned(PalletCall::bench_call { transfer })
110 }
111
112 pub fn new_transfer(transfer: Transfer) -> Self {
115 Self {
116 nonce: Some(transfer.nonce),
117 signer: Some(transfer.from.clone()),
118 metadata_hash: None,
119 ..Self::new(BalancesCall::transfer_allow_death {
120 dest: transfer.to,
121 value: transfer.amount,
122 })
123 }
124 }
125
126 pub fn new_include_data(data: Vec<u8>) -> Self {
128 Self::new(PalletCall::include_data { data })
129 }
130
131 pub fn new_storage_change(key: Vec<u8>, value: Option<Vec<u8>>) -> Self {
134 Self::new_unsigned(PalletCall::storage_change { key, value })
135 }
136
137 pub fn new_offchain_index_set(key: Vec<u8>, value: Vec<u8>) -> Self {
139 Self::new(PalletCall::offchain_index_set { key, value })
140 }
141
142 pub fn new_offchain_index_clear(key: Vec<u8>) -> Self {
144 Self::new(PalletCall::offchain_index_clear { key })
145 }
146
147 pub fn new_indexed_call(data: Vec<u8>) -> Self {
149 Self::new(PalletCall::indexed_call { data })
150 }
151
152 pub fn new_deposit_log_digest_item(log: sp_runtime::generic::DigestItem) -> Self {
154 Self::new_unsigned(PalletCall::deposit_log_digest_item { log })
155 }
156
157 pub fn new_fill_block(ratio: Perbill) -> Self {
159 Self::new(PalletCall::fill_block { ratio })
160 }
161
162 pub fn new_call_do_not_propagate() -> Self {
164 Self::new(PalletCall::call_do_not_propagate {})
165 }
166
167 pub fn new_call_with_priority(priority: TransactionPriority) -> Self {
169 Self::new(PalletCall::call_with_priority { priority })
170 }
171
172 pub fn new_read(count: u32) -> Self {
174 Self::new_unsigned(PalletCall::read { count })
175 }
176
177 pub fn new_read_and_panic(count: u32) -> Self {
179 Self::new_unsigned(PalletCall::read_and_panic { count })
180 }
181
182 pub fn unsigned(mut self) -> Self {
184 self.signer = None;
185 self
186 }
187
188 pub fn nonce(mut self, nonce: Nonce) -> Self {
190 self.nonce = Some(nonce);
191 self
192 }
193
194 pub fn signer(mut self, signer: Pair) -> Self {
196 self.signer = Some(signer);
197 self
198 }
199
200 pub fn metadata_hash(mut self, metadata_hash: [u8; 32]) -> Self {
202 self.metadata_hash = Some(metadata_hash);
203 self
204 }
205
206 pub fn build(self) -> Extrinsic {
208 if let Some(signer) = self.signer {
209 let tx_ext = (
210 (CheckNonce::from(self.nonce.unwrap_or(0)), CheckWeight::new()),
211 CheckSubstrateCall {},
212 self.metadata_hash
213 .map(CheckMetadataHash::new_with_custom_hash)
214 .unwrap_or_else(|| CheckMetadataHash::new(false)),
215 frame_system::WeightReclaim::new(),
216 );
217 let raw_payload = SignedPayload::from_raw(
218 self.function.clone(),
219 tx_ext.clone(),
220 tx_ext.implicit().unwrap(),
221 );
222 let signature = raw_payload.using_encoded(|e| signer.sign(e));
223
224 Extrinsic::new_signed(self.function, signer.public(), signature, tx_ext)
225 } else {
226 Extrinsic::new_bare(self.function)
227 }
228 }
229}