polymesh_api_client/
block.rs

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/// PreparedTransaction holds all data needed to sign a transaction.
321///
322/// This can be used for offline signers.
323#[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  /// Decode from a `SignedPayload` with optional `AccountId`.
348  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    // Try decode optional `AccountId`.
353    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      // Ensure the signer's account matches the transaction.
369      if account != *tx_account {
370        use sp_core::crypto::Ss58Codec;
371        let version = 12u16.into(); // Polymesh
372        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
394/// Current version of the `UncheckedExtrinsic` format.
395pub 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    // 1 byte version id and signature if signed.
447    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    // Decode Vec length.
465    let _len: Compact<u32> = Decode::decode(input)?;
466    // Version and signed flag.
467    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  // TODO: Add Justifications field.
514}
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    // TODO: Add caching of blocks with extrinsic hashes.
526    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}