Skip to content

Commit

Permalink
Define separate signed extension for BHR/BHW (paritytech#1776)
Browse files Browse the repository at this point in the history
- Make signed extensions for indirect runtimes more extensible
- Define separate signed extension for BHR/BHW
  • Loading branch information
serban300 committed Apr 9, 2024
1 parent a288c85 commit c1c6d78
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 104 deletions.
6 changes: 3 additions & 3 deletions bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

use bp_messages::*;
pub use bp_polkadot_core::{
AccountId, AccountInfoStorageMapKeyProvider, AccountPublic, Balance, BlockNumber, Hash, Hasher,
Hashing, Header, Index, Nonce, Perbill, Signature, SignedBlock, SignedExtensions,
UncheckedExtrinsic, TX_EXTRA_BYTES,
AccountId, AccountInfoStorageMapKeyProvider, AccountPublic, Balance, BlockNumber,
BridgeSignedExtension, Hash, Hasher, Hashing, Header, Index, Nonce, Perbill,
PolkadotSignedExtension, Signature, SignedBlock, UncheckedExtrinsic, TX_EXTRA_BYTES,
};
use frame_support::{
dispatch::DispatchClass,
Expand Down
218 changes: 125 additions & 93 deletions bridges/primitives/polkadot-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

use bp_messages::MessageNonce;
use bp_runtime::{Chain, EncodedOrDecodedCall, StorageMapKeyProvider};
use codec::Compact;
use frame_support::{
dispatch::DispatchClass,
parameter_types,
Expand All @@ -29,17 +28,16 @@ use frame_support::{
Blake2_128Concat, RuntimeDebug,
};
use frame_system::limits;
use scale_info::TypeInfo;
use sp_core::{storage::StorageKey, Hasher as HasherT};
use sp_runtime::{
generic,
traits::{BlakeTwo256, DispatchInfoOf, IdentifyAccount, Verify},
transaction_validity::TransactionValidityError,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiAddress, MultiSignature, OpaqueExtrinsic,
};
use sp_std::prelude::Vec;

// Re-export's to avoid extra substrate dependencies in chain-specific crates.
use bp_runtime::extensions::*;
pub use frame_support::{weights::constants::ExtrinsicBaseWeight, Parameter};
pub use sp_runtime::{traits::Convert, Perbill};

Expand Down Expand Up @@ -184,48 +182,81 @@ pub type SignedBlock = generic::SignedBlock<Block>;
pub type Balance = u128;

/// Unchecked Extrinsic type.
pub type UncheckedExtrinsic<Call> = generic::UncheckedExtrinsic<
AccountAddress,
EncodedOrDecodedCall<Call>,
Signature,
SignedExtensions,
>;
pub type UncheckedExtrinsic<Call, SignedExt> =
generic::UncheckedExtrinsic<AccountAddress, EncodedOrDecodedCall<Call>, Signature, SignedExt>;

/// Account address, used by the Polkadot-like chain.
pub type Address = MultiAddress<AccountId, ()>;

/// A type of the data encoded as part of the transaction.
pub type SignedExtra =
((), (), (), (), sp_runtime::generic::Era, Compact<Nonce>, (), Compact<Balance>);

/// Parameters which are part of the payload used to produce transaction signature,
/// but don't end up in the transaction itself (i.e. inherent part of the runtime).
pub type AdditionalSigned = ((), u32, u32, Hash, Hash, (), (), ());

/// A simplified version of signed extensions meant for producing signed transactions
/// and signed payload in the client code.
#[derive(codec::Encode, codec::Decode, PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)]
pub struct SignedExtensions {
encode_payload: SignedExtra,
// It may be set to `None` if extensions are decoded. We are never reconstructing transactions
// (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to
// read fields of `encode_payload`. And when resigning transaction, we're reconstructing
// `SignedExtensions` from the scratch.
#[codec(skip)]
additional_signed: Option<AdditionalSigned>,
/// Polkadot-like chain.
#[derive(RuntimeDebug)]
pub struct PolkadotLike;

impl Chain for PolkadotLike {
type BlockNumber = BlockNumber;
type Hash = Hash;
type Hasher = Hasher;
type Header = Header;

type AccountId = AccountId;
type Balance = Balance;
type Index = Index;
type Signature = Signature;

fn max_extrinsic_size() -> u32 {
*BlockLength::get().max.get(DispatchClass::Normal)
}

fn max_extrinsic_weight() -> Weight {
BlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic
.unwrap_or(Weight::MAX)
}
}

/// Some functionality associated with the default signed extension used by Polkadot and
/// Polkadot-like chains.
pub trait PolkadotSignedExtension {
fn from_params(
spec_version: u32,
transaction_version: u32,
era: bp_runtime::TransactionEraOf<PolkadotLike>,
genesis_hash: Hash,
nonce: Nonce,
tip: Balance,
) -> Self;

fn nonce(&self) -> Nonce;

fn tip(&self) -> Balance;
}

impl SignedExtensions {
pub fn new(
type DefaultSignedExtra = (
CheckNonZeroSender,
CheckSpecVersion,
CheckTxVersion,
CheckGenesis<PolkadotLike>,
CheckEra<PolkadotLike>,
CheckNonce<Nonce>,
CheckWeight,
ChargeTransactionPayment<PolkadotLike>,
);

/// The default signed extension used by Polkadot and Polkadot-like chains.
pub type DefaultSignedExtension = GenericSignedExtension<DefaultSignedExtra>;

impl PolkadotSignedExtension for DefaultSignedExtension {
fn from_params(
spec_version: u32,
transaction_version: u32,
era: bp_runtime::TransactionEraOf<PolkadotLike>,
genesis_hash: Hash,
nonce: Nonce,
tip: Balance,
) -> Self {
Self {
encode_payload: (
Self::new(
(
(), // non-zero sender
(), // spec version
(), // tx version
Expand All @@ -235,7 +266,7 @@ impl SignedExtensions {
(), // Check weight
tip.into(), // transaction payment / tip (compact encoding)
),
additional_signed: Some((
(
(),
spec_version,
transaction_version,
Expand All @@ -244,78 +275,79 @@ impl SignedExtensions {
(),
(),
(),
)),
}
),
)
}
}

impl SignedExtensions {
/// Return signer nonce, used to craft transaction.
pub fn nonce(&self) -> Nonce {
self.encode_payload.5.into()
fn nonce(&self) -> Nonce {
self.payload.5.into()
}

/// Return transaction tip.
pub fn tip(&self) -> Balance {
self.encode_payload.7.into()
fn tip(&self) -> Balance {
self.payload.7.into()
}
}

impl sp_runtime::traits::SignedExtension for SignedExtensions {
const IDENTIFIER: &'static str = "Not needed.";

type AccountId = AccountId;
type Call = ();
type AdditionalSigned = AdditionalSigned;
type Pre = ();

fn additional_signed(
&self,
) -> Result<Self::AdditionalSigned, frame_support::unsigned::TransactionValidityError> {
// we shall not ever see this error in relay, because we are never signing decoded
// transactions. Instead we're constructing and signing new transactions. So the error code
// is kinda random here
self.additional_signed
.ok_or(frame_support::unsigned::TransactionValidityError::Unknown(
frame_support::unsigned::UnknownTransaction::Custom(0xFF),
))
}

fn pre_dispatch(
self,
_who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
Ok(())
type BridgeSignedExtra = (
CheckNonZeroSender,
CheckSpecVersion,
CheckTxVersion,
CheckGenesis<PolkadotLike>,
CheckEra<PolkadotLike>,
CheckNonce<Nonce>,
CheckWeight,
ChargeTransactionPayment<PolkadotLike>,
BridgeRejectObsoleteHeadersAndMessages,
);

/// The default signed extension used by Polkadot and Polkadot-like chains with bridging.
pub type BridgeSignedExtension = GenericSignedExtension<BridgeSignedExtra>;

impl PolkadotSignedExtension for BridgeSignedExtension {
fn from_params(
spec_version: u32,
transaction_version: u32,
era: bp_runtime::TransactionEraOf<PolkadotLike>,
genesis_hash: Hash,
nonce: Nonce,
tip: Balance,
) -> Self {
Self::new(
(
(), // non-zero sender
(), // spec version
(), // tx version
(), // genesis
era.frame_era(), // era
nonce.into(), // nonce (compact encoding)
(), // Check weight
tip.into(), // transaction payment / tip (compact encoding)
(), // bridge reject obsolete headers and msgs
),
(
(),
spec_version,
transaction_version,
genesis_hash,
era.signed_payload(genesis_hash),
(),
(),
(),
(),
),
)
}
}

/// Polkadot-like chain.
#[derive(RuntimeDebug)]
pub struct PolkadotLike;

impl Chain for PolkadotLike {
type BlockNumber = BlockNumber;
type Hash = Hash;
type Hasher = Hasher;
type Header = Header;

type AccountId = AccountId;
type Balance = Balance;
type Index = Index;
type Signature = Signature;

fn max_extrinsic_size() -> u32 {
*BlockLength::get().max.get(DispatchClass::Normal)
/// Return signer nonce, used to craft transaction.
fn nonce(&self) -> Nonce {
self.payload.5.into()
}

fn max_extrinsic_weight() -> Weight {
BlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic
.unwrap_or(Weight::MAX)
/// Return transaction tip.
fn tip(&self) -> Balance {
self.payload.7.into()
}
}

Expand Down
1 change: 1 addition & 0 deletions bridges/primitives/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
hash-db = { version = "0.15.2", default-features = false }
impl-trait-for-tuples = "0.2.2"
num-traits = { version = "0.2", default-features = false }
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
serde = { version = "1.0", optional = true, features = ["derive"] }
Expand Down
Loading

0 comments on commit c1c6d78

Please sign in to comment.