1use codec::{Compact, Decode, Encode, Output};
2
3#[cfg(all(feature = "std", feature = "type_info"))]
4use scale_info::TypeInfo;
5
6#[cfg(not(feature = "std"))]
7use alloc::{format, string::String};
8use sp_core::{hashing::blake2_256, H256};
9use sp_runtime::{ConsensusEngineId, MultiSignature};
10use sp_std::prelude::*;
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15use crate::basic_types::{AccountId, GenericAddress};
16use crate::*;
17
18pub type TxHash = H256;
19pub type BlockHash = H256;
20pub type BlockNumber = u32;
21
22#[cfg(feature = "serde")]
23pub mod block_number {
24 use super::BlockNumber;
25 use sp_core::U256;
26
27 pub fn serialize<S>(num: &BlockNumber, s: S) -> Result<S::Ok, S::Error>
28 where
29 S: serde::Serializer,
30 {
31 let num = U256::from(*num);
32 serde::Serialize::serialize(&num, s)
33 }
34
35 pub fn deserialize<'de, D>(d: D) -> Result<BlockNumber, D::Error>
36 where
37 D: serde::Deserializer<'de>,
38 {
39 let num: U256 = serde::Deserialize::deserialize(d)?;
40 Ok(num.as_u32())
41 }
42}
43
44#[derive(Clone, Debug, Encode, Decode)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
47pub struct Header {
48 pub parent_hash: BlockHash,
49 #[cfg_attr(feature = "serde", serde(with = "block_number"))]
50 #[codec(compact)]
51 pub number: BlockNumber,
52 pub state_root: BlockHash,
53 pub extrinsics_root: BlockHash,
54 pub digest: Digest,
55}
56
57impl Header {
58 pub fn hash(&self) -> BlockHash {
59 H256(self.using_encoded(blake2_256))
60 }
61}
62
63impl From<Header> for sp_runtime::generic::Header<BlockNumber, sp_runtime::traits::BlakeTwo256> {
64 fn from(header: Header) -> Self {
65 let logs = header
66 .digest
67 .logs
68 .into_iter()
69 .map(|item| item.into())
70 .collect();
71 Self {
72 parent_hash: header.parent_hash,
73 number: header.number,
74 state_root: header.state_root,
75 extrinsics_root: header.extrinsics_root,
76 digest: sp_runtime::generic::Digest { logs },
77 }
78 }
79}
80
81#[derive(Clone, Debug, Default, Encode, Decode)]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83pub struct Digest {
84 pub logs: Vec<DigestItem>,
85}
86
87#[derive(Clone, Debug)]
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89#[cfg_attr(feature = "serde", serde(try_from = "RawDigestItem"))]
90#[cfg_attr(feature = "serde", serde(into = "RawDigestItem"))]
91pub enum DigestItem {
92 PreRuntime(ConsensusEngineId, Vec<u8>),
93 Consensus(ConsensusEngineId, Vec<u8>),
94 Seal(ConsensusEngineId, Vec<u8>),
95 Other(Vec<u8>),
96 RuntimeEnvironmentUpdated,
97}
98
99impl Encode for DigestItem {
100 fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
101 let runtime_era: sp_runtime::generic::DigestItem = self.clone().into();
102 runtime_era.encode_to(output)
103 }
104}
105
106impl Decode for DigestItem {
107 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
108 let runtime_era = sp_runtime::generic::DigestItem::decode(input)?;
109 Ok(runtime_era.into())
110 }
111}
112
113impl From<sp_runtime::generic::DigestItem> for DigestItem {
114 fn from(r_item: sp_runtime::generic::DigestItem) -> Self {
115 use sp_runtime::generic::DigestItem::*;
116 match r_item {
117 PreRuntime(id, data) => Self::PreRuntime(id, data),
118 Consensus(id, data) => Self::Consensus(id, data),
119 Seal(id, data) => Self::Seal(id, data),
120 Other(data) => Self::Other(data),
121 RuntimeEnvironmentUpdated => Self::RuntimeEnvironmentUpdated,
122 }
123 }
124}
125
126impl From<DigestItem> for sp_runtime::generic::DigestItem {
127 fn from(item: DigestItem) -> Self {
128 match item {
129 DigestItem::PreRuntime(id, data) => Self::PreRuntime(id, data),
130 DigestItem::Consensus(id, data) => Self::Consensus(id, data),
131 DigestItem::Seal(id, data) => Self::Seal(id, data),
132 DigestItem::Other(data) => Self::Other(data),
133 DigestItem::RuntimeEnvironmentUpdated => Self::RuntimeEnvironmentUpdated,
134 }
135 }
136}
137
138impl TryFrom<RawDigestItem> for DigestItem {
139 type Error = crate::Error;
140
141 fn try_from(raw: RawDigestItem) -> Result<Self, Self::Error> {
142 let item = DigestItem::decode(&mut &raw.0[..])?;
143 Ok(item.into())
144 }
145}
146
147#[derive(Clone, Debug)]
148#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149pub struct RawDigestItem(
150 #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec<u8>,
151);
152
153impl From<DigestItem> for RawDigestItem {
154 fn from(item: DigestItem) -> Self {
155 Self(item.encode())
156 }
157}
158
159#[derive(Clone, Debug)]
160#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
161pub struct StorageData(
162 #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec<u8>,
163);
164
165#[derive(Clone, Debug)]
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
167pub struct StorageKey(
168 #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec<u8>,
169);
170
171#[derive(Clone, Debug, Default, Encode, Decode)]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173pub struct AdditionalSigned {
174 pub spec_version: u32,
175 pub tx_version: u32,
176 pub genesis_hash: BlockHash,
177 pub current_hash: BlockHash,
178}
179
180#[derive(Clone, Copy, Debug, PartialEq, Eq)]
181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
182#[cfg_attr(all(feature = "std", feature = "type_info"), derive(TypeInfo))]
183pub enum Era {
184 Immortal,
185 Mortal(u64, u64),
186}
187
188impl Era {
189 pub fn mortal(current: BlockNumber, period: Option<u64>) -> Self {
190 let period = period.unwrap_or(64);
191 sp_runtime::generic::Era::mortal(period, current.into()).into()
192 }
193
194 pub fn immortal() -> Self {
195 Self::Immortal
196 }
197}
198
199impl Encode for Era {
200 fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
201 let runtime_era: sp_runtime::generic::Era = self.clone().into();
202 runtime_era.encode_to(output)
203 }
204}
205
206impl Decode for Era {
207 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
208 let runtime_era = sp_runtime::generic::Era::decode(input)?;
209 Ok(runtime_era.into())
210 }
211}
212
213impl From<sp_runtime::generic::Era> for Era {
214 fn from(e: sp_runtime::generic::Era) -> Self {
215 match e {
216 sp_runtime::generic::Era::Immortal => Self::Immortal,
217 sp_runtime::generic::Era::Mortal(period, phase) => Self::Mortal(period, phase),
218 }
219 }
220}
221
222impl From<Era> for sp_runtime::generic::Era {
223 fn from(e: Era) -> Self {
224 match e {
225 Era::Immortal => Self::Immortal,
226 Era::Mortal(period, phase) => Self::Mortal(period, phase),
227 }
228 }
229}
230
231#[derive(Clone, Debug, Encode, Decode)]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233pub struct Extra {
234 era: sp_runtime::generic::Era,
235 nonce: Compact<u32>,
236 tip: Compact<u128>,
237}
238
239impl Extra {
240 pub fn new(era: Era, nonce: u32) -> Self {
241 Self {
242 era: era.into(),
243 nonce: nonce.into(),
244 tip: 0u128.into(),
245 }
246 }
247
248 pub fn nonce(&self) -> u32 {
249 self.nonce.0
250 }
251
252 pub fn tip(&self) -> u128 {
253 self.tip.0
254 }
255}
256
257#[derive(Clone, Debug)]
258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
259pub struct Encoded(
260 #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec<u8>,
261);
262
263impl Encoded {
264 pub fn decode_as<T: Decode>(&self) -> Result<T> {
265 Ok(T::decode(&mut &self.0[..])?)
266 }
267}
268
269impl<T: Encode> From<&T> for Encoded {
270 fn from(other: &T) -> Self {
271 Self(other.encode())
272 }
273}
274
275impl Encode for Encoded {
276 fn size_hint(&self) -> usize {
277 self.0.len()
278 }
279 fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
280 dest.write(&self.0);
281 }
282}
283
284impl Decode for Encoded {
285 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
286 if let Some(len) = input.remaining_len()? {
287 let mut data = vec![0u8; len];
288 input.read(&mut data.as_mut_slice())?;
289 Ok(Self(data))
290 } else {
291 let mut data = Vec::new();
292 while let Ok(b) = input.read_byte() {
293 data.push(b);
294 }
295 Ok(Self(data))
296 }
297 }
298}
299
300pub struct SignedPayload<'a>((&'a Encoded, &'a Extra, AdditionalSigned));
301
302impl<'a> SignedPayload<'a> {
303 pub fn new(call: &'a Encoded, extra: &'a Extra, additional: AdditionalSigned) -> Self {
304 Self((call, extra, additional))
305 }
306}
307
308impl<'a> Encode for SignedPayload<'a> {
309 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
310 self.0.using_encoded(|payload| {
311 if payload.len() > 256 {
312 f(&blake2_256(payload)[..])
313 } else {
314 f(payload)
315 }
316 })
317 }
318}
319
320#[derive(Clone, Debug, Encode, Decode)]
324#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
325pub struct PreparedTransaction {
326 pub call: Encoded,
327 pub extra: Extra,
328 pub additional: AdditionalSigned,
329 pub account: Option<AccountId>,
330}
331
332impl PreparedTransaction {
333 pub fn new(
334 account: AccountId,
335 additional: AdditionalSigned,
336 extra: Extra,
337 call: Encoded,
338 ) -> Self {
339 Self {
340 account: Some(account),
341 additional,
342 extra,
343 call,
344 }
345 }
346
347 pub fn decode_signed_payload<Api: ChainApi, I: codec::Input>(input: &mut I) -> Result<Self> {
349 let call = Api::RuntimeCall::decode(input)?;
350 let extra = Decode::decode(input)?;
351 let additional = Decode::decode(input)?;
352 let account = match input.remaining_len()? {
354 Some(33) => Decode::decode(input)?,
355 _ => None,
356 };
357 Ok(Self {
358 call: Encoded(call.encode()),
359 extra,
360 additional,
361 account,
362 })
363 }
364
365 pub async fn sign(self, signer: &mut impl Signer) -> Result<ExtrinsicV4> {
366 let account = signer.account();
367 if let Some(tx_account) = &self.account {
368 if account != *tx_account {
370 use sp_core::crypto::Ss58Codec;
371 let version = 12u16.into(); let a1 = account.to_ss58check_with_version(version);
373 let a2 = tx_account.to_ss58check_with_version(version);
374 return Err(Error::WrongSignerAccount(a1, a2));
375 }
376 }
377 let payload = SignedPayload::new(&self.call, &self.extra, self.additional);
378 let payload = payload.encode();
379 let sig = signer.sign(&payload[..]).await?;
380
381 let xt = ExtrinsicV4::signed(account, sig, self.extra, self.call);
382 Ok(xt)
383 }
384}
385
386#[derive(Clone, Debug, Encode, Decode)]
387#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
388pub struct ExtrinsicSignature {
389 pub account: GenericAddress,
390 pub signature: MultiSignature,
391 pub extra: Extra,
392}
393
394pub const EXTRINSIC_VERSION: u8 = 4;
396
397#[derive(Clone, Debug)]
398#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
399pub struct ExtrinsicV4 {
400 pub signature: Option<ExtrinsicSignature>,
401 pub call: Encoded,
402}
403
404impl ExtrinsicV4 {
405 pub fn tx_hash(tx: &[u8]) -> TxHash {
406 H256(blake2_256(tx))
407 }
408
409 pub fn signed(account: AccountId, sig: MultiSignature, extra: Extra, call: Encoded) -> Self {
410 Self {
411 signature: Some(ExtrinsicSignature {
412 account: GenericAddress::from(account),
413 signature: sig,
414 extra,
415 }),
416 call,
417 }
418 }
419
420 pub fn unsigned(call: Encoded) -> Self {
421 Self {
422 signature: None,
423 call,
424 }
425 }
426
427 pub fn as_hex_and_hash(&self) -> (String, TxHash) {
428 let tx = self.encode();
429 let tx_hash = Self::tx_hash(tx.as_slice());
430 let mut tx_hex = hex::encode(tx);
431 tx_hex.insert_str(0, "0x");
432 (tx_hex, tx_hash)
433 }
434
435 pub fn to_hex(&self) -> String {
436 let mut hex = hex::encode(self.encode());
437 hex.insert_str(0, "0x");
438 hex
439 }
440}
441
442impl Encode for ExtrinsicV4 {
443 fn encode(&self) -> Vec<u8> {
444 let mut buf = Vec::with_capacity(512);
445
446 match &self.signature {
448 Some(sig) => {
449 buf.push(EXTRINSIC_VERSION | 0b1000_0000);
450 sig.encode_to(&mut buf);
451 }
452 None => {
453 buf.push(EXTRINSIC_VERSION & 0b0111_1111);
454 }
455 }
456 self.call.encode_to(&mut buf);
457
458 buf.encode()
459 }
460}
461
462impl Decode for ExtrinsicV4 {
463 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
464 let _len: Compact<u32> = Decode::decode(input)?;
466 let version = input.read_byte()?;
468 let is_signed = version & 0b1000_0000 != 0;
469 if (version & 0b0111_1111) != EXTRINSIC_VERSION {
470 Err("Invalid EXTRINSIC_VERSION")?;
471 }
472
473 let signature = if is_signed {
474 Some(ExtrinsicSignature::decode(input)?)
475 } else {
476 None
477 };
478
479 Ok(Self {
480 signature,
481 call: Decode::decode(input)?,
482 })
483 }
484}
485
486#[derive(Clone, Debug)]
487#[cfg_attr(feature = "serde", derive(Deserialize))]
488pub struct AccountInfo {
489 pub nonce: u32,
490}
491
492#[derive(Clone, Debug, PartialEq)]
493#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
494#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
495pub enum TransactionStatus {
496 Future,
497 Ready,
498 Broadcast(Vec<String>),
499 InBlock(BlockHash),
500 Retracted(BlockHash),
501 FinalityTimeout(BlockHash),
502 Finalized(BlockHash),
503 Usurped(TxHash),
504 Dropped,
505 Invalid,
506}
507
508#[derive(Clone, Debug)]
509#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
510#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
511pub struct SignedBlock {
512 pub block: Block,
513 }
515
516#[derive(Clone, Debug)]
517#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
518pub struct Block {
519 extrinsics: Vec<Encoded>,
520 header: Header,
521}
522
523impl Block {
524 pub fn find_extrinsic(&self, xt_hash: TxHash) -> Option<usize> {
525 self
527 .extrinsics
528 .iter()
529 .position(|xt| ExtrinsicV4::tx_hash(xt.0.as_slice()) == xt_hash)
530 }
531
532 pub fn extrinsics(&self) -> &[Encoded] {
533 self.extrinsics.as_slice()
534 }
535
536 pub fn parent(&self) -> BlockHash {
537 self.header.parent_hash
538 }
539
540 pub fn state_root(&self) -> BlockHash {
541 self.header.state_root
542 }
543
544 pub fn extrinsics_root(&self) -> BlockHash {
545 self.header.extrinsics_root
546 }
547
548 pub fn block_number(&self) -> BlockNumber {
549 self.header.number
550 }
551
552 pub fn to_string(&self) -> String {
553 format!("{:?}", self)
554 }
555}
556
557#[derive(Clone, Debug, Decode, PartialEq, Eq)]
558#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
559pub enum Phase {
560 ApplyExtrinsic(u32),
561 Finalization,
562 Initialization,
563}
564
565#[derive(Clone, Debug, Decode)]
566#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
567pub struct EventRecord<Event> {
568 pub phase: Phase,
569 pub event: Event,
570 pub topics: Vec<BlockHash>,
571}
572
573impl<Event: RuntimeEnumTraits> EventRecord<Event> {
574 pub fn name(&self) -> &'static str {
575 self.event.as_name()
576 }
577
578 pub fn short_doc(&self) -> &'static str {
579 self.event.as_short_doc()
580 }
581
582 pub fn docs(&self) -> &'static [&'static str] {
583 self.event.as_docs()
584 }
585
586 pub fn to_string(&self) -> String {
587 format!("{:#?}", self)
588 }
589}
590
591#[derive(Clone, Debug, Decode, Default)]
592#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
593pub struct EventRecords<Event>(pub Vec<EventRecord<Event>>);
594
595impl<Event: RuntimeEnumTraits> EventRecords<Event> {
596 pub fn from_vec(mut events: Vec<EventRecord<Event>>, filter: Option<Phase>) -> Self {
597 if let Some(filter) = filter {
598 events.retain(|ev| ev.phase == filter);
599 }
600 Self(events)
601 }
602
603 pub fn to_string(&self) -> String {
604 format!("{:#?}", self.0)
605 }
606}