Skip to content

Commit

Permalink
Allow Multiple Bridge Pallet Instances (paritytech#226)
Browse files Browse the repository at this point in the history
* Add Instance type parameter to pallet

* Sketch out what the runtime could look like

* Allow runtime to compile with multiple bridge pallets

* Cargo Fmt

* Allow an instance of a PoA chain to be used with currency-exchange

I specify that it's only _an instance_ instead of _instances_ since the currency-exchange
pallet does not support multiple instances itself. What this commit does is make it so
that the different instances of the PoA chains we currently have are compatible with the
currency-exchange pallet through the implementation of the PeerBlockchain trait.

* Add Instance type parameter to Currency Exchange pallet

* Wire up currency exchange intances in runtime

* Rust Fmt

* Show sccache

* Allow Eth pallet to use a default instance

* Use a default instance in Eth pallet tests

* Remove Rialto and Kovan feature flags

Through some discussions it has been decided that the `bridge-node` should, like
Substrate's `node-template`, be a showcase of the different pallets available in
a project. Because of this I've removed the feature flags for the Rialto and Kovan
networks in favour of having both of them included in the runtime.

* Update the chain_spec to use both Rialto and Kovan configs

* Update pallet level calls used by Substrate client

Allows the project to compile. However, it should be noted that in reality
we shouldn't be hardcoding the pallet we're calling.

* Allow currency-exchange pallet to use a default instance

* Support benchmarking an instance of the Eth pallet

* Update currency exchange benchmarks to work with instances

* Fix test helpers which now need a PoA instance

* Remove Actions for checking Rialto and Kovan features

* Add missing comments

* Update Runtime API string constants

* Add issue number for generic chain support in relay

* Add Runtime APIs for instances of the currency-exchange pallet

* Rust Fmt

Co-authored-by: Denis S. Soldatov aka General-Beck <[email protected]>
  • Loading branch information
2 people authored and bkchr committed Apr 10, 2024
1 parent c4424e5 commit 30844b1
Show file tree
Hide file tree
Showing 19 changed files with 360 additions and 251 deletions.
4 changes: 1 addition & 3 deletions bridges/bin/node/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,7 @@ tag = 'v2.0.0-rc4'
git = "https://github.com/paritytech/substrate.git"

[features]
default = ["bridge-rialto"]
bridge-kovan = ["bridge-node-runtime/bridge-kovan"]
bridge-rialto = ["bridge-node-runtime/bridge-rialto"]
default = []
runtime-benchmarks = [
"bridge-node-runtime/runtime-benchmarks",
]
23 changes: 16 additions & 7 deletions bridges/bin/node/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.

use bridge_node_runtime::{
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig, GenesisConfig, GrandpaConfig, SessionConfig,
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoConfig, GenesisConfig, GrandpaConfig,
SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
};
use grandpa_primitives::AuthorityId as GrandpaId;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
Expand Down Expand Up @@ -152,7 +152,8 @@ fn testnet_genesis(
pallet_aura: Some(AuraConfig {
authorities: Vec::new(),
}),
pallet_bridge_eth_poa: load_bridge_config(),
pallet_bridge_eth_poa_Instance1: load_rialto_bridge_config(),
pallet_bridge_eth_poa_Instance2: load_kovan_bridge_config(),
pallet_grandpa: Some(GrandpaConfig {
authorities: Vec::new(),
}),
Expand All @@ -166,10 +167,18 @@ fn testnet_genesis(
}
}

fn load_bridge_config() -> Option<BridgeEthPoAConfig> {
Some(BridgeEthPoAConfig {
initial_header: bridge_node_runtime::bridge::genesis_header(),
fn load_rialto_bridge_config() -> Option<BridgeRialtoConfig> {
Some(BridgeRialtoConfig {
initial_header: bridge_node_runtime::rialto::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: bridge_node_runtime::bridge::genesis_validators(),
initial_validators: bridge_node_runtime::rialto::genesis_validators(),
})
}

fn load_kovan_bridge_config() -> Option<BridgeKovanConfig> {
Some(BridgeKovanConfig {
initial_header: bridge_node_runtime::kovan::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: bridge_node_runtime::kovan::genesis_validators(),
})
}
5 changes: 1 addition & 4 deletions bridges/bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,7 @@ package = "substrate-wasm-builder-runner"
git = "https://github.com/paritytech/substrate/"

[features]
default = ["std", "bridge-rialto"]
bridge-kovan = []
bridge-rialto = []
default = ["std"]
std = [
"pallet-aura/std",
"pallet-balances/std",
Expand Down Expand Up @@ -268,5 +266,4 @@ runtime-benchmarks = [
"pallet-bridge-eth-poa/runtime-benchmarks",
"sp-bridge-eth-poa/test-helpers",
"sp-runtime/runtime-benchmarks",
"bridge-kovan",
]
26 changes: 3 additions & 23 deletions bridges/bin/node/runtime/src/exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
use codec::{Decode, Encode};
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_currency_exchange::Blockchain;
use sp_bridge_eth_poa::{transaction_decode, RawTransaction};
use sp_currency_exchange::{
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction, Result as ExchangeResult,
Expand Down Expand Up @@ -65,25 +64,6 @@ pub struct EthereumTransactionTag {
pub nonce: sp_core::U256,
}

/// Eth blockchain from runtime perspective.
pub struct EthBlockchain;

impl Blockchain for EthBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;

fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<Self::Transaction> {
let is_transaction_finalized =
crate::BridgeEthPoA::verify_transaction_finalized(proof.block, proof.index, &proof.proof);

if !is_transaction_finalized {
return None;
}

proof.proof.get(proof.index as usize).cloned()
}
}

/// Eth transaction from runtime perspective.
pub struct EthTransaction;

Expand Down Expand Up @@ -147,7 +127,7 @@ impl MaybeLockFundsTransaction for EthTransaction {

/// Prepares everything required to bench claim of funds locked by given transaction.
#[cfg(feature = "runtime-benchmarks")]
pub(crate) fn prepare_environment_for_claim<T: pallet_bridge_eth_poa::Trait>(
pub(crate) fn prepare_environment_for_claim<T: pallet_bridge_eth_poa::Trait<I>, I: pallet_bridge_eth_poa::Instance>(
transactions: &[RawTransaction],
) -> sp_bridge_eth_poa::H256 {
use pallet_bridge_eth_poa::{
Expand All @@ -156,8 +136,8 @@ pub(crate) fn prepare_environment_for_claim<T: pallet_bridge_eth_poa::Trait>(
};
use sp_bridge_eth_poa::compute_merkle_root;

let mut storage = BridgeStorage::<T>::new();
let header = HeaderBuilder::with_parent_number_on_runtime::<T>(0)
let mut storage = BridgeStorage::<T, I>::new();
let header = HeaderBuilder::with_parent_number_on_runtime::<T, I>(0)
.with_transactions_root(compute_merkle_root(transactions.iter()))
.sign_by(&validator(0));
let header_id = header.compute_id();
Expand Down
24 changes: 23 additions & 1 deletion bridges/bin/node/runtime/src/kovan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.

use crate::exchange::EthereumTransactionInclusionProof;

use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_currency_exchange::PeerBlockchain;
use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration, ValidatorsSource,
};
use sp_bridge_eth_poa::{Address, Header, U256};
use sp_bridge_eth_poa::{Address, Header, RawTransaction, U256};
use sp_std::prelude::*;

frame_support::parameter_types! {
Expand Down Expand Up @@ -131,6 +134,25 @@ impl BridgePruningStrategy for PruningStrategy {
}
}

/// The Kovan Blockchain as seen by the runtime.
pub struct KovanBlockchain;

impl PeerBlockchain for KovanBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;

fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<Self::Transaction> {
let is_transaction_finalized =
crate::BridgeKovan::verify_transaction_finalized(proof.block, proof.index, &proof.proof);

if !is_transaction_finalized {
return None;
}

proof.proof.get(proof.index as usize).cloned()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
105 changes: 76 additions & 29 deletions bridges/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,11 @@ pub mod exchange;

#[cfg(feature = "runtime-benchmarks")]
pub mod benches;
#[cfg(feature = "bridge-kovan")]
pub mod kovan;
#[cfg(feature = "bridge-rialto")]
pub mod rialto;

#[cfg(feature = "runtime-benchmarks")]
pub use benches as bridge;
#[cfg(all(feature = "bridge-kovan", not(feature = "runtime-benchmarks")))]
pub use kovan as bridge;
#[cfg(all(feature = "bridge-rialto", not(feature = "runtime-benchmarks")))]
pub use rialto as bridge;

use codec::{Decode, Encode};
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
Expand All @@ -69,10 +63,12 @@ pub use frame_support::{
weights::{IdentityFee, RuntimeDbWeight, Weight},
StorageValue,
};

pub use pallet_balances::Call as BalancesCall;
pub use pallet_bridge_currency_exchange::Call as BridgeCurrencyExchangeCall;
pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall;
pub use pallet_timestamp::Call as TimestampCall;

#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
Expand Down Expand Up @@ -233,17 +229,39 @@ impl pallet_aura::Trait for Runtime {
type AuthorityId = AuraId;
}

impl pallet_bridge_eth_poa::Trait for Runtime {
type AuraConfiguration = bridge::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = bridge::FinalityVotesCachingInterval;
type ValidatorsConfiguration = bridge::BridgeValidatorsConfiguration;
type PruningStrategy = bridge::PruningStrategy;
type Rialto = pallet_bridge_eth_poa::Instance1;
impl pallet_bridge_eth_poa::Trait<Rialto> for Runtime {
type AuraConfiguration = rialto::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = rialto::FinalityVotesCachingInterval;
type ValidatorsConfiguration = rialto::BridgeValidatorsConfiguration;
type PruningStrategy = rialto::PruningStrategy;
type OnHeadersSubmitted = ();
}

type Kovan = pallet_bridge_eth_poa::Instance2;
impl pallet_bridge_eth_poa::Trait<Kovan> for Runtime {
type AuraConfiguration = kovan::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = kovan::FinalityVotesCachingInterval;
type ValidatorsConfiguration = kovan::BridgeValidatorsConfiguration;
type PruningStrategy = kovan::PruningStrategy;
type OnHeadersSubmitted = ();
}

impl pallet_bridge_currency_exchange::Trait for Runtime {
type RialtoCurrencyExchange = pallet_bridge_currency_exchange::Instance1;
impl pallet_bridge_currency_exchange::Trait<RialtoCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = exchange::EthBlockchain;
type PeerBlockchain = rialto::RialtoBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = sp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
type CurrencyConverter = sp_currency_exchange::IdentityCurrencyConverter<Balance>;
type DepositInto = DepositInto;
}

type KovanCurrencyExchange = pallet_bridge_currency_exchange::Instance2;
impl pallet_bridge_currency_exchange::Trait<KovanCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = kovan::KovanBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = sp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
Expand Down Expand Up @@ -439,6 +457,10 @@ construct_runtime!(
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
BridgeRialto: pallet_bridge_eth_poa::<Instance1>::{Module, Call, Config, Storage, ValidateUnsigned},
BridgeKovan: pallet_bridge_eth_poa::<Instance2>::{Module, Call, Config, Storage, ValidateUnsigned},
BridgeRialtoCurrencyExchange: pallet_bridge_currency_exchange::<Instance1>::{Module, Call},
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Module, Call},
System: frame_system::{Module, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
Expand All @@ -448,8 +470,6 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment::{Module, Storage},
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
BridgeEthPoA: pallet_bridge_eth_poa::{Module, Call, Config, Storage, ValidateUnsigned},
BridgeCurrencyExchange: pallet_bridge_currency_exchange::{Module, Call},
}
);

Expand Down Expand Up @@ -535,32 +555,59 @@ impl_runtime_apis! {
}
}

impl sp_bridge_eth_poa::EthereumHeadersApi<Block> for Runtime {
impl sp_bridge_eth_poa::RialtoHeaderApi<Block> for Runtime {
fn best_block() -> (u64, sp_bridge_eth_poa::H256) {
let best_block = BridgeEthPoA::best_block();
let best_block = BridgeRialto::best_block();
(best_block.number, best_block.hash)
}

fn finalized_block() -> (u64, sp_bridge_eth_poa::H256) {
let finalized_block = BridgeEthPoA::finalized_block();
let finalized_block = BridgeRialto::finalized_block();
(finalized_block.number, finalized_block.hash)
}

fn is_import_requires_receipts(header: sp_bridge_eth_poa::Header) -> bool {
BridgeEthPoA::is_import_requires_receipts(header)
BridgeRialto::is_import_requires_receipts(header)
}

fn is_known_block(hash: sp_bridge_eth_poa::H256) -> bool {
BridgeEthPoA::is_known_block(hash)
BridgeRialto::is_known_block(hash)
}
}

impl sp_currency_exchange::CurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
impl sp_bridge_eth_poa::KovanHeaderApi<Block> for Runtime {
fn best_block() -> (u64, sp_bridge_eth_poa::H256) {
let best_block = BridgeKovan::best_block();
(best_block.number, best_block.hash)
}

fn finalized_block() -> (u64, sp_bridge_eth_poa::H256) {
let finalized_block = BridgeKovan::finalized_block();
(finalized_block.number, finalized_block.hash)
}

fn is_import_requires_receipts(header: sp_bridge_eth_poa::Header) -> bool {
BridgeKovan::is_import_requires_receipts(header)
}

fn is_known_block(hash: sp_bridge_eth_poa::H256) -> bool {
BridgeKovan::is_known_block(hash)
}
}

impl sp_currency_exchange::RialtoCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeRialtoCurrencyExchange::filter_transaction_proof(&proof)
}
}

impl sp_currency_exchange::KovanCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeCurrencyExchange::filter_transaction_proof(&proof)
BridgeKovanCurrencyExchange::filter_transaction_proof(&proof)
}
}


impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
Expand Down Expand Up @@ -656,14 +703,14 @@ impl_runtime_apis! {
ProofParams as BridgeCurrencyExchangeProofParams,
};

impl BridgeCurrencyExchangeTrait for Runtime {
impl BridgeCurrencyExchangeTrait<KovanCurrencyExchange> for Runtime {
fn make_proof(
proof_params: BridgeCurrencyExchangeProofParams<AccountId>,
) -> crate::exchange::EthereumTransactionInclusionProof {
use sp_currency_exchange::DepositInto;

if proof_params.recipient_exists {
<Runtime as pallet_bridge_currency_exchange::Trait>::DepositInto::deposit_into(
<Runtime as pallet_bridge_currency_exchange::Trait<KovanCurrencyExchange>>::DepositInto::deposit_into(
proof_params.recipient.clone(),
ExistentialDeposit::get(),
).unwrap();
Expand All @@ -681,7 +728,7 @@ impl_runtime_apis! {
let transactions = sp_std::iter::repeat(transaction.clone())
.take(1 + proof_params.proof_size_factor as usize)
.collect::<Vec<_>>();
let block_hash = crate::exchange::prepare_environment_for_claim::<Runtime>(&transactions);
let block_hash = crate::exchange::prepare_environment_for_claim::<Runtime, Kovan>(&transactions);
crate::exchange::EthereumTransactionInclusionProof {
block: block_hash,
index: 0,
Expand All @@ -690,8 +737,8 @@ impl_runtime_apis! {
}
}

add_benchmark!(params, batches, b"bridge-eth-poa", BridgeEthPoA);
add_benchmark!(params, batches, b"bridge-currency-exchange", BridgeCurrencyExchangeBench::<Runtime>);
add_benchmark!(params, batches, b"bridge-eth-poa", BridgeKovan);
add_benchmark!(params, batches, b"bridge-currency-exchange", BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>);

if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches)
Expand Down Expand Up @@ -785,7 +832,7 @@ mod tests {
let initial_amount =
<pallet_balances::Module<Runtime> as Currency<AccountId>>::free_balance(&existing_account);
let additional_amount = 10_000;
<Runtime as pallet_bridge_currency_exchange::Trait>::DepositInto::deposit_into(
<Runtime as pallet_bridge_currency_exchange::Trait<KovanCurrencyExchange>>::DepositInto::deposit_into(
existing_account.clone(),
additional_amount,
)
Expand All @@ -804,7 +851,7 @@ mod tests {
let initial_amount = 0;
let additional_amount = ExistentialDeposit::get() + 10_000;
let new_account: AccountId = [42u8; 32].into();
<Runtime as pallet_bridge_currency_exchange::Trait>::DepositInto::deposit_into(
<Runtime as pallet_bridge_currency_exchange::Trait<KovanCurrencyExchange>>::DepositInto::deposit_into(
new_account.clone(),
additional_amount,
)
Expand Down
Loading

0 comments on commit 30844b1

Please sign in to comment.