use crate::config::Config;
use codec::{Codec, Decode, DecodeWithMemTracking, Encode};
use primitive_types::H256;
use scale_info::{StaticTypeInfo, TypeInfo};
use sp_runtime::{
generic::Era,
impl_tx_ext_default,
traits::{BlakeTwo256, Dispatchable, Hash, TransactionExtension},
};
#[derive(Decode, Encode, Copy, Clone, Eq, PartialEq, Debug, TypeInfo)]
pub struct GenericTxExtension<Tip, Index> {
pub era: Era,
#[codec(compact)]
pub nonce: Index,
pub tip: Tip,
pub check_hash: u8,
}
impl<Tip, Index> GenericTxExtension<Tip, Index> {
pub fn new(era: Era, nonce: Index, tip: Tip) -> Self {
{
Self { era, nonce, tip, check_hash: 0 }
}
}
}
impl<Call, Tip, Index> TransactionExtension<Call> for GenericTxExtension<Tip, Index>
where
Call: Dispatchable,
GenericTxExtension<Tip, Index>: Codec
+ core::fmt::Debug
+ Sync
+ Send
+ Clone
+ Eq
+ PartialEq
+ StaticTypeInfo
+ DecodeWithMemTracking,
Tip: Codec
+ core::fmt::Debug
+ Sync
+ Send
+ Clone
+ Eq
+ PartialEq
+ StaticTypeInfo
+ DecodeWithMemTracking,
Index: Codec
+ core::fmt::Debug
+ Sync
+ Send
+ Clone
+ Eq
+ PartialEq
+ StaticTypeInfo
+ DecodeWithMemTracking,
{
const IDENTIFIER: &'static str = "GenericTxExtension";
type Implicit = ();
type Pre = ();
type Val = ();
impl_tx_ext_default!(Call; weight validate prepare);
}
pub type GenericImplicit<Hash> = ((), u32, u32, Hash, Hash, (), (), (), Option<H256>, ());
pub trait ExtrinsicParams<Index, Hash> {
type AdditionalParams: Default + Clone;
type TxExtension: Copy + Encode;
type Implicit: Encode;
fn new(
spec_version: u32,
transaction_version: u32,
nonce: Index,
genesis_hash: Hash,
additional_params: Self::AdditionalParams,
) -> Self;
#[deprecated = "Use transaction_extension instead"]
fn signed_extra(&self) -> Self::TxExtension {
self.transaction_extension()
}
fn transaction_extension(&self) -> Self::TxExtension;
#[deprecated = "Use implicit instead"]
fn additional_signed(&self) -> Self::Implicit {
self.implicit()
}
fn implicit(&self) -> Self::Implicit;
}
#[derive(Decode, Encode, Clone, Eq, PartialEq, Debug)]
pub struct GenericExtrinsicParams<T: Config, Tip> {
era: Era,
nonce: T::Index,
tip: Tip,
spec_version: u32,
transaction_version: u32,
genesis_hash: T::Hash,
mortality_checkpoint: T::Hash,
}
#[derive(Decode, Encode, Copy, Clone, Eq, PartialEq, Debug)]
pub struct GenericAdditionalParams<Tip, Hash> {
pub era: Era,
pub mortality_checkpoint: Option<Hash>,
pub tip: Tip,
}
impl<Tip: Default, Hash> GenericAdditionalParams<Tip, Hash> {
pub fn new() -> Self {
Self::default()
}
pub fn era(mut self, era: Era, checkpoint: Hash) -> Self {
self.era = era;
self.mortality_checkpoint = Some(checkpoint);
self
}
pub fn tip(mut self, tip: impl Into<Tip>) -> Self {
self.tip = tip.into();
self
}
}
impl<Tip: Default, Hash> Default for GenericAdditionalParams<Tip, Hash> {
fn default() -> Self {
Self { era: Era::Immortal, mortality_checkpoint: None, tip: Tip::default() }
}
}
impl<T, Tip> ExtrinsicParams<T::Index, T::Hash> for GenericExtrinsicParams<T, Tip>
where
T: Config,
u128: From<Tip>,
Tip: Copy + Default + Encode,
{
type AdditionalParams = GenericAdditionalParams<Tip, T::Hash>;
type TxExtension = GenericTxExtension<Tip, T::Index>;
type Implicit = GenericImplicit<T::Hash>;
fn new(
spec_version: u32,
transaction_version: u32,
nonce: T::Index,
genesis_hash: T::Hash,
additional_params: Self::AdditionalParams,
) -> Self {
GenericExtrinsicParams {
era: additional_params.era,
tip: additional_params.tip,
spec_version,
transaction_version,
genesis_hash,
mortality_checkpoint: additional_params.mortality_checkpoint.unwrap_or(genesis_hash),
nonce,
}
}
fn transaction_extension(&self) -> Self::TxExtension {
Self::TxExtension::new(self.era, self.nonce, self.tip)
}
fn implicit(&self) -> Self::Implicit {
{
(
(),
self.spec_version,
self.transaction_version,
self.genesis_hash,
self.mortality_checkpoint,
(),
(),
(),
None,
(),
)
}
}
}
#[derive(Decode, Encode, Clone, Eq, PartialEq, Debug)]
pub struct SignedPayload<Call, TransactionExtension, Implicit>(
(Call, TransactionExtension, Implicit),
);
impl<Call, TransactionExtension, Implicit> SignedPayload<Call, TransactionExtension, Implicit>
where
Call: Encode,
TransactionExtension: Encode,
Implicit: Encode,
{
pub fn from_raw(call: Call, extra: TransactionExtension, additional_signed: Implicit) -> Self {
Self((call, extra, additional_signed))
}
pub fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(|payload| {
if payload.len() > 256 {
f(&BlakeTwo256::hash(payload)[..])
} else {
f(payload)
}
})
}
}
#[derive(Copy, Clone, Debug, Default, Decode, Encode, Eq, PartialEq)]
pub struct PlainTip<Balance> {
#[codec(compact)]
tip: Balance,
}
impl<Balance> PlainTip<Balance> {
pub fn new(amount: Balance) -> Self {
PlainTip { tip: amount }
}
}
impl<Balance> From<Balance> for PlainTip<Balance> {
fn from(n: Balance) -> Self {
PlainTip::new(n)
}
}
impl From<PlainTip<u128>> for u128 {
fn from(tip: PlainTip<u128>) -> Self {
tip.tip
}
}
#[derive(Copy, Clone, Debug, Default, Decode, Encode, Eq, PartialEq)]
pub struct AssetTip<Balance> {
#[codec(compact)]
tip: Balance,
asset: Option<u32>,
}
impl<Balance> AssetTip<Balance> {
pub fn new(amount: Balance) -> Self {
AssetTip { tip: amount, asset: None }
}
pub fn of_asset(mut self, asset: u32) -> Self {
self.asset = Some(asset);
self
}
}
impl<Balance> From<Balance> for AssetTip<Balance> {
fn from(n: Balance) -> Self {
AssetTip::new(n)
}
}
impl From<AssetTip<u128>> for u128 {
fn from(tip: AssetTip<u128>) -> Self {
tip.tip
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_crypto_hashing::blake2_256;
#[test]
fn encode_blake2_256_works_as_expected() {
let bytes = "afaefafe1204udanfai9lfadmlk9aömlsa".as_bytes();
assert_eq!(&blake2_256(bytes)[..], &BlakeTwo256::hash(bytes)[..]);
}
}