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/// Encoded is a wrapper for data that has already been encoded.
258///
259/// This is used to avoid double encoding.
260#[derive(Clone, Debug)]
261#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
262pub struct Encoded(
263  #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec<u8>,
264);
265
266impl Encoded {
267  pub fn decode_as<T: Decode>(&self) -> Result<T> {
268    Ok(T::decode(&mut &self.0[..])?)
269  }
270}
271
272impl<T: Encode> From<&T> for Encoded {
273  fn from(other: &T) -> Self {
274    Self(other.encode())
275  }
276}
277
278impl Encode for Encoded {
279  fn size_hint(&self) -> usize {
280    self.0.len()
281  }
282  fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
283    dest.write(&self.0);
284  }
285}
286
287impl Decode for Encoded {
288  fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
289    if let Some(len) = input.remaining_len()? {
290      let mut data = vec![0u8; len];
291      input.read(&mut data.as_mut_slice())?;
292      Ok(Self(data))
293    } else {
294      let mut data = Vec::new();
295      while let Ok(b) = input.read_byte() {
296        data.push(b);
297      }
298      Ok(Self(data))
299    }
300  }
301}
302
303/// BytesPayload is a wrapper for signing the raw SCALE bytes of `T`.
304///
305/// The wrapped `T` type will be SCALE encoded and wrapped with a prefix & suffix `<Bytes>...T SCALE Encoded...</Bytes>` before signing.
306pub struct BytesPayload<T>(pub T);
307
308pub const BYTES_PREFIX: &[u8] = b"<Bytes>";
309pub const BYTES_SUFFIX: &[u8] = b"</Bytes>";
310
311impl<T: Encode + Clone> From<&T> for BytesPayload<T> {
312  fn from(other: &T) -> Self {
313    Self(other.clone())
314  }
315}
316
317impl<T: Encode + Clone> Encode for BytesPayload<T> {
318  fn size_hint(&self) -> usize {
319    BYTES_PREFIX.len() + self.0.size_hint() + BYTES_SUFFIX.len()
320  }
321  fn encode_to<D: Output + ?Sized>(&self, dest: &mut D) {
322    dest.write(BYTES_PREFIX);
323    self.0.encode_to(dest);
324    dest.write(BYTES_SUFFIX);
325  }
326}
327
328pub struct SignedPayload<'a>((&'a Encoded, &'a Extra, AdditionalSigned));
329
330impl<'a> SignedPayload<'a> {
331  pub fn new(call: &'a Encoded, extra: &'a Extra, additional: AdditionalSigned) -> Self {
332    Self((call, extra, additional))
333  }
334}
335
336impl<'a> Encode for SignedPayload<'a> {
337  fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
338    self.0.using_encoded(|payload| {
339      if payload.len() > 256 {
340        f(&blake2_256(payload)[..])
341      } else {
342        f(payload)
343      }
344    })
345  }
346}
347
348/// PreparedTransaction holds all data needed to sign a transaction.
349///
350/// This can be used for offline signers.
351#[derive(Clone, Debug, Encode, Decode)]
352#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
353pub struct PreparedTransaction {
354  pub call: Encoded,
355  pub extra: Extra,
356  pub additional: AdditionalSigned,
357  pub account: Option<AccountId>,
358}
359
360impl PreparedTransaction {
361  pub fn new(
362    account: AccountId,
363    additional: AdditionalSigned,
364    extra: Extra,
365    call: Encoded,
366  ) -> Self {
367    Self {
368      account: Some(account),
369      additional,
370      extra,
371      call,
372    }
373  }
374
375  /// Decode from a `SignedPayload` with optional `AccountId`.
376  pub fn decode_signed_payload<Api: ChainApi, I: codec::Input>(input: &mut I) -> Result<Self> {
377    let call = Api::RuntimeCall::decode(input)?;
378    let extra = Decode::decode(input)?;
379    let additional = Decode::decode(input)?;
380    // Try decode optional `AccountId`.
381    let account = match input.remaining_len()? {
382      Some(33) => Decode::decode(input)?,
383      _ => None,
384    };
385    Ok(Self {
386      call: Encoded(call.encode()),
387      extra,
388      additional,
389      account,
390    })
391  }
392
393  pub async fn sign(self, signer: &mut impl Signer) -> Result<ExtrinsicV4> {
394    let account = signer.account();
395    if let Some(tx_account) = &self.account {
396      // Ensure the signer's account matches the transaction.
397      if account != *tx_account {
398        use sp_core::crypto::Ss58Codec;
399        let version = 12u16.into(); // Polymesh
400        let a1 = account.to_ss58check_with_version(version);
401        let a2 = tx_account.to_ss58check_with_version(version);
402        return Err(Error::WrongSignerAccount(a1, a2));
403      }
404    }
405    let payload = SignedPayload::new(&self.call, &self.extra, self.additional);
406    let payload = payload.encode();
407    let sig = signer.sign(&payload[..]).await?;
408
409    let xt = ExtrinsicV4::signed(account, sig, self.extra, self.call);
410    Ok(xt)
411  }
412}
413
414#[derive(Clone, Debug, Encode, Decode)]
415#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
416pub struct ExtrinsicSignature {
417  pub account: GenericAddress,
418  pub signature: MultiSignature,
419  pub extra: Extra,
420}
421
422/// Current version of the `UncheckedExtrinsic` format.
423pub const EXTRINSIC_VERSION: u8 = 4;
424
425#[derive(Clone, Debug)]
426#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
427pub struct ExtrinsicV4 {
428  pub signature: Option<ExtrinsicSignature>,
429  pub call: Encoded,
430}
431
432impl ExtrinsicV4 {
433  pub fn tx_hash(tx: &[u8]) -> TxHash {
434    H256(blake2_256(tx))
435  }
436
437  pub fn signed(account: AccountId, sig: MultiSignature, extra: Extra, call: Encoded) -> Self {
438    Self {
439      signature: Some(ExtrinsicSignature {
440        account: GenericAddress::from(account),
441        signature: sig,
442        extra,
443      }),
444      call,
445    }
446  }
447
448  pub fn unsigned(call: Encoded) -> Self {
449    Self {
450      signature: None,
451      call,
452    }
453  }
454
455  pub fn as_hex_and_hash(&self) -> (String, TxHash) {
456    let tx = self.encode();
457    let tx_hash = Self::tx_hash(tx.as_slice());
458    let mut tx_hex = hex::encode(tx);
459    tx_hex.insert_str(0, "0x");
460    (tx_hex, tx_hash)
461  }
462
463  pub fn to_hex(&self) -> String {
464    let mut hex = hex::encode(self.encode());
465    hex.insert_str(0, "0x");
466    hex
467  }
468}
469
470impl Encode for ExtrinsicV4 {
471  fn encode(&self) -> Vec<u8> {
472    let mut buf = Vec::with_capacity(512);
473
474    // 1 byte version id and signature if signed.
475    match &self.signature {
476      Some(sig) => {
477        buf.push(EXTRINSIC_VERSION | 0b1000_0000);
478        sig.encode_to(&mut buf);
479      }
480      None => {
481        buf.push(EXTRINSIC_VERSION & 0b0111_1111);
482      }
483    }
484    self.call.encode_to(&mut buf);
485
486    buf.encode()
487  }
488}
489
490impl Decode for ExtrinsicV4 {
491  fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
492    // Decode Vec length.
493    let _len: Compact<u32> = Decode::decode(input)?;
494    // Version and signed flag.
495    let version = input.read_byte()?;
496    let is_signed = version & 0b1000_0000 != 0;
497    if (version & 0b0111_1111) != EXTRINSIC_VERSION {
498      Err("Invalid EXTRINSIC_VERSION")?;
499    }
500
501    let signature = if is_signed {
502      Some(ExtrinsicSignature::decode(input)?)
503    } else {
504      None
505    };
506
507    Ok(Self {
508      signature,
509      call: Decode::decode(input)?,
510    })
511  }
512}
513
514#[derive(Clone, Debug)]
515#[cfg_attr(feature = "serde", derive(Deserialize))]
516pub struct AccountInfo {
517  pub nonce: u32,
518}
519
520#[derive(Clone, Debug, PartialEq)]
521#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
522#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
523pub enum TransactionStatus {
524  Future,
525  Ready,
526  Broadcast(Vec<String>),
527  InBlock(BlockHash),
528  Retracted(BlockHash),
529  FinalityTimeout(BlockHash),
530  Finalized(BlockHash),
531  Usurped(TxHash),
532  Dropped,
533  Invalid,
534}
535
536#[derive(Clone, Debug)]
537#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
538#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
539pub struct SignedBlock {
540  pub block: Block,
541  // TODO: Add Justifications field.
542}
543
544#[derive(Clone, Debug)]
545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
546pub struct Block {
547  extrinsics: Vec<Encoded>,
548  header: Header,
549}
550
551impl Block {
552  pub fn find_extrinsic(&self, xt_hash: TxHash) -> Option<usize> {
553    // TODO: Add caching of blocks with extrinsic hashes.
554    self
555      .extrinsics
556      .iter()
557      .position(|xt| ExtrinsicV4::tx_hash(xt.0.as_slice()) == xt_hash)
558  }
559
560  pub fn extrinsics(&self) -> &[Encoded] {
561    self.extrinsics.as_slice()
562  }
563
564  pub fn parent(&self) -> BlockHash {
565    self.header.parent_hash
566  }
567
568  pub fn state_root(&self) -> BlockHash {
569    self.header.state_root
570  }
571
572  pub fn extrinsics_root(&self) -> BlockHash {
573    self.header.extrinsics_root
574  }
575
576  pub fn block_number(&self) -> BlockNumber {
577    self.header.number
578  }
579
580  pub fn to_string(&self) -> String {
581    format!("{:?}", self)
582  }
583}
584
585#[derive(Clone, Debug, Decode, PartialEq, Eq)]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
587pub enum Phase {
588  ApplyExtrinsic(u32),
589  Finalization,
590  Initialization,
591}
592
593#[derive(Clone, Debug, Decode)]
594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
595pub struct EventRecord<Event> {
596  pub phase: Phase,
597  pub event: Event,
598  pub topics: Vec<BlockHash>,
599}
600
601impl<Event: RuntimeEnumTraits> EventRecord<Event> {
602  pub fn name(&self) -> &'static str {
603    self.event.as_name()
604  }
605
606  pub fn short_doc(&self) -> &'static str {
607    self.event.as_short_doc()
608  }
609
610  pub fn docs(&self) -> &'static [&'static str] {
611    self.event.as_docs()
612  }
613
614  pub fn to_string(&self) -> String {
615    format!("{:#?}", self)
616  }
617}
618
619#[derive(Clone, Debug, Decode, Default)]
620#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
621pub struct EventRecords<Event>(pub Vec<EventRecord<Event>>);
622
623impl<Event: RuntimeEnumTraits> EventRecords<Event> {
624  pub fn from_vec(mut events: Vec<EventRecord<Event>>, filter: Option<Phase>) -> Self {
625    if let Some(filter) = filter {
626      events.retain(|ev| ev.phase == filter);
627    }
628    Self(events)
629  }
630
631  pub fn to_string(&self) -> String {
632    format!("{:#?}", self.0)
633  }
634}
635
636#[cfg(test)]
637mod tests {
638  use anyhow::Result;
639
640  use super::*;
641
642  /// Test the `BytesPayload` signing and verification.
643  #[tokio::test]
644  async fn test_bytes_payload() -> Result<()> {
645    let data = b"Hello";
646    let payload = BytesPayload(Encoded::from(data));
647    let encoded = payload.encode();
648    assert_eq!(
649      encoded.len(),
650      BYTES_PREFIX.len() + data.len() + BYTES_SUFFIX.len()
651    );
652    assert_eq!(&encoded[..BYTES_PREFIX.len()], BYTES_PREFIX);
653    assert_eq!(
654      &encoded[BYTES_PREFIX.len()..BYTES_PREFIX.len() + data.len()],
655      data
656    );
657    assert_eq!(&encoded[BYTES_PREFIX.len() + data.len()..], BYTES_SUFFIX);
658
659    // Alice sr25519 keypair.
660    let alice = sp_core::sr25519::Pair::from_string("//Alice", None)?;
661
662    // Sign the payload using Alice.
663    let sig = alice.sign(&encoded[..]);
664
665    // Verify the signature.
666    let verified = alice.verify(&sig, &encoded[..])?;
667    assert!(verified);
668
669    Ok(())
670  }
671
672  /// Test signature from `subkey` tool.
673  #[tokio::test]
674  async fn test_subkey_signature() -> Result<()> {
675    let unwrapped_data = b"Test from subkey";
676    let payload = BytesPayload(Encoded::from(unwrapped_data));
677    let wrapped_data = payload.encode();
678
679    // Signatures from `subkey` tool.
680    let unwrapped_sig = MultiSignature::Sr25519(
681      sp_core::sr25519::Signature::from_slice(
682      &hex::decode("f22a9a82306e09fefab3782f55d1981795803211e3a2ef8f90555bb96dab0d281fd98705f4c675545d1f537b90cefa6596f60617eac5dec5bd4b9306908dc687")?
683      ).expect("Invalid signature"),
684    );
685    let wrapped_sig = MultiSignature::Sr25519(
686      sp_core::sr25519::Signature::from_slice(
687        &hex::decode("8c76d5f31c5ff229a90067063a19feff0e94f28793a490d63e0abd9f5aa5a33fa58fae990b98b6d80ae1ec0085fe19a36cb5b757f46b2d7574c7fc9e35974682")?,
688      )
689      .expect("Invalid signature"),
690    );
691
692    // Alice sr25519 keypair.
693    let alice = sp_core::sr25519::Pair::from_string("//Alice", None)?;
694
695    // Verify the unwrapped data signature.
696    let verified = alice.verify(&unwrapped_sig, &unwrapped_data[..])?;
697    assert!(verified);
698
699    // Verify the wrapped data signature.
700    let verified = alice.verify(&wrapped_sig, &wrapped_data[..])?;
701    assert!(verified);
702
703    Ok(())
704  }
705}