avail_rust_core/substrate/
extrinsic.rs1use crate::{
2 HasHeader,
3 types::{AccountId, ExtrinsicExtra, ExtrinsicSignature, H256, MultiAddress, MultiSignature},
4 utils::decode_already_decoded,
5};
6use codec::{Compact, Decode, Encode};
7use serde::{Deserialize, Serialize};
8use std::borrow::Cow;
9use subxt_core::config::{Hasher, substrate::BlakeTwo256};
10use subxt_signer::sr25519::Keypair;
11
12pub const EXTRINSIC_FORMAT_VERSION: u8 = 4;
18
19#[derive(Debug, Clone)]
20pub struct ExtrinsicAdditional {
21 pub spec_version: u32,
22 pub tx_version: u32,
23 pub genesis_hash: H256,
24 pub fork_hash: H256,
25}
26impl Encode for ExtrinsicAdditional {
27 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
28 self.spec_version.encode_to(dest);
29 self.tx_version.encode_to(dest);
30 self.genesis_hash.encode_to(dest);
31 self.fork_hash.encode_to(dest);
32 }
33}
34impl Decode for ExtrinsicAdditional {
35 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
36 let spec_version = Decode::decode(input)?;
37 let tx_version = Decode::decode(input)?;
38 let genesis_hash = Decode::decode(input)?;
39 let fork_hash = Decode::decode(input)?;
40 Ok(Self { spec_version, tx_version, genesis_hash, fork_hash })
41 }
42}
43
44#[derive(Debug, Clone)]
45pub struct ExtrinsicCall {
46 pub pallet_id: u8,
47 pub variant_id: u8,
48 pub data: Vec<u8>,
49}
50impl ExtrinsicCall {
51 pub fn new(pallet_id: u8, variant_id: u8, data: Vec<u8>) -> Self {
52 Self { pallet_id, variant_id, data }
53 }
54
55 pub fn hash(&self) -> [u8; 32] {
56 let call_vec: Vec<u8> = self.encode();
57 sp_crypto_hashing::blake2_256(&call_vec)
58 }
59}
60impl Encode for ExtrinsicCall {
61 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
62 self.pallet_id.encode_to(dest);
63 self.variant_id.encode_to(dest);
64 dest.write(&self.data);
65 }
66}
67impl Decode for ExtrinsicCall {
68 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
69 let pallet_id = Decode::decode(input)?;
70 let variant_id = Decode::decode(input)?;
71 let data = decode_already_decoded(input)?;
72 Ok(Self { pallet_id, variant_id, data })
73 }
74}
75
76impl<T: HasHeader + Encode> From<&T> for ExtrinsicCall {
77 fn from(value: &T) -> Self {
78 Self {
79 pallet_id: T::HEADER_INDEX.0,
80 variant_id: T::HEADER_INDEX.1,
81 data: value.encode(),
82 }
83 }
84}
85
86impl TryFrom<String> for ExtrinsicCall {
87 type Error = String;
88
89 fn try_from(value: String) -> Result<Self, Self::Error> {
90 Self::try_from(value.as_str())
91 }
92}
93
94impl TryFrom<&str> for ExtrinsicCall {
95 type Error = String;
96
97 fn try_from(value: &str) -> Result<Self, Self::Error> {
98 let decoded = const_hex::decode(value.trim_start_matches("0x")).map_err(|e| e.to_string())?;
99 Self::try_from(decoded.as_slice())
100 }
101}
102
103impl TryFrom<Vec<u8>> for ExtrinsicCall {
104 type Error = String;
105
106 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
107 Self::try_from(value.as_slice())
108 }
109}
110
111impl TryFrom<&Vec<u8>> for ExtrinsicCall {
112 type Error = String;
113
114 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
115 Self::try_from(value.as_slice())
116 }
117}
118
119impl TryFrom<&[u8]> for ExtrinsicCall {
120 type Error = String;
121
122 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
123 if value.len() < 2 {
124 return Err("Failed to convert array to Extrinsic Call. Not Enough data".into());
125 }
126 if value.len() == 2 {
127 return Ok(ExtrinsicCall::new(value[0], value[1], Vec::new()));
128 }
129
130 Ok(ExtrinsicCall::new(value[0], value[1], value[2..].to_vec()))
131 }
132}
133
134#[derive(Debug, Clone)]
136pub struct ExtrinsicPayload<'a> {
137 pub call: Cow<'a, ExtrinsicCall>,
138 pub extra: ExtrinsicExtra,
139 pub additional: ExtrinsicAdditional,
140}
141
142impl<'a> ExtrinsicPayload<'a> {
143 pub fn new(call: ExtrinsicCall, extra: ExtrinsicExtra, additional: ExtrinsicAdditional) -> Self {
144 Self { call: Cow::Owned(call), extra, additional }
145 }
146
147 pub fn new_borrowed(call: &'a ExtrinsicCall, extra: ExtrinsicExtra, additional: ExtrinsicAdditional) -> Self {
148 Self { call: Cow::Borrowed(call), extra, additional }
149 }
150
151 pub fn sign(&self, signer: &Keypair) -> [u8; 64] {
152 let call = self.call.as_ref();
153 let size_hint = call.size_hint() + self.extra.size_hint() + self.additional.size_hint();
154
155 let mut data: Vec<u8> = Vec::with_capacity(size_hint);
156 self.call.encode_to(&mut data);
157 self.extra.encode_to(&mut data);
158 self.additional.encode_to(&mut data);
159
160 if data.len() > 256 {
161 let hash = BlakeTwo256::hash(&data);
162 signer.sign(hash.as_ref()).0
163 } else {
164 signer.sign(&data).0
165 }
166 }
167}
168
169#[derive(Debug, Clone)]
170pub struct GenericExtrinsic<'a> {
171 pub signature: Option<ExtrinsicSignature>,
172 pub call: Cow<'a, ExtrinsicCall>,
173}
174
175impl<'a> GenericExtrinsic<'a> {
176 pub fn new(account_id: AccountId, signature: [u8; 64], payload: ExtrinsicPayload<'a>) -> Self {
177 let address = MultiAddress::Id(account_id);
178 let signature = MultiSignature::Sr25519(signature);
179 let signature = Some(ExtrinsicSignature { address, signature, extra: payload.extra.clone() });
180
181 Self { signature, call: payload.call }
182 }
183
184 pub fn encode(&self) -> Vec<u8> {
185 let mut encoded_tx_inner = Vec::new();
186 if let Some(signed) = &self.signature {
187 0x84u8.encode_to(&mut encoded_tx_inner);
188 signed.address.encode_to(&mut encoded_tx_inner);
189 signed.signature.encode_to(&mut encoded_tx_inner);
190 signed.extra.encode_to(&mut encoded_tx_inner);
191 } else {
192 0x4u8.encode_to(&mut encoded_tx_inner);
193 }
194
195 let call = self.call.as_ref();
196 call.encode_to(&mut encoded_tx_inner);
197 let mut encoded_tx = Compact(encoded_tx_inner.len() as u32).encode();
198 encoded_tx.append(&mut encoded_tx_inner);
199
200 encoded_tx
201 }
202
203 pub fn hash(&self) -> H256 {
204 let encoded = self.encode();
205 BlakeTwo256::hash(&encoded)
206 }
207}
208
209impl TryFrom<&Vec<u8>> for GenericExtrinsic<'_> {
210 type Error = codec::Error;
211
212 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
213 Self::try_from(value.as_slice())
214 }
215}
216
217impl TryFrom<&[u8]> for GenericExtrinsic<'_> {
218 type Error = codec::Error;
219
220 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
221 let mut value = value;
222 Self::decode(&mut value)
223 }
224}
225
226impl Decode for GenericExtrinsic<'_> {
227 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
228 let expected_length = Compact::<u32>::decode(input)?;
232 let before_length = input.remaining_len()?;
233
234 let version = input.read_byte()?;
235
236 let is_signed = version & 0b1000_0000 != 0;
237 let version = version & 0b0111_1111;
238 if version != EXTRINSIC_FORMAT_VERSION {
239 return Err("Invalid transaction version".into());
240 }
241
242 let signed = is_signed.then(|| ExtrinsicSignature::decode(input)).transpose()?;
243 let call = ExtrinsicCall::decode(input)?;
244
245 if let Some((before_length, after_length)) = input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
246 {
247 let length = before_length.saturating_sub(after_length);
248
249 if length != expected_length.0 as usize {
250 return Err("Invalid length prefix".into());
251 }
252 }
253
254 Ok(Self { signature: signed, call: Cow::Owned(call) })
255 }
256}
257
258impl Serialize for GenericExtrinsic<'_> {
259 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
260 where
261 S: serde::Serializer,
262 {
263 let bytes = self.encode();
264 impl_serde::serialize::serialize(&bytes, serializer)
265 }
266}
267
268impl<'a> Deserialize<'a> for GenericExtrinsic<'_> {
269 fn deserialize<D>(de: D) -> Result<Self, D::Error>
270 where
271 D: serde::Deserializer<'a>,
272 {
273 let r = impl_serde::serialize::deserialize(de)?;
274 Decode::decode(&mut &r[..]).map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
275 }
276}