feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
[package]
|
||||
name = "pezpallet-example-authorization-tx-extension"
|
||||
version = "1.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "MIT-0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "FRAME example authorization transaction extension pallet"
|
||||
publish = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { workspace = true }
|
||||
docify = { workspace = true }
|
||||
log = { workspace = true }
|
||||
scale-info = { features = ["derive"], workspace = true }
|
||||
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { features = ["experimental"], workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezpallet-verify-signature = { workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-keyring = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"log/std",
|
||||
"pezpallet-verify-signature/std",
|
||||
"scale-info/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-verify-signature/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-keyring/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-verify-signature/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,139 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: MIT-0
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use core::{fmt, marker::PhantomData};
|
||||
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use pezframe_support::{pezpallet_prelude::TransactionSource, traits::OriginTrait, Parameter};
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_runtime::{
|
||||
impl_tx_ext_default,
|
||||
traits::{
|
||||
DispatchInfoOf, DispatchOriginOf, IdentifyAccount, TransactionExtension, ValidateResult,
|
||||
Verify,
|
||||
},
|
||||
transaction_validity::{InvalidTransaction, ValidTransaction},
|
||||
};
|
||||
|
||||
use crate::pezpallet_coownership::{Config, Origin};
|
||||
|
||||
/// Helper struct to organize the data needed for signature verification of both parties involved.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
|
||||
pub struct AuthCredentials<Signer, Signature> {
|
||||
first: (Signer, Signature),
|
||||
second: (Signer, Signature),
|
||||
}
|
||||
|
||||
/// Extension that, if activated by providing a pair of signers and signatures, will authorize a
|
||||
/// coowner origin of the two signers. Both signers have to construct their signatures on all of the
|
||||
/// data that follows this extension in the `TransactionExtension` pipeline, their implications and
|
||||
/// the call. Essentially re-sign the transaction from this point onwards in the pipeline by using
|
||||
/// the `inherited_implication`, as shown below.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct AuthorizeCoownership<T, Signer, Signature> {
|
||||
inner: Option<AuthCredentials<Signer, Signature>>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config, Signer, Signature> Default for AuthorizeCoownership<T, Signer, Signature> {
|
||||
fn default() -> Self {
|
||||
Self { inner: None, _phantom: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config, Signer, Signature> AuthorizeCoownership<T, Signer, Signature> {
|
||||
/// Creates an active extension that will try to authorize the coownership origin.
|
||||
pub fn new(first: (Signer, Signature), second: (Signer, Signature)) -> Self {
|
||||
Self { inner: Some(AuthCredentials { first, second }), _phantom: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config, Signer, Signature> fmt::Debug for AuthorizeCoownership<T, Signer, Signature> {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "AuthorizeCoownership")
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config + Send + Sync, Signer, Signature> TransactionExtension<T::RuntimeCall>
|
||||
for AuthorizeCoownership<T, Signer, Signature>
|
||||
where
|
||||
Signer: IdentifyAccount<AccountId = T::AccountId> + Parameter + Send + Sync + 'static,
|
||||
Signature: Verify<Signer = Signer> + Parameter + Send + Sync + 'static,
|
||||
{
|
||||
const IDENTIFIER: &'static str = "AuthorizeCoownership";
|
||||
type Implicit = ();
|
||||
type Val = ();
|
||||
type Pre = ();
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
mut origin: DispatchOriginOf<T::RuntimeCall>,
|
||||
_call: &T::RuntimeCall,
|
||||
_info: &DispatchInfoOf<T::RuntimeCall>,
|
||||
_len: usize,
|
||||
_self_implicit: Self::Implicit,
|
||||
inherited_implication: &impl codec::Encode,
|
||||
_source: TransactionSource,
|
||||
) -> ValidateResult<Self::Val, T::RuntimeCall> {
|
||||
// If the extension is inactive, just move on in the pipeline.
|
||||
let Some(auth) = &self.inner else {
|
||||
return Ok((ValidTransaction::default(), (), origin));
|
||||
};
|
||||
let first_account = auth.first.0.clone().into_account();
|
||||
let second_account = auth.second.0.clone().into_account();
|
||||
|
||||
// Construct the payload to sign using the `inherited_implication`.
|
||||
let msg = inherited_implication.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
|
||||
// Both parties' signatures must be correct for the origin to be authorized.
|
||||
// In a prod environment, we're just return a `InvalidTransaction::BadProof` if the
|
||||
// signature isn't valid, but we return these custom errors to be able to assert them in
|
||||
// tests.
|
||||
if !auth.first.1.verify(&msg[..], &first_account) {
|
||||
Err(InvalidTransaction::Custom(100))?
|
||||
}
|
||||
if !auth.second.1.verify(&msg[..], &second_account) {
|
||||
Err(InvalidTransaction::Custom(200))?
|
||||
}
|
||||
// Construct a `pezpallet_coownership::Origin`.
|
||||
let local_origin = Origin::Coowners(first_account, second_account);
|
||||
// Turn it into a local `PalletsOrigin`.
|
||||
let local_origin = <T as Config>::PalletsOrigin::from(local_origin);
|
||||
// Then finally into a pallet `RuntimeOrigin`.
|
||||
let local_origin = <T as Config>::RuntimeOrigin::from(local_origin);
|
||||
// Which the `set_caller_from` function will convert into the overarching `RuntimeOrigin`
|
||||
// created by `construct_runtime!`.
|
||||
origin.set_caller_from(local_origin);
|
||||
// Make sure to return the new origin.
|
||||
Ok((ValidTransaction::default(), (), origin))
|
||||
}
|
||||
// We're not doing any special logic in `TransactionExtension::prepare`, so just impl a default.
|
||||
impl_tx_ext_default!(T::RuntimeCall; weight prepare);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: MIT-0
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! # Authorization Transaction Extension Example Pallet
|
||||
//!
|
||||
//! **This pallet serves as an example and is not meant to be used in production.**
|
||||
//!
|
||||
//! FRAME Transaction Extension reference implementation, origin mutation, origin authorization and
|
||||
//! integration in a `TransactionExtension` pipeline.
|
||||
//!
|
||||
//! The [TransactionExtension](pezsp_runtime::traits::TransactionExtension) used in this example is
|
||||
//! [AuthorizeCoownership](extensions::AuthorizeCoownership). If activated, the extension will
|
||||
//! authorize 2 signers as coowners, with a [coowner origin](pezpallet_coownership::Origin) specific to
|
||||
//! the [coownership example pallet](pezpallet_coownership), by validating a signature of the rest of
|
||||
//! the transaction from each party. This means any extensions after ours in the pipeline, their
|
||||
//! implicits and the actual call. The extension pipeline used in our example checks the genesis
|
||||
//! hash, transaction version and mortality of the transaction after the `AuthorizeCoownership` runs
|
||||
//! as we want these transactions to run regardless of what origin passes through them and/or we
|
||||
//! want their implicit data in any signature authorization happening earlier in the pipeline.
|
||||
//!
|
||||
//! In this example, aside from the [AuthorizeCoownership](extensions::AuthorizeCoownership)
|
||||
//! extension, we use the following pallets:
|
||||
//! - [pezpallet_coownership] - provides a coowner origin and the functionality to authorize it.
|
||||
//! - [pezpallet_assets] - a dummy asset pallet that tracks assets, identified by an
|
||||
//! [AssetId](pezpallet_assets::AssetId), and their respective owners, which can be either an
|
||||
//! [account](pezpallet_assets::Owner::Single) or a [pair of owners](pezpallet_assets::Owner::Double).
|
||||
//!
|
||||
//! Assets are created in [pezpallet_assets] using the
|
||||
//! [create_asset](pezpallet_assets::Call::create_asset) call, which accepts traditionally signed
|
||||
//! origins (a single account) or coowner origins, authorized through the
|
||||
//! [CoownerOrigin](pezpallet_assets::Config::CoownerOrigin) type.
|
||||
//!
|
||||
//! ### Example runtime setup
|
||||
#![doc = docify::embed!("src/mock.rs", example_runtime)]
|
||||
//!
|
||||
//! ### Example usage
|
||||
#![doc = docify::embed!("src/tests.rs", create_coowned_asset_works)]
|
||||
//!
|
||||
//! This example does not focus on any pallet logic or syntax, but rather on `TransactionExtension`
|
||||
//! functionality. The pallets used are just skeletons to provide storage state and custom origin
|
||||
//! choices and requirements, as shown in the examples. Any weight and/or
|
||||
//! transaction fee is out of scope for this example.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod extensions;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
|
||||
#[pezframe_support::pallet(dev_mode)]
|
||||
pub mod pezpallet_coownership {
|
||||
use super::*;
|
||||
use pezframe_support::traits::OriginTrait;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// The aggregated origin which the dispatch will take.
|
||||
type RuntimeOrigin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>
|
||||
+ From<Self::PalletsOrigin>
|
||||
+ IsType<<Self as pezframe_system::Config>::RuntimeOrigin>;
|
||||
|
||||
/// The caller origin, overarching type of all pallets origins.
|
||||
type PalletsOrigin: From<Origin<Self>> + TryInto<Origin<Self>, Error = Self::PalletsOrigin>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
/// Origin that this pallet can authorize. For the purposes of this example, it's just two
|
||||
/// accounts that own something together.
|
||||
#[pallet::origin]
|
||||
#[derive(
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
RuntimeDebug,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
MaxEncodedLen,
|
||||
TypeInfo,
|
||||
)]
|
||||
pub enum Origin<T: Config> {
|
||||
Coowners(T::AccountId, T::AccountId),
|
||||
}
|
||||
}
|
||||
|
||||
#[pezframe_support::pallet(dev_mode)]
|
||||
pub mod pezpallet_assets {
|
||||
use super::*;
|
||||
|
||||
pub type AssetId = u32;
|
||||
|
||||
/// Type that describes possible owners of a particular asset.
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
pub enum Owner<AccountId> {
|
||||
Single(AccountId),
|
||||
Double(AccountId, AccountId),
|
||||
}
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// Type that can authorize an account pair coowner origin.
|
||||
type CoownerOrigin: EnsureOrigin<
|
||||
Self::RuntimeOrigin,
|
||||
Success = (Self::AccountId, Self::AccountId),
|
||||
>;
|
||||
}
|
||||
|
||||
/// Map that holds the owner information for each asset it manages.
|
||||
#[pallet::storage]
|
||||
pub type AssetOwners<T> =
|
||||
StorageMap<_, Blake2_128Concat, AssetId, Owner<<T as pezframe_system::Config>::AccountId>>;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// Asset already exists.
|
||||
AlreadyExists,
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Simple call that just creates an asset with a specific `AssetId`. This call will fail if
|
||||
/// there is already an asset with the same `AssetId`.
|
||||
///
|
||||
/// The origin is either a single account (traditionally signed origin) or a coowner origin.
|
||||
#[pallet::call_index(0)]
|
||||
pub fn create_asset(origin: OriginFor<T>, asset_id: AssetId) -> DispatchResult {
|
||||
let owner: Owner<T::AccountId> = match T::CoownerOrigin::try_origin(origin) {
|
||||
Ok((first, second)) => Owner::Double(first, second),
|
||||
Err(origin) => ensure_signed(origin).map(|account| Owner::Single(account))?,
|
||||
};
|
||||
AssetOwners::<T>::try_mutate(asset_id, |maybe_owner| {
|
||||
if maybe_owner.is_some() {
|
||||
return Err(Error::<T>::AlreadyExists);
|
||||
}
|
||||
*maybe_owner = Some(owner);
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: MIT-0
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::*;
|
||||
pub(crate) use example_runtime::*;
|
||||
use extensions::AuthorizeCoownership;
|
||||
use pezframe_support::derive_impl;
|
||||
use pezframe_system::{CheckEra, CheckGenesis, CheckNonce, CheckTxVersion};
|
||||
use pezpallet_verify_signature::VerifySignature;
|
||||
use pezsp_runtime::{
|
||||
generic,
|
||||
traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify},
|
||||
BuildStorage, MultiSignature, MultiSigner,
|
||||
};
|
||||
|
||||
#[docify::export]
|
||||
mod example_runtime {
|
||||
use super::*;
|
||||
|
||||
/// Our `TransactionExtension` fit for general transactions.
|
||||
pub type TxExtension = (
|
||||
// Validate the signature of regular account transactions (substitutes the old signed
|
||||
// transaction).
|
||||
VerifySignature<Runtime>,
|
||||
// Nonce check (and increment) for the caller.
|
||||
CheckNonce<Runtime>,
|
||||
// If activated, will mutate the origin to a `pezpallet_coownership` origin of 2 accounts that
|
||||
// own something.
|
||||
AuthorizeCoownership<Runtime, MultiSigner, MultiSignature>,
|
||||
// Some other extensions that we want to run for every possible origin and we want captured
|
||||
// in any and all signature and authorization schemes (such as the traditional account
|
||||
// signature or the double signature in `pezpallet_coownership`).
|
||||
CheckGenesis<Runtime>,
|
||||
CheckTxVersion<Runtime>,
|
||||
CheckEra<Runtime>,
|
||||
);
|
||||
/// Convenience type to more easily construct the signature to be signed in case
|
||||
/// `AuthorizeCoownership` is activated.
|
||||
pub type InnerTxExtension = (CheckGenesis<Runtime>, CheckTxVersion<Runtime>, CheckEra<Runtime>);
|
||||
pub type UncheckedExtrinsic =
|
||||
generic::UncheckedExtrinsic<AccountId, RuntimeCall, Signature, TxExtension>;
|
||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
|
||||
pub type Signature = MultiSignature;
|
||||
pub type BlockNumber = u32;
|
||||
|
||||
// For testing the pallet, we construct a mock runtime.
|
||||
pezframe_support::construct_runtime!(
|
||||
pub enum Runtime
|
||||
{
|
||||
System: pezframe_system,
|
||||
VerifySignaturePallet: pezpallet_verify_signature,
|
||||
|
||||
Assets: pezpallet_assets,
|
||||
Coownership: pezpallet_coownership,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type AccountId = AccountId;
|
||||
type Block = Block;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
}
|
||||
|
||||
impl pezpallet_verify_signature::Config for Runtime {
|
||||
type Signature = MultiSignature;
|
||||
type AccountIdentifier = MultiSigner;
|
||||
type WeightInfo = ();
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
/// Type that enables any pallet to ask for a coowner origin.
|
||||
pub struct EnsureCoowner;
|
||||
impl EnsureOrigin<RuntimeOrigin> for EnsureCoowner {
|
||||
type Success = (AccountId, AccountId);
|
||||
|
||||
fn try_origin(o: RuntimeOrigin) -> Result<Self::Success, RuntimeOrigin> {
|
||||
match o.clone().into() {
|
||||
Ok(pezpallet_coownership::Origin::<Runtime>::Coowners(first, second)) =>
|
||||
Ok((first, second)),
|
||||
_ => Err(o),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn try_successful_origin() -> Result<RuntimeOrigin, ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl pezpallet_assets::Config for Runtime {
|
||||
type CoownerOrigin = EnsureCoowner;
|
||||
}
|
||||
|
||||
impl pezpallet_coownership::Config for Runtime {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type PalletsOrigin = OriginCaller;
|
||||
}
|
||||
}
|
||||
|
||||
// This function basically just builds a genesis storage key/value store according to
|
||||
// our desired mockup.
|
||||
pub fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
let t = RuntimeGenesisConfig {
|
||||
// We use default for brevity, but you can configure as desired if needed.
|
||||
system: Default::default(),
|
||||
}
|
||||
.build_storage()
|
||||
.unwrap();
|
||||
t.into()
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: MIT-0
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! Tests for pezpallet-example-authorization-tx-extension.
|
||||
|
||||
use codec::Encode;
|
||||
use pezframe_support::{
|
||||
assert_noop,
|
||||
dispatch::GetDispatchInfo,
|
||||
pezpallet_prelude::{InvalidTransaction, TransactionValidityError},
|
||||
};
|
||||
use pezpallet_verify_signature::VerifySignature;
|
||||
use pezsp_keyring::Sr25519Keyring;
|
||||
use pezsp_runtime::{
|
||||
generic::ExtensionVersion,
|
||||
traits::{Applyable, Checkable, IdentityLookup, TransactionExtension},
|
||||
MultiSignature, MultiSigner,
|
||||
};
|
||||
|
||||
use crate::{extensions::AuthorizeCoownership, mock::*, pezpallet_assets};
|
||||
|
||||
#[test]
|
||||
fn create_asset_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let alice_keyring = Sr25519Keyring::Alice;
|
||||
let alice_account = AccountId::from(alice_keyring.public());
|
||||
// Simple call to create asset with Id `42`.
|
||||
let create_asset_call =
|
||||
RuntimeCall::Assets(pezpallet_assets::Call::create_asset { asset_id: 42 });
|
||||
let ext_version: ExtensionVersion = 0;
|
||||
// Create extension that will be used for dispatch.
|
||||
let initial_nonce = 23;
|
||||
let tx_ext = (
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::default(),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create the transaction signature, to be used in the top level `VerifyMultiSignature`
|
||||
// extension.
|
||||
let tx_sign = MultiSignature::Sr25519(
|
||||
(&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap())
|
||||
.using_encoded(|e| alice_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Add the signature to the extension.
|
||||
let tx_ext = (
|
||||
VerifySignature::new_with_signature(tx_sign, alice_account.clone()),
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::default(),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create the transaction and we're ready for dispatch.
|
||||
let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext);
|
||||
// Check Extrinsic validity and apply it.
|
||||
let uxt_info = uxt.get_dispatch_info();
|
||||
let uxt_len = uxt.using_encoded(|e| e.len());
|
||||
// Manually pay for Alice's nonce.
|
||||
pezframe_system::Account::<Runtime>::mutate(&alice_account, |info| {
|
||||
info.nonce = initial_nonce;
|
||||
info.providers = 1;
|
||||
});
|
||||
// Check should pass.
|
||||
let xt = <UncheckedExtrinsic as Checkable<IdentityLookup<AccountId>>>::check(
|
||||
uxt,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
// Apply the extrinsic.
|
||||
let res = xt.apply::<Runtime>(&uxt_info, uxt_len).unwrap();
|
||||
|
||||
// Asserting the results.
|
||||
assert_eq!(pezframe_system::Account::<Runtime>::get(&alice_account).nonce, initial_nonce + 1);
|
||||
assert_eq!(
|
||||
pezpallet_assets::AssetOwners::<Runtime>::get(42),
|
||||
Some(pezpallet_assets::Owner::<AccountId>::Single(alice_account))
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[test]
|
||||
fn create_coowned_asset_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let alice_keyring = Sr25519Keyring::Alice;
|
||||
let bob_keyring = Sr25519Keyring::Bob;
|
||||
let charlie_keyring = Sr25519Keyring::Charlie;
|
||||
let alice_account = AccountId::from(alice_keyring.public());
|
||||
let bob_account = AccountId::from(bob_keyring.public());
|
||||
let charlie_account = AccountId::from(charlie_keyring.public());
|
||||
// Simple call to create asset with Id `42`.
|
||||
let create_asset_call =
|
||||
RuntimeCall::Assets(pezpallet_assets::Call::create_asset { asset_id: 42 });
|
||||
let ext_version: ExtensionVersion = 0;
|
||||
// Create the inner transaction extension, to be signed by our coowners, Alice and Bob.
|
||||
let inner_ext: InnerTxExtension = (
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create the payload Alice and Bob need to sign.
|
||||
let inner_payload =
|
||||
(&(ext_version, &create_asset_call), &inner_ext, inner_ext.implicit().unwrap());
|
||||
// Create Alice's signature.
|
||||
let alice_inner_sig = MultiSignature::Sr25519(
|
||||
inner_payload.using_encoded(|e| alice_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Create Bob's signature.
|
||||
let bob_inner_sig = MultiSignature::Sr25519(
|
||||
inner_payload.using_encoded(|e| bob_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Create the transaction extension, to be signed by the submitter of the extrinsic, let's
|
||||
// have it be Charlie.
|
||||
let initial_nonce = 23;
|
||||
let tx_ext = (
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::new(
|
||||
(alice_keyring.into(), alice_inner_sig.clone()),
|
||||
(bob_keyring.into(), bob_inner_sig.clone()),
|
||||
),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create Charlie's transaction signature, to be used in the top level
|
||||
// `VerifyMultiSignature` extension.
|
||||
let tx_sign = MultiSignature::Sr25519(
|
||||
(&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap())
|
||||
.using_encoded(|e| charlie_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Add the signature to the extension.
|
||||
let tx_ext = (
|
||||
VerifySignature::new_with_signature(tx_sign, charlie_account.clone()),
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::new(
|
||||
(alice_keyring.into(), alice_inner_sig),
|
||||
(bob_keyring.into(), bob_inner_sig),
|
||||
),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create the transaction and we're ready for dispatch.
|
||||
let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext);
|
||||
// Check Extrinsic validity and apply it.
|
||||
let uxt_info = uxt.get_dispatch_info();
|
||||
let uxt_len = uxt.using_encoded(|e| e.len());
|
||||
// Manually pay for Charlie's nonce.
|
||||
pezframe_system::Account::<Runtime>::mutate(&charlie_account, |info| {
|
||||
info.nonce = initial_nonce;
|
||||
info.providers = 1;
|
||||
});
|
||||
// Check should pass.
|
||||
let xt = <UncheckedExtrinsic as Checkable<IdentityLookup<AccountId>>>::check(
|
||||
uxt,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
// Apply the extrinsic.
|
||||
let res = xt.apply::<Runtime>(&uxt_info, uxt_len).unwrap();
|
||||
|
||||
// Asserting the results.
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(pezframe_system::Account::<Runtime>::get(charlie_account).nonce, initial_nonce + 1);
|
||||
assert_eq!(
|
||||
pezpallet_assets::AssetOwners::<Runtime>::get(42),
|
||||
Some(pezpallet_assets::Owner::<AccountId>::Double(alice_account, bob_account))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_authorization_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let alice_keyring = Sr25519Keyring::Alice;
|
||||
let bob_keyring = Sr25519Keyring::Bob;
|
||||
let charlie_keyring = Sr25519Keyring::Charlie;
|
||||
let charlie_account = AccountId::from(charlie_keyring.public());
|
||||
// Simple call to create asset with Id `42`.
|
||||
let create_asset_call =
|
||||
RuntimeCall::Assets(pezpallet_assets::Call::create_asset { asset_id: 42 });
|
||||
let ext_version: ExtensionVersion = 0;
|
||||
// Create the inner transaction extension, to be signed by our coowners, Alice and Bob. They
|
||||
// are going to sign this transaction as a mortal one.
|
||||
let inner_ext: InnerTxExtension = (
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
// Sign with mortal era check.
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::mortal(4, 0)),
|
||||
);
|
||||
// Create the payload Alice and Bob need to sign.
|
||||
let inner_payload = (&create_asset_call, &inner_ext, inner_ext.implicit().unwrap());
|
||||
// Create Alice's signature.
|
||||
let alice_inner_sig = MultiSignature::Sr25519(
|
||||
inner_payload.using_encoded(|e| alice_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Create Bob's signature.
|
||||
let bob_inner_sig = MultiSignature::Sr25519(
|
||||
inner_payload.using_encoded(|e| bob_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Create the transaction extension, to be signed by the submitter of the extrinsic, let's
|
||||
// have it be Charlie.
|
||||
let initial_nonce = 23;
|
||||
let tx_ext = (
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::new(
|
||||
(alice_keyring.into(), alice_inner_sig.clone()),
|
||||
(bob_keyring.into(), bob_inner_sig.clone()),
|
||||
),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
// Construct the transaction as immortal with a different era check.
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create Charlie's transaction signature, to be used in the top level
|
||||
// `VerifyMultiSignature` extension.
|
||||
let tx_sign = MultiSignature::Sr25519(
|
||||
(&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap())
|
||||
.using_encoded(|e| charlie_keyring.sign(&pezsp_io::hashing::blake2_256(e))),
|
||||
);
|
||||
// Add the signature to the extension that Charlie signed.
|
||||
let tx_ext = (
|
||||
VerifySignature::new_with_signature(tx_sign, charlie_account.clone()),
|
||||
pezframe_system::CheckNonce::<Runtime>::from(initial_nonce),
|
||||
AuthorizeCoownership::<Runtime, MultiSigner, MultiSignature>::new(
|
||||
(alice_keyring.into(), alice_inner_sig),
|
||||
(bob_keyring.into(), bob_inner_sig),
|
||||
),
|
||||
pezframe_system::CheckGenesis::<Runtime>::new(),
|
||||
pezframe_system::CheckTxVersion::<Runtime>::new(),
|
||||
// Construct the transaction as immortal with a different era check.
|
||||
pezframe_system::CheckEra::<Runtime>::from(pezsp_runtime::generic::Era::immortal()),
|
||||
);
|
||||
// Create the transaction and we're ready for dispatch.
|
||||
let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext);
|
||||
// Check Extrinsic validity and apply it.
|
||||
let uxt_info = uxt.get_dispatch_info();
|
||||
let uxt_len = uxt.using_encoded(|e| e.len());
|
||||
// Manually pay for Charlie's nonce.
|
||||
pezframe_system::Account::<Runtime>::mutate(charlie_account, |info| {
|
||||
info.nonce = initial_nonce;
|
||||
info.providers = 1;
|
||||
});
|
||||
// Check should pass.
|
||||
let xt = <UncheckedExtrinsic as Checkable<IdentityLookup<AccountId>>>::check(
|
||||
uxt,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
// The extrinsic should fail as the signature for the `AuthorizeCoownership` doesn't work
|
||||
// for the provided payload with the changed transaction mortality.
|
||||
assert_noop!(
|
||||
xt.apply::<Runtime>(&uxt_info, uxt_len),
|
||||
TransactionValidityError::Invalid(InvalidTransaction::Custom(100))
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user