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