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)]
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
303pub 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#[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 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 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 if account != *tx_account {
398 use sp_core::crypto::Ss58Codec;
399 let version = 12u16.into(); 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
422pub 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 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 let _len: Compact<u32> = Decode::decode(input)?;
494 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 }
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 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 #[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 let alice = sp_core::sr25519::Pair::from_string("//Alice", None)?;
661
662 let sig = alice.sign(&encoded[..]);
664
665 let verified = alice.verify(&sig, &encoded[..])?;
667 assert!(verified);
668
669 Ok(())
670 }
671
672 #[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 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 let alice = sp_core::sr25519::Pair::from_string("//Alice", None)?;
694
695 let verified = alice.verify(&unwrapped_sig, &unwrapped_data[..])?;
697 assert!(verified);
698
699 let verified = alice.verify(&wrapped_sig, &wrapped_data[..])?;
701 assert!(verified);
702
703 Ok(())
704 }
705}