Allow Multiple Bridge Pallet Instances (#226)

* 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 <general.beck@gmail.com>
This commit is contained in:
Hernando Castano
2020-07-27 13:14:36 -04:00
committed by Bastian Köcher
parent c4424e5b73
commit 30844b1e9c
19 changed files with 361 additions and 252 deletions
+1 -3
View File
@@ -146,9 +146,7 @@ tag = 'v2.0.0-rc4'
git = "https://github.com/paritytech/substrate.git" git = "https://github.com/paritytech/substrate.git"
[features] [features]
default = ["bridge-rialto"] default = []
bridge-kovan = ["bridge-node-runtime/bridge-kovan"]
bridge-rialto = ["bridge-node-runtime/bridge-rialto"]
runtime-benchmarks = [ runtime-benchmarks = [
"bridge-node-runtime/runtime-benchmarks", "bridge-node-runtime/runtime-benchmarks",
] ]
+16 -7
View File
@@ -15,8 +15,8 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use bridge_node_runtime::{ use bridge_node_runtime::{
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig, GenesisConfig, GrandpaConfig, SessionConfig, AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoConfig, GenesisConfig, GrandpaConfig,
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
}; };
use grandpa_primitives::AuthorityId as GrandpaId; use grandpa_primitives::AuthorityId as GrandpaId;
use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_aura::sr25519::AuthorityId as AuraId;
@@ -152,7 +152,8 @@ fn testnet_genesis(
pallet_aura: Some(AuraConfig { pallet_aura: Some(AuraConfig {
authorities: Vec::new(), 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 { pallet_grandpa: Some(GrandpaConfig {
authorities: Vec::new(), authorities: Vec::new(),
}), }),
@@ -166,10 +167,18 @@ fn testnet_genesis(
} }
} }
fn load_bridge_config() -> Option<BridgeEthPoAConfig> { fn load_rialto_bridge_config() -> Option<BridgeRialtoConfig> {
Some(BridgeEthPoAConfig { Some(BridgeRialtoConfig {
initial_header: bridge_node_runtime::bridge::genesis_header(), initial_header: bridge_node_runtime::rialto::genesis_header(),
initial_difficulty: 0.into(), 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(),
}) })
} }
+1 -4
View File
@@ -224,9 +224,7 @@ package = "substrate-wasm-builder-runner"
git = "https://github.com/paritytech/substrate/" git = "https://github.com/paritytech/substrate/"
[features] [features]
default = ["std", "bridge-rialto"] default = ["std"]
bridge-kovan = []
bridge-rialto = []
std = [ std = [
"pallet-aura/std", "pallet-aura/std",
"pallet-balances/std", "pallet-balances/std",
@@ -268,5 +266,4 @@ runtime-benchmarks = [
"pallet-bridge-eth-poa/runtime-benchmarks", "pallet-bridge-eth-poa/runtime-benchmarks",
"sp-bridge-eth-poa/test-helpers", "sp-bridge-eth-poa/test-helpers",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"bridge-kovan",
] ]
+3 -23
View File
@@ -30,7 +30,6 @@
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use frame_support::RuntimeDebug; use frame_support::RuntimeDebug;
use hex_literal::hex; use hex_literal::hex;
use pallet_bridge_currency_exchange::Blockchain;
use sp_bridge_eth_poa::{transaction_decode, RawTransaction}; use sp_bridge_eth_poa::{transaction_decode, RawTransaction};
use sp_currency_exchange::{ use sp_currency_exchange::{
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction, Result as ExchangeResult, Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction, Result as ExchangeResult,
@@ -65,25 +64,6 @@ pub struct EthereumTransactionTag {
pub nonce: sp_core::U256, 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. /// Eth transaction from runtime perspective.
pub struct EthTransaction; pub struct EthTransaction;
@@ -147,7 +127,7 @@ impl MaybeLockFundsTransaction for EthTransaction {
/// Prepares everything required to bench claim of funds locked by given transaction. /// Prepares everything required to bench claim of funds locked by given transaction.
#[cfg(feature = "runtime-benchmarks")] #[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], transactions: &[RawTransaction],
) -> sp_bridge_eth_poa::H256 { ) -> sp_bridge_eth_poa::H256 {
use pallet_bridge_eth_poa::{ use pallet_bridge_eth_poa::{
@@ -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; use sp_bridge_eth_poa::compute_merkle_root;
let mut storage = BridgeStorage::<T>::new(); let mut storage = BridgeStorage::<T, I>::new();
let header = HeaderBuilder::with_parent_number_on_runtime::<T>(0) let header = HeaderBuilder::with_parent_number_on_runtime::<T, I>(0)
.with_transactions_root(compute_merkle_root(transactions.iter())) .with_transactions_root(compute_merkle_root(transactions.iter()))
.sign_by(&validator(0)); .sign_by(&validator(0));
let header_id = header.compute_id(); let header_id = header.compute_id();
+23 -1
View File
@@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::exchange::EthereumTransactionInclusionProof;
use frame_support::RuntimeDebug; use frame_support::RuntimeDebug;
use hex_literal::hex; use hex_literal::hex;
use pallet_bridge_currency_exchange::PeerBlockchain;
use pallet_bridge_eth_poa::{ use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration, ValidatorsSource, 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::*; use sp_std::prelude::*;
frame_support::parameter_types! { frame_support::parameter_types! {
@@ -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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
+76 -29
View File
@@ -32,17 +32,11 @@ pub mod exchange;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
pub mod benches; pub mod benches;
#[cfg(feature = "bridge-kovan")]
pub mod kovan; pub mod kovan;
#[cfg(feature = "bridge-rialto")]
pub mod rialto; pub mod rialto;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
pub use benches as bridge; 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 codec::{Decode, Encode};
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
@@ -69,10 +63,12 @@ pub use frame_support::{
weights::{IdentityFee, RuntimeDbWeight, Weight}, weights::{IdentityFee, RuntimeDbWeight, Weight},
StorageValue, StorageValue,
}; };
pub use pallet_balances::Call as BalancesCall; pub use pallet_balances::Call as BalancesCall;
pub use pallet_bridge_currency_exchange::Call as BridgeCurrencyExchangeCall; pub use pallet_bridge_currency_exchange::Call as BridgeCurrencyExchangeCall;
pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall; pub use pallet_bridge_eth_poa::Call as BridgeEthPoACall;
pub use pallet_timestamp::Call as TimestampCall; pub use pallet_timestamp::Call as TimestampCall;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage; pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill}; pub use sp_runtime::{Perbill, Permill};
@@ -233,17 +229,39 @@ impl pallet_aura::Trait for Runtime {
type AuthorityId = AuraId; type AuthorityId = AuraId;
} }
impl pallet_bridge_eth_poa::Trait for Runtime { type Rialto = pallet_bridge_eth_poa::Instance1;
type AuraConfiguration = bridge::BridgeAuraConfiguration; impl pallet_bridge_eth_poa::Trait<Rialto> for Runtime {
type FinalityVotesCachingInterval = bridge::FinalityVotesCachingInterval; type AuraConfiguration = rialto::BridgeAuraConfiguration;
type ValidatorsConfiguration = bridge::BridgeValidatorsConfiguration; type FinalityVotesCachingInterval = rialto::FinalityVotesCachingInterval;
type PruningStrategy = bridge::PruningStrategy; type ValidatorsConfiguration = rialto::BridgeValidatorsConfiguration;
type PruningStrategy = rialto::PruningStrategy;
type OnHeadersSubmitted = (); type OnHeadersSubmitted = ();
} }
impl pallet_bridge_currency_exchange::Trait for Runtime { 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 = ();
}
type RialtoCurrencyExchange = pallet_bridge_currency_exchange::Instance1;
impl pallet_bridge_currency_exchange::Trait<RialtoCurrencyExchange> for Runtime {
type OnTransactionSubmitted = (); 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 PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = sp_currency_exchange::IdentityRecipients<AccountId>; type RecipientsMap = sp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance; type Amount = Balance;
@@ -439,6 +457,10 @@ construct_runtime!(
NodeBlock = opaque::Block, NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic 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>}, System: frame_system::{Module, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
@@ -448,8 +470,6 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment::{Module, Storage}, TransactionPayment: pallet_transaction_payment::{Module, Storage},
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>}, Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
Session: pallet_session::{Module, Call, Storage, Event, Config<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},
} }
); );
@@ -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) { 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) (best_block.number, best_block.hash)
} }
fn finalized_block() -> (u64, sp_bridge_eth_poa::H256) { 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) (finalized_block.number, finalized_block.hash)
} }
fn is_import_requires_receipts(header: sp_bridge_eth_poa::Header) -> bool { 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 { 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 { fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeCurrencyExchange::filter_transaction_proof(&proof) BridgeRialtoCurrencyExchange::filter_transaction_proof(&proof)
} }
} }
impl sp_currency_exchange::KovanCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeKovanCurrencyExchange::filter_transaction_proof(&proof)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime { impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction( fn validate_transaction(
source: TransactionSource, source: TransactionSource,
@@ -656,14 +703,14 @@ impl_runtime_apis! {
ProofParams as BridgeCurrencyExchangeProofParams, ProofParams as BridgeCurrencyExchangeProofParams,
}; };
impl BridgeCurrencyExchangeTrait for Runtime { impl BridgeCurrencyExchangeTrait<KovanCurrencyExchange> for Runtime {
fn make_proof( fn make_proof(
proof_params: BridgeCurrencyExchangeProofParams<AccountId>, proof_params: BridgeCurrencyExchangeProofParams<AccountId>,
) -> crate::exchange::EthereumTransactionInclusionProof { ) -> crate::exchange::EthereumTransactionInclusionProof {
use sp_currency_exchange::DepositInto; use sp_currency_exchange::DepositInto;
if proof_params.recipient_exists { 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(), proof_params.recipient.clone(),
ExistentialDeposit::get(), ExistentialDeposit::get(),
).unwrap(); ).unwrap();
@@ -681,7 +728,7 @@ impl_runtime_apis! {
let transactions = sp_std::iter::repeat(transaction.clone()) let transactions = sp_std::iter::repeat(transaction.clone())
.take(1 + proof_params.proof_size_factor as usize) .take(1 + proof_params.proof_size_factor as usize)
.collect::<Vec<_>>(); .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 { crate::exchange::EthereumTransactionInclusionProof {
block: block_hash, block: block_hash,
index: 0, index: 0,
@@ -690,8 +737,8 @@ impl_runtime_apis! {
} }
} }
add_benchmark!(params, batches, b"bridge-eth-poa", BridgeEthPoA); add_benchmark!(params, batches, b"bridge-eth-poa", BridgeKovan);
add_benchmark!(params, batches, b"bridge-currency-exchange", BridgeCurrencyExchangeBench::<Runtime>); add_benchmark!(params, batches, b"bridge-currency-exchange", BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>);
if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches) Ok(batches)
@@ -785,7 +832,7 @@ mod tests {
let initial_amount = let initial_amount =
<pallet_balances::Module<Runtime> as Currency<AccountId>>::free_balance(&existing_account); <pallet_balances::Module<Runtime> as Currency<AccountId>>::free_balance(&existing_account);
let additional_amount = 10_000; 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(), existing_account.clone(),
additional_amount, additional_amount,
) )
@@ -804,7 +851,7 @@ mod tests {
let initial_amount = 0; let initial_amount = 0;
let additional_amount = ExistentialDeposit::get() + 10_000; let additional_amount = ExistentialDeposit::get() + 10_000;
let new_account: AccountId = [42u8; 32].into(); 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(), new_account.clone(),
additional_amount, additional_amount,
) )
+23 -1
View File
@@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::exchange::EthereumTransactionInclusionProof;
use frame_support::RuntimeDebug; use frame_support::RuntimeDebug;
use hex_literal::hex; use hex_literal::hex;
use pallet_bridge_currency_exchange::PeerBlockchain;
use pallet_bridge_eth_poa::{ use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as TPruningStrategy, ValidatorsConfiguration, ValidatorsSource, AuraConfiguration, PruningStrategy as TPruningStrategy, ValidatorsConfiguration, ValidatorsSource,
}; };
use sp_bridge_eth_poa::{Address, Header, U256}; use sp_bridge_eth_poa::{Address, Header, RawTransaction, U256};
use sp_std::prelude::*; use sp_std::prelude::*;
frame_support::parameter_types! { frame_support::parameter_types! {
@@ -104,6 +107,25 @@ impl TPruningStrategy for PruningStrategy {
} }
} }
/// The Rialto Blockchain as seen by the runtime.
pub struct RialtoBlockchain;
impl PeerBlockchain for RialtoBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;
fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<Self::Transaction> {
let is_transaction_finalized =
crate::BridgeRialto::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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -18,10 +18,10 @@
//! So we are giving runtime opportunity to prepare environment and construct proof //! So we are giving runtime opportunity to prepare environment and construct proof
//! before invoking module calls. //! before invoking module calls.
use super::{Blockchain, Call, Module as CurrencyExchangeModule, Trait as CurrencyExchangeTrait}; use super::{Call, Instance, Module as CurrencyExchangeModule, PeerBlockchain, Trait as CurrencyExchangeTrait};
use sp_std::prelude::*; use sp_std::prelude::*;
use frame_benchmarking::{account, benchmarks}; use frame_benchmarking::{account, benchmarks_instance};
use frame_system::RawOrigin; use frame_system::RawOrigin;
const SEED: u32 = 0; const SEED: u32 = 0;
@@ -29,7 +29,7 @@ const WORST_TX_SIZE_FACTOR: u32 = 1000;
const WORST_PROOF_SIZE_FACTOR: u32 = 1000; const WORST_PROOF_SIZE_FACTOR: u32 = 1000;
/// Module we're benchmarking here. /// Module we're benchmarking here.
pub struct Module<T: Trait>(CurrencyExchangeModule<T>); pub struct Module<T: Trait<I>, I: Instance>(CurrencyExchangeModule<T, I>);
/// Proof benchmarking parameters. /// Proof benchmarking parameters.
pub struct ProofParams<Recipient> { pub struct ProofParams<Recipient> {
@@ -46,14 +46,14 @@ pub struct ProofParams<Recipient> {
} }
/// Trait that must be implemented by runtime. /// Trait that must be implemented by runtime.
pub trait Trait: CurrencyExchangeTrait { pub trait Trait<I: Instance>: CurrencyExchangeTrait<I> {
/// Prepare proof for importing exchange transaction. /// Prepare proof for importing exchange transaction.
fn make_proof( fn make_proof(
proof_params: ProofParams<Self::AccountId>, proof_params: ProofParams<Self::AccountId>,
) -> <<Self as CurrencyExchangeTrait>::PeerBlockchain as Blockchain>::TransactionInclusionProof; ) -> <<Self as CurrencyExchangeTrait<I>>::PeerBlockchain as PeerBlockchain>::TransactionInclusionProof;
} }
benchmarks! { benchmarks_instance! {
_ { } _ { }
// Benchmark `import_peer_transaction` extrinsic with the best possible conditions: // Benchmark `import_peer_transaction` extrinsic with the best possible conditions:
+39 -35
View File
@@ -33,8 +33,8 @@ pub trait OnTransactionSubmitted<AccountId> {
fn on_valid_transaction_submitted(submitter: AccountId); fn on_valid_transaction_submitted(submitter: AccountId);
} }
/// Peer blockhain interface. /// Peer blockchain interface.
pub trait Blockchain { pub trait PeerBlockchain {
/// Transaction type. /// Transaction type.
type Transaction: Parameter; type Transaction: Parameter;
/// Transaction inclusion proof type. /// Transaction inclusion proof type.
@@ -47,14 +47,14 @@ pub trait Blockchain {
} }
/// The module configuration trait /// The module configuration trait
pub trait Trait: frame_system::Trait { pub trait Trait<I = DefaultInstance>: frame_system::Trait {
/// Handler for transaction submission result. /// Handler for transaction submission result.
type OnTransactionSubmitted: OnTransactionSubmitted<Self::AccountId>; type OnTransactionSubmitted: OnTransactionSubmitted<Self::AccountId>;
/// Peer blockchain type. /// Represents the blockchain that we'll be exchanging currency with.
type PeerBlockchain: Blockchain; type PeerBlockchain: PeerBlockchain;
/// Peer blockchain transaction parser. /// Peer blockchain transaction parser.
type PeerMaybeLockFundsTransaction: MaybeLockFundsTransaction< type PeerMaybeLockFundsTransaction: MaybeLockFundsTransaction<
Transaction = <Self::PeerBlockchain as Blockchain>::Transaction, Transaction = <Self::PeerBlockchain as PeerBlockchain>::Transaction,
>; >;
/// Map between blockchains recipients. /// Map between blockchains recipients.
type RecipientsMap: RecipientsMap< type RecipientsMap: RecipientsMap<
@@ -73,7 +73,7 @@ pub trait Trait: frame_system::Trait {
} }
decl_error! { decl_error! {
pub enum Error for Module<T: Trait> { pub enum Error for Module<T: Trait<I>, I: Instance> {
/// Invalid peer blockchain transaction provided. /// Invalid peer blockchain transaction provided.
InvalidTransaction, InvalidTransaction,
/// Peer transaction has invalid amount. /// Peer transaction has invalid amount.
@@ -96,17 +96,17 @@ decl_error! {
} }
decl_module! { decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {
/// Imports lock fund transaction of the peer blockchain. /// Imports lock fund transaction of the peer blockchain.
#[weight = 0] // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) #[weight = 0] // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78)
pub fn import_peer_transaction( pub fn import_peer_transaction(
origin, origin,
proof: <<T as Trait>::PeerBlockchain as Blockchain>::TransactionInclusionProof, proof: <<T as Trait<I>>::PeerBlockchain as PeerBlockchain>::TransactionInclusionProof,
) -> DispatchResult { ) -> DispatchResult {
let submitter = frame_system::ensure_signed(origin)?; let submitter = frame_system::ensure_signed(origin)?;
// verify and parse transaction proof // verify and parse transaction proof
let deposit = prepare_deposit_details::<T>(&proof)?; let deposit = prepare_deposit_details::<T, I>(&proof)?;
// make sure to update the mapping if we deposit successfully to avoid double spending, // make sure to update the mapping if we deposit successfully to avoid double spending,
// i.e. whenever `deposit_into` is successful we MUST update `Transfers`. // i.e. whenever `deposit_into` is successful we MUST update `Transfers`.
@@ -117,9 +117,9 @@ decl_module! {
match deposit_result { match deposit_result {
Ok(_) => (), Ok(_) => (),
Err(ExchangeError::DepositPartiallyFailed) => (), Err(ExchangeError::DepositPartiallyFailed) => (),
Err(error) => return Err(Error::<T>::from(error).into()), Err(error) => return Err(Error::<T, I>::from(error).into()),
} }
Transfers::<T>::insert(&deposit.transfer_id, ()) Transfers::<T, I>::insert(&deposit.transfer_id, ())
} }
// reward submitter for providing valid message // reward submitter for providing valid message
@@ -137,17 +137,17 @@ decl_module! {
} }
decl_storage! { decl_storage! {
trait Store for Module<T: Trait> as Bridge { trait Store for Module<T: Trait<I>, I: Instance = DefaultInstance> as Bridge {
/// All transfers that have already been claimed. /// All transfers that have already been claimed.
Transfers: map hasher(blake2_128_concat) <T::PeerMaybeLockFundsTransaction as MaybeLockFundsTransaction>::Id => (); Transfers: map hasher(blake2_128_concat) <T::PeerMaybeLockFundsTransaction as MaybeLockFundsTransaction>::Id => ();
} }
} }
impl<T: Trait> Module<T> { impl<T: Trait<I>, I: Instance> Module<T, I> {
/// Returns true if currency exchange module is able to import given transaction proof in /// Returns true if currency exchange module is able to import given transaction proof in
/// its current state. /// its current state.
pub fn filter_transaction_proof(proof: &<T::PeerBlockchain as Blockchain>::TransactionInclusionProof) -> bool { pub fn filter_transaction_proof(proof: &<T::PeerBlockchain as PeerBlockchain>::TransactionInclusionProof) -> bool {
if prepare_deposit_details::<T>(proof).is_err() { if prepare_deposit_details::<T, I>(proof).is_err() {
return false; return false;
} }
@@ -155,7 +155,7 @@ impl<T: Trait> Module<T> {
} }
} }
impl<T: Trait> From<ExchangeError> for Error<T> { impl<T: Trait<I>, I: Instance> From<ExchangeError> for Error<T, I> {
fn from(error: ExchangeError) -> Self { fn from(error: ExchangeError) -> Self {
match error { match error {
ExchangeError::InvalidTransaction => Error::InvalidTransaction, ExchangeError::InvalidTransaction => Error::InvalidTransaction,
@@ -174,7 +174,7 @@ impl<AccountId> OnTransactionSubmitted<AccountId> for () {
} }
/// Exchange deposit details. /// Exchange deposit details.
struct DepositDetails<T: Trait> { struct DepositDetails<T: Trait<I>, I: Instance> {
/// Transfer id. /// Transfer id.
pub transfer_id: <T::PeerMaybeLockFundsTransaction as MaybeLockFundsTransaction>::Id, pub transfer_id: <T::PeerMaybeLockFundsTransaction as MaybeLockFundsTransaction>::Id,
/// Transfer recipient. /// Transfer recipient.
@@ -185,21 +185,25 @@ struct DepositDetails<T: Trait> {
/// Verify and parse transaction proof, preparing everything required for importing /// Verify and parse transaction proof, preparing everything required for importing
/// this transaction proof. /// this transaction proof.
fn prepare_deposit_details<T: Trait>( fn prepare_deposit_details<T: Trait<I>, I: Instance>(
proof: &<<T as Trait>::PeerBlockchain as Blockchain>::TransactionInclusionProof, proof: &<<T as Trait<I>>::PeerBlockchain as PeerBlockchain>::TransactionInclusionProof,
) -> Result<DepositDetails<T>, Error<T>> { ) -> Result<DepositDetails<T, I>, Error<T, I>> {
// ensure that transaction is included in finalized block that we know of // ensure that transaction is included in finalized block that we know of
let transaction = <T as Trait>::PeerBlockchain::verify_transaction_inclusion_proof(proof) let transaction = <T as Trait<I>>::PeerBlockchain::verify_transaction_inclusion_proof(proof)
.ok_or_else(|| Error::<T>::UnfinalizedTransaction)?; .ok_or_else(|| Error::<T, I>::UnfinalizedTransaction)?;
// parse transaction // parse transaction
let transaction = <T as Trait>::PeerMaybeLockFundsTransaction::parse(&transaction).map_err(Error::<T>::from)?; let transaction =
<T as Trait<I>>::PeerMaybeLockFundsTransaction::parse(&transaction).map_err(Error::<T, I>::from)?;
let transfer_id = transaction.id; let transfer_id = transaction.id;
ensure!(!Transfers::<T>::contains_key(&transfer_id), Error::<T>::AlreadyClaimed); ensure!(
!Transfers::<T, I>::contains_key(&transfer_id),
Error::<T, I>::AlreadyClaimed
);
// grant recipient // grant recipient
let recipient = T::RecipientsMap::map(transaction.recipient).map_err(Error::<T>::from)?; let recipient = T::RecipientsMap::map(transaction.recipient).map_err(Error::<T, I>::from)?;
let amount = T::CurrencyConverter::convert(transaction.amount).map_err(Error::<T>::from)?; let amount = T::CurrencyConverter::convert(transaction.amount).map_err(Error::<T, I>::from)?;
Ok(DepositDetails { Ok(DepositDetails {
transfer_id, transfer_id,
@@ -235,13 +239,13 @@ mod tests {
impl OnTransactionSubmitted<AccountId> for DummyTransactionSubmissionHandler { impl OnTransactionSubmitted<AccountId> for DummyTransactionSubmissionHandler {
fn on_valid_transaction_submitted(submitter: AccountId) { fn on_valid_transaction_submitted(submitter: AccountId) {
Transfers::<TestRuntime>::insert(submitter, ()); Transfers::<TestRuntime, DefaultInstance>::insert(submitter, ());
} }
} }
pub struct DummyBlockchain; pub struct DummyBlockchain;
impl Blockchain for DummyBlockchain { impl PeerBlockchain for DummyBlockchain {
type Transaction = RawTransaction; type Transaction = RawTransaction;
type TransactionInclusionProof = (bool, RawTransaction); type TransactionInclusionProof = (bool, RawTransaction);
@@ -386,7 +390,7 @@ mod tests {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
assert_noop!( assert_noop!(
Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (false, transaction(0))), Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (false, transaction(0))),
Error::<TestRuntime>::UnfinalizedTransaction, Error::<TestRuntime, DefaultInstance>::UnfinalizedTransaction,
); );
}); });
} }
@@ -399,7 +403,7 @@ mod tests {
Origin::signed(SUBMITTER), Origin::signed(SUBMITTER),
(true, transaction(INVALID_TRANSACTION_ID)), (true, transaction(INVALID_TRANSACTION_ID)),
), ),
Error::<TestRuntime>::InvalidTransaction, Error::<TestRuntime, DefaultInstance>::InvalidTransaction,
); );
}); });
} }
@@ -413,7 +417,7 @@ mod tests {
Origin::signed(SUBMITTER), Origin::signed(SUBMITTER),
(true, transaction(ALREADY_CLAIMED_TRANSACTION_ID)), (true, transaction(ALREADY_CLAIMED_TRANSACTION_ID)),
), ),
Error::<TestRuntime>::AlreadyClaimed, Error::<TestRuntime, DefaultInstance>::AlreadyClaimed,
); );
}); });
} }
@@ -425,7 +429,7 @@ mod tests {
transaction.recipient = UNKNOWN_RECIPIENT_ID; transaction.recipient = UNKNOWN_RECIPIENT_ID;
assert_noop!( assert_noop!(
Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)), Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)),
Error::<TestRuntime>::FailedToMapRecipients, Error::<TestRuntime, DefaultInstance>::FailedToMapRecipients,
); );
}); });
} }
@@ -437,7 +441,7 @@ mod tests {
transaction.amount = INVALID_AMOUNT; transaction.amount = INVALID_AMOUNT;
assert_noop!( assert_noop!(
Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)), Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)),
Error::<TestRuntime>::FailedToConvertCurrency, Error::<TestRuntime, DefaultInstance>::FailedToConvertCurrency,
); );
}); });
} }
@@ -449,7 +453,7 @@ mod tests {
transaction.amount = MAX_DEPOSIT_AMOUNT + 1; transaction.amount = MAX_DEPOSIT_AMOUNT + 1;
assert_noop!( assert_noop!(
Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)), Exchange::import_peer_transaction(Origin::signed(SUBMITTER), (true, transaction)),
Error::<TestRuntime>::DepositFailed, Error::<TestRuntime, DefaultInstance>::DepositFailed,
); );
}); });
} }
+21 -21
View File
@@ -21,11 +21,11 @@ use crate::test_utils::{
HeaderBuilder, HeaderBuilder,
}; };
use frame_benchmarking::benchmarks; use frame_benchmarking::benchmarks_instance;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use primitives::{compute_merkle_root, U256}; use primitives::{compute_merkle_root, U256};
benchmarks! { benchmarks_instance! {
_ { } _ { }
// Benchmark `import_unsigned_header` extrinsic with the best possible conditions: // Benchmark `import_unsigned_header` extrinsic with the best possible conditions:
@@ -37,7 +37,7 @@ benchmarks! {
let n in 1..1000; let n in 1..1000;
let num_validators = 2; let num_validators = 2;
let initial_header = initialize_bench::<T>(num_validators); let initial_header = initialize_bench::<T, I>(num_validators);
// prepare header to be inserted // prepare header to be inserted
let header = build_custom_header( let header = build_custom_header(
@@ -50,7 +50,7 @@ benchmarks! {
); );
}: import_unsigned_header(RawOrigin::None, header, None) }: import_unsigned_header(RawOrigin::None, header, None)
verify { verify {
let storage = BridgeStorage::<T>::new(); let storage = BridgeStorage::<T, I>::new();
assert_eq!(storage.best_block().0.number, 1); assert_eq!(storage.best_block().0.number, 1);
assert_eq!(storage.finalized_block().number, 0); assert_eq!(storage.finalized_block().number, 0);
} }
@@ -67,9 +67,9 @@ benchmarks! {
// finalization. // finalization.
let n in 1..7; let n in 1..7;
let mut storage = BridgeStorage::<T>::new(); let mut storage = BridgeStorage::<T, I>::new();
let num_validators: u32 = 2; let num_validators: u32 = 2;
let initial_header = initialize_bench::<T>(num_validators as usize); let initial_header = initialize_bench::<T, I>(num_validators as usize);
// Since we only have two validators we need to make sure the number of blocks is even to // Since we only have two validators we need to make sure the number of blocks is even to
// make sure the right validator signs the final block // make sure the right validator signs the final block
@@ -95,7 +95,7 @@ benchmarks! {
let header = HeaderBuilder::with_parent(&last_header).sign_by(&last_authority); let header = HeaderBuilder::with_parent(&last_header).sign_by(&last_authority);
}: import_unsigned_header(RawOrigin::None, header, None) }: import_unsigned_header(RawOrigin::None, header, None)
verify { verify {
let storage = BridgeStorage::<T>::new(); let storage = BridgeStorage::<T, I>::new();
assert_eq!(storage.best_block().0.number, (num_blocks + 1) as u64); assert_eq!(storage.best_block().0.number, (num_blocks + 1) as u64);
assert_eq!(storage.finalized_block().number, num_blocks as u64); assert_eq!(storage.finalized_block().number, num_blocks as u64);
} }
@@ -108,9 +108,9 @@ benchmarks! {
// finalization. // finalization.
let n in 7..100; let n in 7..100;
let mut storage = BridgeStorage::<T>::new(); let mut storage = BridgeStorage::<T, I>::new();
let num_validators: u32 = 2; let num_validators: u32 = 2;
let initial_header = initialize_bench::<T>(num_validators as usize); let initial_header = initialize_bench::<T, I>(num_validators as usize);
// Since we only have two validators we need to make sure the number of blocks is even to // Since we only have two validators we need to make sure the number of blocks is even to
// make sure the right validator signs the final block // make sure the right validator signs the final block
@@ -136,7 +136,7 @@ benchmarks! {
let header = HeaderBuilder::with_parent(&last_header).sign_by(&last_authority); let header = HeaderBuilder::with_parent(&last_header).sign_by(&last_authority);
}: import_unsigned_header(RawOrigin::None, header, None) }: import_unsigned_header(RawOrigin::None, header, None)
verify { verify {
let storage = BridgeStorage::<T>::new(); let storage = BridgeStorage::<T, I>::new();
assert_eq!(storage.best_block().0.number, (num_blocks + 1) as u64); assert_eq!(storage.best_block().0.number, (num_blocks + 1) as u64);
assert_eq!(storage.finalized_block().number, num_blocks as u64); assert_eq!(storage.finalized_block().number, num_blocks as u64);
} }
@@ -148,14 +148,14 @@ benchmarks! {
import_unsigned_pruning { import_unsigned_pruning {
let n in 1..MAX_BLOCKS_TO_PRUNE_IN_SINGLE_IMPORT as u32; let n in 1..MAX_BLOCKS_TO_PRUNE_IN_SINGLE_IMPORT as u32;
let mut storage = BridgeStorage::<T>::new(); let mut storage = BridgeStorage::<T, I>::new();
let num_validators = 3; let num_validators = 3;
let initial_header = initialize_bench::<T>(num_validators as usize); let initial_header = initialize_bench::<T, I>(num_validators as usize);
let validators = validators(num_validators); let validators = validators(num_validators);
// Want to prune eligible blocks between [0, n) // Want to prune eligible blocks between [0, n)
BlocksToPrune::put(PruningRange { BlocksToPrune::<I>::put(PruningRange {
oldest_unpruned_block: 0, oldest_unpruned_block: 0,
oldest_block_to_keep: n as u64, oldest_block_to_keep: n as u64,
}); });
@@ -171,11 +171,11 @@ benchmarks! {
let header = HeaderBuilder::with_parent(&parent).sign_by_set(&validators); let header = HeaderBuilder::with_parent(&parent).sign_by_set(&validators);
}: import_unsigned_header(RawOrigin::None, header, None) }: import_unsigned_header(RawOrigin::None, header, None)
verify { verify {
let storage = BridgeStorage::<T>::new(); let storage = BridgeStorage::<T, I>::new();
let max_pruned: u64 = (n - 1) as _; let max_pruned: u64 = (n - 1) as _;
assert_eq!(storage.best_block().0.number, (n + 1) as u64); assert_eq!(storage.best_block().0.number, (n + 1) as u64);
assert!(HeadersByNumber::get(&0).is_none()); assert!(HeadersByNumber::<I>::get(&0).is_none());
assert!(HeadersByNumber::get(&max_pruned).is_none()); assert!(HeadersByNumber::<I>::get(&max_pruned).is_none());
} }
// The goal of this bench is to import a block which contains a transaction receipt. The receipt // The goal of this bench is to import a block which contains a transaction receipt. The receipt
@@ -184,10 +184,10 @@ benchmarks! {
import_unsigned_with_receipts { import_unsigned_with_receipts {
let n in 1..100; let n in 1..100;
let mut storage = BridgeStorage::<T>::new(); let mut storage = BridgeStorage::<T, I>::new();
let num_validators = 1; let num_validators = 1;
let initial_header = initialize_bench::<T>(num_validators as usize); let initial_header = initialize_bench::<T, I>(num_validators as usize);
let mut receipts = vec![]; let mut receipts = vec![];
for i in 1..=n { for i in 1..=n {
@@ -213,18 +213,18 @@ benchmarks! {
); );
}: import_unsigned_header(RawOrigin::None, header, Some(receipts)) }: import_unsigned_header(RawOrigin::None, header, Some(receipts))
verify { verify {
let storage = BridgeStorage::<T>::new(); let storage = BridgeStorage::<T, I>::new();
assert_eq!(storage.best_block().0.number, 2); assert_eq!(storage.best_block().0.number, 2);
} }
} }
fn initialize_bench<T: Trait>(num_validators: usize) -> Header { fn initialize_bench<T: Trait<I>, I: Instance>(num_validators: usize) -> Header {
// Initialize storage with some initial header // Initialize storage with some initial header
let initial_header = build_genesis_header(&validator(0)); let initial_header = build_genesis_header(&validator(0));
let initial_difficulty = initial_header.difficulty; let initial_difficulty = initial_header.difficulty;
let initial_validators = validators_addresses(num_validators as usize); let initial_validators = validators_addresses(num_validators as usize);
initialize_storage::<T>(&initial_header, initial_difficulty, &initial_validators); initialize_storage::<T, I>(&initial_header, initial_difficulty, &initial_validators);
initial_header initial_header
} }
+3 -2
View File
@@ -169,6 +169,7 @@ mod tests {
validators_change_receipt, HeaderBuilder, KeepSomeHeadersBehindBest, TestRuntime, GAS_LIMIT, validators_change_receipt, HeaderBuilder, KeepSomeHeadersBehindBest, TestRuntime, GAS_LIMIT,
}; };
use crate::validators::ValidatorsSource; use crate::validators::ValidatorsSource;
use crate::DefaultInstance;
use crate::{BlocksToPrune, BridgeStorage, Headers, PruningRange}; use crate::{BlocksToPrune, BridgeStorage, Headers, PruningRange};
use frame_support::{StorageMap, StorageValue}; use frame_support::{StorageMap, StorageValue};
use secp256k1::SecretKey; use secp256k1::SecretKey;
@@ -352,7 +353,7 @@ mod tests {
step += 3; step += 3;
} }
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 11, oldest_unpruned_block: 11,
oldest_block_to_keep: 14, oldest_block_to_keep: 14,
@@ -378,7 +379,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(finalized_blocks, expected_blocks); assert_eq!(finalized_blocks, expected_blocks);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 15, oldest_unpruned_block: 15,
oldest_block_to_keep: 15, oldest_block_to_keep: 15,
+93 -89
View File
@@ -351,7 +351,7 @@ impl<AccountId> OnHeadersSubmitted<AccountId> for () {
} }
/// The module configuration trait. /// The module configuration trait.
pub trait Trait: frame_system::Trait { pub trait Trait<I = DefaultInstance>: frame_system::Trait {
/// Aura configuration. /// Aura configuration.
type AuraConfiguration: Get<AuraConfiguration>; type AuraConfiguration: Get<AuraConfiguration>;
/// Validators configuration. /// Validators configuration.
@@ -372,14 +372,14 @@ pub trait Trait: frame_system::Trait {
} }
decl_module! { decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {
/// Import single Aura header. Requires transaction to be **UNSIGNED**. /// Import single Aura header. Requires transaction to be **UNSIGNED**.
#[weight = 0] // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) #[weight = 0] // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78)
pub fn import_unsigned_header(origin, header: Header, receipts: Option<Vec<Receipt>>) { pub fn import_unsigned_header(origin, header: Header, receipts: Option<Vec<Receipt>>) {
frame_system::ensure_none(origin)?; frame_system::ensure_none(origin)?;
import::import_header( import::import_header(
&mut BridgeStorage::<T>::new(), &mut BridgeStorage::<T, I>::new(),
&mut T::PruningStrategy::default(), &mut T::PruningStrategy::default(),
&T::AuraConfiguration::get(), &T::AuraConfiguration::get(),
&T::ValidatorsConfiguration::get(), &T::ValidatorsConfiguration::get(),
@@ -400,7 +400,7 @@ decl_module! {
let submitter = frame_system::ensure_signed(origin)?; let submitter = frame_system::ensure_signed(origin)?;
let mut finalized_headers = BTreeMap::new(); let mut finalized_headers = BTreeMap::new();
let import_result = import::import_headers( let import_result = import::import_headers(
&mut BridgeStorage::<T>::new(), &mut BridgeStorage::<T, I>::new(),
&mut T::PruningStrategy::default(), &mut T::PruningStrategy::default(),
&T::AuraConfiguration::get(), &T::AuraConfiguration::get(),
&T::ValidatorsConfiguration::get(), &T::ValidatorsConfiguration::get(),
@@ -434,7 +434,7 @@ decl_module! {
} }
decl_storage! { decl_storage! {
trait Store for Module<T: Trait> as Bridge { trait Store for Module<T: Trait<I>, I: Instance = DefaultInstance> as Bridge {
/// Best known block. /// Best known block.
BestBlock: (HeaderId, U256); BestBlock: (HeaderId, U256);
/// Best finalized block. /// Best finalized block.
@@ -473,7 +473,7 @@ decl_storage! {
"Initial validators set can't be empty", "Initial validators set can't be empty",
); );
initialize_storage::<T>( initialize_storage::<T, I>(
&config.initial_header, &config.initial_header,
config.initial_difficulty, config.initial_difficulty,
&config.initial_validators, &config.initial_validators,
@@ -482,43 +482,47 @@ decl_storage! {
} }
} }
impl<T: Trait> Module<T> { impl<T: Trait<I>, I: Instance> Module<T, I> {
/// Returns number and hash of the best block known to the bridge module. /// Returns number and hash of the best block known to the bridge module.
/// The caller should only submit `import_header` transaction that makes /// The caller should only submit `import_header` transaction that makes
/// (or leads to making) other header the best one. /// (or leads to making) other header the best one.
pub fn best_block() -> HeaderId { pub fn best_block() -> HeaderId {
BridgeStorage::<T>::new().best_block().0 BridgeStorage::<T, I>::new().best_block().0
} }
/// Returns number and hash of the best finalized block known to the bridge module. /// Returns number and hash of the best finalized block known to the bridge module.
pub fn finalized_block() -> HeaderId { pub fn finalized_block() -> HeaderId {
BridgeStorage::<T>::new().finalized_block() BridgeStorage::<T, I>::new().finalized_block()
} }
/// Returns true if the import of given block requires transactions receipts. /// Returns true if the import of given block requires transactions receipts.
pub fn is_import_requires_receipts(header: Header) -> bool { pub fn is_import_requires_receipts(header: Header) -> bool {
import::header_import_requires_receipts(&BridgeStorage::<T>::new(), &T::ValidatorsConfiguration::get(), &header) import::header_import_requires_receipts(
&BridgeStorage::<T, I>::new(),
&T::ValidatorsConfiguration::get(),
&header,
)
} }
/// Returns true if header is known to the runtime. /// Returns true if header is known to the runtime.
pub fn is_known_block(hash: H256) -> bool { pub fn is_known_block(hash: H256) -> bool {
BridgeStorage::<T>::new().header(&hash).is_some() BridgeStorage::<T, I>::new().header(&hash).is_some()
} }
/// Verify that transaction is included into given finalized block. /// Verify that transaction is included into given finalized block.
pub fn verify_transaction_finalized(block: H256, tx_index: u64, proof: &[RawTransaction]) -> bool { pub fn verify_transaction_finalized(block: H256, tx_index: u64, proof: &[RawTransaction]) -> bool {
crate::verify_transaction_finalized(&BridgeStorage::<T>::new(), block, tx_index, proof) crate::verify_transaction_finalized(&BridgeStorage::<T, I>::new(), block, tx_index, proof)
} }
} }
impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> { impl<T: Trait<I>, I: Instance> frame_support::unsigned::ValidateUnsigned for Module<T, I> {
type Call = Call<T>; type Call = Call<T, I>;
fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
match *call { match *call {
Self::Call::import_unsigned_header(ref header, ref receipts) => { Self::Call::import_unsigned_header(ref header, ref receipts) => {
let accept_result = verification::accept_aura_header_into_pool( let accept_result = verification::accept_aura_header_into_pool(
&BridgeStorage::<T>::new(), &BridgeStorage::<T, I>::new(),
&T::AuraConfiguration::get(), &T::AuraConfiguration::get(),
&T::ValidatorsConfiguration::get(), &T::ValidatorsConfiguration::get(),
&pool_configuration(), &pool_configuration(),
@@ -550,17 +554,17 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
/// Runtime bridge storage. /// Runtime bridge storage.
#[derive(Default)] #[derive(Default)]
pub struct BridgeStorage<T>(sp_std::marker::PhantomData<T>); pub struct BridgeStorage<T, I = DefaultInstance>(sp_std::marker::PhantomData<(T, I)>);
impl<T: Trait> BridgeStorage<T> { impl<T: Trait<I>, I: Instance> BridgeStorage<T, I> {
/// Create new BridgeStorage. /// Create new BridgeStorage.
pub fn new() -> Self { pub fn new() -> Self {
BridgeStorage(sp_std::marker::PhantomData::<T>::default()) BridgeStorage(sp_std::marker::PhantomData::<(T, I)>::default())
} }
/// Prune old blocks. /// Prune old blocks.
fn prune_blocks(&self, mut max_blocks_to_prune: u64, finalized_number: u64, prune_end: u64) { fn prune_blocks(&self, mut max_blocks_to_prune: u64, finalized_number: u64, prune_end: u64) {
let pruning_range = BlocksToPrune::get(); let pruning_range = BlocksToPrune::<I>::get();
let mut new_pruning_range = pruning_range.clone(); let mut new_pruning_range = pruning_range.clone();
// update oldest block we want to keep // update oldest block we want to keep
@@ -579,7 +583,7 @@ impl<T: Trait> BridgeStorage<T> {
} }
// read hashes of blocks with given number and try to prune these blocks // read hashes of blocks with given number and try to prune these blocks
let blocks_at_number = HeadersByNumber::take(number); let blocks_at_number = HeadersByNumber::<I>::take(number);
if let Some(mut blocks_at_number) = blocks_at_number { if let Some(mut blocks_at_number) = blocks_at_number {
self.prune_blocks_by_hashes( self.prune_blocks_by_hashes(
&mut max_blocks_to_prune, &mut max_blocks_to_prune,
@@ -590,7 +594,7 @@ impl<T: Trait> BridgeStorage<T> {
// if we haven't pruned all blocks, remember unpruned // if we haven't pruned all blocks, remember unpruned
if !blocks_at_number.is_empty() { if !blocks_at_number.is_empty() {
HeadersByNumber::insert(number, blocks_at_number); HeadersByNumber::<I>::insert(number, blocks_at_number);
break; break;
} }
} }
@@ -606,7 +610,7 @@ impl<T: Trait> BridgeStorage<T> {
// update pruning range in storage // update pruning range in storage
if pruning_range != new_pruning_range { if pruning_range != new_pruning_range {
BlocksToPrune::put(new_pruning_range); BlocksToPrune::<I>::put(new_pruning_range);
} }
} }
@@ -619,13 +623,13 @@ impl<T: Trait> BridgeStorage<T> {
blocks_at_number: &mut Vec<H256>, blocks_at_number: &mut Vec<H256>,
) { ) {
// ensure that unfinalized headers we want to prune do not have scheduled changes // ensure that unfinalized headers we want to prune do not have scheduled changes
if number > finalized_number && blocks_at_number.iter().any(ScheduledChanges::contains_key) { if number > finalized_number && blocks_at_number.iter().any(ScheduledChanges::<I>::contains_key) {
return; return;
} }
// physically remove headers and (probably) obsolete validators sets // physically remove headers and (probably) obsolete validators sets
while let Some(hash) = blocks_at_number.pop() { while let Some(hash) = blocks_at_number.pop() {
let header = Headers::<T>::take(&hash); let header = Headers::<T, I>::take(&hash);
frame_support::debug::trace!( frame_support::debug::trace!(
target: "runtime", target: "runtime",
"Pruning PoA header: ({}, {})", "Pruning PoA header: ({}, {})",
@@ -633,10 +637,10 @@ impl<T: Trait> BridgeStorage<T> {
hash, hash,
); );
ScheduledChanges::remove(hash); ScheduledChanges::<I>::remove(hash);
FinalityCache::<T>::remove(hash); FinalityCache::<T, I>::remove(hash);
if let Some(header) = header { if let Some(header) = header {
ValidatorsSetsRc::mutate(header.next_validators_set_id, |rc| match *rc { ValidatorsSetsRc::<I>::mutate(header.next_validators_set_id, |rc| match *rc {
Some(rc) if rc > 1 => Some(rc - 1), Some(rc) if rc > 1 => Some(rc - 1),
_ => None, _ => None,
}); });
@@ -651,19 +655,19 @@ impl<T: Trait> BridgeStorage<T> {
} }
} }
impl<T: Trait> Storage for BridgeStorage<T> { impl<T: Trait<I>, I: Instance> Storage for BridgeStorage<T, I> {
type Submitter = T::AccountId; type Submitter = T::AccountId;
fn best_block(&self) -> (HeaderId, U256) { fn best_block(&self) -> (HeaderId, U256) {
BestBlock::get() BestBlock::<I>::get()
} }
fn finalized_block(&self) -> HeaderId { fn finalized_block(&self) -> HeaderId {
FinalizedBlock::get() FinalizedBlock::<I>::get()
} }
fn header(&self, hash: &H256) -> Option<(Header, Option<Self::Submitter>)> { fn header(&self, hash: &H256) -> Option<(Header, Option<Self::Submitter>)> {
Headers::<T>::get(hash).map(|header| (header.header, header.submitter)) Headers::<T, I>::get(hash).map(|header| (header.header, header.submitter))
} }
fn cached_finality_votes( fn cached_finality_votes(
@@ -675,7 +679,7 @@ impl<T: Trait> Storage for BridgeStorage<T> {
let mut votes = CachedFinalityVotes::default(); let mut votes = CachedFinalityVotes::default();
let mut current_id = *parent; let mut current_id = *parent;
loop { loop {
// if we have reached finalized block' sibling => stop with special signal // if we have reached finalized block's sibling => stop with special signal
if current_id.number == best_finalized.number && current_id.hash != best_finalized.hash { if current_id.number == best_finalized.number && current_id.hash != best_finalized.hash {
votes.stopped_at_finalized_sibling = true; votes.stopped_at_finalized_sibling = true;
return votes; return votes;
@@ -687,14 +691,14 @@ impl<T: Trait> Storage for BridgeStorage<T> {
} }
// if we have found cached votes => stop // if we have found cached votes => stop
let cached_votes = FinalityCache::<T>::get(&current_id.hash); let cached_votes = FinalityCache::<T, I>::get(&current_id.hash);
if let Some(cached_votes) = cached_votes { if let Some(cached_votes) = cached_votes {
votes.votes = Some(cached_votes); votes.votes = Some(cached_votes);
return votes; return votes;
} }
// read next parent header id // read next parent header id
let header = match Headers::<T>::get(&current_id.hash) { let header = match Headers::<T, I>::get(&current_id.hash) {
Some(header) if header.header.number != 0 => header, Some(header) if header.header.number != 0 => header,
_ => return votes, _ => return votes,
}; };
@@ -717,10 +721,10 @@ impl<T: Trait> Storage for BridgeStorage<T> {
submitter: Option<Self::Submitter>, submitter: Option<Self::Submitter>,
parent_hash: &H256, parent_hash: &H256,
) -> Option<ImportContext<Self::Submitter>> { ) -> Option<ImportContext<Self::Submitter>> {
Headers::<T>::get(parent_hash).map(|parent_header| { Headers::<T, I>::get(parent_hash).map(|parent_header| {
let validators_set = ValidatorsSets::get(parent_header.next_validators_set_id) let validators_set = ValidatorsSets::<I>::get(parent_header.next_validators_set_id)
.expect("validators set is only pruned when last ref is pruned; there is a ref; qed"); .expect("validators set is only pruned when last ref is pruned; there is a ref; qed");
let parent_scheduled_change = ScheduledChanges::get(parent_hash); let parent_scheduled_change = ScheduledChanges::<I>::get(parent_hash);
ImportContext { ImportContext {
submitter, submitter,
parent_hash: *parent_hash, parent_hash: *parent_hash,
@@ -735,15 +739,15 @@ impl<T: Trait> Storage for BridgeStorage<T> {
} }
fn scheduled_change(&self, hash: &H256) -> Option<ScheduledChange> { fn scheduled_change(&self, hash: &H256) -> Option<ScheduledChange> {
ScheduledChanges::get(hash) ScheduledChanges::<I>::get(hash)
} }
fn insert_header(&mut self, header: HeaderToImport<Self::Submitter>) { fn insert_header(&mut self, header: HeaderToImport<Self::Submitter>) {
if header.is_best { if header.is_best {
BestBlock::put((header.id, header.total_difficulty)); BestBlock::<I>::put((header.id, header.total_difficulty));
} }
if let Some(scheduled_change) = header.scheduled_change { if let Some(scheduled_change) = header.scheduled_change {
ScheduledChanges::insert( ScheduledChanges::<I>::insert(
&header.id.hash, &header.id.hash,
ScheduledChange { ScheduledChange {
validators: scheduled_change, validators: scheduled_change,
@@ -753,12 +757,12 @@ impl<T: Trait> Storage for BridgeStorage<T> {
} }
let next_validators_set_id = match header.enacted_change { let next_validators_set_id = match header.enacted_change {
Some(enacted_change) => { Some(enacted_change) => {
let next_validators_set_id = NextValidatorsSetId::mutate(|set_id| { let next_validators_set_id = NextValidatorsSetId::<I>::mutate(|set_id| {
let next_set_id = *set_id; let next_set_id = *set_id;
*set_id += 1; *set_id += 1;
next_set_id next_set_id
}); });
ValidatorsSets::insert( ValidatorsSets::<I>::insert(
next_validators_set_id, next_validators_set_id,
ValidatorsSet { ValidatorsSet {
validators: enacted_change.validators, validators: enacted_change.validators,
@@ -766,11 +770,11 @@ impl<T: Trait> Storage for BridgeStorage<T> {
signal_block: enacted_change.signal_block, signal_block: enacted_change.signal_block,
}, },
); );
ValidatorsSetsRc::insert(next_validators_set_id, 1); ValidatorsSetsRc::<I>::insert(next_validators_set_id, 1);
next_validators_set_id next_validators_set_id
} }
None => { None => {
ValidatorsSetsRc::mutate(header.context.validators_set_id, |rc| { ValidatorsSetsRc::<I>::mutate(header.context.validators_set_id, |rc| {
*rc = Some(rc.map(|rc| rc + 1).unwrap_or(1)); *rc = Some(rc.map(|rc| rc + 1).unwrap_or(1));
*rc *rc
}); });
@@ -782,7 +786,7 @@ impl<T: Trait> Storage for BridgeStorage<T> {
if let Some(finality_votes_caching_interval) = finality_votes_caching_interval { if let Some(finality_votes_caching_interval) = finality_votes_caching_interval {
let cache_entry_required = header.id.number != 0 && header.id.number % finality_votes_caching_interval == 0; let cache_entry_required = header.id.number != 0 && header.id.number % finality_votes_caching_interval == 0;
if cache_entry_required { if cache_entry_required {
FinalityCache::<T>::insert(header.id.hash, header.finality_votes); FinalityCache::<T, I>::insert(header.id.hash, header.finality_votes);
} }
} }
@@ -794,8 +798,8 @@ impl<T: Trait> Storage for BridgeStorage<T> {
); );
let last_signal_block = header.context.last_signal_block(); let last_signal_block = header.context.last_signal_block();
HeadersByNumber::append(header.id.number, header.id.hash); HeadersByNumber::<I>::append(header.id.number, header.id.hash);
Headers::<T>::insert( Headers::<T, I>::insert(
&header.id.hash, &header.id.hash,
StoredHeader { StoredHeader {
submitter: header.context.submitter, submitter: header.context.submitter,
@@ -812,7 +816,7 @@ impl<T: Trait> Storage for BridgeStorage<T> {
let finalized_number = finalized let finalized_number = finalized
.as_ref() .as_ref()
.map(|f| f.number) .map(|f| f.number)
.unwrap_or_else(|| FinalizedBlock::get().number); .unwrap_or_else(|| FinalizedBlock::<I>::get().number);
if let Some(finalized) = finalized { if let Some(finalized) = finalized {
frame_support::debug::trace!( frame_support::debug::trace!(
target: "runtime", target: "runtime",
@@ -821,7 +825,7 @@ impl<T: Trait> Storage for BridgeStorage<T> {
finalized.hash, finalized.hash,
); );
FinalizedBlock::put(finalized); FinalizedBlock::<I>::put(finalized);
} }
// and now prune headers if we need to // and now prune headers if we need to
@@ -831,7 +835,7 @@ impl<T: Trait> Storage for BridgeStorage<T> {
/// Initialize storage. /// Initialize storage.
#[cfg(any(feature = "std", feature = "runtime-benchmarks"))] #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
pub(crate) fn initialize_storage<T: Trait>( pub(crate) fn initialize_storage<T: Trait<I>, I: Instance>(
initial_header: &Header, initial_header: &Header,
initial_difficulty: U256, initial_difficulty: U256,
initial_validators: &[Address], initial_validators: &[Address],
@@ -848,14 +852,14 @@ pub(crate) fn initialize_storage<T: Trait>(
number: initial_header.number, number: initial_header.number,
hash: initial_hash, hash: initial_hash,
}; };
BestBlock::put((initial_id, initial_difficulty)); BestBlock::<I>::put((initial_id, initial_difficulty));
FinalizedBlock::put(initial_id); FinalizedBlock::<I>::put(initial_id);
BlocksToPrune::put(PruningRange { BlocksToPrune::<I>::put(PruningRange {
oldest_unpruned_block: initial_header.number, oldest_unpruned_block: initial_header.number,
oldest_block_to_keep: initial_header.number, oldest_block_to_keep: initial_header.number,
}); });
HeadersByNumber::insert(initial_header.number, vec![initial_hash]); HeadersByNumber::<I>::insert(initial_header.number, vec![initial_hash]);
Headers::<T>::insert( Headers::<T, I>::insert(
initial_hash, initial_hash,
StoredHeader { StoredHeader {
submitter: None, submitter: None,
@@ -865,8 +869,8 @@ pub(crate) fn initialize_storage<T: Trait>(
last_signal_block: None, last_signal_block: None,
}, },
); );
NextValidatorsSetId::put(1); NextValidatorsSetId::<I>::put(1);
ValidatorsSets::insert( ValidatorsSets::<I>::insert(
0, 0,
ValidatorsSet { ValidatorsSet {
validators: initial_validators.to_vec(), validators: initial_validators.to_vec(),
@@ -874,7 +878,7 @@ pub(crate) fn initialize_storage<T: Trait>(
enact_block: initial_id, enact_block: initial_id,
}, },
); );
ValidatorsSetsRc::insert(0, 1); ValidatorsSetsRc::<I>::insert(0, 1);
} }
/// Verify that transaction is included into given finalized block. /// Verify that transaction is included into given finalized block.
@@ -988,7 +992,7 @@ pub(crate) mod tests {
); );
if i == 7 && j == 1 { if i == 7 && j == 1 {
ScheduledChanges::insert( ScheduledChanges::<DefaultInstance>::insert(
hash, hash,
ScheduledChange { ScheduledChange {
validators: validators_addresses(5), validators: validators_addresses(5),
@@ -997,7 +1001,7 @@ pub(crate) mod tests {
); );
} }
} }
HeadersByNumber::insert(i, headers_by_number); HeadersByNumber::<DefaultInstance>::insert(i, headers_by_number);
} }
f(BridgeStorage::new()) f(BridgeStorage::new())
@@ -1007,16 +1011,16 @@ pub(crate) mod tests {
#[test] #[test]
fn blocks_are_not_pruned_if_range_is_empty() { fn blocks_are_not_pruned_if_range_is_empty() {
with_headers_to_prune(|storage| { with_headers_to_prune(|storage| {
BlocksToPrune::put(PruningRange { BlocksToPrune::<DefaultInstance>::put(PruningRange {
oldest_unpruned_block: 5, oldest_unpruned_block: 5,
oldest_block_to_keep: 5, oldest_block_to_keep: 5,
}); });
// try to prune blocks [5; 10) // try to prune blocks [5; 10)
storage.prune_blocks(0xFFFF, 10, 5); storage.prune_blocks(0xFFFF, 10, 5);
assert_eq!(HeadersByNumber::get(&5).unwrap().len(), 5); assert_eq!(HeadersByNumber::<DefaultInstance>::get(&5).unwrap().len(), 5);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 5, oldest_unpruned_block: 5,
oldest_block_to_keep: 5, oldest_block_to_keep: 5,
@@ -1028,7 +1032,7 @@ pub(crate) mod tests {
#[test] #[test]
fn blocks_to_prune_never_shrinks_from_the_end() { fn blocks_to_prune_never_shrinks_from_the_end() {
with_headers_to_prune(|storage| { with_headers_to_prune(|storage| {
BlocksToPrune::put(PruningRange { BlocksToPrune::<DefaultInstance>::put(PruningRange {
oldest_unpruned_block: 0, oldest_unpruned_block: 0,
oldest_block_to_keep: 5, oldest_block_to_keep: 5,
}); });
@@ -1036,7 +1040,7 @@ pub(crate) mod tests {
// try to prune blocks [5; 10) // try to prune blocks [5; 10)
storage.prune_blocks(0xFFFF, 10, 3); storage.prune_blocks(0xFFFF, 10, 3);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 5, oldest_unpruned_block: 5,
oldest_block_to_keep: 5, oldest_block_to_keep: 5,
@@ -1050,12 +1054,12 @@ pub(crate) mod tests {
with_headers_to_prune(|storage| { with_headers_to_prune(|storage| {
// try to prune blocks [0; 10) // try to prune blocks [0; 10)
storage.prune_blocks(0, 10, 10); storage.prune_blocks(0, 10, 10);
assert!(HeadersByNumber::get(&0).is_some()); assert!(HeadersByNumber::<DefaultInstance>::get(&0).is_some());
assert!(HeadersByNumber::get(&1).is_some()); assert!(HeadersByNumber::<DefaultInstance>::get(&1).is_some());
assert!(HeadersByNumber::get(&2).is_some()); assert!(HeadersByNumber::<DefaultInstance>::get(&2).is_some());
assert!(HeadersByNumber::get(&3).is_some()); assert!(HeadersByNumber::<DefaultInstance>::get(&3).is_some());
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 0, oldest_unpruned_block: 0,
oldest_block_to_keep: 10, oldest_block_to_keep: 10,
@@ -1070,13 +1074,13 @@ pub(crate) mod tests {
// try to prune blocks [0; 10) // try to prune blocks [0; 10)
storage.prune_blocks(7, 10, 10); storage.prune_blocks(7, 10, 10);
// 1 headers with number = 0 is pruned (1 total) // 1 headers with number = 0 is pruned (1 total)
assert!(HeadersByNumber::get(&0).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&0).is_none());
// 5 headers with number = 1 are pruned (6 total) // 5 headers with number = 1 are pruned (6 total)
assert!(HeadersByNumber::get(&1).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&1).is_none());
// 1 header with number = 2 are pruned (7 total) // 1 header with number = 2 are pruned (7 total)
assert_eq!(HeadersByNumber::get(&2).unwrap().len(), 4); assert_eq!(HeadersByNumber::<DefaultInstance>::get(&2).unwrap().len(), 4);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 2, oldest_unpruned_block: 2,
oldest_block_to_keep: 10, oldest_block_to_keep: 10,
@@ -1086,13 +1090,13 @@ pub(crate) mod tests {
// try to prune blocks [2; 10) // try to prune blocks [2; 10)
storage.prune_blocks(11, 10, 10); storage.prune_blocks(11, 10, 10);
// 4 headers with number = 2 are pruned (4 total) // 4 headers with number = 2 are pruned (4 total)
assert!(HeadersByNumber::get(&2).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&2).is_none());
// 5 headers with number = 3 are pruned (9 total) // 5 headers with number = 3 are pruned (9 total)
assert!(HeadersByNumber::get(&3).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&3).is_none());
// 2 headers with number = 4 are pruned (11 total) // 2 headers with number = 4 are pruned (11 total)
assert_eq!(HeadersByNumber::get(&4).unwrap().len(), 3); assert_eq!(HeadersByNumber::<DefaultInstance>::get(&4).unwrap().len(), 3);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 4, oldest_unpruned_block: 4,
oldest_block_to_keep: 10, oldest_block_to_keep: 10,
@@ -1109,16 +1113,16 @@ pub(crate) mod tests {
// and one of blocks#7 has scheduled change // and one of blocks#7 has scheduled change
// => we won't prune any block#7 at all // => we won't prune any block#7 at all
storage.prune_blocks(0xFFFF, 5, 10); storage.prune_blocks(0xFFFF, 5, 10);
assert!(HeadersByNumber::get(&0).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&0).is_none());
assert!(HeadersByNumber::get(&1).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&1).is_none());
assert!(HeadersByNumber::get(&2).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&2).is_none());
assert!(HeadersByNumber::get(&3).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&3).is_none());
assert!(HeadersByNumber::get(&4).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&4).is_none());
assert!(HeadersByNumber::get(&5).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&5).is_none());
assert!(HeadersByNumber::get(&6).is_none()); assert!(HeadersByNumber::<DefaultInstance>::get(&6).is_none());
assert_eq!(HeadersByNumber::get(&7).unwrap().len(), 5); assert_eq!(HeadersByNumber::<DefaultInstance>::get(&7).unwrap().len(), 5);
assert_eq!( assert_eq!(
BlocksToPrune::get(), BlocksToPrune::<DefaultInstance>::get(),
PruningRange { PruningRange {
oldest_unpruned_block: 7, oldest_unpruned_block: 7,
oldest_block_to_keep: 10, oldest_block_to_keep: 10,
@@ -1151,7 +1155,7 @@ pub(crate) mod tests {
); );
// when we later prune this header, cache entry is removed // when we later prune this header, cache entry is removed
BlocksToPrune::put(PruningRange { BlocksToPrune::<DefaultInstance>::put(PruningRange {
oldest_unpruned_block: interval - 1, oldest_unpruned_block: interval - 1,
oldest_block_to_keep: interval - 1, oldest_block_to_keep: interval - 1,
}); });
@@ -1238,7 +1242,7 @@ pub(crate) mod tests {
insert_header(&mut storage, header1s); insert_header(&mut storage, header1s);
// header1 is finalized // header1 is finalized
FinalizedBlock::put(header1_id); FinalizedBlock::<DefaultInstance>::put(header1_id);
// trying to get finality votes when importing header2 -> header1 succeeds // trying to get finality votes when importing header2 -> header1 succeeds
assert!( assert!(
+1 -1
View File
@@ -136,7 +136,7 @@ pub fn run_test_with_genesis<T>(genesis: Header, total_validators: usize, test:
initial_difficulty: 0.into(), initial_difficulty: 0.into(),
initial_validators: addresses.clone(), initial_validators: addresses.clone(),
} }
.build_storage::<TestRuntime>() .build_storage::<TestRuntime, crate::DefaultInstance>()
.unwrap(), .unwrap(),
) )
.execute_with(|| { .execute_with(|| {
+7 -7
View File
@@ -63,31 +63,31 @@ impl HeaderBuilder {
/// Creates default header on top of test parent with given hash. /// Creates default header on top of test parent with given hash.
#[cfg(test)] #[cfg(test)]
pub fn with_parent_hash(parent_hash: H256) -> Self { pub fn with_parent_hash(parent_hash: H256) -> Self {
Self::with_parent_hash_on_runtime::<crate::mock::TestRuntime>(parent_hash) Self::with_parent_hash_on_runtime::<crate::mock::TestRuntime, crate::DefaultInstance>(parent_hash)
} }
/// Creates default header on top of test parent with given number. First parent is selected. /// Creates default header on top of test parent with given number. First parent is selected.
#[cfg(test)] #[cfg(test)]
pub fn with_parent_number(parent_number: u64) -> Self { pub fn with_parent_number(parent_number: u64) -> Self {
Self::with_parent_number_on_runtime::<crate::mock::TestRuntime>(parent_number) Self::with_parent_number_on_runtime::<crate::mock::TestRuntime, crate::DefaultInstance>(parent_number)
} }
/// Creates default header on top of parent with given hash. /// Creates default header on top of parent with given hash.
pub fn with_parent_hash_on_runtime<T: Trait>(parent_hash: H256) -> Self { pub fn with_parent_hash_on_runtime<T: Trait<I>, I: crate::Instance>(parent_hash: H256) -> Self {
use crate::Headers; use crate::Headers;
use frame_support::StorageMap; use frame_support::StorageMap;
let parent_header = Headers::<T>::get(&parent_hash).unwrap().header; let parent_header = Headers::<T, I>::get(&parent_hash).unwrap().header;
Self::with_parent(&parent_header) Self::with_parent(&parent_header)
} }
/// Creates default header on top of parent with given number. First parent is selected. /// Creates default header on top of parent with given number. First parent is selected.
pub fn with_parent_number_on_runtime<T: Trait>(parent_number: u64) -> Self { pub fn with_parent_number_on_runtime<T: Trait<I>, I: crate::Instance>(parent_number: u64) -> Self {
use crate::HeadersByNumber; use crate::HeadersByNumber;
use frame_support::StorageMap; use frame_support::StorageMap;
let parent_hash = HeadersByNumber::get(parent_number).unwrap()[0]; let parent_hash = HeadersByNumber::<I>::get(parent_number).unwrap()[0];
Self::with_parent_hash_on_runtime::<T>(parent_hash) Self::with_parent_hash_on_runtime::<T, I>(parent_hash)
} }
/// Creates default header on top of non-existent parent. /// Creates default header on top of non-existent parent.
+2 -1
View File
@@ -276,6 +276,7 @@ impl ValidatorsSource {
pub(crate) mod tests { pub(crate) mod tests {
use super::*; use super::*;
use crate::mock::{run_test, validators_addresses, validators_change_receipt, TestRuntime}; use crate::mock::{run_test, validators_addresses, validators_change_receipt, TestRuntime};
use crate::DefaultInstance;
use crate::{BridgeStorage, Headers, ScheduledChange, ScheduledChanges, StoredHeader}; use crate::{BridgeStorage, Headers, ScheduledChange, ScheduledChanges, StoredHeader};
use frame_support::StorageMap; use frame_support::StorageMap;
use primitives::compute_merkle_root; use primitives::compute_merkle_root;
@@ -433,7 +434,7 @@ pub(crate) mod tests {
}; };
Headers::<TestRuntime>::insert(id100.hash, header100); Headers::<TestRuntime>::insert(id100.hash, header100);
if let Some(scheduled_at) = scheduled_at { if let Some(scheduled_at) = scheduled_at {
ScheduledChanges::insert(scheduled_at.hash, scheduled_change); ScheduledChanges::<DefaultInstance>::insert(scheduled_at.hash, scheduled_change);
} }
validators.finalize_validators_change(&storage, &finalized_blocks) validators.finalize_validators_change(&storage, &finalized_blocks)
+8 -7
View File
@@ -361,6 +361,7 @@ mod tests {
validators_change_receipt, AccountId, HeaderBuilder, TestRuntime, GAS_LIMIT, validators_change_receipt, AccountId, HeaderBuilder, TestRuntime, GAS_LIMIT,
}; };
use crate::validators::ValidatorsSource; use crate::validators::ValidatorsSource;
use crate::DefaultInstance;
use crate::{ use crate::{
pool_configuration, BridgeStorage, FinalizedBlock, Headers, HeadersByNumber, NextValidatorsSetId, pool_configuration, BridgeStorage, FinalizedBlock, Headers, HeadersByNumber, NextValidatorsSetId,
ScheduledChanges, ValidatorsSet, ValidatorsSets, ScheduledChanges, ValidatorsSet, ValidatorsSets,
@@ -402,7 +403,7 @@ mod tests {
let block3 = HeaderBuilder::with_parent_number(2).sign_by_set(&validators); let block3 = HeaderBuilder::with_parent_number(2).sign_by_set(&validators);
insert_header(&mut storage, block3); insert_header(&mut storage, block3);
FinalizedBlock::put(block2_id); FinalizedBlock::<DefaultInstance>::put(block2_id);
let validators_config = let validators_config =
ValidatorsConfiguration::Single(ValidatorsSource::Contract(Default::default(), Vec::new())); ValidatorsConfiguration::Single(ValidatorsSource::Contract(Default::default(), Vec::new()));
@@ -419,21 +420,21 @@ mod tests {
} }
fn change_validators_set_at(number: u64, finalized_set: Vec<Address>, signalled_set: Option<Vec<Address>>) { fn change_validators_set_at(number: u64, finalized_set: Vec<Address>, signalled_set: Option<Vec<Address>>) {
let set_id = NextValidatorsSetId::get(); let set_id = NextValidatorsSetId::<DefaultInstance>::get();
NextValidatorsSetId::put(set_id + 1); NextValidatorsSetId::<DefaultInstance>::put(set_id + 1);
ValidatorsSets::insert( ValidatorsSets::<DefaultInstance>::insert(
set_id, set_id,
ValidatorsSet { ValidatorsSet {
validators: finalized_set, validators: finalized_set,
signal_block: None, signal_block: None,
enact_block: HeaderId { enact_block: HeaderId {
number: 0, number: 0,
hash: HeadersByNumber::get(&0).unwrap()[0], hash: HeadersByNumber::<DefaultInstance>::get(&0).unwrap()[0],
}, },
}, },
); );
let header_hash = HeadersByNumber::get(&number).unwrap()[0]; let header_hash = HeadersByNumber::<DefaultInstance>::get(&number).unwrap()[0];
let mut header = Headers::<TestRuntime>::get(&header_hash).unwrap(); let mut header = Headers::<TestRuntime>::get(&header_hash).unwrap();
header.next_validators_set_id = set_id; header.next_validators_set_id = set_id;
if let Some(signalled_set) = signalled_set { if let Some(signalled_set) = signalled_set {
@@ -441,7 +442,7 @@ mod tests {
number: header.header.number - 1, number: header.header.number - 1,
hash: header.header.parent_hash, hash: header.header.parent_hash,
}); });
ScheduledChanges::insert( ScheduledChanges::<DefaultInstance>::insert(
header.header.parent_hash, header.header.parent_hash,
ScheduledChange { ScheduledChange {
validators: signalled_set, validators: signalled_set,
@@ -134,8 +134,15 @@ impl<Amount> CurrencyConverter for IdentityCurrencyConverter<Amount> {
} }
decl_runtime_apis! { decl_runtime_apis! {
/// API for exchange transactions submitters. /// API for Rialto exchange transactions submitters.
pub trait CurrencyExchangeApi<Proof: Parameter> { pub trait RialtoCurrencyExchangeApi<Proof: Parameter> {
/// Returns true if currency exchange module is able to import transaction proof in
/// its current state.
fn filter_transaction_proof(proof: Proof) -> bool;
}
/// API for Kovan exchange transactions submitters.
pub trait KovanCurrencyExchangeApi<Proof: Parameter> {
/// Returns true if currency exchange module is able to import transaction proof in /// Returns true if currency exchange module is able to import transaction proof in
/// its current state. /// its current state.
fn filter_transaction_proof(proof: Proof) -> bool; fn filter_transaction_proof(proof: Proof) -> bool;
+18 -5
View File
@@ -505,19 +505,32 @@ pub fn step_validator<T>(header_validators: &[T], header_step: u64) -> &T {
} }
sp_api::decl_runtime_apis! { sp_api::decl_runtime_apis! {
/// API for headers submitters. /// API for querying information about headers from the Rialto Bridge Pallet
pub trait EthereumHeadersApi { pub trait RialtoHeaderApi {
/// Returns number and hash of the best block known to the bridge module. /// Returns number and hash of the best block known to the bridge module.
/// The caller should only submit `import_header` transaction that makes ///
/// The caller should only submit an `import_header` transaction that makes
/// (or leads to making) other header the best one. /// (or leads to making) other header the best one.
fn best_block() -> (u64, H256); fn best_block() -> (u64, H256);
/// Returns number and hash of the best finalized block known to the bridge module. /// Returns number and hash of the best finalized block known to the bridge module.
fn finalized_block() -> (u64, H256); fn finalized_block() -> (u64, H256);
/// Returns true if the import of given block requires transactions receipts. /// Returns true if the import of given block requires transactions receipts.
fn is_import_requires_receipts(header: Header) -> bool; fn is_import_requires_receipts(header: Header) -> bool;
/// Returns true if header is known to the runtime.
fn is_known_block(hash: H256) -> bool;
}
/// API for querying information about headers from the Kovan Bridge Pallet
pub trait KovanHeaderApi {
/// Returns number and hash of the best block known to the bridge module.
///
/// The caller should only submit an `import_header` transaction that makes
/// (or leads to making) other header the best one.
fn best_block() -> (u64, H256);
/// Returns number and hash of the best finalized block known to the bridge module.
fn finalized_block() -> (u64, H256);
/// Returns true if the import of given block requires transactions receipts.
fn is_import_requires_receipts(header: Header) -> bool;
/// Returns true if header is known to the runtime. /// Returns true if header is known to the runtime.
fn is_known_block(hash: H256) -> bool; fn is_known_block(hash: H256) -> bool;
} }
@@ -34,10 +34,10 @@ use sp_core::crypto::Pair;
use sp_runtime::traits::IdentifyAccount; use sp_runtime::traits::IdentifyAccount;
use std::collections::VecDeque; use std::collections::VecDeque;
const ETH_API_IMPORT_REQUIRES_RECEIPTS: &str = "EthereumHeadersApi_is_import_requires_receipts"; const ETH_API_IMPORT_REQUIRES_RECEIPTS: &str = "RialtoHeaderApi_is_import_requires_receipts";
const ETH_API_IS_KNOWN_BLOCK: &str = "EthereumHeadersApi_is_known_block"; const ETH_API_IS_KNOWN_BLOCK: &str = "RialtoHeaderApi_is_known_block";
const ETH_API_BEST_BLOCK: &str = "EthereumHeadersApi_best_block"; const ETH_API_BEST_BLOCK: &str = "RialtoHeaderApi_best_block";
const ETH_API_BEST_FINALIZED_BLOCK: &str = "EthereumHeadersApi_finalized_block"; const ETH_API_BEST_FINALIZED_BLOCK: &str = "RialtoHeaderApi_finalized_block";
const EXCH_API_FILTER_TRANSACTION_PROOF: &str = "CurrencyExchangeApi_filter_transaction_proof"; const EXCH_API_FILTER_TRANSACTION_PROOF: &str = "CurrencyExchangeApi_filter_transaction_proof";
const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities"; const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities";
@@ -336,7 +336,8 @@ impl SubmitEthereumExchangeTransactionProof for SubstrateRpcClient {
let nonce = self.next_account_index(account_id).await?; let nonce = self.next_account_index(account_id).await?;
let transaction = create_signed_transaction( let transaction = create_signed_transaction(
bridge_node_runtime::Call::BridgeCurrencyExchange( // TODO [#209]: Change so that that it's dynamic
bridge_node_runtime::Call::BridgeRialtoCurrencyExchange(
bridge_node_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof), bridge_node_runtime::BridgeCurrencyExchangeCall::import_peer_transaction(proof),
), ),
&params.signer, &params.signer,
@@ -356,7 +357,8 @@ fn create_signed_submit_transaction(
genesis_hash: H256, genesis_hash: H256,
) -> bridge_node_runtime::UncheckedExtrinsic { ) -> bridge_node_runtime::UncheckedExtrinsic {
create_signed_transaction( create_signed_transaction(
bridge_node_runtime::Call::BridgeEthPoA(bridge_node_runtime::BridgeEthPoACall::import_signed_headers( // TODO [#209]: Change so that that it's dynamic
bridge_node_runtime::Call::BridgeRialto(bridge_node_runtime::BridgeEthPoACall::import_signed_headers(
headers headers
.into_iter() .into_iter()
.map(|header| { .map(|header| {
@@ -376,7 +378,8 @@ fn create_signed_submit_transaction(
/// Create unsigned Substrate transaction for submitting Ethereum header. /// Create unsigned Substrate transaction for submitting Ethereum header.
fn create_unsigned_submit_transaction(header: QueuedEthereumHeader) -> bridge_node_runtime::UncheckedExtrinsic { fn create_unsigned_submit_transaction(header: QueuedEthereumHeader) -> bridge_node_runtime::UncheckedExtrinsic {
let function = let function =
bridge_node_runtime::Call::BridgeEthPoA(bridge_node_runtime::BridgeEthPoACall::import_unsigned_header( // TODO [#209]: Change so that that it's dynamic
bridge_node_runtime::Call::BridgeRialto(bridge_node_runtime::BridgeEthPoACall::import_unsigned_header(
into_substrate_ethereum_header(header.header()), into_substrate_ethereum_header(header.header()),
into_substrate_ethereum_receipts(header.extra()), into_substrate_ethereum_receipts(header.extra()),
)); ));