pdotc/
lib.rs

1use std::str::FromStr;
2
3use base58::ToBase58;
4use blake2::{Blake2b512, Digest};
5use parity_scale_codec::{Compact, Decode, Encode, Error, Input};
6use serde::{Deserialize, Serialize};
7pub use sp_core::crypto::{AccountId32, Ss58AddressFormat, Ss58AddressFormatRegistry};
8pub use sp_core::ecdsa::{Public as EcdsaPublic, Signature as EcdsaSignature};
9pub use sp_core::ed25519::{Public as Ed25519Public, Signature as Ed25519Signature};
10pub use sp_core::{blake2_256, H256};
11
12use crate::pallets::timestamp::decode_timestamp;
13use crate::ss58::Ss58Codec;
14use crate::utils::deser_number_or_hex;
15
16pub mod client;
17pub mod network;
18pub mod pallets;
19pub mod rpc;
20pub mod ss58;
21mod utils;
22
23pub type GenericAddress = MultiAddress<AccountId32, ()>;
24
25pub type Balance = u128;
26
27#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
28pub enum MultiAddress<AccountId, AccountIndex> {
29    /// It's an account ID (pubkey).
30    Id(AccountId),
31    /// It's an account index.
32    Index(#[codec(compact)] AccountIndex),
33    /// It's some arbitrary raw bytes.
34    Raw(Vec<u8>),
35    /// It's a 32 byte representation.
36    Address32([u8; 32]),
37    /// Its a 20 byte representation.
38    Address20([u8; 20]),
39}
40
41impl From<AccountId32> for GenericAddress {
42    fn from(a: AccountId32) -> Self {
43        MultiAddress::Id(a)
44    }
45}
46
47impl From<EcdsaPublic> for GenericAddress {
48    fn from(p: EcdsaPublic) -> Self {
49        let acct = public_into_account(p);
50        MultiAddress::Id(acct)
51    }
52}
53
54impl FromStr for GenericAddress {
55    type Err = &'static str;
56
57    fn from_str(s: &str) -> Result<Self, Self::Err> {
58        Ok(AccountId32::from_ss58check(s)
59            .map_err(|_| "Expected ss58 address")?
60            .into())
61    }
62}
63
64pub fn public_into_account(p: EcdsaPublic) -> AccountId32 {
65    let hash = blake2_256(&p.0);
66    hash.into()
67}
68
69pub fn pub_to_account_string(
70    p: [u8; 32],
71    prefix: u16,
72) -> Result<String, Box<dyn std::error::Error>> {
73    let raw_key = p;
74    let mut hasher = Blake2b512::new();
75    hasher.update(b"SS58PRE");
76    let simple_prefix: u8 = (prefix & 0x3F) as _;
77    let full_prefix = 0x4000 | ((prefix >> 8) & 0x3F) | ((prefix & 0xFF) << 6);
78    let prefix_hi: u8 = (full_prefix >> 8) as _;
79    let prefix_low: u8 = (full_prefix & 0xFF) as _;
80    if prefix == simple_prefix as u16 {
81        hasher.update([simple_prefix]);
82    } else {
83        hasher.update([prefix_hi]);
84        hasher.update([prefix_low]);
85    }
86    hasher.update(raw_key);
87    let checksum = hasher.finalize();
88
89    let mut raw_address: Vec<u8> = Vec::with_capacity(64);
90    if prefix == simple_prefix as u16 {
91        raw_address.push(simple_prefix);
92    } else {
93        raw_address.push(prefix_hi);
94        raw_address.push(prefix_low);
95    }
96    raw_address.append(&mut raw_key.to_vec());
97    raw_address.extend_from_slice(&checksum[0..2]);
98    Ok(raw_address[..].to_base58())
99}
100
101#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
102pub enum MultiSignature {
103    /// An Ed25519 signature.
104    #[codec(index = 0)]
105    Ed25519(Ed25519Signature),
106    /// An ECDSA/SECP256k1 signature.
107    #[codec(index = 2)]
108    Ecdsa(EcdsaSignature),
109}
110
111impl From<EcdsaSignature> for MultiSignature {
112    fn from(value: EcdsaSignature) -> Self {
113        MultiSignature::Ecdsa(value)
114    }
115}
116
117impl From<Ed25519Signature> for MultiSignature {
118    fn from(value: Ed25519Signature) -> Self {
119        MultiSignature::Ed25519(value)
120    }
121}
122
123/// runtime spec verion, transaction version, genesis hash, genesis hash or
124/// current hash, ...others
125pub type SignedExtra = (u32, u32, H256, H256, (), (), ());
126
127#[derive(Clone, Copy, Debug, Decode, Encode, PartialEq, Eq)]
128pub struct GenericExtra(Era, Compact<u32>, Compact<Balance>);
129
130impl GenericExtra {
131    pub fn new(era: Era, nonce: u32) -> GenericExtra {
132        GenericExtra(era, Compact(nonce), Compact(0u128))
133    }
134}
135
136#[derive(Clone, Copy, Debug, Decode, Encode, PartialEq, Eq)]
137pub enum Era {
138    Immortal,
139}
140
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct UncheckedExtrinsic<Call> {
143    /// Address pubkey, Signature, Extras
144    pub signature: Option<(GenericAddress, MultiSignature, GenericExtra)>,
145    pub function: Call,
146}
147
148impl<Call: Encode> UncheckedExtrinsic<Call> {
149    pub fn as_hex(&self) -> String {
150        format!("0x{}", hex::encode(self.encode()))
151    }
152
153    pub fn call_as_hex(&self) -> String {
154        format!("0x{}", hex::encode(self.function.encode()))
155    }
156}
157
158impl<Call> Encode for UncheckedExtrinsic<Call>
159where
160    Call: Encode,
161{
162    fn encode(&self) -> Vec<u8> {
163        encode_with_vec_prefix::<Self, _>(|v| {
164            match self.signature.as_ref() {
165                Some(s) => {
166                    v.push(4 | 0b1000_0000);
167                    s.encode_to(v);
168                }
169                None => {
170                    v.push(4 & 0b0111_1111);
171                }
172            }
173            self.function.encode_to(v);
174        })
175    }
176}
177
178impl<Call> Decode for UncheckedExtrinsic<Call>
179where
180    Call: Decode + Encode,
181{
182    fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
183        // This is a little more complicated than usual since the binary format must be
184        // compatible with substrate's generic `Vec<u8>` type. Basically this
185        // just means accepting that there will be a prefix of vector length (we
186        // don't need to use this).
187        let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?;
188
189        let version = input.read_byte()?;
190
191        let is_signed = version & 0b1000_0000 != 0;
192        let version = version & 0b0111_1111;
193        if version != 4 {
194            return Err("Invalid transaction version".into());
195        }
196
197        Ok(UncheckedExtrinsic {
198            signature: if is_signed {
199                Some(Decode::decode(input)?)
200            } else {
201                None
202            },
203            function: Decode::decode(input)?,
204        })
205    }
206}
207
208/// Same function as in primitives::generic. Needed to be copied as it is
209/// private there.
210fn encode_with_vec_prefix<T: Encode, F: Fn(&mut Vec<u8>)>(encoder: F) -> Vec<u8> {
211    let size = core::mem::size_of::<T>();
212    let reserve = match size {
213        0..=0b0011_1111 => 1,
214        0b0100_0000..=0b0011_1111_1111_1111 => 2,
215        _ => 4,
216    };
217    let mut v = Vec::with_capacity(reserve + size);
218    v.resize(reserve, 0);
219    encoder(&mut v);
220
221    // need to prefix with the total length to ensure it's binary compatible with
222    // Vec<u8>.
223    let mut length: Vec<()> = Vec::new();
224    length.resize(v.len() - reserve, ());
225    length.using_encoded(|s| {
226        v.splice(0..reserve, s.iter().cloned());
227    });
228
229    v
230}
231
232#[derive(Clone, Copy, Debug, Encode)]
233pub struct SignedPayload<Call>((Call, GenericExtra, SignedExtra));
234
235impl<Call: Encode> SignedPayload<Call> {
236    pub fn new(call: Call, extra: GenericExtra, s_extra: SignedExtra) -> SignedPayload<Call> {
237        SignedPayload((call, extra, s_extra))
238    }
239
240    /// Get an encoded version of this payload.
241    ///
242    /// Payloads longer than 256 bytes are going to be `blake2_256`-hashed.
243    pub fn encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
244        self.0.using_encoded(|payload| {
245            if payload.len() > 256 {
246                f(&blake2_256(payload))
247            } else {
248                f(payload)
249            }
250        })
251    }
252}
253
254#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
255#[serde(rename_all = "camelCase")]
256pub struct RuntimeVersion {
257    pub spec_version: u32,
258    pub transaction_version: u32,
259}
260
261/// Redefinition from `pallet-balances`.
262#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, Deserialize)]
263pub struct AccountDataGen<Balance> {
264    /// Non-reserved part of the balance. There may still be restrictions on
265    /// this, but it is the total pool what may in principle be transferred,
266    /// reserved and used for tipping.
267    ///
268    /// This is the only balance that matters in terms of most operations on
269    /// tokens. It alone is used to determine the balance when in the
270    /// contract execution environment.
271    pub free: Balance,
272    /// Balance which is reserved and may not be used at all.
273    ///
274    /// This can still get slashed, but gets slashed last of all.
275    ///
276    /// This balance is a 'reserve' balance that other subsystems use in order
277    /// to set aside tokens that are still 'owned' by the account holder,
278    /// but which are suspendable.
279    pub reserved: Balance,
280    /// The amount that `free` may not drop below when reducing the balance,
281    /// except for actions where the account owner cannot reasonably benefit
282    /// from thr balance reduction, such as slashing.
283    pub frozen: Balance,
284    /// Extra information about this account. The MSB is a flag indicating
285    /// whether the new ref- counting logic is in place for this account.
286    pub flags: ExtraFlags,
287}
288
289const IS_NEW_LOGIC: u128 = 0x80000000_00000000_00000000_00000000u128;
290
291#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Deserialize)]
292pub struct ExtraFlags(u128);
293
294impl Default for ExtraFlags {
295    fn default() -> Self {
296        Self(IS_NEW_LOGIC)
297    }
298}
299impl ExtraFlags {
300    pub fn old_logic() -> Self {
301        Self(0)
302    }
303    pub fn set_new_logic(&mut self) {
304        self.0 |= IS_NEW_LOGIC
305    }
306    pub fn is_new_logic(&self) -> bool {
307        (self.0 & IS_NEW_LOGIC) == IS_NEW_LOGIC
308    }
309}
310
311/// Type used to encode the number of references an account has.
312pub type RefCount = u32;
313/// Index of a transaction.
314pub type Index = u32;
315
316/// Redefinition from `frame-system`.
317#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, Deserialize)]
318pub struct AccountInfoGen<Index, AccountData> {
319    /// The number of transactions this account has sent.
320    pub nonce: Index,
321    /// The number of other pallets that currently depend on this account's
322    /// existence. The account cannot be reaped until this is zero.
323    pub consumers: RefCount,
324    /// The number of other pallets that allow this account to exist. The
325    /// account may not be reaped until this and `sufficients` are both
326    /// zero.
327    pub providers: RefCount,
328    /// The number of pallets that allow this account to exist for their own
329    /// purposes only. The account may not be reaped until this and
330    /// `providers` are both zero.
331    pub sufficients: RefCount,
332    /// The additional data that belongs to this account. Used to store the
333    /// balance(s) in a lot of chains.
334    pub data: AccountData,
335}
336
337pub type AccountData = AccountDataGen<Balance>;
338pub type AccountInfo = AccountInfoGen<Index, AccountData>;
339
340#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
341#[serde(rename_all = "camelCase")]
342pub struct FeeDetails {
343    /// The minimum fee for a transaction to be included in a block.
344    pub inclusion_fee: Option<InclusionFee>,
345    // Do not serialize and deserialize `tip` as we actually can not pass any tip to the RPC.
346    #[serde(skip)]
347    #[serde(deserialize_with = "deser_number_or_hex")]
348    pub tip: Balance,
349}
350
351impl FeeDetails {
352    /// Returns the final fee.
353    ///
354    /// final_fee = inclusion_fee + tip;
355    pub fn final_fee(&self) -> Balance {
356        self.inclusion_fee
357            .as_ref()
358            .map(|i| i.inclusion_fee())
359            .unwrap_or_default()
360            .saturating_add(self.tip)
361    }
362}
363
364#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
365#[serde(rename_all = "camelCase")]
366pub struct InclusionFee {
367    /// This is the minimum amount a user pays for a transaction. It is declared
368    /// as a base _weight_ in the runtime and converted to a fee using
369    /// `WeightToFee`.
370    #[serde(deserialize_with = "deser_number_or_hex")]
371    pub base_fee: Balance,
372    /// The length fee, the amount paid for the encoded length (in bytes) of the
373    /// transaction.
374    #[serde(deserialize_with = "deser_number_or_hex")]
375    pub len_fee: Balance,
376    /// - `targeted_fee_adjustment`: This is a multiplier that can tune the
377    ///   final fee based on the congestion of the network.
378    /// - `weight_fee`: This amount is computed based on the weight of the
379    ///   transaction. Weight
380    /// accounts for the execution time of a transaction.
381    ///
382    /// adjusted_weight_fee = targeted_fee_adjustment * weight_fee
383    #[serde(deserialize_with = "deser_number_or_hex")]
384    pub adjusted_weight_fee: Balance,
385}
386
387impl InclusionFee {
388    pub fn inclusion_fee(&self) -> Balance {
389        self.base_fee
390            .saturating_add(self.len_fee)
391            .saturating_add(self.adjusted_weight_fee)
392    }
393}
394
395#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
396#[serde(rename_all = "camelCase")]
397pub struct SignedBlock {
398    pub block: Block,
399}
400
401#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
402#[serde(rename_all = "camelCase")]
403pub struct Block {
404    pub header: Header,
405    pub extrinsics: Vec<String>,
406}
407
408impl Block {
409    /// Get timestamp that is set on the Block
410    pub fn timestamp(&self) -> Option<u64> {
411        self.extrinsics.iter().find_map(|e| decode_timestamp(e))
412    }
413}
414
415#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
416#[serde(rename_all = "camelCase")]
417pub struct Header {
418    pub parent_hash: H256,
419    #[serde(deserialize_with = "deser_number_or_hex")]
420    pub number: u128,
421}