Merge pull request #4427 from paritytech/update-bridges-subtree-r/w

Update bridges subtree r/w
This commit is contained in:
Tomasz Drwięga
2021-12-02 11:20:45 +01:00
committed by GitHub
366 changed files with 21556 additions and 36681 deletions
+7 -8
View File
@@ -10,23 +10,26 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
jsonrpc-core = "15.1.0"
jsonrpc-core = "18.0"
structopt = "0.3.21"
serde_json = "1.0.59"
# Bridge dependencies
bp-messages = { path = "../../../primitives/messages" }
bp-millau= { path = "../../../primitives/chain-millau" }
bp-millau = { path = "../../../primitives/chain-millau" }
bp-runtime = { path = "../../../primitives/runtime" }
millau-runtime = { path = "../runtime" }
pallet-bridge-messages = { path = "../../../modules/messages" }
# Substrate Dependencies
beefy-gadget = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-gadget-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["wasmtime"] }
@@ -45,7 +48,6 @@ sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "mast
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -56,9 +58,6 @@ frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", bran
[features]
default = []
# TODO: https://github.com/paritytech/parity-bridges-common/issues/390
# I've left the feature flag here to test our CI configuration
runtime-benchmarks = [
# "millau-runtime/runtime-benchmarks",
"millau-runtime/runtime-benchmarks",
]
@@ -14,10 +14,12 @@
// 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 beefy_primitives::crypto::AuthorityId as BeefyId;
use bp_millau::derive_account_from_rialto_id;
use millau_runtime::{
AccountId, AuraConfig, BalancesConfig, BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, SessionConfig,
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
AccountId, AuraConfig, BalancesConfig, BeefyConfig, BridgeRialtoMessagesConfig,
BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys,
Signature, SudoConfig, SystemConfig, WASM_BINARY,
};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{sr25519, Pair, Public};
@@ -56,10 +58,11 @@ where
}
/// Helper function to generate an authority key for Aura
pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, BeefyId, GrandpaId) {
(
get_account_id_from_seed::<sr25519::Public>(s),
get_from_seed::<AuraId>(s),
get_from_seed::<BeefyId>(s),
get_from_seed::<GrandpaId>(s),
)
}
@@ -70,10 +73,7 @@ impl Alternative {
let properties = Some(
serde_json::json!({
"tokenDecimals": 9,
"tokenSymbol": "MLAU",
"bridgeIds": {
"Rialto": bp_runtime::RIALTO_CHAIN_ID,
}
"tokenSymbol": "MLAU"
})
.as_object()
.expect("Map given; qed")
@@ -81,8 +81,8 @@ impl Alternative {
);
match self {
Alternative::Development => ChainSpec::from_genesis(
"Development",
"dev",
"Millau Development",
"millau_dev",
sc_service::ChainType::Development,
|| {
testnet_genesis(
@@ -107,8 +107,8 @@ impl Alternative {
None,
),
Alternative::LocalTestnet => ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
"Millau Local",
"millau_local",
sc_service::ChainType::Local,
|| {
testnet_genesis(
@@ -137,10 +137,12 @@ impl Alternative {
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
get_account_id_from_seed::<sr25519::Public>("George//stash"),
get_account_id_from_seed::<sr25519::Public>("Harry//stash"),
pallet_bridge_messages::Pallet::<
millau_runtime::Runtime,
pallet_bridge_messages::DefaultInstance,
>::relayer_fund_account_id(),
get_account_id_from_seed::<sr25519::Public>("RialtoMessagesOwner"),
get_account_id_from_seed::<sr25519::Public>("WithRialtoTokenSwap"),
pallet_bridge_messages::relayer_fund_account_id::<
bp_millau::AccountId,
bp_millau::AccountIdConverter,
>(),
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Alice"),
)),
@@ -173,12 +175,12 @@ impl Alternative {
}
}
fn session_keys(aura: AuraId, grandpa: GrandpaId) -> SessionKeys {
SessionKeys { aura, grandpa }
fn session_keys(aura: AuraId, beefy: BeefyId, grandpa: GrandpaId) -> SessionKeys {
SessionKeys { aura, beefy, grandpa }
}
fn testnet_genesis(
initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>,
initial_authorities: Vec<(AccountId, AuraId, BeefyId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
@@ -186,22 +188,20 @@ fn testnet_genesis(
GenesisConfig {
system: SystemConfig {
code: WASM_BINARY.expect("Millau development WASM not available").to_vec(),
changes_trie_config: Default::default(),
},
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
},
aura: AuraConfig {
authorities: Vec::new(),
},
grandpa: GrandpaConfig {
authorities: Vec::new(),
},
aura: AuraConfig { authorities: Vec::new() },
beefy: BeefyConfig { authorities: Vec::new() },
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
keys: initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone())))
.map(|x| {
(x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone(), x.3.clone()))
})
.collect::<Vec<_>>(),
},
bridge_westend_grandpa: BridgeWestendGrandpaConfig {
@@ -211,15 +211,17 @@ fn testnet_genesis(
owner: Some(get_account_id_from_seed::<sr25519::Public>("George")),
..Default::default()
},
bridge_rialto_messages: BridgeRialtoMessagesConfig {
owner: Some(get_account_id_from_seed::<sr25519::Public>("RialtoMessagesOwner")),
..Default::default()
},
}
}
#[test]
fn derived_dave_account_is_as_expected() {
let dave = get_account_id_from_seed::<sr25519::Public>("Dave");
let derived: AccountId = derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(dave));
assert_eq!(
derived.to_string(),
"5DNW6UVnb7TN6wX5KwXtDYR3Eccecbdzuw89HqjyNfkzce6J".to_string()
);
let derived: AccountId =
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(dave));
assert_eq!(derived.to_string(), "5DNW6UVnb7TN6wX5KwXtDYR3Eccecbdzuw89HqjyNfkzce6J".to_string());
}
+2 -2
View File
@@ -29,10 +29,10 @@ pub struct Cli {
/// Possible subcommands of the main binary.
#[derive(Debug, StructOpt)]
pub enum Subcommand {
/// Key management cli utilities
/// Key management CLI utilities
Key(sc_cli::KeySubcommand),
/// Verify a signature for a message, provided on STDIN, with a given (public or secret) key.
/// Verify a signature for a message, provided on `STDIN`, with a given (public or secret) key.
Verify(sc_cli::VerifyCmd),
/// Generate a seed that provides a vanity address.
+29 -48
View File
@@ -14,11 +14,13 @@
// 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::cli::{Cli, Subcommand};
use crate::service;
use crate::service::new_partial;
use crate::{
cli::{Cli, Subcommand},
service,
service::new_partial,
};
use millau_runtime::{Block, RuntimeApi};
use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli};
use sc_service::PartialComponents;
impl SubstrateCli for Cli {
@@ -70,24 +72,23 @@ impl SubstrateCli for Cli {
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
// make sure to set correct crypto version.
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::Custom(
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom(
millau_runtime::SS58Prefix::get() as u16,
));
match &cli.subcommand {
Some(Subcommand::Benchmark(cmd)) => {
Some(Subcommand::Benchmark(cmd)) =>
if cfg!(feature = "runtime-benchmarks") {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
runner.sync_run(|config| cmd.run::<Block, service::ExecutorDispatch>(config))
} else {
println!(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
);
Ok(())
}
}
},
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
Some(Subcommand::Sign(cmd)) => cmd.run(),
Some(Subcommand::Verify(cmd)) => cmd.run(),
@@ -95,78 +96,58 @@ pub fn run() -> sc_cli::Result<()> {
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
}
},
Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
import_queue,
..
} = new_partial(&config)?;
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
}
},
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client, task_manager, ..
} = new_partial(&config)?;
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
Ok((cmd.run(client, config.database), task_manager))
})
}
},
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client, task_manager, ..
} = new_partial(&config)?;
let PartialComponents { client, task_manager, .. } = new_partial(&config)?;
Ok((cmd.run(client, config.chain_spec), task_manager))
})
}
},
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
import_queue,
..
} = new_partial(&config)?;
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
}
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.database))
}
},
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
backend,
..
} = new_partial(&config)?;
let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?;
Ok((cmd.run(client, backend), task_manager))
})
}
},
Some(Subcommand::Inspect(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, service::Executor>(config))
}
runner
.sync_run(|config| cmd.run::<Block, RuntimeApi, service::ExecutorDispatch>(config))
},
None => {
let runner = cli.create_runner(&cli.run)?;
runner.run_node_until_exit(|config| async move {
match config.role {
Role::Light => service::new_light(config),
_ => service::new_full(config),
}
.map_err(sc_cli::Error::Service)
service::new_full(config).map_err(sc_cli::Error::Service)
})
}
},
}
}
+154 -212
View File
@@ -21,18 +21,19 @@
// =====================================================================================
// UPDATE GUIDE:
// 1) replace everything with node-template/src/service.rs contents (found in main Substrate repo);
// 2) the only thing to keep from old code, is `rpc_extensions_builder` - we use our own custom RPCs;
// 3) fix compilation errors;
// 4) test :)
// 2) from old code keep `rpc_extensions_builder` - we use our own custom RPCs;
// 3) from old code keep the Beefy gadget;
// 4) fix compilation errors;
// 5) test :)
// =====================================================================================
// =====================================================================================
// =====================================================================================
use millau_runtime::{self, opaque::Block, RuntimeApi};
use sc_client_api::{ExecutorProvider, RemoteBackend};
use sc_client_api::ExecutorProvider;
use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams};
pub use sc_executor::NativeElseWasmExecutor;
use sc_finality_grandpa::SharedVoterState;
use sc_keystore::LocalKeystore;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker};
@@ -44,7 +45,12 @@ use std::{sync::Arc, time::Duration};
pub struct ExecutorDispatch;
impl sc_executor::NativeExecutionDispatch for ExecutorDispatch {
/// Only enable the benchmarking host functions when we actually want to benchmark.
#[cfg(feature = "runtime-benchmarks")]
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
/// Otherwise we only use the default Substrate host functions.
#[cfg(not(feature = "runtime-benchmarks"))]
type ExtendHostFunctions = ();
fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
millau_runtime::api::dispatch(method, data)
@@ -55,11 +61,11 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch {
}
}
type FullClient = sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
type FullClient =
sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
#[allow(clippy::type_complexity)]
pub fn new_partial(
config: &Configuration,
) -> Result<
@@ -70,7 +76,12 @@ pub fn new_partial(
sc_consensus::DefaultImportQueue<Block, FullClient>,
sc_transaction_pool::FullPool<Block, FullClient>,
(
sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>,
sc_finality_grandpa::GrandpaBlockImport<
FullBackend,
Block,
FullClient,
FullSelectChain,
>,
sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
Option<Telemetry>,
),
@@ -78,7 +89,7 @@ pub fn new_partial(
ServiceError,
> {
if config.keystore_remote.is_some() {
return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
return Err(ServiceError::Other(format!("Remote Keystores are not supported.")))
}
let telemetry = config
@@ -92,14 +103,22 @@ pub fn new_partial(
})
.transpose()?;
let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
)?;
let executor = NativeElseWasmExecutor::<ExecutorDispatch>::new(
config.wasm_method,
config.default_heap_pages,
config.max_runtime_instances,
);
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, _>(
&config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
executor,
)?;
let client = Arc::new(client);
let telemetry = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", worker.run());
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
@@ -122,26 +141,30 @@ pub fn new_partial(
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import.clone())),
client: client.clone(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let import_queue =
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import.clone())),
client: client.clone(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
})?;
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(
client.executor().clone(),
),
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
})?;
Ok(sc_service::PartialComponents {
client,
@@ -155,7 +178,7 @@ pub fn new_partial(
})
}
fn remote_keystore(_url: &str) -> Result<Arc<LocalKeystore>, &'static str> {
fn remote_keystore(_url: &String) -> Result<Arc<LocalKeystore>, &'static str> {
// FIXME: here would the concrete keystore be built,
// must return a concrete type (NOT `LocalKeystore`) that
// implements `CryptoStore` and `SyncCryptoStore`
@@ -178,32 +201,40 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
if let Some(url) = &config.keystore_remote {
match remote_keystore(url) {
Ok(k) => keystore_container.set_remote_keystore(k),
Err(e) => {
Err(e) =>
return Err(ServiceError::Other(format!(
"Error hooking up remote keystore for {}: {}",
url, e
)))
}
))),
};
}
config
.network
.extra_sets
.push(sc_finality_grandpa::grandpa_peers_set_config());
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config());
let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new(
backend.clone(),
grandpa_link.shared_authority_set().clone(),
Vec::default(),
));
let (network, system_rpc_tx, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: None,
block_announce_validator_builder: None,
})?;
let (network, system_rpc_tx, network_starter) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
block_announce_validator_builder: None,
warp_sync: Some(warp_sync),
})?;
if config.offchain_worker.enabled {
sc_service::build_offchain_workers(&config, task_manager.spawn_handle(), client.clone(), network.clone());
sc_service::build_offchain_workers(
&config,
task_manager.spawn_handle(),
client.clone(),
network.clone(),
);
}
let role = config.role.clone();
@@ -212,7 +243,9 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
let name = config.network.node_name.clone();
let enable_grandpa = !config.disable_grandpa;
let prometheus_registry = config.prometheus_registry().cloned();
let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty();
let shared_voter_state = SharedVoterState::empty();
let (signed_commitment_sender, signed_commitment_stream) =
beefy_gadget::notification::BeefySignedCommitmentStream::channel();
let rpc_extensions_builder = {
use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
@@ -230,10 +263,12 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
let shared_authority_set = grandpa_link.shared_authority_set().clone();
let shared_voter_state = shared_voter_state.clone();
let finality_proof_provider =
GrandpaFinalityProofProvider::new_for_service(backend, Some(shared_authority_set.clone()));
let finality_proof_provider = GrandpaFinalityProofProvider::new_for_service(
backend,
Some(shared_authority_set.clone()),
);
Box::new(move |_, subscription_executor| {
Box::new(move |_, subscription_executor: sc_rpc::SubscriptionTaskExecutor| {
let mut io = jsonrpc_core::IoHandler::default();
io.extend_with(SystemApi::to_delegate(FullSystem::new(
client.clone(),
@@ -247,10 +282,19 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
shared_authority_set.clone(),
shared_voter_state.clone(),
justification_stream.clone(),
subscription_executor,
subscription_executor.clone(),
finality_proof_provider.clone(),
)));
io
io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate(
beefy_gadget_rpc::BeefyRpcHandler::new(
signed_commitment_stream.clone(),
subscription_executor,
),
));
io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new(
client.clone(),
)));
Ok(io)
})
};
@@ -261,9 +305,7 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
task_manager: &mut task_manager,
transaction_pool: transaction_pool.clone(),
rpc_extensions_builder,
on_demand: None,
remote_blockchain: None,
backend,
backend: backend.clone(),
system_rpc_tx,
config,
telemetry: telemetry.as_mut(),
@@ -278,51 +320,71 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
telemetry.as_ref().map(|x| x.handle()),
);
let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
let can_author_with =
sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
let raw_slot_duration = slot_duration.slot_duration();
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _, _>(StartAuraParams {
slot_duration,
client,
select_chain,
block_import,
proposer_factory,
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _, _>(
StartAuraParams {
slot_duration,
client: client.clone(),
select_chain,
block_import,
proposer_factory,
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
raw_slot_duration,
);
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
raw_slot_duration,
);
Ok((timestamp, slot))
Ok((timestamp, slot))
},
force_authoring,
backoff_authoring_blocks,
keystore: keystore_container.sync_keystore(),
can_author_with,
sync_oracle: network.clone(),
justification_sync_link: network.clone(),
block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32),
max_block_proposal_slot_portion: None,
telemetry: telemetry.as_ref().map(|x| x.handle()),
},
force_authoring,
backoff_authoring_blocks,
keystore: keystore_container.sync_keystore(),
can_author_with,
sync_oracle: network.clone(),
justification_sync_link: network.clone(),
block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32),
max_block_proposal_slot_portion: None,
telemetry: telemetry.as_ref().map(|x| x.handle()),
})?;
)?;
// the AURA authoring task is considered essential, i.e. if it
// fails we take down the service with it.
task_manager.spawn_essential_handle().spawn_blocking("aura", aura);
task_manager
.spawn_essential_handle()
.spawn_blocking("aura", Some("block-authoring"), aura);
}
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() {
Some(keystore_container.sync_keystore())
} else {
None
let keystore =
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
let beefy_params = beefy_gadget::BeefyParams {
client,
backend,
key_store: keystore.clone(),
network: network.clone(),
signed_commitment_sender,
min_block_delta: 4,
prometheus_registry: prometheus_registry.clone(),
};
// Start the BEEFY bridge gadget.
task_manager.spawn_essential_handle().spawn_blocking(
"beefy-gadget",
None,
beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params),
);
let grandpa_config = sc_finality_grandpa::Config {
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
@@ -353,133 +415,13 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
// the GRANDPA voter task is considered infallible, i.e.
// if it fails we take down the service with it.
task_manager
.spawn_essential_handle()
.spawn_blocking("grandpa-voter", sc_finality_grandpa::run_grandpa_voter(grandpa_config)?);
}
network_starter.start_network();
Ok(task_manager)
}
/// Builds a new service for a light client.
pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?;
let telemetry = worker.handle().new_telemetry(endpoints);
Ok((worker, telemetry))
})
.transpose()?;
let (client, backend, keystore_container, mut task_manager, on_demand) =
sc_service::new_light_parts::<Block, RuntimeApi, Executor>(
&config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
)?;
let mut telemetry = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", worker.run());
telemetry
});
config
.network
.extra_sets
.push(sc_finality_grandpa::grandpa_peers_set_config());
let select_chain = sc_consensus::LongestChain::new(backend.clone());
let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light(
config.transaction_pool.clone(),
config.prometheus_registry(),
task_manager.spawn_essential_handle(),
client.clone(),
on_demand.clone(),
));
let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import(
client.clone(),
&(client.clone() as Arc<_>),
select_chain,
telemetry.as_ref().map(|x| x.handle()),
)?;
let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import)),
client: client.clone(),
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*timestamp,
slot_duration,
);
Ok((timestamp, slot))
},
spawner: &task_manager.spawn_essential_handle(),
can_author_with: sp_consensus::NeverCanAuthor,
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
})?;
let (network, system_rpc_tx, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: Some(on_demand.clone()),
block_announce_validator_builder: None,
})?;
if config.offchain_worker.enabled {
sc_service::build_offchain_workers(&config, task_manager.spawn_handle(), client.clone(), network.clone());
}
let enable_grandpa = !config.disable_grandpa;
if enable_grandpa {
let name = config.network.node_name.clone();
let config = sc_finality_grandpa::Config {
gossip_duration: std::time::Duration::from_millis(333),
justification_period: 512,
name: Some(name),
observer_enabled: false,
keystore: None,
local_role: config.role.clone(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
};
task_manager.spawn_handle().spawn_blocking(
"grandpa-observer",
sc_finality_grandpa::run_grandpa_observer(config, grandpa_link, network.clone())?,
task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter",
None,
sc_finality_grandpa::run_grandpa_voter(grandpa_config)?,
);
}
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
remote_blockchain: Some(backend.remote_blockchain()),
transaction_pool,
task_manager: &mut task_manager,
on_demand: Some(on_demand),
rpc_extensions_builder: Box::new(|_, _| ()),
config,
client,
keystore: keystore_container.sync_keystore(),
backend,
network,
system_rpc_tx,
telemetry: telemetry.as_mut(),
})?;
network_starter.start_network();
Ok(task_manager)
}
+48 -31
View File
@@ -8,9 +8,10 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
hex-literal = "0.3"
serde = { version = "1.0.124", optional = true, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = "1.0", optional = true, features = ["derive"] }
# Bridge dependencies
@@ -24,36 +25,43 @@ bridge-runtime-common = { path = "../../runtime-common", default-features = fals
pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
pallet-bridge-token-swap = { path = "../../../modules/token-swap", default-features = false }
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
# Substrate Dependencies
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -61,6 +69,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
"beefy-primitives/std",
"bp-header-chain/std",
"bp-messages/std",
"bp-millau/std",
@@ -75,10 +84,14 @@ std = [
"frame-system/std",
"pallet-aura/std",
"pallet-balances/std",
"pallet-beefy/std",
"pallet-beefy-mmr/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-bridge-token-swap/std",
"pallet-grandpa/std",
"pallet-mmr/std",
"pallet-randomness-collective-flip/std",
"pallet-session/std",
"pallet-shift-session-manager/std",
@@ -86,6 +99,7 @@ std = [
"pallet-timestamp/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
"scale-info/std",
"serde",
"sp-api/std",
"sp-block-builder/std",
@@ -101,6 +115,9 @@ std = [
"sp-trie/std",
"sp-version/std",
]
# TODO: https://github.com/paritytech/parity-bridges-common/issues/390
# I've left the feature flag here to test our CI configuration
runtime-benchmarks = []
runtime-benchmarks = [
"frame-benchmarking",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-bridge-token-swap/runtime-benchmarks",
]
+270 -62
View File
@@ -34,18 +34,25 @@ pub mod rialto_messages;
use crate::rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge};
use bridge_runtime_common::messages::{source::estimate_message_dispatch_and_delivery_fee, MessageBridge};
use codec::Decode;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bridge_runtime_common::messages::{
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
};
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
use pallet_mmr_primitives::{
DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof,
};
use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature, MultiSigner,
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
};
use sp_std::prelude::*;
#[cfg(feature = "std")]
@@ -62,8 +69,7 @@ pub use frame_support::{
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_bridge_grandpa::Call as BridgeGrandpaRialtoCall;
pub use pallet_bridge_grandpa::Call as BridgeGrandpaWestendCall;
pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall;
pub use pallet_bridge_messages::Call as MessagesCall;
pub use pallet_sudo::Call as SudoCall;
pub use pallet_timestamp::Call as TimestampCall;
@@ -90,7 +96,7 @@ pub type AccountIndex = u32;
pub type Balance = bp_millau::Balance;
/// Index of a transaction in the chain.
pub type Index = u32;
pub type Index = bp_millau::Index;
/// A hash of some data used by the chain.
pub type Hash = bp_millau::Hash;
@@ -98,9 +104,6 @@ pub type Hash = bp_millau::Hash;
/// Hashing algorithm used by the chain.
pub type Hashing = bp_millau::Hasher;
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
@@ -121,6 +124,7 @@ pub mod opaque {
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
pub beefy: Beefy,
pub grandpa: Grandpa,
}
}
@@ -139,10 +143,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
NativeVersion {
runtime_version: VERSION,
can_author_with: Default::default(),
}
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
parameter_types! {
@@ -214,10 +215,16 @@ parameter_types! {
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
type MaxAuthorities = MaxAuthorities;
type DisabledValidators = ();
}
impl pallet_beefy::Config for Runtime {
type BeefyId = BeefyId;
}
impl pallet_bridge_dispatch::Config for Runtime {
type Event = Event;
type MessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
type Call = Call;
type CallFilter = frame_support::traits::Everything;
type EncodedCall = crate::rialto_messages::FromRialtoEncodedCall;
@@ -231,12 +238,50 @@ impl pallet_grandpa::Config for Runtime {
type Event = Event;
type Call = Call;
type KeyOwnerProofSystem = ();
type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
type KeyOwnerIdentification =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::IdentificationTuple;
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
GrandpaId,
)>>::IdentificationTuple;
type HandleEquivocation = ();
// TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78)
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;
}
type MmrHash = <Keccak256 as sp_runtime::traits::Hash>::Output;
impl pallet_mmr::Config for Runtime {
const INDEXING_PREFIX: &'static [u8] = b"mmr";
type Hashing = Keccak256;
type Hash = MmrHash;
type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
type WeightInfo = ();
type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
}
parameter_types! {
/// Version of the produced MMR leaf.
///
/// The version consists of two parts;
/// - `major` (3 bits)
/// - `minor` (5 bits)
///
/// `major` should be updated only if decoding the previous MMR Leaf format from the payload
/// is not possible (i.e. backward incompatible change).
/// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE
/// encoding does not prevent old leafs from being decoded.
///
/// Hence we expect `major` to be changed really rarely (think never).
/// See [`MmrLeafVersion`] type documentation for more details.
pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);
}
impl pallet_beefy_mmr::Config for Runtime {
type LeafVersion = LeafVersion;
type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
type ParachainHeads = ();
}
parameter_types! {
@@ -244,7 +289,7 @@ parameter_types! {
}
impl pallet_timestamp::Config for Runtime {
/// A timestamp: milliseconds since the Unix epoch.
/// A timestamp: milliseconds since the UNIX epoch.
type Moment = u64;
type OnTimestampSet = Aura;
type MinimumPeriod = MinimumPeriod;
@@ -278,13 +323,25 @@ impl pallet_balances::Config for Runtime {
parameter_types! {
pub const TransactionBaseFee: Balance = 0;
pub const TransactionByteFee: Balance = 1;
pub const OperationalFeeMultiplier: u8 = 5;
// values for following parameters are copied from polkadot repo, but it is fine
// not to sync them - we're not going to make Rialto a full copy of one of Polkadot-like chains
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000);
pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128);
}
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
type OperationalFeeMultiplier = OperationalFeeMultiplier;
type WeightToFee = bp_millau::WeightToFee;
type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment<
Runtime,
TargetBlockFullness,
AdjustmentVariable,
MinimumMultiplier,
>;
}
impl pallet_sudo::Config for Runtime {
@@ -357,10 +414,11 @@ parameter_types! {
pub const GetDeliveryConfirmationTransactionFee: Balance =
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _;
pub const RootAccountForPayments: Option<AccountId> = None;
pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
}
/// Instance of the messages pallet used to relay messages to/from Rialto chain.
pub type WithRialtoMessagesInstance = pallet_bridge_messages::DefaultInstance;
pub type WithRialtoMessagesInstance = ();
impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
type Event = Event;
@@ -382,16 +440,45 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
type TargetHeaderChain = crate::rialto_messages::Rialto;
type LaneMessageVerifier = crate::rialto_messages::ToRialtoMessageVerifier;
type MessageDeliveryAndDispatchPayment = pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
Runtime,
pallet_balances::Pallet<Runtime>,
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
>;
type OnDeliveryConfirmed = ();
type MessageDeliveryAndDispatchPayment =
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
Runtime,
(),
pallet_balances::Pallet<Runtime>,
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
>;
type OnMessageAccepted = ();
type OnDeliveryConfirmed =
pallet_bridge_token_swap::Pallet<Runtime, WithRialtoTokenSwapInstance>;
type SourceHeaderChain = crate::rialto_messages::Rialto;
type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch;
type BridgedChainId = RialtoChainId;
}
parameter_types! {
pub const TokenSwapMessagesLane: bp_messages::LaneId = *b"swap";
}
/// Instance of the with-Rialto token swap pallet.
pub type WithRialtoTokenSwapInstance = ();
impl pallet_bridge_token_swap::Config<WithRialtoTokenSwapInstance> for Runtime {
type Event = Event;
type WeightInfo = ();
type BridgedChainId = RialtoChainId;
type OutboundMessageLaneId = TokenSwapMessagesLane;
#[cfg(not(feature = "runtime-benchmarks"))]
type MessagesBridge = pallet_bridge_messages::Pallet<Runtime, WithRialtoMessagesInstance>;
#[cfg(feature = "runtime-benchmarks")]
type MessagesBridge = bp_messages::source_chain::NoopMessagesBridge;
type ThisCurrency = pallet_balances::Pallet<Runtime>;
type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter;
type BridgedChain = bp_rialto::Rialto;
type FromBridgedToThisAccountIdConverter = bp_millau::AccountIdConverter;
}
construct_runtime!(
@@ -400,20 +487,35 @@ construct_runtime!(
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Must be before session.
Aura: pallet_aura::{Pallet, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Consensus support.
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
// BEEFY Bridges support.
Beefy: pallet_beefy::{Pallet, Storage, Config<T>},
Mmr: pallet_mmr::{Pallet, Storage},
MmrLeaf: pallet_beefy_mmr::{Pallet, Storage},
// Rialto bridge modules.
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event<T>},
// Westend bridge modules.
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
}
);
@@ -449,7 +551,7 @@ pub type Executive = frame_executive::Executive<
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
AllPallets,
>;
impl_runtime_apis! {
@@ -522,7 +624,7 @@ impl_runtime_apis! {
}
fn authorities() -> Vec<AuraId> {
Aura::authorities()
Aura::authorities().to_vec()
}
}
@@ -550,7 +652,50 @@ impl_runtime_apis! {
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {
fn validator_set() -> ValidatorSet<BeefyId> {
Beefy::validator_set()
}
}
impl pallet_mmr_primitives::MmrApi<Block, MmrHash> for Runtime {
fn generate_proof(leaf_index: u64)
-> Result<(EncodableOpaqueLeaf, MmrProof<MmrHash>), MmrError>
{
Mmr::generate_proof(leaf_index)
.map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof))
}
fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof<MmrHash>)
-> Result<(), MmrError>
{
pub type Leaf = <
<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider
>::LeafData;
let leaf: Leaf = leaf
.into_opaque_leaf()
.try_decode()
.ok_or(MmrError::Verify)?;
Mmr::verify_leaf(leaf, proof)
}
fn verify_proof_stateless(
root: MmrHash,
leaf: EncodableOpaqueLeaf,
proof: MmrProof<MmrHash>
) -> Result<(), MmrError> {
type MmrHashing = <Runtime as pallet_mmr::Config>::Hashing;
let node = DataOrHash::Data(leaf.into_opaque_leaf());
pallet_mmr::verify_leaf_proof::<MmrHashing, _>(root, node, proof)
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
fn current_set_id() -> fg_primitives::SetId {
Grandpa::current_set_id()
}
fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities()
}
@@ -619,20 +764,11 @@ impl_runtime_apis! {
begin: bp_messages::MessageNonce,
end: bp_messages::MessageNonce,
) -> Vec<bp_messages::MessageDetails<Balance>> {
(begin..=end).filter_map(|nonce| {
let message_data = BridgeRialtoMessages::outbound_message_data(lane, nonce)?;
let decoded_payload = rialto_messages::ToRialtoMessagePayload::decode(
&mut &message_data.payload[..]
).ok()?;
Some(bp_messages::MessageDetails {
nonce,
dispatch_weight: decoded_payload.weight,
size: message_data.payload.len() as _,
delivery_and_dispatch_fee: message_data.fee,
dispatch_fee_payment: decoded_payload.dispatch_fee_payment,
})
})
.collect()
bridge_runtime_common::messages_api::outbound_message_details::<
Runtime,
WithRialtoMessagesInstance,
WithRialtoMessageBridge,
>(lane, begin, end)
}
fn latest_received_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce {
@@ -657,6 +793,67 @@ impl_runtime_apis! {
BridgeRialtoMessages::inbound_unrewarded_relayers_state(lane)
}
}
#[cfg(feature = "runtime-benchmarks")]
impl frame_benchmarking::Benchmark<Block> for Runtime {
fn benchmark_metadata(extra: bool) -> (
Vec<frame_benchmarking::BenchmarkList>,
Vec<frame_support::traits::StorageInfo>,
) {
use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
let mut list = Vec::<BenchmarkList>::new();
list_benchmark!(list, extra, pallet_bridge_token_swap, BridgeRialtoTokenSwap);
let storage_info = AllPalletsWithSystem::storage_info();
return (list, storage_info)
}
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig,
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey, add_benchmark};
let whitelist: Vec<TrackedStorageKey> = vec![
// Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
// Execution Phase
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
// Event Count
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
// System Events
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
// Caller 0 Account
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da946c154ffd9992e395af90b5b13cc6f295c77033fce8a9045824a6690bbf99c6db269502f0a8d1d2a008542d5690a0749").to_vec().into(),
];
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
use pallet_bridge_token_swap::benchmarking::Config as TokenSwapConfig;
impl TokenSwapConfig<WithRialtoTokenSwapInstance> for Runtime {
fn initialize_environment() {
let relayers_fund_account = pallet_bridge_messages::relayer_fund_account_id::<
bp_millau::AccountId,
bp_millau::AccountIdConverter,
>();
pallet_balances::Pallet::<Runtime>::make_free_balance_be(
&relayers_fund_account,
Balance::MAX / 100,
);
}
}
add_benchmark!(params, batches, pallet_bridge_token_swap, BridgeRialtoTokenSwap);
if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches)
}
}
}
/// Rialto account ownership digest from Millau.
@@ -698,6 +895,7 @@ mod tests {
bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
DbWeight::get(),
);
let max_incoming_message_proof_size = bp_rialto::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
@@ -707,21 +905,31 @@ mod tests {
bp_millau::max_extrinsic_size(),
bp_millau::max_extrinsic_weight(),
max_incoming_message_proof_size,
messages::target::maximal_incoming_message_dispatch_weight(bp_millau::max_extrinsic_weight()),
messages::target::maximal_incoming_message_dispatch_weight(
bp_millau::max_extrinsic_weight(),
),
);
let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint(
bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE,
bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _,
bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE as _,
)
.unwrap_or(u32::MAX);
let max_incoming_inbound_lane_data_proof_size =
bp_messages::InboundLaneData::<()>::encoded_size_hint(
bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE,
bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _,
bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE as _,
)
.unwrap_or(u32::MAX);
pallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights>(
bp_millau::max_extrinsic_size(),
bp_millau::max_extrinsic_weight(),
max_incoming_inbound_lane_data_proof_size,
bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
DbWeight::get(),
);
}
#[test]
fn call_size() {
const MAX_CALL_SIZE: usize = 230; // value from polkadot-runtime tests
assert!(core::mem::size_of::<Call>() <= MAX_CALL_SIZE);
}
}
@@ -31,25 +31,34 @@ use frame_support::{
weights::{DispatchClass, Weight},
RuntimeDebug,
};
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
use scale_info::TypeInfo;
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive};
/// Initial value of `RialtoToMillauConversionRate` parameter.
pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 =
FixedU128::from_inner(FixedU128::DIV);
/// Initial value of `RialtoFeeMultiplier` parameter.
pub const INITIAL_RIALTO_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
parameter_types! {
/// Rialto to Millau conversion rate. Initially we treat both tokens as equal.
pub storage RialtoToMillauConversionRate: FixedU128 = INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE;
/// Fee multiplier value at Rialto chain.
pub storage RialtoFeeMultiplier: FixedU128 = INITIAL_RIALTO_FEE_MULTIPLIER;
}
/// Message payload for Millau -> Rialto messages.
pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload<WithRialtoMessageBridge>;
pub type ToRialtoMessagePayload =
messages::source::FromThisChainMessagePayload<WithRialtoMessageBridge>;
/// Message verifier for Millau -> Rialto messages.
pub type ToRialtoMessageVerifier = messages::source::FromThisChainMessageVerifier<WithRialtoMessageBridge>;
pub type ToRialtoMessageVerifier =
messages::source::FromThisChainMessageVerifier<WithRialtoMessageBridge>;
/// Message payload for Rialto -> Millau messages.
pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload<WithRialtoMessageBridge>;
pub type FromRialtoMessagePayload =
messages::target::FromBridgedChainMessagePayload<WithRialtoMessageBridge>;
/// Encoded Millau Call as it comes from Rialto.
pub type FromRialtoEncodedCall = messages::target::FromBridgedChainEncodedMessageCall<crate::Call>;
@@ -58,14 +67,15 @@ pub type FromRialtoEncodedCall = messages::target::FromBridgedChainEncodedMessag
type FromRialtoMessagesProof = messages::target::FromBridgedChainMessagesProof<bp_rialto::Hash>;
/// Messages delivery proof for Millau -> Rialto messages.
type ToRialtoMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<bp_rialto::Hash>;
type ToRialtoMessagesDeliveryProof =
messages::source::FromBridgedChainMessagesDeliveryProof<bp_rialto::Hash>;
/// Call-dispatch based message dispatch for Rialto -> Millau messages.
pub type FromRialtoMessageDispatch = messages::target::FromBridgedChainMessageDispatch<
WithRialtoMessageBridge,
crate::Runtime,
pallet_balances::Pallet<Runtime>,
pallet_bridge_dispatch::DefaultInstance,
(),
>;
/// Millau <-> Rialto message bridge.
@@ -76,14 +86,16 @@ impl MessageBridge for WithRialtoMessageBridge {
const RELAYER_FEE_PERCENT: u32 = 10;
const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
const BRIDGED_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME;
type ThisChain = Millau;
type BridgedChain = Rialto;
type BridgedMessagesInstance = crate::WithRialtoMessagesInstance;
fn bridged_balance_to_this_balance(bridged_balance: bp_rialto::Balance) -> bp_millau::Balance {
bp_millau::Balance::try_from(RialtoToMillauConversionRate::get().saturating_mul_int(bridged_balance))
.unwrap_or(bp_millau::Balance::MAX)
bp_millau::Balance::try_from(
RialtoToMillauConversionRate::get().saturating_mul_int(bridged_balance),
)
.unwrap_or(bp_millau::Balance::MAX)
}
}
@@ -104,7 +116,9 @@ impl messages::ThisChainWithMessages for Millau {
type Call = crate::Call;
fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1]
*lane == [0, 0, 0, 0] ||
*lane == [0, 0, 0, 1] ||
*lane == crate::TokenSwapMessagesLane::get()
}
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
@@ -128,11 +142,15 @@ impl messages::ThisChainWithMessages for Millau {
}
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
// `transaction` may represent transaction from the future, when multiplier value will
// be larger, so let's use slightly increased value
let multiplier = FixedU128::saturating_from_rational(110, 100)
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
// in our testnets, both per-byte fee and weight-to-fee are 1:1
messages::transaction_payment(
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
1,
FixedU128::zero(),
multiplier,
|weight| weight as _,
transaction,
)
@@ -159,12 +177,15 @@ impl messages::BridgedChainWithMessages for Rialto {
fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Weight> {
// we don't want to relay too large messages + keep reserve for future upgrades
let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(bp_rialto::max_extrinsic_weight());
let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(
bp_rialto::max_extrinsic_weight(),
);
// we're charging for payload bytes in `WithRialtoMessageBridge::transaction_payment` function
// we're charging for payload bytes in `WithRialtoMessageBridge::transaction_payment`
// function
//
// this bridge may be used to deliver all kind of messages, so we're not making any assumptions about
// minimal dispatch weight here
// this bridge may be used to deliver all kind of messages, so we're not making any
// assumptions about minimal dispatch weight here
0..=upper_limit
}
@@ -195,11 +216,14 @@ impl messages::BridgedChainWithMessages for Rialto {
}
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
// we don't have a direct access to the value of multiplier at Rialto chain
// => it is a messages module parameter
let multiplier = RialtoFeeMultiplier::get();
// in our testnets, both per-byte fee and weight-to-fee are 1:1
messages::transaction_payment(
bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
1,
FixedU128::zero(),
multiplier,
|weight| weight as _,
transaction,
)
@@ -221,9 +245,11 @@ impl TargetHeaderChain<ToRialtoMessagePayload, bp_rialto::AccountId> for Rialto
fn verify_messages_delivery_proof(
proof: Self::MessagesDeliveryProof,
) -> Result<(LaneId, InboundLaneData<bp_millau::AccountId>), Self::Error> {
messages::source::verify_messages_delivery_proof::<WithRialtoMessageBridge, Runtime, crate::RialtoGrandpaInstance>(
proof,
)
messages::source::verify_messages_delivery_proof::<
WithRialtoMessageBridge,
Runtime,
crate::RialtoGrandpaInstance,
>(proof)
}
}
@@ -240,15 +266,16 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
proof: Self::MessagesProof,
messages_count: u32,
) -> Result<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
messages::target::verify_messages_proof::<WithRialtoMessageBridge, Runtime, crate::RialtoGrandpaInstance>(
proof,
messages_count,
)
messages::target::verify_messages_proof::<
WithRialtoMessageBridge,
Runtime,
crate::RialtoGrandpaInstance,
>(proof, messages_count)
}
}
/// Millau -> Rialto message lane pallet parameters.
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq)]
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
pub enum MillauToRialtoMessagesParameter {
/// The conversion formula we use is: `MillauTokens = RialtoTokens * conversion_rate`.
RialtoToMillauConversionRate(FixedU128),
@@ -257,9 +284,8 @@ pub enum MillauToRialtoMessagesParameter {
impl MessagesParameter for MillauToRialtoMessagesParameter {
fn save(&self) {
match *self {
MillauToRialtoMessagesParameter::RialtoToMillauConversionRate(ref conversion_rate) => {
RialtoToMillauConversionRate::set(conversion_rate)
}
MillauToRialtoMessagesParameter::RialtoToMillauConversionRate(ref conversion_rate) =>
RialtoToMillauConversionRate::set(conversion_rate),
}
}
}
@@ -0,0 +1,89 @@
[package]
name = "rialto-parachain-collator"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[build-dependencies]
substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
[[bin]]
name = 'rialto-parachain-collator'
[features]
default = []
runtime-benchmarks = ['rialto-parachain-runtime/runtime-benchmarks']
[dependencies]
derive_more = '0.99.2'
log = '0.4.14'
codec = { package = 'parity-scale-codec', version = '2.0.0' }
structopt = '0.3.8'
serde = { version = '1.0', features = ['derive'] }
hex-literal = '0.3.1'
# RPC related Dependencies
jsonrpc-core = '18.0'
# Local Dependencies
rialto-parachain-runtime = { path = '../runtime' }
# Substrate Dependencies
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
## Substrate Client Dependencies
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", features = ['wasmtime'] }
sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
## Substrate Primitive Dependencies
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Cumulus dependencies
cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-client-collator = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master" }
cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "master" }
# Polkadot dependencies
polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
@@ -0,0 +1,22 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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 substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
fn main() {
generate_cargo_keys();
rerun_if_git_head_changed();
}
@@ -0,0 +1,164 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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 cumulus_primitives_core::ParaId;
use rialto_parachain_runtime::{AccountId, AuraId, Signature};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type ChainSpec =
sc_service::GenericChainSpec<rialto_parachain_runtime::GenesisConfig, Extensions>;
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// The extensions for the [`ChainSpec`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct Extensions {
/// The relay chain of the Parachain.
pub relay_chain: String,
/// The id of the Parachain.
pub para_id: u32,
}
impl Extensions {
/// Try to get the extension from the given `ChainSpec`.
pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
sc_chain_spec::get_extension(chain_spec.extensions())
}
}
type AccountPublic = <Signature as Verify>::Signer;
/// Helper function to generate an account ID from seed
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
pub fn development_config(id: ParaId) -> ChainSpec {
// Give your base currency a unit name and decimal places
let mut properties = sc_chain_spec::Properties::new();
properties.insert("tokenSymbol".into(), "UNIT".into());
properties.insert("tokenDecimals".into(), 12.into());
ChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Local,
move || {
testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![get_from_seed::<AuraId>("Alice"), get_from_seed::<AuraId>("Bob")],
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
],
id,
)
},
vec![],
None,
None,
None,
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
para_id: id.into(),
},
)
}
pub fn local_testnet_config(id: ParaId) -> ChainSpec {
// Give your base currency a unit name and decimal places
let mut properties = sc_chain_spec::Properties::new();
properties.insert("tokenSymbol".into(), "UNIT".into());
properties.insert("tokenDecimals".into(), 12.into());
ChainSpec::from_genesis(
// Name
"Local Testnet",
// ID
"local_testnet",
ChainType::Local,
move || {
testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![get_from_seed::<AuraId>("Alice"), get_from_seed::<AuraId>("Bob")],
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
],
id,
)
},
Vec::new(),
None,
None,
None,
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
para_id: id.into(),
},
)
}
fn testnet_genesis(
root_key: AccountId,
initial_authorities: Vec<AuraId>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> rialto_parachain_runtime::GenesisConfig {
rialto_parachain_runtime::GenesisConfig {
system: rialto_parachain_runtime::SystemConfig {
code: rialto_parachain_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
},
balances: rialto_parachain_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
},
sudo: rialto_parachain_runtime::SudoConfig { key: root_key },
parachain_info: rialto_parachain_runtime::ParachainInfoConfig { parachain_id: id },
aura: rialto_parachain_runtime::AuraConfig { authorities: initial_authorities },
aura_ext: Default::default(),
// parachain_system: Default::default(),
}
}
@@ -0,0 +1,140 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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::chain_spec;
use std::path::PathBuf;
use structopt::StructOpt;
/// Sub-commands supported by the collator.
#[derive(Debug, StructOpt)]
pub enum Subcommand {
/// Export the genesis state of the parachain.
#[structopt(name = "export-genesis-state")]
ExportGenesisState(ExportGenesisStateCommand),
/// Export the genesis wasm of the parachain.
#[structopt(name = "export-genesis-wasm")]
ExportGenesisWasm(ExportGenesisWasmCommand),
/// Build a chain specification.
BuildSpec(sc_cli::BuildSpecCmd),
/// Validate blocks.
CheckBlock(sc_cli::CheckBlockCmd),
/// Export blocks.
ExportBlocks(sc_cli::ExportBlocksCmd),
/// Export the state of a given block into a chain spec.
ExportState(sc_cli::ExportStateCmd),
/// Import blocks.
ImportBlocks(sc_cli::ImportBlocksCmd),
/// Remove the whole chain.
PurgeChain(cumulus_client_cli::PurgeChainCmd),
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),
/// The custom benchmark subcommmand benchmarking runtime pallets.
#[structopt(name = "benchmark", about = "Benchmark runtime pallets.")]
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
}
/// Command for exporting the genesis state of the parachain
#[derive(Debug, StructOpt)]
pub struct ExportGenesisStateCommand {
/// Output file name or stdout if unspecified.
#[structopt(parse(from_os_str))]
pub output: Option<PathBuf>,
/// Id of the parachain this state is for.
///
/// Default: 100
#[structopt(long, conflicts_with = "chain")]
pub parachain_id: Option<u32>,
/// Write output in binary. Default is to write in hex.
#[structopt(short, long)]
pub raw: bool,
/// The name of the chain for that the genesis state should be exported.
#[structopt(long, conflicts_with = "parachain-id")]
pub chain: Option<String>,
}
/// Command for exporting the genesis wasm file.
#[derive(Debug, StructOpt)]
pub struct ExportGenesisWasmCommand {
/// Output file name or stdout if unspecified.
#[structopt(parse(from_os_str))]
pub output: Option<PathBuf>,
/// Write output in binary. Default is to write in hex.
#[structopt(short, long)]
pub raw: bool,
/// The name of the chain for that the genesis wasm file should be exported.
#[structopt(long)]
pub chain: Option<String>,
}
#[derive(Debug, StructOpt)]
#[structopt(settings = &[
structopt::clap::AppSettings::GlobalVersion,
structopt::clap::AppSettings::ArgsNegateSubcommands,
structopt::clap::AppSettings::SubcommandsNegateReqs,
])]
pub struct Cli {
#[structopt(subcommand)]
pub subcommand: Option<Subcommand>,
#[structopt(long)]
pub parachain_id: Option<u32>,
#[structopt(flatten)]
pub run: cumulus_client_cli::RunCmd,
/// Relaychain arguments
#[structopt(raw = true)]
pub relaychain_args: Vec<String>,
}
#[derive(Debug)]
pub struct RelayChainCli {
/// The actual relay chain cli object.
pub base: polkadot_cli::RunCmd,
/// Optional chain id that should be passed to the relay chain.
pub chain_id: Option<String>,
/// The base path that should be used by the relay chain.
pub base_path: Option<PathBuf>,
}
impl RelayChainCli {
/// Parse the relay chain CLI parameters using the para chain `Configuration`.
pub fn new<'a>(
para_config: &sc_service::Configuration,
relay_chain_args: impl Iterator<Item = &'a String>,
) -> Self {
let extension = chain_spec::Extensions::try_get(&*para_config.chain_spec);
let chain_id = extension.map(|e| e.relay_chain.clone());
let base_path = para_config.base_path.as_ref().map(|x| x.path().join("rialto-bridge-node"));
Self { base_path, chain_id, base: polkadot_cli::RunCmd::from_iter(relay_chain_args) }
}
}
@@ -0,0 +1,424 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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::{
chain_spec,
cli::{Cli, RelayChainCli, Subcommand},
service::{new_partial, ParachainRuntimeExecutor},
};
use codec::Encode;
use cumulus_client_service::genesis::generate_genesis_block;
use cumulus_primitives_core::ParaId;
use log::info;
use polkadot_parachain::primitives::AccountIdConversion;
use rialto_parachain_runtime::{Block, RuntimeApi};
use sc_cli::{
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
};
use sc_service::config::{BasePath, PrometheusConfig};
use sp_core::hexdisplay::HexDisplay;
use sp_runtime::traits::Block as BlockT;
use std::{io::Write, net::SocketAddr};
fn load_spec(
id: &str,
para_id: ParaId,
) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_config(para_id)),
"" | "local" => Box::new(chain_spec::local_testnet_config(para_id)),
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
impl SubstrateCli for Cli {
fn impl_name() -> String {
"Parachain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
format!(
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
passed to the parachain node, while the arguments provided after -- will be passed \
to the relaychain node.\n\n\
{} [parachain-args] -- [relaychain-args]",
Self::executable_name()
)
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/substrate-developer-hub/substrate-parachain-template/issues/new".into()
}
fn copyright_start_year() -> i32 {
2017
}
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
load_spec(id, self.parachain_id.unwrap_or(2000).into())
}
fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {
&rialto_parachain_runtime::VERSION
}
}
impl SubstrateCli for RelayChainCli {
fn impl_name() -> String {
"Parachain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
passed to the parachain node, while the arguments provided after -- will be passed \
to the relaychain node.\n\n\
parachain-collator [parachain-args] -- [relaychain-args]"
.into()
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/substrate-developer-hub/substrate-parachain-template/issues/new".into()
}
fn copyright_start_year() -> i32 {
2017
}
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)
}
fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {
polkadot_cli::Cli::native_runtime_version(chain_spec)
}
}
fn extract_genesis_wasm(chain_spec: &dyn sc_service::ChainSpec) -> Result<Vec<u8>> {
let mut storage = chain_spec.build_storage()?;
storage
.top
.remove(sp_core::storage::well_known_keys::CODE)
.ok_or_else(|| "Could not find wasm file in genesis state!".into())
}
macro_rules! construct_async_run {
(|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{
let runner = $cli.create_runner($cmd)?;
runner.async_run(|$config| {
let $components = new_partial::<
RuntimeApi,
ParachainRuntimeExecutor,
_
>(
&$config,
crate::service::parachain_build_import_queue,
)?;
let task_manager = $components.task_manager;
{ $( $code )* }.map(|v| (v, task_manager))
})
}}
}
/// Parse command line arguments into service configuration.
pub fn run() -> Result<()> {
let cli = Cli::from_args();
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom(
rialto_parachain_runtime::SS58Prefix::get() as u16,
));
match &cli.subcommand {
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
},
Some(Subcommand::CheckBlock(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
},
Some(Subcommand::ExportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| Ok(
cmd.run(components.client, config.database)
))
},
Some(Subcommand::ExportState(cmd)) => {
construct_async_run!(|components, cli, cmd, config| Ok(
cmd.run(components.client, config.chain_spec)
))
},
Some(Subcommand::ImportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
let polkadot_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()),
);
let polkadot_config = SubstrateCli::create_configuration(
&polkadot_cli,
&polkadot_cli,
config.tokio_handle.clone(),
)
.map_err(|err| format!("Relay chain argument error: {}", err))?;
cmd.run(config, polkadot_config)
})
},
Some(Subcommand::Revert(cmd)) => {
construct_async_run!(|components, cli, cmd, config| Ok(
cmd.run(components.client, components.backend)
))
},
Some(Subcommand::ExportGenesisState(params)) => {
let mut builder = sc_cli::LoggerBuilder::new("");
builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
let _ = builder.init();
let block: Block = generate_genesis_block(&load_spec(
&params.chain.clone().unwrap_or_default(),
params.parachain_id.expect("Missing ParaId").into(),
)?)?;
let raw_header = block.header().encode();
let output_buf = if params.raw {
raw_header
} else {
format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()
};
if let Some(output) = &params.output {
std::fs::write(output, output_buf)?;
} else {
std::io::stdout().write_all(&output_buf)?;
}
Ok(())
},
Some(Subcommand::ExportGenesisWasm(params)) => {
let mut builder = sc_cli::LoggerBuilder::new("");
builder.with_profiling(sc_tracing::TracingReceiver::Log, "");
let _ = builder.init();
let raw_wasm_blob =
extract_genesis_wasm(&*cli.load_spec(&params.chain.clone().unwrap_or_default())?)?;
let output_buf = if params.raw {
raw_wasm_blob
} else {
format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()
};
if let Some(output) = &params.output {
std::fs::write(output, output_buf)?;
} else {
std::io::stdout().write_all(&output_buf)?;
}
Ok(())
},
Some(Subcommand::Benchmark(cmd)) =>
if cfg!(feature = "runtime-benchmarks") {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, ParachainRuntimeExecutor>(config))
} else {
Err("Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
.into())
},
None => {
let runner = cli.create_runner(&cli.run.normalize())?;
runner.run_node_until_exit(|config| async move {
let para_id =
chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id);
let polkadot_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()),
);
let id = ParaId::from(cli.parachain_id.or(para_id).expect("Missing ParaId"));
let parachain_account =
AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);
let block: Block =
generate_genesis_block(&config.chain_spec).map_err(|e| format!("{:?}", e))?;
let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));
let polkadot_config = SubstrateCli::create_configuration(
&polkadot_cli,
&polkadot_cli,
config.tokio_handle.clone(),
)
.map_err(|err| format!("Relay chain argument error: {}", err))?;
info!("Parachain id: {:?}", id);
info!("Parachain Account: {}", parachain_account);
info!("Parachain genesis state: {}", genesis_state);
info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
crate::service::start_node(config, polkadot_config, id)
.await
.map(|r| r.0)
.map_err(Into::into)
})
},
}
}
impl DefaultConfigurationValues for RelayChainCli {
fn p2p_listen_port() -> u16 {
30334
}
fn rpc_ws_listen_port() -> u16 {
9945
}
fn rpc_http_listen_port() -> u16 {
9934
}
fn prometheus_listen_port() -> u16 {
9616
}
}
impl CliConfiguration<Self> for RelayChainCli {
fn shared_params(&self) -> &SharedParams {
self.base.base.shared_params()
}
fn import_params(&self) -> Option<&ImportParams> {
self.base.base.import_params()
}
fn network_params(&self) -> Option<&NetworkParams> {
self.base.base.network_params()
}
fn keystore_params(&self) -> Option<&KeystoreParams> {
self.base.base.keystore_params()
}
fn base_path(&self) -> Result<Option<BasePath>> {
Ok(self
.shared_params()
.base_path()
.or_else(|| self.base_path.clone().map(Into::into)))
}
fn rpc_http(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
self.base.base.rpc_http(default_listen_port)
}
fn rpc_ipc(&self) -> Result<Option<String>> {
self.base.base.rpc_ipc()
}
fn rpc_ws(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
self.base.base.rpc_ws(default_listen_port)
}
fn prometheus_config(&self, default_listen_port: u16) -> Result<Option<PrometheusConfig>> {
self.base.base.prometheus_config(default_listen_port)
}
fn init<C: SubstrateCli>(&self) -> Result<()> {
unreachable!("PolkadotCli is never initialized; qed");
}
fn chain_id(&self, is_dev: bool) -> Result<String> {
let chain_id = self.base.base.chain_id(is_dev)?;
Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id })
}
fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
self.base.base.role(is_dev)
}
fn transaction_pool(&self) -> Result<sc_service::config::TransactionPoolOptions> {
self.base.base.transaction_pool()
}
fn state_cache_child_ratio(&self) -> Result<Option<usize>> {
self.base.base.state_cache_child_ratio()
}
fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
self.base.base.rpc_methods()
}
fn rpc_ws_max_connections(&self) -> Result<Option<usize>> {
self.base.base.rpc_ws_max_connections()
}
fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
self.base.base.rpc_cors(is_dev)
}
fn default_heap_pages(&self) -> Result<Option<u64>> {
self.base.base.default_heap_pages()
}
fn force_authoring(&self) -> Result<bool> {
self.base.base.force_authoring()
}
fn disable_grandpa(&self) -> Result<bool> {
self.base.base.disable_grandpa()
}
fn max_runtime_instances(&self) -> Result<Option<usize>> {
self.base.base.max_runtime_instances()
}
fn announce_block(&self) -> Result<bool> {
self.base.base.announce_block()
}
fn telemetry_endpoints(
&self,
chain_spec: &Box<dyn ChainSpec>,
) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
self.base.base.telemetry_endpoints(chain_spec)
}
}
@@ -0,0 +1,18 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
pub mod chain_spec;
pub mod service;
@@ -0,0 +1,29 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Substrate Parachain Node Template CLI
#![warn(missing_docs)]
mod chain_spec;
#[macro_use]
mod service;
mod cli;
mod command;
fn main() -> sc_cli::Result<()> {
command::run()
}
@@ -0,0 +1,493 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
// std
use std::sync::Arc;
// Local Runtime Types
use rialto_parachain_runtime::RuntimeApi;
// Cumulus Imports
use cumulus_client_consensus_aura::{
build_aura_consensus, BuildAuraConsensusParams, SlotProportion,
};
use cumulus_client_consensus_common::ParachainConsensus;
use cumulus_client_network::build_block_announce_validator;
use cumulus_client_service::{
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
};
use cumulus_primitives_core::ParaId;
// Substrate Imports
use sc_client_api::ExecutorProvider;
use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch};
use sc_network::NetworkService;
use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
use sp_api::ConstructRuntimeApi;
use sp_consensus::SlotData;
use sp_keystore::SyncCryptoStorePtr;
use sp_runtime::traits::BlakeTwo256;
use substrate_prometheus_endpoint::Registry;
// Runtime type overrides
type BlockNumber = u32;
type Header = sp_runtime::generic::Header<BlockNumber, sp_runtime::traits::BlakeTwo256>;
pub type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;
type Hash = sp_core::H256;
pub type ParachainRuntimeExecutor = ExecutorDispatch;
// Our native executor instance.
pub struct ExecutorDispatch;
impl NativeExecutionDispatch for ExecutorDispatch {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
rialto_parachain_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
rialto_parachain_runtime::native_version()
}
}
/// Starts a `ServiceBuilder` for a full service.
///
/// Use this macro if you don't actually need the full service, but just the builder in order to
/// be able to perform chain operations.
#[allow(clippy::type_complexity)]
pub fn new_partial<RuntimeApi, Executor, BIQ>(
config: &Configuration,
build_import_queue: BIQ,
) -> Result<
PartialComponents<
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
TFullBackend<Block>,
(),
sc_consensus::DefaultImportQueue<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
>,
sc_transaction_pool::FullPool<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
>,
(Option<Telemetry>, Option<TelemetryWorkerHandle>),
>,
sc_service::Error,
>
where
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>
+ Send
+ Sync
+ 'static,
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::Metadata<Block>
+ sp_session::SessionKeys<Block>
+ sp_api::ApiExt<
Block,
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
> + sp_offchain::OffchainWorkerApi<Block>
+ sp_block_builder::BlockBuilder<Block>,
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
Executor: NativeExecutionDispatch + 'static,
BIQ: FnOnce(
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
&Configuration,
Option<TelemetryHandle>,
&TaskManager,
) -> Result<
sc_consensus::DefaultImportQueue<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
>,
sc_service::Error,
>,
{
let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?;
let telemetry = worker.handle().new_telemetry(endpoints);
Ok((worker, telemetry))
})
.transpose()?;
let executor = sc_executor::NativeElseWasmExecutor::<Executor>::new(
config.wasm_method,
config.default_heap_pages,
config.max_runtime_instances,
);
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, _>(
config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
executor,
)?;
let client = Arc::new(client);
let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle());
let telemetry = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(),
config.role.is_authority().into(),
config.prometheus_registry(),
task_manager.spawn_essential_handle(),
client.clone(),
);
let import_queue = build_import_queue(
client.clone(),
config,
telemetry.as_ref().map(|telemetry| telemetry.handle()),
&task_manager,
)?;
let params = PartialComponents {
backend,
client,
import_queue,
keystore_container,
task_manager,
transaction_pool,
select_chain: (),
other: (telemetry, telemetry_worker_handle),
};
Ok(params)
}
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
///
/// This is the actual implementation that is abstract over the executor and the runtime api.
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_node_impl<RuntimeApi, Executor, RB, BIQ, BIC>(
parachain_config: Configuration,
polkadot_config: Configuration,
id: ParaId,
rpc_ext_builder: RB,
build_import_queue: BIQ,
build_consensus: BIC,
) -> sc_service::error::Result<(
TaskManager,
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
)>
where
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>
+ Send
+ Sync
+ 'static,
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::Metadata<Block>
+ sp_session::SessionKeys<Block>
+ sp_api::ApiExt<
Block,
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
> + sp_offchain::OffchainWorkerApi<Block>
+ sp_block_builder::BlockBuilder<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>,
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
Executor: NativeExecutionDispatch + 'static,
RB: Fn(
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
+ Send
+ 'static,
BIQ: FnOnce(
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
&Configuration,
Option<TelemetryHandle>,
&TaskManager,
) -> Result<
sc_consensus::DefaultImportQueue<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
>,
sc_service::Error,
>,
BIC: FnOnce(
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>,
Option<&Registry>,
Option<TelemetryHandle>,
&TaskManager,
&polkadot_service::NewFull<polkadot_service::Client>,
Arc<
sc_transaction_pool::FullPool<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>,
>,
>,
Arc<NetworkService<Block, Hash>>,
SyncCryptoStorePtr,
bool,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,
{
if matches!(parachain_config.role, Role::Light) {
return Err("Light client not supported!".into())
}
let parachain_config = prepare_node_config(parachain_config);
let params = new_partial::<RuntimeApi, Executor, BIQ>(&parachain_config, build_import_queue)?;
let (mut telemetry, telemetry_worker_handle) = params.other;
let relay_chain_full_node =
cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle)
.map_err(|e| match e {
polkadot_service::Error::Sub(x) => x,
s => format!("{}", s).into(),
})?;
let client = params.client.clone();
let backend = params.backend.clone();
let block_announce_validator = build_block_announce_validator(
relay_chain_full_node.client.clone(),
id,
Box::new(relay_chain_full_node.network.clone()),
relay_chain_full_node.backend.clone(),
);
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
let mut task_manager = params.task_manager;
let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue);
let (network, system_rpc_tx, start_network) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &parachain_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue: import_queue.clone(),
block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)),
warp_sync: None,
})?;
let rpc_client = client.clone();
let rpc_extensions_builder = Box::new(move |_, _| Ok(rpc_ext_builder(rpc_client.clone())));
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
rpc_extensions_builder,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
task_manager: &mut task_manager,
config: parachain_config,
keystore: params.keystore_container.sync_keystore(),
backend: backend.clone(),
network: network.clone(),
system_rpc_tx,
telemetry: telemetry.as_mut(),
})?;
let announce_block = {
let network = network.clone();
Arc::new(move |hash, data| network.announce_block(hash, data))
};
if validator {
let parachain_consensus = build_consensus(
client.clone(),
prometheus_registry.as_ref(),
telemetry.as_ref().map(|t| t.handle()),
&task_manager,
&relay_chain_full_node,
transaction_pool,
network,
params.keystore_container.sync_keystore(),
force_authoring,
)?;
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id: id,
block_status: client.clone(),
announce_block,
client: client.clone(),
task_manager: &mut task_manager,
relay_chain_full_node,
spawner,
parachain_consensus,
import_queue,
};
start_collator(params).await?;
} else {
let params = StartFullNodeParams {
client: client.clone(),
announce_block,
task_manager: &mut task_manager,
para_id: id,
relay_chain_full_node,
};
start_full_node(params)?;
}
start_network.start_network();
Ok((task_manager, client))
}
/// Build the import queue for the the parachain runtime.
#[allow(clippy::type_complexity)]
pub fn parachain_build_import_queue(
client: Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ParachainRuntimeExecutor>>>,
config: &Configuration,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
) -> Result<
sc_consensus::DefaultImportQueue<
Block,
TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ParachainRuntimeExecutor>>,
>,
sc_service::Error,
> {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
cumulus_client_consensus_aura::import_queue::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
>(cumulus_client_consensus_aura::ImportQueueParams {
block_import: client.clone(),
client: client.clone(),
create_inherent_data_providers: move |_, _| async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*time,
slot_duration.slot_duration(),
);
Ok((time, slot))
},
registry: config.prometheus_registry(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
spawner: &task_manager.spawn_essential_handle(),
telemetry,
})
.map_err(Into::into)
}
/// Start a normal parachain node.
pub async fn start_node(
parachain_config: Configuration,
polkadot_config: Configuration,
id: ParaId,
) -> sc_service::error::Result<(
TaskManager,
Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ParachainRuntimeExecutor>>>,
)> {
start_node_impl::<RuntimeApi, ParachainRuntimeExecutor, _, _, _>(
parachain_config,
polkadot_config,
id,
|_| Default::default(),
parachain_build_import_queue,
|client,
prometheus_registry,
telemetry,
task_manager,
relay_chain_node,
transaction_pool,
sync_oracle,
keystore,
force_authoring| {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry,
telemetry.clone(),
);
let relay_chain_backend = relay_chain_node.backend.clone();
let relay_chain_client = relay_chain_node.client.clone();
Ok(build_aura_consensus::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
_,
_,
_,
>(BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client(
relay_parent,
&relay_chain_client,
&*relay_chain_backend,
&validation_data,
id,
);
async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*time,
slot_duration.slot_duration(),
);
let parachain_inherent = parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((time, slot, parachain_inherent))
}
},
block_import: client.clone(),
relay_chain_client: relay_chain_node.client.clone(),
relay_chain_backend: relay_chain_node.backend.clone(),
para_client: client,
backoff_authoring_blocks: Option::<()>::None,
sync_oracle,
keystore,
force_authoring,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
telemetry,
max_block_proposal_slot_portion: None,
}))
},
)
.await
}
@@ -0,0 +1,122 @@
[package]
name = "rialto-parachain-runtime"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
[dependencies]
codec = { package = 'parity-scale-codec', version = '2.0.0', default-features = false, features = ['derive']}
log = { version = "0.4.14", default-features = false }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = '1.0', optional = true, features = ['derive'] }
# Bridge depedencies
bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false }
# Substrate Dependencies
## Substrate Primitive Dependencies
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
## Substrate FRAME Dependencies
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
## Substrate Pallet Dependencies
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Cumulus Dependencies
cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false }
# Polkadot Dependencies
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
[features]
default = ['std']
runtime-benchmarks = [
'sp-runtime/runtime-benchmarks',
'frame-benchmarking',
'frame-support/runtime-benchmarks',
'frame-system-benchmarking',
'frame-system/runtime-benchmarks',
'pallet-balances/runtime-benchmarks',
'pallet-timestamp/runtime-benchmarks',
]
std = [
"bp-rialto-parachain/std",
"codec/std",
"log/std",
"scale-info/std",
"serde",
"sp-api/std",
"sp-std/std",
"sp-io/std",
"sp-core/std",
"sp-runtime/std",
"sp-version/std",
"sp-offchain/std",
"sp-session/std",
"sp-block-builder/std",
"sp-transaction-pool/std",
"sp-inherents/std",
"frame-support/std",
"frame-executive/std",
"frame-system/std",
"pallet-balances/std",
"pallet-randomness-collective-flip/std",
"pallet-timestamp/std",
"pallet-sudo/std",
"pallet-transaction-payment/std",
"parachain-info/std",
"cumulus-pallet-aura-ext/std",
"cumulus-pallet-parachain-system/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-pallet-xcm/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"xcm/std",
"xcm-builder/std",
"xcm-executor/std",
"pallet-aura/std",
"sp-consensus-aura/std",
]
@@ -0,0 +1,25 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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 substrate_wasm_builder::WasmBuilder;
fn main() {
WasmBuilder::new()
.with_current_project()
.export_heap_base()
.import_memory()
.build()
}
@@ -0,0 +1,646 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! The Rialto parachain runtime. This can be compiled with `#[no_std]`, ready for Wasm.
//!
//! Originally a copy of runtime from https://github.com/substrate-developer-hub/substrate-parachain-template.
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, Block as BlockT},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult,
};
use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
// A few exports that help ease life for downstream crates.
pub use frame_support::{
construct_runtime, match_type, parameter_types,
traits::{Everything, IsInVec, Randomness},
weights::{
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
DispatchClass, IdentityFee, Weight,
},
StorageValue,
};
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{MultiAddress, Perbill, Permill};
pub use bp_rialto_parachain::{
AccountId, Balance, BlockLength, BlockNumber, BlockWeights, Hash, Hasher as Hashing, Header,
Index, Signature, MAXIMUM_BLOCK_WEIGHT,
};
// Polkadot & XCM imports
use pallet_xcm::XcmPassthrough;
use polkadot_parachain::primitives::Sibling;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset,
ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
};
use xcm_executor::{Config, XcmExecutor};
/// The address format for describing accounts.
pub type Address = MultiAddress<AccountId, ()>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
/// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPallets,
>;
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
}
}
/// This runtime version.
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("template-parachain"),
impl_name: create_runtime_str!("template-parachain"),
authoring_version: 1,
spec_version: 1,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
};
/// This determines the average expected block time that we are targeting.
/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
/// up by `pallet_aura` to implement `fn slot_duration()`.
///
/// Change this to adjust the block time.
pub const MILLISECS_PER_BLOCK: u64 = 12000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES;
// Time is measured by number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
// Unit = the base number of indivisible units for balances
pub const UNIT: Balance = 1_000_000_000_000;
pub const MILLIUNIT: Balance = 1_000_000_000;
pub const MICROUNIT: Balance = 1_000_000;
// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks.
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
parameter_types! {
pub const BlockHashCount: BlockNumber = 250;
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u8 = 48;
}
// Configure FRAME pallets to include in runtime.
impl frame_system::Config for Runtime {
/// The identifier used to distinguish between accounts.
type AccountId = AccountId;
/// The aggregated dispatch type that is available for extrinsics.
type Call = Call;
/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
type Lookup = AccountIdLookup<AccountId, ()>;
/// The index type for storing how many extrinsics an account has signed.
type Index = Index;
/// The index type for blocks.
type BlockNumber = BlockNumber;
/// The type for hashing blocks and tries.
type Hash = Hash;
/// The hashing algorithm used.
type Hashing = Hashing;
/// The header type.
type Header = generic::Header<BlockNumber, Hashing>;
/// The ubiquitous event type.
type Event = Event;
/// The ubiquitous origin type.
type Origin = Origin;
/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
type BlockHashCount = BlockHashCount;
/// Runtime version.
type Version = Version;
/// Converts a module to an index of this module in the runtime.
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
/// What to do if a new account is created.
type OnNewAccount = ();
/// What to do if an account is fully reaped from the system.
type OnKilledAccount = ();
/// The weight of database operations that the runtime can invoke.
type DbWeight = ();
/// The basic call filter to use in dispatchable.
type BaseCallFilter = Everything;
/// Weight information for the extrinsics of this pallet.
type SystemWeightInfo = ();
/// Block & extrinsics weights: base values and limits.
type BlockWeights = BlockWeights;
/// The maximum length of a block (in bytes).
type BlockLength = BlockLength;
/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
type SS58Prefix = SS58Prefix;
/// The action to take on a Runtime Upgrade
type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
}
parameter_types! {
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
}
impl pallet_timestamp::Config for Runtime {
/// A timestamp: milliseconds since the Unix epoch.
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = MinimumPeriod;
type WeightInfo = ();
}
parameter_types! {
pub const ExistentialDeposit: u128 = MILLIUNIT;
pub const TransferFee: u128 = MILLIUNIT;
pub const CreationFee: u128 = MILLIUNIT;
pub const TransactionByteFee: u128 = MICROUNIT;
pub const OperationalFeeMultiplier: u8 = 5;
pub const MaxLocks: u32 = 50;
pub const MaxReserves: u32 = 50;
}
impl pallet_balances::Config for Runtime {
/// The type for recording an account's balance.
type Balance = Balance;
/// The ubiquitous event type.
type Event = Event;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
type MaxLocks = MaxLocks;
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
}
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>;
type TransactionByteFee = TransactionByteFee;
type OperationalFeeMultiplier = OperationalFeeMultiplier;
type WeightToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
}
impl pallet_sudo::Config for Runtime {
type Call = Call;
type Event = Event;
}
parameter_types! {
pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
}
impl cumulus_pallet_parachain_system::Config for Runtime {
type Event = Event;
type OnValidationData = ();
type SelfParaId = parachain_info::Pallet<Runtime>;
type OutboundXcmpMessageSource = XcmpQueue;
type DmpMessageHandler = DmpQueue;
type ReservedDmpWeight = ReservedDmpWeight;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
}
impl parachain_info::Config for Runtime {}
impl cumulus_pallet_aura_ext::Config for Runtime {}
impl pallet_randomness_collective_flip::Config for Runtime {}
parameter_types! {
pub const RelayLocation: MultiLocation = MultiLocation::parent();
pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
}
/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
/// `Transact` in order to determine the dispatch Origin.
pub type LocationToAccountId = (
// The parent (Relay-chain) origin converts to the default `AccountId`.
ParentIsDefault<AccountId>,
// Sibling parachain origins convert to AccountId via the `ParaId::into`.
SiblingParachainConvertsVia<Sibling, AccountId>,
// Straight up local `AccountId32` origins just alias directly to `AccountId`.
AccountId32Aliases<RelayNetwork, AccountId>,
);
/// Means for transacting assets on this chain.
pub type LocalAssetTransactor = CurrencyAdapter<
// Use this currency:
Balances,
// Use this currency when it is a fungible asset matching the given location or name:
IsConcrete<RelayLocation>,
// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
LocationToAccountId,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
AccountId,
// We don't track any teleports.
(),
>;
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
/// ready for dispatching a transaction with XCM `Transact`. There is an `OriginKind` which can
/// biases the kind of local `Origin` it will become.
pub type XcmOriginToTransactDispatchOrigin = (
// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
// foreign chains who want to have a local sovereign account on this chain which they control.
SovereignSignedViaLocation<LocationToAccountId, Origin>,
// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
// recognised.
RelayChainAsNative<RelayOrigin, Origin>,
// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
// recognised.
SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
// transaction from the Root origin.
ParentAsSuperuser<Origin>,
// Native signed account converter; this just converts an `AccountId32` origin into a normal
// `Origin::Signed` origin of the same 32-byte value.
SignedAccountId32AsNative<RelayNetwork, Origin>,
// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
XcmPassthrough<Origin>,
);
parameter_types! {
// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
pub UnitWeightCost: Weight = 1_000_000;
// One UNIT buys 1 second of weight.
pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), UNIT);
pub const MaxInstructions: u32 = 100;
pub const MaxAuthorities: u32 = 100_000;
}
match_type! {
pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
MultiLocation { parents: 1, interior: Here } |
MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
};
}
pub type Barrier = (
TakeWeightCredit,
AllowTopLevelPaidExecutionFrom<Everything>,
AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,
// ^^^ Parent & its unit plurality gets free execution
);
pub struct XcmConfig;
impl Config for XcmConfig {
type Call = Call;
type XcmSender = XcmRouter;
// How to withdraw and deposit an asset.
type AssetTransactor = LocalAssetTransactor;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
type IsReserve = NativeAsset;
type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of UNIT
type LocationInverter = LocationInverter<Ancestry>;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
type Trader = UsingComponents<IdentityFee<Balance>, RelayLocation, AccountId, Balances, ()>;
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetClaims = PolkadotXcm;
type SubscriptionService = PolkadotXcm;
}
/// No local origins on this chain are allowed to dispatch XCM sends/executions.
pub type LocalOriginToLocation = SignedToAccountId32<Origin, AccountId, RelayNetwork>;
/// The means for routing XCM messages which are not for local execution into the right message
/// queues.
pub type XcmRouter = (
// Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
// ..and XCMP to communicate with the sibling chains.
XcmpQueue,
);
impl pallet_xcm::Config for Runtime {
type Event = Event;
type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
type XcmExecuteFilter = Everything;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Everything;
type XcmReserveTransferFilter = Everything;
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
type LocationInverter = LocationInverter<Ancestry>;
type Origin = Origin;
type Call = Call;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
}
impl cumulus_pallet_xcm::Config for Runtime {
type Event = Event;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
impl cumulus_pallet_xcmp_queue::Config for Runtime {
type Event = Event;
type XcmExecutor = XcmExecutor<XcmConfig>;
type ChannelInfo = ParachainSystem;
type VersionWrapper = ();
}
impl cumulus_pallet_dmp_queue::Config for Runtime {
type Event = Event;
type XcmExecutor = XcmExecutor<XcmConfig>;
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
}
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
type DisabledValidators = ();
type MaxAuthorities = MaxAuthorities;
}
// /// Configure the pallet template in pallets/template.
// impl template::Config for Runtime {
// type Event = Event;
// }
// Create the runtime by composing the FRAME pallets that were previously configured.
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = generic::Block<Header, sp_runtime::OpaqueExtrinsic>,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event<T>} = 20,
ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
Aura: pallet_aura::{Pallet, Config<T>},
AuraExt: cumulus_pallet_aura_ext::{Pallet, Config},
// XCM helpers.
XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
// //Template
// TemplatePallet: template::{Pallet, Call, Storage, Event<T>},
}
);
impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn execute_block(block: Block) {
Executive::execute_block(block)
}
fn initialize_block(header: &<Block as BlockT>::Header) {
Executive::initialize_block(header)
}
}
impl sp_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
OpaqueMetadata::new(Runtime::metadata().into())
}
}
impl sp_block_builder::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(
extrinsic: <Block as BlockT>::Extrinsic,
) -> ApplyExtrinsicResult {
Executive::apply_extrinsic(extrinsic)
}
fn finalize_block() -> <Block as BlockT>::Header {
Executive::finalize_block()
}
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics()
}
fn check_inherents(
block: Block,
data: sp_inherents::InherentData,
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
tx: <Block as BlockT>::Extrinsic,
block_hash: <Block as BlockT>::Hash,
) -> TransactionValidity {
Executive::validate_transaction(source, tx, block_hash)
}
}
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &<Block as BlockT>::Header) {
Executive::offchain_worker(header)
}
}
impl sp_session::SessionKeys<Block> for Runtime {
fn decode_session_keys(
encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
SessionKeys::decode_into_raw_public_keys(&encoded)
}
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
SessionKeys::generate(seed)
}
}
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
}
fn authorities() -> Vec<AuraId> {
Aura::authorities().to_vec()
}
}
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
fn collect_collation_info() -> cumulus_primitives_core::CollationInfo {
ParachainSystem::collect_collation_info()
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
fn account_nonce(account: AccountId) -> Index {
System::account_nonce(account)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
fn query_info(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_info(uxt, len)
}
fn query_fee_details(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_fee_details(uxt, len)
}
}
#[cfg(feature = "runtime-benchmarks")]
impl frame_benchmarking::Benchmark<Block> for Runtime {
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
use frame_system_benchmarking::Pallet as SystemBench;
impl frame_system_benchmarking::Config for Runtime {}
let whitelist: Vec<TrackedStorageKey> = vec![
// Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
// Total Issuance
hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
// Execution Phase
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
// Event Count
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
// System Events
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
];
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
add_benchmark!(params, batches, frame_system, SystemBench::<Runtime>);
add_benchmark!(params, batches, pallet_balances, Balances);
add_benchmark!(params, batches, pallet_timestamp, Timestamp);
if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches)
}
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block!(
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
);
+63 -5
View File
@@ -10,13 +10,17 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
jsonrpc-core = "15.1.0"
futures = "0.3"
jsonrpc-core = "18.0"
kvdb = "0.10"
kvdb-rocksdb = "0.12"
lru = "0.7"
structopt = "0.3.21"
serde_json = "1.0.59"
thiserror = "1.0"
# Bridge dependencies
bp-messages = { path = "../../../primitives/messages" }
bp-runtime = { path = "../../../primitives/runtime" }
bp-rialto = { path = "../../../primitives/chain-rialto" }
pallet-bridge-messages = { path = "../../../modules/messages" }
@@ -24,32 +28,86 @@ rialto-runtime = { path = "../runtime" }
# Substrate Dependencies
beefy-gadget = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-gadget-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["wasmtime"] }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-consensus-uncles = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
#sc-finality-grandpa-warp-sync = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Polkadot Dependencies
polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
# Polkadot (parachain) Dependencies
polkadot-approval-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-availability-bitfield-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-availability-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-availability-recovery = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-collator-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-dispute-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-gossip-support = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-network-bridge = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-collation-generation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-approval-voting = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-av-store = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-backing = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-bitfield-signing = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-candidate-validation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-chain-api = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-chain-selection = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-parachains-inherent = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-provisioner = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-runtime-api = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-core-dispute-coordinator = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-network-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-subsystem-util = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-statement-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
[build-dependencies]
substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -14,13 +14,17 @@
// 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 beefy_primitives::crypto::AuthorityId as BeefyId;
use bp_rialto::derive_account_from_millau_id;
use polkadot_primitives::v1::{AssignmentId, ValidatorId};
use rialto_runtime::{
AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeRialtoPoaConfig, GenesisConfig, GrandpaConfig,
SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig,
ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature,
SudoConfig, SystemConfig, WASM_BINARY,
};
use serde_json::json;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_consensus_babe::AuthorityId as BabeId;
use sp_core::{sr25519, Pair, Public};
use sp_finality_grandpa::AuthorityId as GrandpaId;
use sp_runtime::traits::{IdentifyAccount, Verify};
@@ -56,12 +60,18 @@ where
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
/// Helper function to generate an authority key for Aura
pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
/// Helper function to generate authority keys.
pub fn get_authority_keys_from_seed(
s: &str,
) -> (AccountId, BabeId, BeefyId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
(
get_account_id_from_seed::<sr25519::Public>(s),
get_from_seed::<AuraId>(s),
get_from_seed::<BabeId>(s),
get_from_seed::<BeefyId>(s),
get_from_seed::<GrandpaId>(s),
get_from_seed::<ValidatorId>(s),
get_from_seed::<AssignmentId>(s),
get_from_seed::<AuthorityDiscoveryId>(s),
)
}
@@ -71,10 +81,7 @@ impl Alternative {
let properties = Some(
json!({
"tokenDecimals": 9,
"tokenSymbol": "RLT",
"bridgeIds": {
"Millau": bp_runtime::MILLAU_CHAIN_ID,
}
"tokenSymbol": "RLT"
})
.as_object()
.expect("Map given; qed")
@@ -82,8 +89,8 @@ impl Alternative {
);
match self {
Alternative::Development => ChainSpec::from_genesis(
"Development",
"dev",
"Rialto Development",
"rialto_dev",
sc_service::ChainType::Development,
|| {
testnet_genesis(
@@ -108,8 +115,8 @@ impl Alternative {
None,
),
Alternative::LocalTestnet => ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
"Rialto Local",
"rialto_local",
sc_service::ChainType::Local,
|| {
testnet_genesis(
@@ -138,10 +145,12 @@ impl Alternative {
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
get_account_id_from_seed::<sr25519::Public>("George//stash"),
get_account_id_from_seed::<sr25519::Public>("Harry//stash"),
pallet_bridge_messages::Pallet::<
rialto_runtime::Runtime,
pallet_bridge_messages::DefaultInstance,
>::relayer_fund_account_id(),
get_account_id_from_seed::<sr25519::Public>("MillauMessagesOwner"),
get_account_id_from_seed::<sr25519::Public>("WithMillauTokenSwap"),
pallet_bridge_messages::relayer_fund_account_id::<
bp_rialto::AccountId,
bp_rialto::AccountIdConverter,
>(),
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
get_account_id_from_seed::<sr25519::Public>("Alice"),
)),
@@ -174,12 +183,27 @@ impl Alternative {
}
}
fn session_keys(aura: AuraId, grandpa: GrandpaId) -> SessionKeys {
SessionKeys { aura, grandpa }
fn session_keys(
babe: BabeId,
beefy: BeefyId,
grandpa: GrandpaId,
para_validator: ValidatorId,
para_assignment: AssignmentId,
authority_discovery: AuthorityDiscoveryId,
) -> SessionKeys {
SessionKeys { babe, beefy, grandpa, para_validator, para_assignment, authority_discovery }
}
fn testnet_genesis(
initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>,
initial_authorities: Vec<(
AccountId,
BabeId,
BeefyId,
GrandpaId,
ValidatorId,
AssignmentId,
AuthorityDiscoveryId,
)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
@@ -187,51 +211,93 @@ fn testnet_genesis(
GenesisConfig {
system: SystemConfig {
code: WASM_BINARY.expect("Rialto development WASM not available").to_vec(),
changes_trie_config: Default::default(),
},
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
},
aura: AuraConfig {
authorities: Vec::new(),
},
bridge_rialto_poa: load_rialto_poa_bridge_config(),
bridge_kovan: load_kovan_bridge_config(),
grandpa: GrandpaConfig {
babe: BabeConfig {
authorities: Vec::new(),
epoch_config: Some(rialto_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
beefy: BeefyConfig { authorities: Vec::new() },
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
keys: initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone())))
.map(|x| {
(
x.0.clone(),
x.0.clone(),
session_keys(
x.1.clone(),
x.2.clone(),
x.3.clone(),
x.4.clone(),
x.5.clone(),
x.6.clone(),
),
)
})
.collect::<Vec<_>>(),
},
}
}
fn load_rialto_poa_bridge_config() -> BridgeRialtoPoaConfig {
BridgeRialtoPoaConfig {
initial_header: rialto_runtime::rialto_poa::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: rialto_runtime::rialto_poa::genesis_validators(),
}
}
fn load_kovan_bridge_config() -> BridgeKovanConfig {
BridgeKovanConfig {
initial_header: rialto_runtime::kovan::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: rialto_runtime::kovan::genesis_validators(),
authority_discovery: Default::default(),
hrmp: Default::default(),
// this configuration is exact copy of configuration from Polkadot repo
// (see /node/service/src/chain_spec.rs:default_parachains_host_configuration)
configuration: ConfigurationConfig {
config: polkadot_runtime_parachains::configuration::HostConfiguration {
validation_upgrade_frequency: 1u32,
validation_upgrade_delay: 1,
code_retention_period: 1200,
max_code_size: polkadot_primitives::v1::MAX_CODE_SIZE,
max_pov_size: polkadot_primitives::v1::MAX_POV_SIZE,
max_head_data_size: 32 * 1024,
group_rotation_frequency: 20,
chain_availability_period: 4,
thread_availability_period: 4,
max_upward_queue_count: 8,
max_upward_queue_size: 1024 * 1024,
max_downward_message_size: 1024,
// this is approximatelly 4ms.
//
// Same as `4 * frame_support::weights::WEIGHT_PER_MILLIS`. We don't bother with
// an import since that's a made up number and should be replaced with a constant
// obtained by benchmarking anyway.
ump_service_total_weight: 4 * 1_000_000_000,
max_upward_message_size: 1024 * 1024,
max_upward_message_num_per_candidate: 5,
hrmp_sender_deposit: 0,
hrmp_recipient_deposit: 0,
hrmp_channel_max_capacity: 8,
hrmp_channel_max_total_size: 8 * 1024,
hrmp_max_parachain_inbound_channels: 4,
hrmp_max_parathread_inbound_channels: 4,
hrmp_channel_max_message_size: 1024 * 1024,
hrmp_max_parachain_outbound_channels: 4,
hrmp_max_parathread_outbound_channels: 4,
hrmp_max_message_num_per_candidate: 5,
dispute_period: 6,
no_show_slots: 2,
n_delay_tranches: 25,
needed_approvals: 2,
relay_vrf_modulo_samples: 2,
zeroth_delay_tranche_width: 0,
..Default::default()
},
},
paras: Default::default(),
bridge_millau_messages: BridgeMillauMessagesConfig {
owner: Some(get_account_id_from_seed::<sr25519::Public>("MillauMessagesOwner")),
..Default::default()
},
}
}
#[test]
fn derived_dave_account_is_as_expected() {
let dave = get_account_id_from_seed::<sr25519::Public>("Dave");
let derived: AccountId = derive_account_from_millau_id(bp_runtime::SourceAccount::Account(dave));
assert_eq!(
derived.to_string(),
"5HZhdv53gSJmWWtD8XR5Ypu4PgbT5JNWwGw2mkE75cN61w9t".to_string()
);
let derived: AccountId =
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(dave));
assert_eq!(derived.to_string(), "5HZhdv53gSJmWWtD8XR5Ypu4PgbT5JNWwGw2mkE75cN61w9t".to_string());
}
+17 -2
View File
@@ -29,10 +29,10 @@ pub struct Cli {
/// Possible subcommands of the main binary.
#[derive(Debug, StructOpt)]
pub enum Subcommand {
/// Key management cli utilities
/// Key management CLI utilities
Key(sc_cli::KeySubcommand),
/// Verify a signature for a message, provided on STDIN, with a given (public or secret) key.
/// Verify a signature for a message, provided on `STDIN`, with a given (public or secret) key.
Verify(sc_cli::VerifyCmd),
/// Generate a seed that provides a vanity address.
@@ -67,4 +67,19 @@ pub enum Subcommand {
/// Benchmark runtime pallets.
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
/// FOR INTERNAL USE: analog of the "prepare-worker" command of the polkadot binary.
#[structopt(name = "prepare-worker", setting = structopt::clap::AppSettings::Hidden)]
PvfPrepareWorker(ValidationWorkerCommand),
/// FOR INTERNAL USE: analog of the "execute-worker" command of the polkadot binary.
#[structopt(name = "execute-worker", setting = structopt::clap::AppSettings::Hidden)]
PvfExecuteWorker(ValidationWorkerCommand),
}
/// Validation worker command.
#[derive(Debug, StructOpt)]
pub struct ValidationWorkerCommand {
/// The path to the validation host's socket.
pub socket_path: String,
}
+75 -55
View File
@@ -14,9 +14,10 @@
// 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::cli::{Cli, Subcommand};
use crate::service;
use crate::service::new_partial;
use crate::{
cli::{Cli, Subcommand},
service::new_partial,
};
use rialto_runtime::{Block, RuntimeApi};
use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
use sc_service::PartialComponents;
@@ -69,24 +70,23 @@ impl SubstrateCli for Cli {
/// Parse and run command line arguments
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::Custom(
sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom(
rialto_runtime::SS58Prefix::get() as u16,
));
match &cli.subcommand {
Some(Subcommand::Benchmark(cmd)) => {
Some(Subcommand::Benchmark(cmd)) =>
if cfg!(feature = "runtime-benchmarks") {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
runner.sync_run(|config| cmd.run::<Block, crate::service::ExecutorDispatch>(config))
} else {
println!(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
);
Ok(())
}
}
},
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
Some(Subcommand::Sign(cmd)) => cmd.run(),
Some(Subcommand::Verify(cmd)) => cmd.run(),
@@ -94,79 +94,99 @@ pub fn run() -> sc_cli::Result<()> {
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
}
},
Some(Subcommand::CheckBlock(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
import_queue,
..
} = new_partial(&config)?;
runner.async_run(|mut config| {
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&mut config).map_err(service_error)?;
Ok((cmd.run(client, import_queue), task_manager))
})
}
},
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client, task_manager, ..
} = new_partial(&config)?;
runner.async_run(|mut config| {
let PartialComponents { client, task_manager, .. } =
new_partial(&mut config).map_err(service_error)?;
Ok((cmd.run(client, config.database), task_manager))
})
}
},
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client, task_manager, ..
} = new_partial(&config)?;
runner.async_run(|mut config| {
let PartialComponents { client, task_manager, .. } =
new_partial(&mut config).map_err(service_error)?;
Ok((cmd.run(client, config.chain_spec), task_manager))
})
}
},
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
import_queue,
..
} = new_partial(&config)?;
runner.async_run(|mut config| {
let PartialComponents { client, task_manager, import_queue, .. } =
new_partial(&mut config).map_err(service_error)?;
Ok((cmd.run(client, import_queue), task_manager))
})
}
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.database))
}
},
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents {
client,
task_manager,
backend,
..
} = new_partial(&config)?;
runner.async_run(|mut config| {
let PartialComponents { client, task_manager, backend, .. } =
new_partial(&mut config).map_err(service_error)?;
Ok((cmd.run(client, backend), task_manager))
})
}
},
Some(Subcommand::Inspect(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block, RuntimeApi, service::Executor>(config))
}
runner.sync_run(|config| {
cmd.run::<Block, RuntimeApi, crate::service::ExecutorDispatch>(config)
})
},
Some(Subcommand::PvfPrepareWorker(cmd)) => {
let mut builder = sc_cli::LoggerBuilder::new("");
builder.with_colors(false);
let _ = builder.init();
polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path);
Ok(())
},
Some(crate::cli::Subcommand::PvfExecuteWorker(cmd)) => {
let mut builder = sc_cli::LoggerBuilder::new("");
builder.with_colors(false);
let _ = builder.init();
polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path);
Ok(())
},
None => {
let runner = cli.create_runner(&cli.run)?;
runner
.run_node_until_exit(|config| async move {
match config.role {
Role::Light => service::new_light(config),
_ => service::new_full(config),
}
})
.map_err(sc_cli::Error::Service)
}
// some parameters that are used by polkadot nodes, but that are not used by our binary
// let jaeger_agent = None;
// let grandpa_pause = None;
// let no_beefy = true;
// let telemetry_worker_handler = None;
// let is_collator = crate::service::IsCollator::No;
let overseer_gen = crate::overseer::RealOverseerGen;
runner.run_node_until_exit(|config| async move {
match config.role {
Role::Light => Err(sc_cli::Error::Service(sc_service::Error::Other(
"Light client is not supported by this node".into(),
))),
_ => crate::service::build_full(config, overseer_gen)
.map(|full| full.task_manager)
.map_err(service_error),
}
})
},
}
}
// We don't want to change 'service.rs' too much to ease future updates => it'll keep using
// its own error enum like original polkadot service does.
fn service_error(err: crate::service::Error) -> sc_cli::Error {
sc_cli::Error::Application(Box::new(err))
}
@@ -23,6 +23,8 @@ mod chain_spec;
mod service;
mod cli;
mod command;
mod overseer;
mod parachains_db;
/// Run the Rialto Node
fn main() -> sc_cli::Result<()> {
@@ -0,0 +1,316 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! This is almost 1:1 copy of `node/service/src/overseer.rs` file from Polkadot repository.
//! The only exception is that we don't support db upgrades => no `upgrade.rs` module.
// this warning comes from `polkadot_overseer::AllSubsystems` type
#![allow(clippy::type_complexity)]
use crate::service::{AuthorityDiscoveryApi, Error};
use rialto_runtime::{opaque::Block, Hash};
use lru::LruCache;
use polkadot_availability_distribution::IncomingRequestReceivers;
use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig;
use polkadot_node_core_av_store::Config as AvailabilityConfig;
use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
use polkadot_node_core_chain_selection::Config as ChainSelectionConfig;
use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig;
use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver};
use polkadot_overseer::{
metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, OverseerBuilder,
OverseerConnector, OverseerHandle,
};
use polkadot_primitives::v1::ParachainHost;
use sc_authority_discovery::Service as AuthorityDiscoveryService;
use sc_client_api::AuxStore;
use sc_keystore::LocalKeystore;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_consensus_babe::BabeApi;
use sp_core::traits::SpawnNamed;
use std::sync::Arc;
use substrate_prometheus_endpoint::Registry;
pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem;
pub use polkadot_availability_bitfield_distribution::BitfieldDistribution as BitfieldDistributionSubsystem;
pub use polkadot_availability_distribution::AvailabilityDistributionSubsystem;
pub use polkadot_availability_recovery::AvailabilityRecoverySubsystem;
pub use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide};
pub use polkadot_dispute_distribution::DisputeDistributionSubsystem;
pub use polkadot_gossip_support::GossipSupport as GossipSupportSubsystem;
pub use polkadot_network_bridge::NetworkBridge as NetworkBridgeSubsystem;
pub use polkadot_node_collation_generation::CollationGenerationSubsystem;
pub use polkadot_node_core_approval_voting::ApprovalVotingSubsystem;
pub use polkadot_node_core_av_store::AvailabilityStoreSubsystem;
pub use polkadot_node_core_backing::CandidateBackingSubsystem;
pub use polkadot_node_core_bitfield_signing::BitfieldSigningSubsystem;
pub use polkadot_node_core_candidate_validation::CandidateValidationSubsystem;
pub use polkadot_node_core_chain_api::ChainApiSubsystem;
pub use polkadot_node_core_chain_selection::ChainSelectionSubsystem;
pub use polkadot_node_core_dispute_coordinator::DisputeCoordinatorSubsystem;
pub use polkadot_node_core_provisioner::ProvisionerSubsystem;
pub use polkadot_node_core_runtime_api::RuntimeApiSubsystem;
pub use polkadot_statement_distribution::StatementDistribution as StatementDistributionSubsystem;
/// Arguments passed for overseer construction.
pub struct OverseerGenArgs<'a, Spawner, RuntimeClient>
where
RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Spawner: 'static + SpawnNamed + Clone + Unpin,
{
/// Set of initial relay chain leaves to track.
pub leaves: Vec<BlockInfo>,
/// The keystore to use for i.e. validator keys.
pub keystore: Arc<LocalKeystore>,
/// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others.
pub runtime_client: Arc<RuntimeClient>,
/// The underlying key value store for the parachains.
pub parachains_db: Arc<dyn kvdb::KeyValueDB>,
/// Underlying network service implementation.
pub network_service: Arc<sc_network::NetworkService<Block, Hash>>,
/// Underlying authority discovery service.
pub authority_discovery_service: AuthorityDiscoveryService,
/// POV request receiver
pub pov_req_receiver: IncomingRequestReceiver<request_v1::PoVFetchingRequest>,
pub chunk_req_receiver: IncomingRequestReceiver<request_v1::ChunkFetchingRequest>,
pub collation_req_receiver: IncomingRequestReceiver<request_v1::CollationFetchingRequest>,
pub available_data_req_receiver:
IncomingRequestReceiver<request_v1::AvailableDataFetchingRequest>,
pub statement_req_receiver: IncomingRequestReceiver<request_v1::StatementFetchingRequest>,
pub dispute_req_receiver: IncomingRequestReceiver<request_v1::DisputeRequest>,
/// Prometheus registry, commonly used for production systems, less so for test.
pub registry: Option<&'a Registry>,
/// Task spawner to be used throughout the overseer and the APIs it provides.
pub spawner: Spawner,
/// Configuration for the approval voting subsystem.
pub approval_voting_config: ApprovalVotingConfig,
/// Configuration for the availability store subsystem.
pub availability_config: AvailabilityConfig,
/// Configuration for the candidate validation subsystem.
pub candidate_validation_config: CandidateValidationConfig,
/// Configuration for the chain selection subsystem.
pub chain_selection_config: ChainSelectionConfig,
/// Configuration for the dispute coordinator subsystem.
pub dispute_coordinator_config: DisputeCoordinatorConfig,
}
/// Obtain a prepared `OverseerBuilder`, that is initialized
/// with all default values.
pub fn prepared_overseer_builder<Spawner, RuntimeClient>(
OverseerGenArgs {
leaves,
keystore,
runtime_client,
parachains_db,
network_service,
authority_discovery_service,
pov_req_receiver,
chunk_req_receiver,
collation_req_receiver: _,
available_data_req_receiver,
statement_req_receiver,
dispute_req_receiver,
registry,
spawner,
approval_voting_config,
availability_config,
candidate_validation_config,
chain_selection_config,
dispute_coordinator_config,
}: OverseerGenArgs<'_, Spawner, RuntimeClient>,
) -> Result<
OverseerBuilder<
Spawner,
Arc<RuntimeClient>,
CandidateValidationSubsystem,
CandidateBackingSubsystem<Spawner>,
StatementDistributionSubsystem,
AvailabilityDistributionSubsystem,
AvailabilityRecoverySubsystem,
BitfieldSigningSubsystem<Spawner>,
BitfieldDistributionSubsystem,
ProvisionerSubsystem<Spawner>,
RuntimeApiSubsystem<RuntimeClient>,
AvailabilityStoreSubsystem,
NetworkBridgeSubsystem<
Arc<sc_network::NetworkService<Block, Hash>>,
AuthorityDiscoveryService,
>,
ChainApiSubsystem<RuntimeClient>,
CollationGenerationSubsystem,
CollatorProtocolSubsystem,
ApprovalDistributionSubsystem,
ApprovalVotingSubsystem,
GossipSupportSubsystem<AuthorityDiscoveryService>,
DisputeCoordinatorSubsystem,
DisputeDistributionSubsystem<AuthorityDiscoveryService>,
ChainSelectionSubsystem,
>,
Error,
>
where
RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Spawner: 'static + SpawnNamed + Clone + Unpin,
{
use polkadot_node_subsystem_util::metrics::Metrics;
use std::iter::FromIterator;
let metrics = <OverseerMetrics as MetricsTrait>::register(registry)?;
let builder = Overseer::builder()
.availability_distribution(AvailabilityDistributionSubsystem::new(
keystore.clone(),
IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver },
Metrics::register(registry)?,
))
.availability_recovery(AvailabilityRecoverySubsystem::with_chunks_only(
available_data_req_receiver,
Metrics::register(registry)?,
))
.availability_store(AvailabilityStoreSubsystem::new(
parachains_db.clone(),
availability_config,
Metrics::register(registry)?,
))
.bitfield_distribution(BitfieldDistributionSubsystem::new(Metrics::register(registry)?))
.bitfield_signing(BitfieldSigningSubsystem::new(
spawner.clone(),
keystore.clone(),
Metrics::register(registry)?,
))
.candidate_backing(CandidateBackingSubsystem::new(
spawner.clone(),
keystore.clone(),
Metrics::register(registry)?,
))
.candidate_validation(CandidateValidationSubsystem::with_config(
candidate_validation_config,
Metrics::register(registry)?, // candidate-validation metrics
Metrics::register(registry)?, // validation host metrics
))
.chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?))
.collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?))
.collator_protocol(CollatorProtocolSubsystem::new(ProtocolSide::Validator {
keystore: keystore.clone(),
eviction_policy: Default::default(),
metrics: Metrics::register(registry)?,
}))
.network_bridge(NetworkBridgeSubsystem::new(
network_service.clone(),
authority_discovery_service.clone(),
Box::new(network_service.clone()),
Metrics::register(registry)?,
))
.provisioner(ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?))
.runtime_api(RuntimeApiSubsystem::new(
runtime_client.clone(),
Metrics::register(registry)?,
spawner.clone(),
))
.statement_distribution(StatementDistributionSubsystem::new(
keystore.clone(),
statement_req_receiver,
Metrics::register(registry)?,
))
.approval_distribution(ApprovalDistributionSubsystem::new(Metrics::register(registry)?))
.approval_voting(ApprovalVotingSubsystem::with_config(
approval_voting_config,
parachains_db.clone(),
keystore.clone(),
Box::new(network_service),
Metrics::register(registry)?,
))
.gossip_support(GossipSupportSubsystem::new(
keystore.clone(),
authority_discovery_service.clone(),
))
.dispute_coordinator(DisputeCoordinatorSubsystem::new(
parachains_db.clone(),
dispute_coordinator_config,
keystore.clone(),
Metrics::register(registry)?,
))
.dispute_distribution(DisputeDistributionSubsystem::new(
keystore,
dispute_req_receiver,
authority_discovery_service,
Metrics::register(registry)?,
))
.chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db))
.leaves(Vec::from_iter(
leaves
.into_iter()
.map(|BlockInfo { hash, parent_hash: _, number }| (hash, number)),
))
.activation_external_listeners(Default::default())
.span_per_active_leaf(Default::default())
.active_leaves(Default::default())
.supports_parachains(runtime_client)
.known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE))
.metrics(metrics)
.spawner(spawner);
Ok(builder)
}
/// Trait for the `fn` generating the overseer.
///
/// Default behavior is to create an unmodified overseer, as `RealOverseerGen`
/// would do.
pub trait OverseerGen {
/// Overwrite the full generation of the overseer, including the subsystems.
fn generate<Spawner, RuntimeClient>(
&self,
connector: OverseerConnector,
args: OverseerGenArgs<'_, Spawner, RuntimeClient>,
) -> Result<(Overseer<Spawner, Arc<RuntimeClient>>, OverseerHandle), Error>
where
RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Spawner: 'static + SpawnNamed + Clone + Unpin,
{
let gen = RealOverseerGen;
RealOverseerGen::generate::<Spawner, RuntimeClient>(&gen, connector, args)
}
// It would be nice to make `create_subsystems` part of this trait,
// but the amount of generic arguments that would be required as
// as consequence make this rather annoying to implement and use.
}
use polkadot_overseer::KNOWN_LEAVES_CACHE_SIZE;
/// The regular set of subsystems.
pub struct RealOverseerGen;
impl OverseerGen for RealOverseerGen {
fn generate<Spawner, RuntimeClient>(
&self,
connector: OverseerConnector,
args: OverseerGenArgs<'_, Spawner, RuntimeClient>,
) -> Result<(Overseer<Spawner, Arc<RuntimeClient>>, OverseerHandle), Error>
where
RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Spawner: 'static + SpawnNamed + Clone + Unpin,
{
prepared_overseer_builder(args)?
.build_with_connector(connector)
.map_err(|e| e.into())
}
}
@@ -0,0 +1,104 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! This is almost 1:1 copy of `node/service/parachains_db/mod.rs` file from Polkadot repository.
//! The only exception is that we don't support db upgrades => no `upgrade.rs` module.
use kvdb::KeyValueDB;
use std::{io, path::PathBuf, sync::Arc};
mod columns {
pub const NUM_COLUMNS: u32 = 5;
pub const COL_AVAILABILITY_DATA: u32 = 0;
pub const COL_AVAILABILITY_META: u32 = 1;
pub const COL_APPROVAL_DATA: u32 = 2;
pub const COL_CHAIN_SELECTION_DATA: u32 = 3;
pub const COL_DISPUTE_COORDINATOR_DATA: u32 = 4;
}
/// Columns used by different subsystems.
#[derive(Debug, Clone)]
pub struct ColumnsConfig {
/// The column used by the av-store for data.
pub col_availability_data: u32,
/// The column used by the av-store for meta information.
pub col_availability_meta: u32,
/// The column used by approval voting for data.
pub col_approval_data: u32,
/// The column used by chain selection for data.
pub col_chain_selection_data: u32,
/// The column used by dispute coordinator for data.
pub col_dispute_coordinator_data: u32,
}
/// The real columns used by the parachains DB.
pub const REAL_COLUMNS: ColumnsConfig = ColumnsConfig {
col_availability_data: columns::COL_AVAILABILITY_DATA,
col_availability_meta: columns::COL_AVAILABILITY_META,
col_approval_data: columns::COL_APPROVAL_DATA,
col_chain_selection_data: columns::COL_CHAIN_SELECTION_DATA,
col_dispute_coordinator_data: columns::COL_DISPUTE_COORDINATOR_DATA,
};
/// The cache size for each column, in megabytes.
#[derive(Debug, Clone)]
pub struct CacheSizes {
/// Cache used by availability data.
pub availability_data: usize,
/// Cache used by availability meta.
pub availability_meta: usize,
/// Cache used by approval data.
pub approval_data: usize,
}
impl Default for CacheSizes {
fn default() -> Self {
CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 }
}
}
fn other_io_error(err: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}
/// Open the database on disk, creating it if it doesn't exist.
pub fn open_creating(root: PathBuf, cache_sizes: CacheSizes) -> io::Result<Arc<dyn KeyValueDB>> {
use kvdb_rocksdb::{Database, DatabaseConfig};
let path = root.join("parachains").join("db");
let mut db_config = DatabaseConfig::with_columns(columns::NUM_COLUMNS);
let _ = db_config
.memory_budget
.insert(columns::COL_AVAILABILITY_DATA, cache_sizes.availability_data);
let _ = db_config
.memory_budget
.insert(columns::COL_AVAILABILITY_META, cache_sizes.availability_meta);
let _ = db_config
.memory_budget
.insert(columns::COL_APPROVAL_DATA, cache_sizes.approval_data);
let path_str = path
.to_str()
.ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?;
std::fs::create_dir_all(&path_str)?;
let db = Database::open(&db_config, path_str)?;
Ok(Arc::new(db))
}
File diff suppressed because it is too large Load Diff
+57 -45
View File
@@ -8,16 +8,15 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
hex-literal = "0.3"
libsecp256k1 = { version = "0.3.4", optional = true, default-features = false, features = ["hmac"] }
libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac"] }
log = { version = "0.4.14", default-features = false }
serde = { version = "1.0.124", optional = true, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
serde = { version = "1.0", optional = true, features = ["derive"] }
# Bridge dependencies
bp-currency-exchange = { path = "../../../primitives/currency-exchange", default-features = false }
bp-eth-poa = { path = "../../../primitives/ethereum-poa", default-features = false }
bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false }
bp-messages = { path = "../../../primitives/messages", default-features = false }
@@ -25,47 +24,56 @@ bp-millau = { path = "../../../primitives/chain-millau", default-features = fals
bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
bp-runtime = { path = "../../../primitives/runtime", default-features = false }
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
pallet-bridge-currency-exchange = { path = "../../../modules/currency-exchange", default-features = false }
pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
pallet-bridge-eth-poa = { path = "../../../modules/ethereum", default-features = false }
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
# Substrate Dependencies
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Polkadot (parachain) Dependencies
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
[dev-dependencies]
libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
libsecp256k1 = { version = "0.7", features = ["hmac"] }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -73,8 +81,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
"bp-currency-exchange/std",
"bp-eth-poa/std",
"beefy-primitives/std",
"bp-header-chain/std",
"bp-message-dispatch/std",
"bp-messages/std",
@@ -89,24 +96,31 @@ std = [
"frame-system-rpc-runtime-api/std",
"frame-system/std",
"log/std",
"pallet-aura/std",
"pallet-authority-discovery/std",
"pallet-babe/std",
"pallet-balances/std",
"pallet-bridge-currency-exchange/std",
"pallet-beefy/std",
"pallet-beefy-mmr/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-eth-poa/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-grandpa/std",
"pallet-randomness-collective-flip/std",
"pallet-mmr/std",
"pallet-mmr-primitives/std",
"pallet-shift-session-manager/std",
"pallet-sudo/std",
"pallet-timestamp/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
"polkadot-primitives/std",
"polkadot-runtime-common/std",
"polkadot-runtime-parachains/std",
"scale-info/std",
"serde",
"sp-api/std",
"sp-authority-discovery/std",
"sp-block-builder/std",
"sp-consensus-aura/std",
"sp-consensus-babe/std",
"sp-core/std",
"sp-finality-grandpa/std",
"sp-inherents/std",
@@ -125,8 +139,6 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"libsecp256k1",
"pallet-bridge-currency-exchange/runtime-benchmarks",
"pallet-bridge-eth-poa/runtime-benchmarks",
"pallet-bridge-messages/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
@@ -1,37 +0,0 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! We want to use a different validator configuration for benchmarking than what's used in Kovan
//! or in our Rialto test network. However, we can't configure a new validator set on the fly which
//! means we need to wire the runtime together like this
use pallet_bridge_eth_poa::{ValidatorsConfiguration, ValidatorsSource};
use sp_std::vec;
pub use crate::kovan::{
genesis_header, genesis_validators, BridgeAuraConfiguration, FinalityVotesCachingInterval, PruningStrategy,
};
frame_support::parameter_types! {
pub BridgeValidatorsConfiguration: pallet_bridge_eth_poa::ValidatorsConfiguration = bench_validator_config();
}
fn bench_validator_config() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(vec![[1; 20].into()])),
(1, ValidatorsSource::Contract([3; 20].into(), vec![[1; 20].into()])),
])
}
@@ -1,260 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Support for PoA -> Substrate native tokens exchange.
//!
//! If you want to exchange native PoA tokens for native Substrate
//! chain tokens, you need to:
//! 1) send some PoA tokens to `LOCK_FUNDS_ADDRESS` address on PoA chain. Data field of
//! the transaction must be SCALE-encoded id of Substrate account that will receive
//! funds on Substrate chain;
//! 2) wait until the 'lock funds' transaction is mined on PoA chain;
//! 3) wait until the block containing the 'lock funds' transaction is finalized on PoA chain;
//! 4) wait until the required PoA header and its finality are provided
//! to the PoA -> Substrate bridge module (it can be provided by you);
//! 5) receive tokens by providing proof-of-inclusion of PoA transaction.
use bp_currency_exchange::{
Error as ExchangeError, LockFundsTransaction, MaybeLockFundsTransaction, Result as ExchangeResult,
};
use bp_eth_poa::{transaction_decode_rlp, RawTransaction, RawTransactionReceipt};
use codec::{Decode, Encode};
use frame_support::RuntimeDebug;
use hex_literal::hex;
use sp_std::vec::Vec;
/// Ethereum address where locked PoA funds must be sent to.
pub const LOCK_FUNDS_ADDRESS: [u8; 20] = hex!("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF");
/// Ethereum transaction inclusion proof.
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)]
pub struct EthereumTransactionInclusionProof {
/// Hash of the block with transaction.
pub block: sp_core::H256,
/// Index of the transaction within the block.
pub index: u64,
/// The proof itself (right now it is all RLP-encoded transactions of the block +
/// RLP-encoded receipts of all transactions of the block).
pub proof: Vec<(RawTransaction, RawTransactionReceipt)>,
}
/// We uniquely identify transfer by the pair (sender, nonce).
///
/// The assumption is that this pair will never appear more than once in
/// transactions included into finalized blocks. This is obviously true
/// for any existing eth-like chain (that keep current transaction format),
/// because otherwise transaction can be replayed over and over.
#[derive(Encode, Decode, PartialEq, RuntimeDebug)]
pub struct EthereumTransactionTag {
/// Account that has locked funds.
pub account: [u8; 20],
/// Lock transaction nonce.
pub nonce: sp_core::U256,
}
/// Eth transaction from runtime perspective.
pub struct EthTransaction;
impl MaybeLockFundsTransaction for EthTransaction {
type Transaction = RawTransaction;
type Id = EthereumTransactionTag;
type Recipient = crate::AccountId;
type Amount = crate::Balance;
fn parse(
raw_tx: &Self::Transaction,
) -> ExchangeResult<LockFundsTransaction<Self::Id, Self::Recipient, Self::Amount>> {
let tx = transaction_decode_rlp(raw_tx).map_err(|_| ExchangeError::InvalidTransaction)?;
// we only accept transactions sending funds directly to the pre-configured address
if tx.unsigned.to != Some(LOCK_FUNDS_ADDRESS.into()) {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid peer recipient: {:?}",
tx.unsigned.to,
);
return Err(ExchangeError::InvalidTransaction);
}
let mut recipient_raw = sp_core::H256::default();
match tx.unsigned.payload.len() {
32 => recipient_raw.as_fixed_bytes_mut().copy_from_slice(&tx.unsigned.payload),
len => {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid recipient length: {}",
len,
);
return Err(ExchangeError::InvalidRecipient);
}
}
let amount = tx.unsigned.value.low_u128();
if tx.unsigned.value != amount.into() {
log::trace!(
target: "runtime",
"Failed to parse fund locks transaction. Invalid amount: {}",
tx.unsigned.value,
);
return Err(ExchangeError::InvalidAmount);
}
Ok(LockFundsTransaction {
id: EthereumTransactionTag {
account: *tx.sender.as_fixed_bytes(),
nonce: tx.unsigned.nonce,
},
recipient: crate::AccountId::from(*recipient_raw.as_fixed_bytes()),
amount,
})
}
}
/// 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::Config<I>, I: frame_support::traits::Instance>(
transactions: &[(RawTransaction, RawTransactionReceipt)],
) -> bp_eth_poa::H256 {
use bp_eth_poa::compute_merkle_root;
use pallet_bridge_eth_poa::{
test_utils::{insert_dummy_header, validator_utils::validator, HeaderBuilder},
BridgeStorage, Storage,
};
let mut storage = BridgeStorage::<T, I>::new();
let header = HeaderBuilder::with_parent_number_on_runtime::<T, I>(0)
.transactions_root(compute_merkle_root(transactions.iter().map(|(tx, _)| tx)))
.receipts_root(compute_merkle_root(transactions.iter().map(|(_, receipt)| receipt)))
.sign_by(&validator(0));
let header_id = header.compute_id();
insert_dummy_header(&mut storage, header);
storage.finalize_and_prune_headers(Some(header_id), 0);
header_id.hash
}
/// Prepare signed ethereum lock-funds transaction.
#[cfg(any(feature = "runtime-benchmarks", test))]
pub(crate) fn prepare_ethereum_transaction(
recipient: &crate::AccountId,
editor: impl Fn(&mut bp_eth_poa::UnsignedTransaction),
) -> (RawTransaction, RawTransactionReceipt) {
use bp_eth_poa::{signatures::SignTransaction, Receipt, TransactionOutcome};
// prepare tx for OpenEthereum private dev chain:
// chain id is 0x11
// sender secret is 0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7
let chain_id = 0x11;
let signer = secp256k1::SecretKey::parse(&hex!(
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7"
))
.unwrap();
let recipient_raw: &[u8; 32] = recipient.as_ref();
let mut eth_tx = bp_eth_poa::UnsignedTransaction {
nonce: 0.into(),
to: Some(LOCK_FUNDS_ADDRESS.into()),
value: 100.into(),
gas: 100_000.into(),
gas_price: 100_000.into(),
payload: recipient_raw.to_vec(),
};
editor(&mut eth_tx);
(
eth_tx.sign_by(&signer, Some(chain_id)),
Receipt {
outcome: TransactionOutcome::StatusCode(1),
gas_used: Default::default(),
log_bloom: Default::default(),
logs: Vec::new(),
}
.rlp(),
)
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
fn ferdie() -> crate::AccountId {
hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c").into()
}
#[test]
fn valid_transaction_accepted() {
assert_eq!(
EthTransaction::parse(&prepare_ethereum_transaction(&ferdie(), |_| {}).0),
Ok(LockFundsTransaction {
id: EthereumTransactionTag {
account: hex!("00a329c0648769a73afac7f9381e08fb43dbea72"),
nonce: 0.into(),
},
recipient: ferdie(),
amount: 100,
}),
);
}
#[test]
fn invalid_transaction_rejected() {
assert_eq!(
EthTransaction::parse(&Vec::new()),
Err(ExchangeError::InvalidTransaction),
);
}
#[test]
fn transaction_with_invalid_peer_recipient_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.to = None;
})
.0
),
Err(ExchangeError::InvalidTransaction),
);
}
#[test]
fn transaction_with_invalid_recipient_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.payload.clear();
})
.0
),
Err(ExchangeError::InvalidRecipient),
);
}
#[test]
fn transaction_with_invalid_amount_rejected() {
assert_eq!(
EthTransaction::parse(
&prepare_ethereum_transaction(&ferdie(), |tx| {
tx.value = sp_core::U256::from(u128::MAX) + sp_core::U256::from(1);
})
.0
),
Err(ExchangeError::InvalidAmount),
);
}
}
@@ -1,192 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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 bp_eth_poa::{Address, AuraHeader, RawTransaction, U256};
use bp_header_chain::InclusionProofVerifier;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration,
ValidatorsSource,
};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(16);
pub BridgeAuraConfiguration: AuraConfiguration =
kovan_aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
kovan_validators_configuration();
}
/// Max number of finalized headers to keep. It is equivalent of approximately
/// 24 hours of finalized blocks on current Kovan chain.
const FINALIZED_HEADERS_TO_KEEP: u64 = 20_000;
/// Aura engine configuration for Kovan chain.
pub fn kovan_aura_configuration() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: u64::MAX,
strict_empty_steps_transition: 0,
validate_step_transition: 0x16e360,
validate_score_transition: 0x41a3c4,
two_thirds_majority_transition: u64::MAX,
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::MAX,
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration for Kovan chain.
pub fn kovan_validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(genesis_validators())),
(
10960440,
ValidatorsSource::List(vec![
hex!("00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED").into(),
hex!("0010f94b296a852aaac52ea6c5ac72e03afd032d").into(),
hex!("00a0a24b9f0e5ec7aa4c7389b8302fd0123194de").into(),
]),
),
(
10960500,
ValidatorsSource::Contract(
hex!("aE71807C1B0a093cB1547b682DC78316D945c9B8").into(),
vec![
hex!("d05f7478c6aa10781258c5cc8b4f385fc8fa989c").into(),
hex!("03801efb0efe2a25ede5dd3a003ae880c0292e4d").into(),
hex!("a4df255ecf08bbf2c28055c65225c9a9847abd94").into(),
hex!("596e8221a30bfe6e7eff67fee664a01c73ba3c56").into(),
hex!("faadface3fbd81ce37b0e19c0b65ff4234148132").into(),
],
),
),
])
}
/// Genesis validators set of Kovan chain.
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED").into(),
hex!("00427feae2419c15b89d1c21af10d1b6650a4d3d").into(),
hex!("4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c").into(),
hex!("0020ee4Be0e2027d76603cB751eE069519bA81A1").into(),
hex!("0010f94b296a852aaac52ea6c5ac72e03afd032d").into(),
hex!("007733a1FE69CF3f2CF989F81C7b4cAc1693387A").into(),
hex!("00E6d2b931F55a3f1701c7389d592a7778897879").into(),
hex!("00e4a10650e5a6D6001C38ff8E64F97016a1645c").into(),
hex!("00a0a24b9f0e5ec7aa4c7389b8302fd0123194de").into(),
]
}
/// Genesis header of the Kovan chain.
pub fn genesis_header() -> AuraHeader {
AuraHeader {
parent_hash: Default::default(),
timestamp: 0,
number: 0,
author: Default::default(),
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
extra_data: vec![],
state_root: hex!("2480155b48a1cea17d67dbfdfaafe821c1d19cdd478c5358e8ec56dec24502b2").into(),
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
log_bloom: Default::default(),
gas_used: Default::default(),
gas_limit: 6000000.into(),
difficulty: 131072.into(),
seal: vec![
vec![128],
vec![
184, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
],
}
}
/// Kovan headers pruning strategy.
///
/// We do not prune unfinalized headers because exchange module only accepts
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct PruningStrategy;
impl BridgePruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number.saturating_sub(FINALIZED_HEADERS_TO_KEEP)
}
}
/// PoA Header timestamp verification against `Timestamp` pallet.
#[derive(Default, RuntimeDebug)]
pub struct ChainTime;
impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}
/// The Kovan Blockchain as seen by the runtime.
pub struct KovanBlockchain;
impl InclusionProofVerifier 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).map(|(tx, _)| tx.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
0,
"10_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 20_000),
0,
"20_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 30_000),
10_000,
"20_000 <= 30_000 => we're ready to prune first 10_000 headers",
);
}
}
+354 -364
View File
@@ -30,34 +30,32 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub mod exchange;
#[cfg(feature = "runtime-benchmarks")]
pub mod benches;
pub mod kovan;
pub mod millau_messages;
pub mod rialto_poa;
pub mod parachains;
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bridge_runtime_common::messages::{
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
};
use codec::Decode;
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use pallet_mmr_primitives::{
DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof,
};
use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys},
traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature, MultiSigner,
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
};
use sp_std::prelude::*;
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
@@ -72,8 +70,6 @@ pub use frame_support::{
pub use frame_system::Call as SystemCall;
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_bridge_grandpa::Call as BridgeGrandpaMillauCall;
pub use pallet_bridge_messages::Call as MessagesCall;
pub use pallet_sudo::Call as SudoCall;
@@ -101,7 +97,7 @@ pub type AccountIndex = u32;
pub type Balance = bp_rialto::Balance;
/// Index of a transaction in the chain.
pub type Index = u32;
pub type Index = bp_rialto::Index;
/// A hash of some data used by the chain.
pub type Hash = bp_rialto::Hash;
@@ -109,9 +105,6 @@ pub type Hash = bp_rialto::Hash;
/// Hashing algorithm used by the chain.
pub type Hashing = bp_rialto::Hasher;
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
@@ -131,8 +124,12 @@ pub mod opaque {
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
pub babe: Babe,
pub grandpa: Grandpa,
pub beefy: Beefy,
pub para_validator: Initializer,
pub para_assignment: SessionInfo,
pub authority_discovery: AuthorityDiscovery,
}
}
@@ -171,7 +168,7 @@ impl frame_system::Config for Runtime {
/// The aggregated dispatch type that is available for extrinsics.
type Call = Call;
/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
type Lookup = IdentityLookup<AccountId>;
type Lookup = AccountIdLookup<AccountId, ()>;
/// The index type for storing how many extrinsics an account has signed.
type Index = Index;
/// The index type for blocks.
@@ -213,62 +210,50 @@ impl frame_system::Config for Runtime {
type OnSetCode = ();
}
impl pallet_randomness_collective_flip::Config for Runtime {}
/// The BABE epoch configuration at genesis.
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
sp_consensus_babe::BabeEpochConfiguration {
c: bp_rialto::time_units::PRIMARY_PROBABILITY,
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryVRFSlots,
};
parameter_types! {
pub const EpochDuration: u64 = bp_rialto::EPOCH_DURATION_IN_SLOTS as u64;
pub const ExpectedBlockTime: bp_rialto::Moment = bp_rialto::time_units::MILLISECS_PER_BLOCK;
pub const MaxAuthorities: u32 = 10;
}
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
impl pallet_babe::Config for Runtime {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
type MaxAuthorities = MaxAuthorities;
// session module is the trigger
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
// equivocation related configuration - we don't expect any equivocations in our testnets
type KeyOwnerProofSystem = ();
type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
)>>::IdentificationTuple;
type HandleEquivocation = ();
type DisabledValidators = ();
type WeightInfo = ();
}
type RialtoPoA = pallet_bridge_eth_poa::Instance1;
impl pallet_bridge_eth_poa::Config<RialtoPoA> for Runtime {
type AuraConfiguration = rialto_poa::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = rialto_poa::FinalityVotesCachingInterval;
type ValidatorsConfiguration = rialto_poa::BridgeValidatorsConfiguration;
type PruningStrategy = rialto_poa::PruningStrategy;
type ChainTime = rialto_poa::ChainTime;
type OnHeadersSubmitted = ();
}
type Kovan = pallet_bridge_eth_poa::Instance2;
impl pallet_bridge_eth_poa::Config<Kovan> for Runtime {
type AuraConfiguration = kovan::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = kovan::FinalityVotesCachingInterval;
type ValidatorsConfiguration = kovan::BridgeValidatorsConfiguration;
type PruningStrategy = kovan::PruningStrategy;
type ChainTime = kovan::ChainTime;
type OnHeadersSubmitted = ();
}
type RialtoCurrencyExchange = pallet_bridge_currency_exchange::Instance1;
impl pallet_bridge_currency_exchange::Config<RialtoCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = rialto_poa::RialtoBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = bp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
type CurrencyConverter = bp_currency_exchange::IdentityCurrencyConverter<Balance>;
type DepositInto = DepositInto;
}
type KovanCurrencyExchange = pallet_bridge_currency_exchange::Instance2;
impl pallet_bridge_currency_exchange::Config<KovanCurrencyExchange> for Runtime {
type OnTransactionSubmitted = ();
type PeerBlockchain = kovan::KovanBlockchain;
type PeerMaybeLockFundsTransaction = exchange::EthTransaction;
type RecipientsMap = bp_currency_exchange::IdentityRecipients<AccountId>;
type Amount = Balance;
type CurrencyConverter = bp_currency_exchange::IdentityCurrencyConverter<Balance>;
type DepositInto = DepositInto;
impl pallet_beefy::Config for Runtime {
type BeefyId = BeefyId;
}
impl pallet_bridge_dispatch::Config for Runtime {
type Event = Event;
type MessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
type Call = Call;
type CallFilter = frame_support::traits::Everything;
type EncodedCall = crate::millau_messages::FromMillauEncodedCall;
@@ -278,71 +263,10 @@ impl pallet_bridge_dispatch::Config for Runtime {
type AccountIdConverter = bp_rialto::AccountIdConverter;
}
pub struct DepositInto;
impl bp_currency_exchange::DepositInto for DepositInto {
type Recipient = AccountId;
type Amount = Balance;
fn deposit_into(
recipient: Self::Recipient,
amount: Self::Amount,
) -> bp_currency_exchange::Result<()> {
// let balances module make all checks for us (it won't allow depositing lower than existential
// deposit, balance overflow, ...)
let deposited = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
&recipient, amount,
);
// I'm dropping deposited here explicitly to illustrate the fact that it'll update `TotalIssuance`
// on drop
let deposited_amount = deposited.peek();
drop(deposited);
// we have 3 cases here:
// - deposited == amount: success
// - deposited == 0: deposit has failed and no changes to storage were made
// - deposited != 0: (should never happen in practice) deposit has been partially completed
match deposited_amount {
_ if deposited_amount == amount => {
log::trace!(
target: "runtime",
"Deposited {} to {:?}",
amount,
recipient,
);
Ok(())
},
_ if deposited_amount == 0 => {
log::error!(
target: "runtime",
"Deposit of {} to {:?} has failed",
amount,
recipient,
);
Err(bp_currency_exchange::Error::DepositFailed)
},
_ => {
log::error!(
target: "runtime",
"Deposit of {} to {:?} has partially competed. {} has been deposited",
amount,
recipient,
deposited_amount,
);
// we can't return DepositFailed error here, because storage changes were made
Err(bp_currency_exchange::Error::DepositPartiallyFailed)
},
}
}
}
impl pallet_grandpa::Config for Runtime {
type Event = Event;
type Call = Call;
type MaxAuthorities = MaxAuthorities;
type KeyOwnerProofSystem = ();
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
@@ -356,14 +280,46 @@ impl pallet_grandpa::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
}
impl pallet_mmr::Config for Runtime {
const INDEXING_PREFIX: &'static [u8] = b"mmr";
type Hashing = Keccak256;
type Hash = <Keccak256 as sp_runtime::traits::Hash>::Output;
type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
type WeightInfo = ();
type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
}
parameter_types! {
/// Version of the produced MMR leaf.
///
/// The version consists of two parts;
/// - `major` (3 bits)
/// - `minor` (5 bits)
///
/// `major` should be updated only if decoding the previous MMR Leaf format from the payload
/// is not possible (i.e. backward incompatible change).
/// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE
/// encoding does not prevent old leafs from being decoded.
///
/// Hence we expect `major` to be changed really rarely (think never).
/// See [`MmrLeafVersion`] type documentation for more details.
pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);
}
impl pallet_beefy_mmr::Config for Runtime {
type LeafVersion = LeafVersion;
type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
type ParachainHeads = ();
}
parameter_types! {
pub const MinimumPeriod: u64 = bp_rialto::SLOT_DURATION / 2;
}
impl pallet_timestamp::Config for Runtime {
/// A timestamp: milliseconds since the Unix epoch.
type Moment = u64;
type OnTimestampSet = Aura;
/// A timestamp: milliseconds since the UNIX epoch.
type Moment = bp_rialto::Moment;
type OnTimestampSet = Babe;
type MinimumPeriod = MinimumPeriod;
// TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78)
type WeightInfo = ();
@@ -395,13 +351,25 @@ impl pallet_balances::Config for Runtime {
parameter_types! {
pub const TransactionBaseFee: Balance = 0;
pub const TransactionByteFee: Balance = 1;
pub const OperationalFeeMultiplier: u8 = 5;
// values for following parameters are copied from polkadot repo, but it is fine
// not to sync them - we're not going to make Rialto a full copy of one of Polkadot-like chains
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000);
pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128);
}
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
type OperationalFeeMultiplier = OperationalFeeMultiplier;
type WeightToFee = bp_rialto::WeightToFee;
type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment<
Runtime,
TargetBlockFullness,
AdjustmentVariable,
MinimumMultiplier,
>;
}
impl pallet_sudo::Config for Runtime {
@@ -409,17 +377,12 @@ impl pallet_sudo::Config for Runtime {
type Call = Call;
}
parameter_types! {
pub const Period: BlockNumber = bp_rialto::SESSION_LENGTH;
pub const Offset: BlockNumber = 0;
}
impl pallet_session::Config for Runtime {
type Event = Event;
type ValidatorId = <Self as frame_system::Config>::AccountId;
type ValidatorIdOf = ();
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type ShouldEndSession = Babe;
type NextSessionRotation = Babe;
type SessionManager = pallet_shift_session_manager::Pallet<Runtime>;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
@@ -427,6 +390,10 @@ impl pallet_session::Config for Runtime {
type WeightInfo = ();
}
impl pallet_authority_discovery::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
}
parameter_types! {
/// This is a pretty unscientific cap.
///
@@ -475,10 +442,11 @@ parameter_types! {
pub const GetDeliveryConfirmationTransactionFee: Balance =
bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _;
pub const RootAccountForPayments: Option<AccountId> = None;
pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
}
/// Instance of the messages pallet used to relay messages to/from Millau chain.
pub type WithMillauMessagesInstance = pallet_bridge_messages::DefaultInstance;
pub type WithMillauMessagesInstance = ();
impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
type Event = Event;
@@ -502,14 +470,17 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
type MessageDeliveryAndDispatchPayment =
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
Runtime,
(),
pallet_balances::Pallet<Runtime>,
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
>;
type OnMessageAccepted = ();
type OnDeliveryConfirmed = ();
type SourceHeaderChain = crate::millau_messages::Millau;
type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch;
type BridgedChainId = BridgedChainId;
}
construct_runtime!(
@@ -518,28 +489,55 @@ construct_runtime!(
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
BridgeRialtoPoa: pallet_bridge_eth_poa::<Instance1>::{Pallet, Call, Config, Storage, ValidateUnsigned},
BridgeKovan: pallet_bridge_eth_poa::<Instance2>::{Pallet, Call, Config, Storage, ValidateUnsigned},
BridgeRialtoCurrencyExchange: pallet_bridge_currency_exchange::<Instance1>::{Pallet, Call},
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Pallet, Call},
BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>},
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Must be before session.
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Aura: pallet_aura::{Pallet, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Consensus support.
AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
// BEEFY Bridges support.
Beefy: pallet_beefy::{Pallet, Storage, Config<T>},
Mmr: pallet_mmr::{Pallet, Storage},
MmrLeaf: pallet_beefy_mmr::{Pallet, Storage},
// Millau bridge modules.
BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
// Parachain modules.
ParachainsOrigin: polkadot_runtime_parachains::origin::{Pallet, Origin},
Configuration: polkadot_runtime_parachains::configuration::{Pallet, Call, Storage, Config<T>},
Shared: polkadot_runtime_parachains::shared::{Pallet, Call, Storage},
Inclusion: polkadot_runtime_parachains::inclusion::{Pallet, Call, Storage, Event<T>},
ParasInherent: polkadot_runtime_parachains::paras_inherent::{Pallet, Call, Storage, Inherent},
Scheduler: polkadot_runtime_parachains::scheduler::{Pallet, Storage},
Paras: polkadot_runtime_parachains::paras::{Pallet, Call, Storage, Event, Config},
Initializer: polkadot_runtime_parachains::initializer::{Pallet, Call, Storage},
Dmp: polkadot_runtime_parachains::dmp::{Pallet, Call, Storage},
Ump: polkadot_runtime_parachains::ump::{Pallet, Call, Storage, Event},
Hrmp: polkadot_runtime_parachains::hrmp::{Pallet, Call, Storage, Event<T>, Config},
SessionInfo: polkadot_runtime_parachains::session_info::{Pallet, Storage},
// Parachain Onboarding Pallets
Registrar: polkadot_runtime_common::paras_registrar::{Pallet, Call, Storage, Event<T>},
Slots: polkadot_runtime_common::slots::{Pallet, Call, Storage, Event<T>},
ParasSudoWrapper: polkadot_runtime_common::paras_sudo_wrapper::{Pallet, Call},
}
);
/// The address format for describing accounts.
pub type Address = AccountId;
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, Hashing>;
/// Block type as expected by this runtime.
@@ -570,7 +568,7 @@ pub type Executive = frame_executive::Executive<
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
AllPallets,
>;
impl_runtime_apis! {
@@ -621,43 +619,42 @@ impl_runtime_apis! {
}
}
impl bp_eth_poa::RialtoPoAHeaderApi<Block> for Runtime {
fn best_block() -> (u64, bp_eth_poa::H256) {
let best_block = BridgeRialtoPoa::best_block();
(best_block.number, best_block.hash)
}
fn finalized_block() -> (u64, bp_eth_poa::H256) {
let finalized_block = BridgeRialtoPoa::finalized_block();
(finalized_block.number, finalized_block.hash)
}
fn is_import_requires_receipts(header: bp_eth_poa::AuraHeader) -> bool {
BridgeRialtoPoa::is_import_requires_receipts(header)
}
fn is_known_block(hash: bp_eth_poa::H256) -> bool {
BridgeRialtoPoa::is_known_block(hash)
impl beefy_primitives::BeefyApi<Block> for Runtime {
fn validator_set() -> ValidatorSet<BeefyId> {
Beefy::validator_set()
}
}
impl bp_eth_poa::KovanHeaderApi<Block> for Runtime {
fn best_block() -> (u64, bp_eth_poa::H256) {
let best_block = BridgeKovan::best_block();
(best_block.number, best_block.hash)
impl pallet_mmr_primitives::MmrApi<Block, Hash> for Runtime {
fn generate_proof(leaf_index: u64)
-> Result<(EncodableOpaqueLeaf, MmrProof<Hash>), MmrError>
{
Mmr::generate_proof(leaf_index)
.map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof))
}
fn finalized_block() -> (u64, bp_eth_poa::H256) {
let finalized_block = BridgeKovan::finalized_block();
(finalized_block.number, finalized_block.hash)
fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof<Hash>)
-> Result<(), MmrError>
{
pub type Leaf = <
<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider
>::LeafData;
let leaf: Leaf = leaf
.into_opaque_leaf()
.try_decode()
.ok_or(MmrError::Verify)?;
Mmr::verify_leaf(leaf, proof)
}
fn is_import_requires_receipts(header: bp_eth_poa::AuraHeader) -> bool {
BridgeKovan::is_import_requires_receipts(header)
}
fn is_known_block(hash: bp_eth_poa::H256) -> bool {
BridgeKovan::is_known_block(hash)
fn verify_proof_stateless(
root: Hash,
leaf: EncodableOpaqueLeaf,
proof: MmrProof<Hash>
) -> Result<(), MmrError> {
type MmrHashing = <Runtime as pallet_mmr::Config>::Hashing;
let node = DataOrHash::Data(leaf.into_opaque_leaf());
pallet_mmr::verify_leaf_proof::<MmrHashing, _>(root, node, proof)
}
}
@@ -672,18 +669,6 @@ impl_runtime_apis! {
}
}
impl bp_currency_exchange::RialtoCurrencyExchangeApi<Block, exchange::EthereumTransactionInclusionProof> for Runtime {
fn filter_transaction_proof(proof: exchange::EthereumTransactionInclusionProof) -> bool {
BridgeRialtoCurrencyExchange::filter_transaction_proof(&proof)
}
}
impl bp_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 {
fn validate_transaction(
source: TransactionSource,
@@ -700,13 +685,152 @@ impl_runtime_apis! {
}
}
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
impl sp_consensus_babe::BabeApi<Block> for Runtime {
fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration {
// The choice of `c` parameter (where `1 - c` represents the
// probability of a slot being empty), is done in accordance to the
// slot duration and expected target block time, for safely
// resisting network delays of maximum two seconds.
// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
sp_consensus_babe::BabeGenesisConfiguration {
slot_duration: Babe::slot_duration(),
epoch_length: EpochDuration::get(),
c: BABE_GENESIS_EPOCH_CONFIG.c,
genesis_authorities: Babe::authorities().to_vec(),
randomness: Babe::randomness(),
allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots,
}
}
fn authorities() -> Vec<AuraId> {
Aura::authorities()
fn current_epoch_start() -> sp_consensus_babe::Slot {
Babe::current_epoch_start()
}
fn current_epoch() -> sp_consensus_babe::Epoch {
Babe::current_epoch()
}
fn next_epoch() -> sp_consensus_babe::Epoch {
Babe::next_epoch()
}
fn generate_key_ownership_proof(
_slot: sp_consensus_babe::Slot,
_authority_id: sp_consensus_babe::AuthorityId,
) -> Option<sp_consensus_babe::OpaqueKeyOwnershipProof> {
None
}
fn submit_report_equivocation_unsigned_extrinsic(
equivocation_proof: sp_consensus_babe::EquivocationProof<<Block as BlockT>::Header>,
key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof,
) -> Option<()> {
let key_owner_proof = key_owner_proof.decode()?;
Babe::submit_unsigned_equivocation_report(
equivocation_proof,
key_owner_proof,
)
}
}
impl polkadot_primitives::v1::ParachainHost<Block, Hash, BlockNumber> for Runtime {
fn validators() -> Vec<polkadot_primitives::v1::ValidatorId> {
polkadot_runtime_parachains::runtime_api_impl::v1::validators::<Runtime>()
}
fn validator_groups() -> (
Vec<Vec<polkadot_primitives::v1::ValidatorIndex>>,
polkadot_primitives::v1::GroupRotationInfo<BlockNumber>,
) {
polkadot_runtime_parachains::runtime_api_impl::v1::validator_groups::<Runtime>()
}
fn availability_cores() -> Vec<polkadot_primitives::v1::CoreState<Hash, BlockNumber>> {
polkadot_runtime_parachains::runtime_api_impl::v1::availability_cores::<Runtime>()
}
fn persisted_validation_data(
para_id: polkadot_primitives::v1::Id,
assumption: polkadot_primitives::v1::OccupiedCoreAssumption,
)
-> Option<polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>> {
polkadot_runtime_parachains::runtime_api_impl::v1::persisted_validation_data::<Runtime>(para_id, assumption)
}
fn assumed_validation_data(
para_id: polkadot_primitives::v1::Id,
expected_persisted_validation_data_hash: Hash,
) -> Option<(polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>, polkadot_primitives::v1::ValidationCodeHash)> {
polkadot_runtime_parachains::runtime_api_impl::v1::assumed_validation_data::<Runtime>(para_id, expected_persisted_validation_data_hash)
}
fn check_validation_outputs(
para_id: polkadot_primitives::v1::Id,
outputs: polkadot_primitives::v1::CandidateCommitments,
) -> bool {
polkadot_runtime_parachains::runtime_api_impl::v1::check_validation_outputs::<Runtime>(para_id, outputs)
}
fn session_index_for_child() -> polkadot_primitives::v1::SessionIndex {
polkadot_runtime_parachains::runtime_api_impl::v1::session_index_for_child::<Runtime>()
}
fn validation_code(
para_id: polkadot_primitives::v1::Id,
assumption: polkadot_primitives::v1::OccupiedCoreAssumption,
)
-> Option<polkadot_primitives::v1::ValidationCode> {
polkadot_runtime_parachains::runtime_api_impl::v1::validation_code::<Runtime>(para_id, assumption)
}
fn candidate_pending_availability(
para_id: polkadot_primitives::v1::Id,
) -> Option<polkadot_primitives::v1::CommittedCandidateReceipt<Hash>> {
polkadot_runtime_parachains::runtime_api_impl::v1::candidate_pending_availability::<Runtime>(para_id)
}
fn candidate_events() -> Vec<polkadot_primitives::v1::CandidateEvent<Hash>> {
polkadot_runtime_parachains::runtime_api_impl::v1::candidate_events::<Runtime, _>(|ev| {
match ev {
Event::Inclusion(ev) => {
Some(ev)
}
_ => None,
}
})
}
fn session_info(index: polkadot_primitives::v1::SessionIndex) -> Option<polkadot_primitives::v1::SessionInfo> {
polkadot_runtime_parachains::runtime_api_impl::v1::session_info::<Runtime>(index)
}
fn dmq_contents(
recipient: polkadot_primitives::v1::Id,
) -> Vec<polkadot_primitives::v1::InboundDownwardMessage<BlockNumber>> {
polkadot_runtime_parachains::runtime_api_impl::v1::dmq_contents::<Runtime>(recipient)
}
fn inbound_hrmp_channels_contents(
recipient: polkadot_primitives::v1::Id
) -> BTreeMap<polkadot_primitives::v1::Id, Vec<polkadot_primitives::v1::InboundHrmpMessage<BlockNumber>>> {
polkadot_runtime_parachains::runtime_api_impl::v1::inbound_hrmp_channels_contents::<Runtime>(recipient)
}
fn validation_code_by_hash(
hash: polkadot_primitives::v1::ValidationCodeHash,
) -> Option<polkadot_primitives::v1::ValidationCode> {
polkadot_runtime_parachains::runtime_api_impl::v1::validation_code_by_hash::<Runtime>(hash)
}
fn on_chain_votes() -> Option<polkadot_primitives::v1::ScrapedOnChainVotes<Hash>> {
polkadot_runtime_parachains::runtime_api_impl::v1::on_chain_votes::<Runtime>()
}
}
impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityDiscoveryId> {
polkadot_runtime_parachains::runtime_api_impl::v1::relevant_authority_ids::<Runtime>()
}
}
@@ -735,6 +859,10 @@ impl_runtime_apis! {
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
fn current_set_id() -> fg_primitives::SetId {
Grandpa::current_set_id()
}
fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities()
}
@@ -781,20 +909,11 @@ impl_runtime_apis! {
begin: bp_messages::MessageNonce,
end: bp_messages::MessageNonce,
) -> Vec<bp_messages::MessageDetails<Balance>> {
(begin..=end).filter_map(|nonce| {
let message_data = BridgeMillauMessages::outbound_message_data(lane, nonce)?;
let decoded_payload = millau_messages::ToMillauMessagePayload::decode(
&mut &message_data.payload[..]
).ok()?;
Some(bp_messages::MessageDetails {
nonce,
dispatch_weight: decoded_payload.weight,
size: message_data.payload.len() as _,
delivery_and_dispatch_fee: message_data.fee,
dispatch_fee_payment: decoded_payload.dispatch_fee_payment,
})
})
.collect()
bridge_runtime_common::messages_api::outbound_message_details::<
Runtime,
WithMillauMessagesInstance,
WithMillauMessageBridge,
>(lane, begin, end)
}
fn latest_received_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce {
@@ -829,18 +948,11 @@ impl_runtime_apis! {
use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
list_benchmark!(
list,
extra,
pallet_bridge_currency_exchange,
BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>
);
list_benchmark!(
list,
extra,
pallet_bridge_messages,
MessagesBench::<Runtime, WithMillauMessagesInstance>
);
use pallet_bridge_messages::benchmarking::Pallet as MessagesBench;
let mut list = Vec::<BenchmarkList>::new();
list_benchmark!(list, extra, pallet_bridge_messages, MessagesBench::<Runtime, WithMillauMessagesInstance>);
list_benchmark!(list, extra, pallet_bridge_grandpa, BridgeMillauGrandpa);
let storage_info = AllPalletsWithSystem::storage_info();
@@ -873,46 +985,6 @@ impl_runtime_apis! {
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
use pallet_bridge_currency_exchange::benchmarking::{
Pallet as BridgeCurrencyExchangeBench,
Config as BridgeCurrencyExchangeConfig,
ProofParams as BridgeCurrencyExchangeProofParams,
};
impl BridgeCurrencyExchangeConfig<KovanCurrencyExchange> for Runtime {
fn make_proof(
proof_params: BridgeCurrencyExchangeProofParams<AccountId>,
) -> crate::exchange::EthereumTransactionInclusionProof {
use bp_currency_exchange::DepositInto;
if proof_params.recipient_exists {
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
proof_params.recipient.clone(),
ExistentialDeposit::get(),
).unwrap();
}
let (transaction, receipt) = crate::exchange::prepare_ethereum_transaction(
&proof_params.recipient,
|tx| {
// our runtime only supports transactions where data is exactly 32 bytes long
// (receiver key)
// => we are ignoring `transaction_size_factor` here
tx.value = (ExistentialDeposit::get() * 10).into();
},
);
let transactions = sp_std::iter::repeat((transaction, receipt))
.take(1 + proof_params.proof_size_factor as usize)
.collect::<Vec<_>>();
let block_hash = crate::exchange::prepare_environment_for_claim::<Runtime, Kovan>(&transactions);
crate::exchange::EthereumTransactionInclusionProof {
block: block_hash,
index: 0,
proof: transactions,
}
}
}
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
use bp_runtime::messages::DispatchFeePayment;
use bridge_runtime_common::messages;
@@ -981,7 +1053,7 @@ impl_runtime_apis! {
MessagesProofSize::Minimal(ref size) => vec![0u8; *size as _],
_ => vec![],
};
let call = Call::System(SystemCall::remark(remark));
let call = Call::System(SystemCall::remark { remark });
let call_weight = call.get_dispatch_info().weight;
let millau_account_id: bp_millau::AccountId = Default::default();
@@ -1001,14 +1073,12 @@ impl_runtime_apis! {
Self::endow_account(&rialto_public.clone().into_account());
}
let make_millau_message_key = |message_key: MessageKey| storage_keys::message_key::<
<WithMillauMessageBridge as MessageBridge>::BridgedMessagesInstance,
>(
let make_millau_message_key = |message_key: MessageKey| storage_keys::message_key(
<WithMillauMessageBridge as MessageBridge>::BRIDGED_MESSAGES_PALLET_NAME,
&message_key.lane_id, message_key.nonce,
).0;
let make_millau_outbound_lane_data_key = |lane_id| storage_keys::outbound_lane_data_key::<
<WithMillauMessageBridge as MessageBridge>::BridgedMessagesInstance,
>(
let make_millau_outbound_lane_data_key = |lane_id| storage_keys::outbound_lane_data_key(
<WithMillauMessageBridge as MessageBridge>::BRIDGED_MESSAGES_PALLET_NAME,
&lane_id,
).0;
@@ -1054,9 +1124,8 @@ impl_runtime_apis! {
prepare_message_delivery_proof::<WithMillauMessageBridge, bp_millau::Hasher, Runtime, (), _, _>(
params,
|lane_id| pallet_bridge_messages::storage_keys::inbound_lane_data_key::<
<WithMillauMessageBridge as MessageBridge>::BridgedMessagesInstance,
>(
|lane_id| pallet_bridge_messages::storage_keys::inbound_lane_data_key(
<WithMillauMessageBridge as MessageBridge>::BRIDGED_MESSAGES_PALLET_NAME,
&lane_id,
).0,
|state_root| bp_millau::Header::new(
@@ -1082,12 +1151,6 @@ impl_runtime_apis! {
}
}
add_benchmark!(
params,
batches,
pallet_bridge_currency_exchange,
BridgeCurrencyExchangeBench::<Runtime, KovanCurrencyExchange>
);
add_benchmark!(
params,
batches,
@@ -1104,8 +1167,8 @@ impl_runtime_apis! {
/// Millau account ownership digest from Rialto.
///
/// The byte vector returned by this function should be signed with a Millau account private key.
/// This way, the owner of `rialto_account_id` on Rialto proves that the Millau account private key
/// is also under his control.
/// This way, the owner of `rialto_account_id` on Rialto proves that the 'millau' account private
/// key is also under his control.
pub fn rialto_to_millau_account_ownership_digest<Call, AccountId, SpecVersion>(
millau_call: &Call,
rialto_account_id: AccountId,
@@ -1128,48 +1191,8 @@ where
#[cfg(test)]
mod tests {
use super::*;
use bp_currency_exchange::DepositInto;
use bridge_runtime_common::messages;
fn run_deposit_into_test(test: impl Fn(AccountId) -> Balance) {
let mut ext: sp_io::TestExternalities =
SystemConfig::default().build_storage::<Runtime>().unwrap().into();
ext.execute_with(|| {
// initially issuance is zero
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
0,
);
// create account
let account: AccountId = [1u8; 32].into();
let initial_amount = ExistentialDeposit::get();
let deposited =
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
&account,
initial_amount,
);
drop(deposited);
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
initial_amount,
);
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&account),
initial_amount,
);
// run test
let total_issuance_change = test(account);
// check that total issuance has changed by `run_deposit_into_test`
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::total_issuance(),
initial_amount + total_issuance_change,
);
});
}
#[test]
fn ensure_rialto_message_lane_weights_are_correct() {
type Weights = pallet_bridge_messages::weights::RialtoWeight<Runtime>;
@@ -1179,6 +1202,7 @@ mod tests {
bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
DbWeight::get(),
);
let max_incoming_message_proof_size = bp_millau::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
@@ -1206,50 +1230,16 @@ mod tests {
max_incoming_inbound_lane_data_proof_size,
bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
DbWeight::get(),
);
}
#[test]
fn deposit_into_existing_account_works() {
run_deposit_into_test(|existing_account| {
let initial_amount =
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&existing_account,
);
let additional_amount = 10_000;
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
existing_account.clone(),
additional_amount,
)
.unwrap();
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&existing_account
),
initial_amount + additional_amount,
);
additional_amount
});
}
#[test]
fn deposit_into_new_account_works() {
run_deposit_into_test(|_| {
let initial_amount = 0;
let additional_amount = ExistentialDeposit::get() + 10_000;
let new_account: AccountId = [42u8; 32].into();
<Runtime as pallet_bridge_currency_exchange::Config<KovanCurrencyExchange>>::DepositInto::deposit_into(
new_account.clone(),
additional_amount,
)
.unwrap();
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&new_account
),
initial_amount + additional_amount,
);
additional_amount
});
fn call_size() {
const DOT_MAX_CALL_SZ: usize = 230;
assert!(core::mem::size_of::<pallet_bridge_grandpa::Call<Runtime>>() <= DOT_MAX_CALL_SZ);
// FIXME: get this down to 230. https://github.com/paritytech/grandpa-bridge-gadget/issues/359
const BEEFY_MAX_CALL_SZ: usize = 232;
assert!(core::mem::size_of::<pallet_bridge_messages::Call<Runtime>>() <= BEEFY_MAX_CALL_SZ);
}
}
@@ -31,25 +31,34 @@ use frame_support::{
weights::{DispatchClass, Weight},
RuntimeDebug,
};
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128};
use scale_info::TypeInfo;
use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
use sp_std::{convert::TryFrom, ops::RangeInclusive};
/// Initial value of `MillauToRialtoConversionRate` parameter.
pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 =
FixedU128::from_inner(FixedU128::DIV);
/// Initial value of `MillauFeeMultiplier` parameter.
pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
parameter_types! {
/// Millau to Rialto conversion rate. Initially we treat both tokens as equal.
pub storage MillauToRialtoConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE;
/// Fee multiplier value at Millau chain.
pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER;
}
/// Message payload for Rialto -> Millau messages.
pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload<WithMillauMessageBridge>;
pub type ToMillauMessagePayload =
messages::source::FromThisChainMessagePayload<WithMillauMessageBridge>;
/// Message verifier for Rialto -> Millau messages.
pub type ToMillauMessageVerifier = messages::source::FromThisChainMessageVerifier<WithMillauMessageBridge>;
pub type ToMillauMessageVerifier =
messages::source::FromThisChainMessageVerifier<WithMillauMessageBridge>;
/// Message payload for Millau -> Rialto messages.
pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload<WithMillauMessageBridge>;
pub type FromMillauMessagePayload =
messages::target::FromBridgedChainMessagePayload<WithMillauMessageBridge>;
/// Encoded Rialto Call as it comes from Millau.
pub type FromMillauEncodedCall = messages::target::FromBridgedChainEncodedMessageCall<crate::Call>;
@@ -59,14 +68,15 @@ pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDi
WithMillauMessageBridge,
crate::Runtime,
pallet_balances::Pallet<Runtime>,
pallet_bridge_dispatch::DefaultInstance,
(),
>;
/// Messages proof for Millau -> Rialto messages.
pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof<bp_millau::Hash>;
/// Messages delivery proof for Rialto -> Millau messages.
pub type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<bp_millau::Hash>;
pub type ToMillauMessagesDeliveryProof =
messages::source::FromBridgedChainMessagesDeliveryProof<bp_millau::Hash>;
/// Millau <-> Rialto message bridge.
#[derive(RuntimeDebug, Clone, Copy)]
@@ -76,14 +86,16 @@ impl MessageBridge for WithMillauMessageBridge {
const RELAYER_FEE_PERCENT: u32 = 10;
const THIS_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME;
type ThisChain = Rialto;
type BridgedChain = Millau;
type BridgedMessagesInstance = crate::WithMillauMessagesInstance;
fn bridged_balance_to_this_balance(bridged_balance: bp_millau::Balance) -> bp_rialto::Balance {
bp_rialto::Balance::try_from(MillauToRialtoConversionRate::get().saturating_mul_int(bridged_balance))
.unwrap_or(bp_rialto::Balance::MAX)
bp_rialto::Balance::try_from(
MillauToRialtoConversionRate::get().saturating_mul_int(bridged_balance),
)
.unwrap_or(bp_rialto::Balance::MAX)
}
}
@@ -128,11 +140,15 @@ impl messages::ThisChainWithMessages for Rialto {
}
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
// `transaction` may represent transaction from the future, when multiplier value will
// be larger, so let's use slightly increased value
let multiplier = FixedU128::saturating_from_rational(110, 100)
.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
// in our testnets, both per-byte fee and weight-to-fee are 1:1
messages::transaction_payment(
bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
1,
FixedU128::zero(),
multiplier,
|weight| weight as _,
transaction,
)
@@ -159,12 +175,15 @@ impl messages::BridgedChainWithMessages for Millau {
fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Weight> {
// we don't want to relay too large messages + keep reserve for future upgrades
let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(bp_millau::max_extrinsic_weight());
let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(
bp_millau::max_extrinsic_weight(),
);
// we're charging for payload bytes in `WithMillauMessageBridge::transaction_payment` function
// we're charging for payload bytes in `WithMillauMessageBridge::transaction_payment`
// function
//
// this bridge may be used to deliver all kind of messages, so we're not making any assumptions about
// minimal dispatch weight here
// this bridge may be used to deliver all kind of messages, so we're not making any
// assumptions about minimal dispatch weight here
0..=upper_limit
}
@@ -195,11 +214,14 @@ impl messages::BridgedChainWithMessages for Millau {
}
fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
// we don't have a direct access to the value of multiplier at Millau chain
// => it is a messages module parameter
let multiplier = MillauFeeMultiplier::get();
// in our testnets, both per-byte fee and weight-to-fee are 1:1
messages::transaction_payment(
bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
1,
FixedU128::zero(),
multiplier,
|weight| weight as _,
transaction,
)
@@ -221,9 +243,11 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_millau::AccountId> for Millau
fn verify_messages_delivery_proof(
proof: Self::MessagesDeliveryProof,
) -> Result<(LaneId, InboundLaneData<bp_rialto::AccountId>), Self::Error> {
messages::source::verify_messages_delivery_proof::<WithMillauMessageBridge, Runtime, crate::MillauGrandpaInstance>(
proof,
)
messages::source::verify_messages_delivery_proof::<
WithMillauMessageBridge,
Runtime,
crate::MillauGrandpaInstance,
>(proof)
}
}
@@ -240,15 +264,16 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
proof: Self::MessagesProof,
messages_count: u32,
) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
messages::target::verify_messages_proof::<WithMillauMessageBridge, Runtime, crate::MillauGrandpaInstance>(
proof,
messages_count,
)
messages::target::verify_messages_proof::<
WithMillauMessageBridge,
Runtime,
crate::MillauGrandpaInstance,
>(proof, messages_count)
}
}
/// Rialto -> Millau message lane pallet parameters.
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq)]
#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
pub enum RialtoToMillauMessagesParameter {
/// The conversion formula we use is: `RialtoTokens = MillauTokens * conversion_rate`.
MillauToRialtoConversionRate(FixedU128),
@@ -257,9 +282,8 @@ pub enum RialtoToMillauMessagesParameter {
impl MessagesParameter for RialtoToMillauMessagesParameter {
fn save(&self) {
match *self {
RialtoToMillauMessagesParameter::MillauToRialtoConversionRate(ref conversion_rate) => {
MillauToRialtoConversionRate::set(conversion_rate)
}
RialtoToMillauMessagesParameter::MillauToRialtoConversionRate(ref conversion_rate) =>
MillauToRialtoConversionRate::set(conversion_rate),
}
}
}
@@ -274,7 +298,9 @@ mod tests {
MessageKey,
};
use bp_runtime::{derive_account_id, messages::DispatchFeePayment, SourceAccount};
use bridge_runtime_common::messages::target::{FromBridgedChainEncodedMessageCall, FromBridgedChainMessagePayload};
use bridge_runtime_common::messages::target::{
FromBridgedChainEncodedMessageCall, FromBridgedChainMessagePayload,
};
use frame_support::{
traits::Currency,
weights::{GetDispatchInfo, WeightToFeePolynomial},
@@ -286,12 +312,15 @@ mod tests {
// this test actually belongs to the `bridge-runtime-common` crate, but there we have no
// mock runtime. Making another one there just for this test, given that both crates
// live n single repo is an overkill
let mut ext: sp_io::TestExternalities = SystemConfig::default().build_storage::<Runtime>().unwrap().into();
let mut ext: sp_io::TestExternalities =
SystemConfig::default().build_storage::<Runtime>().unwrap().into();
ext.execute_with(|| {
let bridge = MILLAU_CHAIN_ID;
let call: Call = SystemCall::remark(vec![]).into();
let call: Call = SystemCall::remark { remark: vec![] }.into();
let dispatch_weight = call.get_dispatch_info().weight;
let dispatch_fee = <Runtime as pallet_transaction_payment::Config>::WeightToFee::calc(&dispatch_weight);
let dispatch_fee = <Runtime as pallet_transaction_payment::Config>::WeightToFee::calc(
&dispatch_weight,
);
assert!(dispatch_fee > 0);
// create relayer account with minimal balance
@@ -303,12 +332,13 @@ mod tests {
);
// create dispatch account with minimal balance + dispatch fee
let dispatch_account = derive_account_id::<<Runtime as pallet_bridge_dispatch::Config>::SourceChainAccountId>(
bridge,
SourceAccount::Root,
);
let dispatch_account = derive_account_id::<
<Runtime as pallet_bridge_dispatch::Config>::SourceChainAccountId,
>(bridge, SourceAccount::Root);
let dispatch_account =
<Runtime as pallet_bridge_dispatch::Config>::AccountIdConverter::convert(dispatch_account);
<Runtime as pallet_bridge_dispatch::Config>::AccountIdConverter::convert(
dispatch_account,
);
let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
&dispatch_account,
initial_amount + dispatch_fee,
@@ -318,10 +348,7 @@ mod tests {
FromMillauMessageDispatch::dispatch(
&relayer_account,
DispatchMessage {
key: MessageKey {
lane_id: Default::default(),
nonce: 0,
},
key: MessageKey { lane_id: Default::default(), nonce: 0 },
data: DispatchMessageData {
payload: Ok(FromBridgedChainMessagePayload::<WithMillauMessageBridge> {
spec_version: VERSION.spec_version,
@@ -337,11 +364,15 @@ mod tests {
// ensure that fee has been transferred from dispatch to relayer account
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&relayer_account),
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&relayer_account
),
initial_amount + dispatch_fee,
);
assert_eq!(
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(&dispatch_account),
<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
&dispatch_account
),
initial_amount,
);
});
@@ -0,0 +1,160 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Parachains support in Rialto runtime.
use crate::{AccountId, Balance, Balances, BlockNumber, Event, Origin, Registrar, Runtime, Slots};
use frame_support::{parameter_types, weights::Weight};
use frame_system::EnsureRoot;
use polkadot_primitives::v1::ValidatorIndex;
use polkadot_runtime_common::{paras_registrar, paras_sudo_wrapper, slots};
use polkadot_runtime_parachains::{
configuration as parachains_configuration, dmp as parachains_dmp, hrmp as parachains_hrmp,
inclusion as parachains_inclusion, initializer as parachains_initializer,
origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, scheduler as parachains_scheduler,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump,
};
/// Special `RewardValidators` that does nothing ;)
pub struct RewardValidators;
impl polkadot_runtime_parachains::inclusion::RewardValidators for RewardValidators {
fn reward_backing(_: impl IntoIterator<Item = ValidatorIndex>) {}
fn reward_bitfields(_: impl IntoIterator<Item = ValidatorIndex>) {}
}
// all required parachain modules from `polkadot-runtime-parachains` crate
impl parachains_configuration::Config for Runtime {
type WeightInfo = parachains_configuration::TestWeightInfo;
}
impl parachains_dmp::Config for Runtime {}
impl parachains_hrmp::Config for Runtime {
type Event = Event;
type Origin = Origin;
type Currency = Balances;
}
impl parachains_inclusion::Config for Runtime {
type Event = Event;
type RewardValidators = RewardValidators;
type DisputesHandler = ();
}
impl parachains_initializer::Config for Runtime {
type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
type ForceOrigin = EnsureRoot<AccountId>;
type WeightInfo = ();
}
impl parachains_origin::Config for Runtime {}
impl parachains_paras::Config for Runtime {
type Origin = Origin;
type Event = Event;
type WeightInfo = parachains_paras::TestWeightInfo;
}
impl parachains_paras_inherent::Config for Runtime {
type WeightInfo = parachains_paras_inherent::TestWeightInfo;
}
impl parachains_scheduler::Config for Runtime {}
impl parachains_session_info::Config for Runtime {}
impl parachains_shared::Config for Runtime {}
parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100;
}
impl parachains_ump::Config for Runtime {
type Event = Event;
type UmpSink = ();
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
}
// required onboarding pallets. We're not going to use auctions or crowdloans, so they're missing
parameter_types! {
pub const ParaDeposit: Balance = 0;
pub const DataDepositPerByte: Balance = 0;
}
impl paras_registrar::Config for Runtime {
type Event = Event;
type Origin = Origin;
type Currency = Balances;
type OnSwap = Slots;
type ParaDeposit = ParaDeposit;
type DataDepositPerByte = DataDepositPerByte;
type WeightInfo = paras_registrar::TestWeightInfo;
}
parameter_types! {
pub const LeasePeriod: BlockNumber = 10 * bp_rialto::MINUTES;
}
impl slots::Config for Runtime {
type Event = Event;
type Currency = Balances;
type Registrar = Registrar;
type LeasePeriod = LeasePeriod;
type WeightInfo = slots::TestWeightInfo;
type LeaseOffset = ();
}
impl paras_sudo_wrapper::Config for Runtime {}
pub struct ZeroWeights;
impl polkadot_runtime_common::paras_registrar::WeightInfo for ZeroWeights {
fn reserve() -> Weight {
0
}
fn register() -> Weight {
0
}
fn force_register() -> Weight {
0
}
fn deregister() -> Weight {
0
}
fn swap() -> Weight {
0
}
}
impl polkadot_runtime_common::slots::WeightInfo for ZeroWeights {
fn force_lease() -> Weight {
0
}
fn manage_lease_period_start(_c: u32, _t: u32) -> Weight {
0
}
fn clear_all_leases() -> Weight {
0
}
fn trigger_onboard() -> Weight {
0
}
}
@@ -1,175 +0,0 @@
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Configuration parameters for the Rialto PoA chain.
use crate::exchange::EthereumTransactionInclusionProof;
use bp_eth_poa::{Address, AuraHeader, RawTransaction, U256};
use bp_header_chain::InclusionProofVerifier;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as TPruningStrategy, ValidatorsConfiguration,
ValidatorsSource,
};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(8);
pub BridgeAuraConfiguration: AuraConfiguration =
aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
validators_configuration();
}
/// Max number of finalized headers to keep.
const FINALIZED_HEADERS_TO_KEEP: u64 = 5_000;
/// Aura engine configuration for Rialto chain.
pub fn aura_configuration() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: 0xfffffffff,
strict_empty_steps_transition: 0,
validate_step_transition: 0,
validate_score_transition: 0,
two_thirds_majority_transition: u64::MAX,
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::MAX,
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration for Rialto PoA chain.
pub fn validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Single(ValidatorsSource::List(genesis_validators()))
}
/// Genesis validators set of Rialto PoA chain.
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("005e714f896a8b7cede9d38688c1a81de72a58e4").into(),
hex!("007594304039c2937a12220338aab821d819f5a4").into(),
hex!("004e7a39907f090e19b0b80a277e77b72b22e269").into(),
]
}
/// Genesis header of the Rialto PoA chain.
///
/// To obtain genesis header from a running node, invoke:
/// ```bash
/// $ http localhost:8545 jsonrpc=2.0 id=1 method=eth_getBlockByNumber params:='["earliest", false]' -v
/// ```
pub fn genesis_header() -> AuraHeader {
AuraHeader {
parent_hash: Default::default(),
timestamp: 0,
number: 0,
author: Default::default(),
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
extra_data: vec![],
state_root: hex!("a992d04c791620ed7ed96555a80cf0568355bb4bee2656f46899a4372f25f248").into(),
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
log_bloom: Default::default(),
gas_used: Default::default(),
gas_limit: 0x222222.into(),
difficulty: 0x20000.into(),
seal: vec![vec![0x80], {
let mut vec = vec![0xb8, 0x41];
vec.resize(67, 0);
vec
}],
}
}
/// Rialto PoA headers pruning strategy.
///
/// We do not prune unfinalized headers because exchange module only accepts
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct PruningStrategy;
impl TPruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number.saturating_sub(FINALIZED_HEADERS_TO_KEEP)
}
}
/// `ChainTime` provider
#[derive(Default)]
pub struct ChainTime;
impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}
/// The Rialto PoA Blockchain as seen by the runtime.
pub struct RialtoBlockchain;
impl InclusionProofVerifier for RialtoBlockchain {
type Transaction = RawTransaction;
type TransactionInclusionProof = EthereumTransactionInclusionProof;
fn verify_transaction_inclusion_proof(proof: &Self::TransactionInclusionProof) -> Option<Self::Transaction> {
let is_transaction_finalized =
crate::BridgeRialtoPoa::verify_transaction_finalized(proof.block, proof.index, &proof.proof);
if !is_transaction_finalized {
return None;
}
proof.proof.get(proof.index as usize).map(|(tx, _)| tx.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn genesis_hash_matches() {
assert_eq!(
genesis_header().compute_hash(),
hex!("1468e1a0fa20d30025a5a0f87e1cced4fdc393b84b7d2850b11ca5863db482cb").into(),
);
}
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 1_000),
0,
"1_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 5_000),
0,
"5_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
5_000,
"5_000 <= 10_000 => we're ready to prune first 5_000 headers",
);
}
}
@@ -8,7 +8,7 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
ed25519-dalek = { version = "1.0", default-features = false, optional = true }
hash-db = { version = "0.15.2", default-features = false }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
@@ -24,13 +24,13 @@ pallet-bridge-messages = { path = "../../modules/messages", default-features = f
# Substrate dependencies
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false, optional = true }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[features]
default = ["std"]
@@ -19,4 +19,5 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod messages;
pub mod messages_api;
pub mod messages_benchmarking;
@@ -32,17 +32,20 @@ use bp_runtime::{
};
use codec::{Decode, Encode};
use frame_support::{
traits::{Currency, ExistenceRequirement, Instance},
traits::{Currency, ExistenceRequirement},
weights::{Weight, WeightToFeePolynomial},
RuntimeDebug,
};
use hash_db::Hasher;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul},
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Saturating, Zero},
FixedPointNumber, FixedPointOperand, FixedU128,
};
use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive, vec::Vec};
use sp_std::{
cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive,
vec::Vec,
};
use sp_trie::StorageProof;
/// Bidirectional message bridge.
@@ -54,16 +57,20 @@ pub trait MessageBridge {
const THIS_CHAIN_ID: ChainId;
/// Identifier of the Bridged chain.
const BRIDGED_CHAIN_ID: ChainId;
/// Name of the paired messages pallet instance at the Bridged chain.
///
/// Should be the name that is used in the `construct_runtime!()` macro.
const BRIDGED_MESSAGES_PALLET_NAME: &'static str;
/// This chain in context of message bridge.
type ThisChain: ThisChainWithMessages;
/// Bridged chain in context of message bridge.
type BridgedChain: BridgedChainWithMessages;
/// Instance of the `pallet-bridge-messages` pallet at the Bridged chain.
type BridgedMessagesInstance: Instance;
/// Convert Bridged chain balance into This chain balance.
fn bridged_balance_to_this_balance(bridged_balance: BalanceOf<BridgedChain<Self>>) -> BalanceOf<ThisChain<Self>>;
fn bridged_balance_to_this_balance(
bridged_balance: BalanceOf<BridgedChain<Self>>,
) -> BalanceOf<ThisChain<Self>>;
}
/// Chain that has `pallet-bridge-messages` and `dispatch` modules.
@@ -73,16 +80,23 @@ pub trait ChainWithMessages {
/// Accound id on the chain.
type AccountId: Encode + Decode;
/// Public key of the chain account that may be used to verify signatures.
type Signer: Decode;
type Signer: Encode + Decode;
/// Signature type used on the chain.
type Signature: Decode;
type Signature: Encode + Decode;
/// Type of weight that is used on the chain. This would almost always be a regular
/// `frame_support::weight::Weight`. But since the meaning of weight on different chains
/// may be different, the `WeightOf<>` construct is used to avoid confusion between
/// different weights.
type Weight: From<frame_support::weights::Weight> + PartialOrd;
/// Type of balances that is used on the chain.
type Balance: Encode + Decode + CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;
type Balance: Encode
+ Decode
+ CheckedAdd
+ CheckedDiv
+ CheckedMul
+ PartialOrd
+ From<u32>
+ Copy;
}
/// Message related transaction parameters estimation.
@@ -137,30 +151,40 @@ pub trait BridgedChainWithMessages: ChainWithMessages {
message_dispatch_weight: WeightOf<Self>,
) -> MessageTransaction<WeightOf<Self>>;
/// Returns minimal transaction fee that must be paid for given transaction at the Bridged chain.
/// Returns minimal transaction fee that must be paid for given transaction at the Bridged
/// chain.
fn transaction_payment(transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self>;
}
pub(crate) type ThisChain<B> = <B as MessageBridge>::ThisChain;
pub(crate) type BridgedChain<B> = <B as MessageBridge>::BridgedChain;
pub(crate) type HashOf<C> = <C as ChainWithMessages>::Hash;
pub(crate) type AccountIdOf<C> = <C as ChainWithMessages>::AccountId;
pub(crate) type SignerOf<C> = <C as ChainWithMessages>::Signer;
pub(crate) type SignatureOf<C> = <C as ChainWithMessages>::Signature;
pub(crate) type WeightOf<C> = <C as ChainWithMessages>::Weight;
pub(crate) type BalanceOf<C> = <C as ChainWithMessages>::Balance;
pub(crate) type CallOf<C> = <C as ThisChainWithMessages>::Call;
/// This chain in context of message bridge.
pub type ThisChain<B> = <B as MessageBridge>::ThisChain;
/// Bridged chain in context of message bridge.
pub type BridgedChain<B> = <B as MessageBridge>::BridgedChain;
/// Hash used on the chain.
pub type HashOf<C> = <C as ChainWithMessages>::Hash;
/// Account id used on the chain.
pub type AccountIdOf<C> = <C as ChainWithMessages>::AccountId;
/// Public key of the chain account that may be used to verify signature.
pub type SignerOf<C> = <C as ChainWithMessages>::Signer;
/// Signature type used on the chain.
pub type SignatureOf<C> = <C as ChainWithMessages>::Signature;
/// Type of weight that used on the chain.
pub type WeightOf<C> = <C as ChainWithMessages>::Weight;
/// Type of balances that is used on the chain.
pub type BalanceOf<C> = <C as ChainWithMessages>::Balance;
/// Type of call that is used on this chain.
pub type CallOf<C> = <C as ThisChainWithMessages>::Call;
/// Raw storage proof type (just raw trie nodes).
type RawStorageProof = Vec<Vec<u8>>;
/// Compute fee of transaction at runtime where regular transaction payment pallet is being used.
///
/// The value of `multiplier` parameter is the expected value of `pallet_transaction_payment::NextFeeMultiplier`
/// at the moment when transaction is submitted. If you're charging this payment in advance (and that's what
/// happens with delivery and confirmation transaction in this crate), then there's a chance that the actual
/// fee will be larger than what is paid in advance. So the value must be chosen carefully.
/// The value of `multiplier` parameter is the expected value of
/// `pallet_transaction_payment::NextFeeMultiplier` at the moment when transaction is submitted. If
/// you're charging this payment in advance (and that's what happens with delivery and confirmation
/// transaction in this crate), then there's a chance that the actual fee will be larger than what
/// is paid in advance. So the value must be chosen carefully.
pub fn transaction_payment<Balance: AtLeast32BitUnsigned + FixedPointOperand>(
base_extrinsic_weight: Weight,
per_byte_fee: Balance,
@@ -223,7 +247,8 @@ pub mod source {
}
/// 'Parsed' message delivery proof - inbound lane id and its state.
pub type ParsedMessagesDeliveryProofFromBridgedChain<B> = (LaneId, InboundLaneData<AccountIdOf<ThisChain<B>>>);
pub type ParsedMessagesDeliveryProofFromBridgedChain<B> =
(LaneId, InboundLaneData<AccountIdOf<ThisChain<B>>>);
/// Message verifier that is doing all basic checks.
///
@@ -235,19 +260,30 @@ pub mod source {
/// Following checks are made:
///
/// - message is rejected if its lane is currently blocked;
/// - message is rejected if there are too many pending (undelivered) messages at the outbound lane;
/// - check that the sender has rights to dispatch the call on target chain using provided dispatch origin;
/// - message is rejected if there are too many pending (undelivered) messages at the outbound
/// lane;
/// - check that the sender has rights to dispatch the call on target chain using provided
/// dispatch origin;
/// - check that the sender has paid enough funds for both message delivery and dispatch.
#[derive(RuntimeDebug)]
pub struct FromThisChainMessageVerifier<B>(PhantomData<B>);
pub(crate) const OUTBOUND_LANE_DISABLED: &str = "The outbound message lane is disabled.";
pub(crate) const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
pub(crate) const BAD_ORIGIN: &str = "Unable to match the source origin to expected target origin.";
pub(crate) const TOO_LOW_FEE: &str = "Provided fee is below minimal threshold required by the lane.";
/// The error message returned from LaneMessageVerifier when outbound lane is disabled.
pub const OUTBOUND_LANE_DISABLED: &str = "The outbound message lane is disabled.";
/// The error message returned from LaneMessageVerifier when too many pending messages at the
/// lane.
pub const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
/// The error message returned from LaneMessageVerifier when call origin is mismatch.
pub const BAD_ORIGIN: &str = "Unable to match the source origin to expected target origin.";
/// The error message returned from LaneMessageVerifier when the message fee is too low.
pub const TOO_LOW_FEE: &str = "Provided fee is below minimal threshold required by the lane.";
impl<B> LaneMessageVerifier<AccountIdOf<ThisChain<B>>, FromThisChainMessagePayload<B>, BalanceOf<ThisChain<B>>>
for FromThisChainMessageVerifier<B>
impl<B>
LaneMessageVerifier<
AccountIdOf<ThisChain<B>>,
FromThisChainMessagePayload<B>,
BalanceOf<ThisChain<B>>,
> for FromThisChainMessageVerifier<B>
where
B: MessageBridge,
AccountIdOf<ThisChain<B>>: PartialEq + Clone,
@@ -263,7 +299,7 @@ pub mod source {
) -> Result<(), Self::Error> {
// reject message if lane is blocked
if !ThisChain::<B>::is_outbound_lane_enabled(lane) {
return Err(OUTBOUND_LANE_DISABLED);
return Err(OUTBOUND_LANE_DISABLED)
}
// reject message if there are too many pending messages at this lane
@@ -272,19 +308,20 @@ pub mod source {
.latest_generated_nonce
.saturating_sub(lane_outbound_data.latest_received_nonce);
if pending_messages > max_pending_messages {
return Err(TOO_MANY_PENDING_MESSAGES);
return Err(TOO_MANY_PENDING_MESSAGES)
}
// Do the dispatch-specific check. We assume that the target chain uses
// `Dispatch`, so we verify the message accordingly.
pallet_bridge_dispatch::verify_message_origin(submitter, payload).map_err(|_| BAD_ORIGIN)?;
pallet_bridge_dispatch::verify_message_origin(submitter, payload)
.map_err(|_| BAD_ORIGIN)?;
let minimal_fee_in_this_tokens =
estimate_message_dispatch_and_delivery_fee::<B>(payload, B::RELAYER_FEE_PERCENT)?;
// compare with actual fee paid
if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens {
return Err(TOO_LOW_FEE);
return Err(TOO_LOW_FEE)
}
Ok(())
@@ -306,13 +343,13 @@ pub mod source {
) -> Result<(), &'static str> {
let weight_limits = BridgedChain::<B>::message_weight_limits(&payload.call);
if !weight_limits.contains(&payload.weight.into()) {
return Err("Incorrect message weight declared");
return Err("Incorrect message weight declared")
}
// The maximal size of extrinsic at Substrate-based chain depends on the
// `frame_system::Config::MaximumBlockLength` and `frame_system::Config::AvailableBlockRatio`
// constants. This check is here to be sure that the lane won't stuck because message is too
// large to fit into delivery transaction.
// `frame_system::Config::MaximumBlockLength` and
// `frame_system::Config::AvailableBlockRatio` constants. This check is here to be sure that
// the lane won't stuck because message is too large to fit into delivery transaction.
//
// **IMPORTANT NOTE**: the delivery transaction contains storage proof of the message, not
// the message itself. The proof is always larger than the message. But unless chain state
@@ -320,16 +357,17 @@ pub mod source {
// transaction also contains signatures and signed extensions. Because of this, we reserve
// 1/3 of the the maximal extrinsic weight for this data.
if payload.call.len() > maximal_message_size::<B>() as usize {
return Err("The message is too large to be sent over the lane");
return Err("The message is too large to be sent over the lane")
}
Ok(())
}
/// Estimate delivery and dispatch fee that must be paid for delivering a message to the Bridged chain.
/// Estimate delivery and dispatch fee that must be paid for delivering a message to the Bridged
/// chain.
///
/// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional conversions.
/// Returns `None` if overflow has happened.
/// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional
/// conversions. Returns `None` if overflow has happened.
pub fn estimate_message_dispatch_and_delivery_fee<B: MessageBridge>(
payload: &FromThisChainMessagePayload<B>,
relayer_fee_percent: u32,
@@ -338,25 +376,23 @@ pub mod source {
//
// if we're going to pay dispatch fee at the target chain, then we don't include weight
// of the message dispatch in the delivery transaction cost
let pay_dispatch_fee_at_target_chain = payload.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
let pay_dispatch_fee_at_target_chain =
payload.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
let delivery_transaction = BridgedChain::<B>::estimate_delivery_transaction(
&payload.call,
&payload.encode(),
pay_dispatch_fee_at_target_chain,
if pay_dispatch_fee_at_target_chain {
0.into()
} else {
payload.weight.into()
},
if pay_dispatch_fee_at_target_chain { 0.into() } else { payload.weight.into() },
);
let delivery_transaction_fee = BridgedChain::<B>::transaction_payment(delivery_transaction);
// the fee (in This tokens) of all transactions that are made on This chain
let confirmation_transaction = ThisChain::<B>::estimate_delivery_confirmation_transaction();
let confirmation_transaction_fee = ThisChain::<B>::transaction_payment(confirmation_transaction);
let confirmation_transaction_fee =
ThisChain::<B>::transaction_payment(confirmation_transaction);
// minimal fee (in This tokens) is a sum of all required fees
let minimal_fee =
B::bridged_balance_to_this_balance(delivery_transaction_fee).checked_add(&confirmation_transaction_fee);
let minimal_fee = B::bridged_balance_to_this_balance(delivery_transaction_fee)
.checked_add(&confirmation_transaction_fee);
// before returning, add extra fee that is paid to the relayer (relayer interest)
minimal_fee
@@ -377,14 +413,14 @@ pub mod source {
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
where
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
HashOf<BridgedChain<B>>:
Into<bp_runtime::HashOf<<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain>>,
HashOf<BridgedChain<B>>: Into<
bp_runtime::HashOf<
<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain,
>,
>,
{
let FromBridgedChainMessagesDeliveryProof {
bridged_header_hash,
storage_proof,
lane,
} = proof;
let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } =
proof;
pallet_bridge_grandpa::Pallet::<ThisRuntime, GrandpaInstance>::parse_finalized_storage_proof(
bridged_header_hash.into(),
StorageProof::new(storage_proof),
@@ -392,7 +428,7 @@ pub mod source {
// Messages delivery proof is just proof of single storage key read => any error
// is fatal.
let storage_inbound_lane_data_key =
pallet_bridge_messages::storage_keys::inbound_lane_data_key::<B::BridgedMessagesInstance>(&lane);
pallet_bridge_messages::storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane);
let raw_inbound_lane_data = storage
.read_value(storage_inbound_lane_data_key.0.as_ref())
.map_err(|_| "Failed to read inbound lane state from storage proof")?
@@ -469,14 +505,13 @@ pub mod target {
impl<DecodedCall> FromBridgedChainEncodedMessageCall<DecodedCall> {
/// Create encoded call.
pub fn new(encoded_call: Vec<u8>) -> Self {
FromBridgedChainEncodedMessageCall {
encoded_call,
_marker: PhantomData::default(),
}
FromBridgedChainEncodedMessageCall { encoded_call, _marker: PhantomData::default() }
}
}
impl<DecodedCall: Decode> From<FromBridgedChainEncodedMessageCall<DecodedCall>> for Result<DecodedCall, ()> {
impl<DecodedCall: Decode> From<FromBridgedChainEncodedMessageCall<DecodedCall>>
for Result<DecodedCall, ()>
{
fn from(encoded_call: FromBridgedChainEncodedMessageCall<DecodedCall>) -> Self {
DecodedCall::decode(&mut &encoded_call.encoded_call[..]).map_err(drop)
}
@@ -492,20 +527,24 @@ pub mod target {
MessageDispatch<AccountIdOf<ThisChain<B>>, BalanceOf<BridgedChain<B>>>
for FromBridgedChainMessageDispatch<B, ThisRuntime, ThisCurrency, ThisDispatchInstance>
where
ThisDispatchInstance: frame_support::traits::Instance,
ThisRuntime: pallet_bridge_dispatch::Config<ThisDispatchInstance, MessageId = (LaneId, MessageNonce)>
+ pallet_transaction_payment::Config,
BalanceOf<ThisChain<B>>: Saturating + FixedPointOperand,
ThisDispatchInstance: 'static,
ThisRuntime: pallet_bridge_dispatch::Config<
ThisDispatchInstance,
BridgeMessageId = (LaneId, MessageNonce),
> + pallet_transaction_payment::Config,
<ThisRuntime as pallet_transaction_payment::Config>::OnChargeTransaction:
pallet_transaction_payment::OnChargeTransaction<ThisRuntime, Balance = BalanceOf<ThisChain<B>>>,
pallet_transaction_payment::OnChargeTransaction<
ThisRuntime,
Balance = BalanceOf<ThisChain<B>>,
>,
ThisCurrency: Currency<AccountIdOf<ThisChain<B>>, Balance = BalanceOf<ThisChain<B>>>,
<ThisRuntime as pallet_bridge_dispatch::Config<ThisDispatchInstance>>::Event: From<
pallet_bridge_dispatch::RawEvent<(LaneId, MessageNonce), AccountIdOf<ThisChain<B>>, ThisDispatchInstance>,
>,
pallet_bridge_dispatch::Pallet<ThisRuntime, ThisDispatchInstance>: bp_message_dispatch::MessageDispatch<
AccountIdOf<ThisChain<B>>,
(LaneId, MessageNonce),
Message = FromBridgedChainMessagePayload<B>,
>,
pallet_bridge_dispatch::Pallet<ThisRuntime, ThisDispatchInstance>:
bp_message_dispatch::MessageDispatch<
AccountIdOf<ThisChain<B>>,
(LaneId, MessageNonce),
Message = FromBridgedChainMessagePayload<B>,
>,
{
type DispatchPayload = FromBridgedChainMessagePayload<B>;
@@ -526,13 +565,22 @@ pub mod target {
message_id,
message.data.payload.map_err(drop),
|dispatch_origin, dispatch_weight| {
ThisCurrency::transfer(
dispatch_origin,
relayer_account,
ThisRuntime::WeightToFee::calc(&dispatch_weight),
ExistenceRequirement::AllowDeath,
)
.map_err(drop)
let unadjusted_weight_fee = ThisRuntime::WeightToFee::calc(&dispatch_weight);
let fee_multiplier =
pallet_transaction_payment::Pallet::<ThisRuntime>::next_fee_multiplier();
let adjusted_weight_fee =
fee_multiplier.saturating_mul_int(unadjusted_weight_fee);
if !adjusted_weight_fee.is_zero() {
ThisCurrency::transfer(
dispatch_origin,
relayer_account,
adjusted_weight_fee,
ExistenceRequirement::AllowDeath,
)
.map_err(drop)
} else {
Ok(())
}
},
)
}
@@ -559,9 +607,11 @@ pub mod target {
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
where
ThisRuntime: pallet_bridge_grandpa::Config<GrandpaInstance>,
ThisRuntime: pallet_bridge_messages::Config<B::BridgedMessagesInstance>,
HashOf<BridgedChain<B>>:
Into<bp_runtime::HashOf<<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain>>,
HashOf<BridgedChain<B>>: Into<
bp_runtime::HashOf<
<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain,
>,
>,
{
verify_messages_proof_with_parser::<B, _, _>(
proof,
@@ -596,12 +646,13 @@ pub mod target {
fn from(err: MessageProofError) -> &'static str {
match err {
MessageProofError::Empty => "Messages proof is empty",
MessageProofError::MessagesCountMismatch => "Declared messages count doesn't match actual value",
MessageProofError::MessagesCountMismatch =>
"Declared messages count doesn't match actual value",
MessageProofError::MissingRequiredMessage => "Message is missing from the proof",
MessageProofError::FailedToDecodeMessage => "Failed to decode message from the proof",
MessageProofError::FailedToDecodeOutboundLaneState => {
"Failed to decode outbound lane data from the proof"
}
MessageProofError::FailedToDecodeMessage =>
"Failed to decode message from the proof",
MessageProofError::FailedToDecodeOutboundLaneState =>
"Failed to decode outbound lane data from the proof",
MessageProofError::Custom(err) => err,
}
}
@@ -624,14 +675,16 @@ pub mod target {
{
fn read_raw_outbound_lane_data(&self, lane_id: &LaneId) -> Option<Vec<u8>> {
let storage_outbound_lane_data_key =
pallet_bridge_messages::storage_keys::outbound_lane_data_key::<B::BridgedMessagesInstance>(lane_id);
self.storage
.read_value(storage_outbound_lane_data_key.0.as_ref())
.ok()?
pallet_bridge_messages::storage_keys::outbound_lane_data_key(
B::BRIDGED_MESSAGES_PALLET_NAME,
lane_id,
);
self.storage.read_value(storage_outbound_lane_data_key.0.as_ref()).ok()?
}
fn read_raw_message(&self, message_key: &MessageKey) -> Option<Vec<u8>> {
let storage_message_key = pallet_bridge_messages::storage_keys::message_key::<B::BridgedMessagesInstance>(
let storage_message_key = pallet_bridge_messages::storage_keys::message_key(
B::BRIDGED_MESSAGES_PALLET_NAME,
&message_key.lane_id,
message_key.nonce,
);
@@ -646,7 +699,8 @@ pub mod target {
build_parser: BuildParser,
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, MessageProofError>
where
BuildParser: FnOnce(HashOf<BridgedChain<B>>, RawStorageProof) -> Result<Parser, MessageProofError>,
BuildParser:
FnOnce(HashOf<BridgedChain<B>>, RawStorageProof) -> Result<Parser, MessageProofError>,
Parser: MessageProofParser,
{
let FromBridgedChainMessagesProof {
@@ -658,18 +712,19 @@ pub mod target {
} = proof;
// receiving proofs where end < begin is ok (if proof includes outbound lane state)
let messages_in_the_proof = if let Some(nonces_difference) = nonces_end.checked_sub(nonces_start) {
// let's check that the user (relayer) has passed correct `messages_count`
// (this bounds maximal capacity of messages vec below)
let messages_in_the_proof = nonces_difference.saturating_add(1);
if messages_in_the_proof != MessageNonce::from(messages_count) {
return Err(MessageProofError::MessagesCountMismatch);
}
let messages_in_the_proof =
if let Some(nonces_difference) = nonces_end.checked_sub(nonces_start) {
// let's check that the user (relayer) has passed correct `messages_count`
// (this bounds maximal capacity of messages vec below)
let messages_in_the_proof = nonces_difference.saturating_add(1);
if messages_in_the_proof != MessageNonce::from(messages_count) {
return Err(MessageProofError::MessagesCountMismatch)
}
messages_in_the_proof
} else {
0
};
messages_in_the_proof
} else {
0
};
let parser = build_parser(bridged_header_hash, storage_proof)?;
@@ -683,20 +738,15 @@ pub mod target {
let raw_message_data = parser
.read_raw_message(&message_key)
.ok_or(MessageProofError::MissingRequiredMessage)?;
let message_data = MessageData::<BalanceOf<BridgedChain<B>>>::decode(&mut &raw_message_data[..])
.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
messages.push(Message {
key: message_key,
data: message_data,
});
let message_data =
MessageData::<BalanceOf<BridgedChain<B>>>::decode(&mut &raw_message_data[..])
.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
messages.push(Message { key: message_key, data: message_data });
}
// Now let's check if proof contains outbound lane state proof. It is optional, so we
// simply ignore `read_value` errors and missing value.
let mut proved_lane_messages = ProvedLaneMessages {
lane_state: None,
messages,
};
let mut proved_lane_messages = ProvedLaneMessages { lane_state: None, messages };
let raw_outbound_lane_data = parser.read_raw_outbound_lane_data(&lane);
if let Some(raw_outbound_lane_data) = raw_outbound_lane_data {
proved_lane_messages.lane_state = Some(
@@ -707,7 +757,7 @@ pub mod target {
// Now we may actually check if the proof is empty or not.
if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() {
return Err(MessageProofError::Empty);
return Err(MessageProofError::Empty)
}
// We only support single lane messages in this schema
@@ -733,7 +783,8 @@ mod tests {
const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: Weight = 2048;
const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024;
/// Bridge that is deployed on ThisChain and allows sending/receiving messages to/from BridgedChain;
/// Bridge that is deployed on ThisChain and allows sending/receiving messages to/from
/// BridgedChain;
#[derive(Debug, PartialEq, Eq)]
struct OnThisChainBridge;
@@ -741,17 +792,20 @@ mod tests {
const RELAYER_FEE_PERCENT: u32 = 10;
const THIS_CHAIN_ID: ChainId = *b"this";
const BRIDGED_CHAIN_ID: ChainId = *b"brdg";
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
type ThisChain = ThisChain;
type BridgedChain = BridgedChain;
type BridgedMessagesInstance = pallet_bridge_messages::DefaultInstance;
fn bridged_balance_to_this_balance(bridged_balance: BridgedChainBalance) -> ThisChainBalance {
fn bridged_balance_to_this_balance(
bridged_balance: BridgedChainBalance,
) -> ThisChainBalance {
ThisChainBalance(bridged_balance.0 * BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE as u32)
}
}
/// Bridge that is deployed on BridgedChain and allows sending/receiving messages to/from ThisChain;
/// Bridge that is deployed on BridgedChain and allows sending/receiving messages to/from
/// ThisChain;
#[derive(Debug, PartialEq, Eq)]
struct OnBridgedChainBridge;
@@ -759,10 +813,10 @@ mod tests {
const RELAYER_FEE_PERCENT: u32 = 20;
const THIS_CHAIN_ID: ChainId = *b"brdg";
const BRIDGED_CHAIN_ID: ChainId = *b"this";
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
type ThisChain = BridgedChain;
type BridgedChain = ThisChain;
type BridgedMessagesInstance = pallet_bridge_messages::DefaultInstance;
fn bridged_balance_to_this_balance(_this_balance: ThisChainBalance) -> BridgedChainBalance {
unreachable!()
@@ -886,7 +940,9 @@ mod tests {
}
fn transaction_payment(transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
ThisChainBalance(transaction.dispatch_weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
ThisChainBalance(
transaction.dispatch_weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32,
)
}
}
@@ -907,7 +963,9 @@ mod tests {
unreachable!()
}
fn transaction_payment(_transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
fn transaction_payment(
_transaction: MessageTransaction<WeightOf<Self>>,
) -> BalanceOf<Self> {
unreachable!()
}
}
@@ -938,7 +996,9 @@ mod tests {
unreachable!()
}
fn transaction_payment(_transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
fn transaction_payment(
_transaction: MessageTransaction<WeightOf<Self>>,
) -> BalanceOf<Self> {
unreachable!()
}
}
@@ -949,7 +1009,8 @@ mod tests {
}
fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive<Self::Weight> {
let begin = std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight);
let begin =
std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight);
begin..=BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
}
@@ -965,7 +1026,9 @@ mod tests {
}
fn transaction_payment(transaction: MessageTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
BridgedChainBalance(transaction.dispatch_weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
BridgedChainBalance(
transaction.dispatch_weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32,
)
}
}
@@ -976,19 +1039,22 @@ mod tests {
#[test]
fn message_from_bridged_chain_is_decoded() {
// the message is encoded on the bridged chain
let message_on_bridged_chain = source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
spec_version: 1,
weight: 100,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
call: ThisChainCall::Transfer.encode(),
}
.encode();
let message_on_bridged_chain =
source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
spec_version: 1,
weight: 100,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
call: ThisChainCall::Transfer.encode(),
}
.encode();
// and sent to this chain where it is decoded
let message_on_this_chain =
target::FromBridgedChainMessagePayload::<OnThisChainBridge>::decode(&mut &message_on_bridged_chain[..])
.unwrap();
target::FromBridgedChainMessagePayload::<OnThisChainBridge>::decode(
&mut &message_on_bridged_chain[..],
)
.unwrap();
assert_eq!(
message_on_this_chain,
target::FromBridgedChainMessagePayload::<OnThisChainBridge> {
@@ -1007,7 +1073,8 @@ mod tests {
const TEST_LANE_ID: &LaneId = b"test";
const MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE: MessageNonce = 32;
fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload<OnThisChainBridge> {
fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload<OnThisChainBridge>
{
source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 100,
@@ -1036,11 +1103,14 @@ mod tests {
// let's check if estimation is less than hardcoded, if dispatch is paid at target chain
let mut payload_with_pay_on_target = regular_outbound_message_payload();
payload_with_pay_on_target.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
let fee_at_source = source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
&payload_with_pay_on_target,
OnThisChainBridge::RELAYER_FEE_PERCENT,
)
.expect("estimate_message_dispatch_and_delivery_fee failed for pay-at-target-chain message");
let fee_at_source =
source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
&payload_with_pay_on_target,
OnThisChainBridge::RELAYER_FEE_PERCENT,
)
.expect(
"estimate_message_dispatch_and_delivery_fee failed for pay-at-target-chain message",
);
assert!(
fee_at_source < EXPECTED_MINIMAL_FEE.into(),
"Computed fee {:?} without prepaid dispatch must be less than the fee with prepaid dispatch {}",
@@ -1059,16 +1129,14 @@ mod tests {
),
Err(source::TOO_LOW_FEE)
);
assert!(
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Root,
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),
);
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Root,
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),);
}
#[test]
@@ -1103,16 +1171,14 @@ mod tests {
),
Err(source::BAD_ORIGIN)
);
assert!(
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Root,
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),
);
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Root,
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),);
}
#[test]
@@ -1137,16 +1203,14 @@ mod tests {
),
Err(source::BAD_ORIGIN)
);
assert!(
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Signed(ThisChainAccountId(1)),
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),
);
assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
&Sender::Signed(ThisChainAccountId(1)),
&ThisChainBalance(1_000_000),
TEST_LANE_ID,
&test_lane_outbound_data(),
&payload,
)
.is_ok(),);
}
#[test]
@@ -1183,64 +1247,58 @@ mod tests {
#[test]
fn verify_chain_message_rejects_message_with_too_small_declared_weight() {
assert!(
source::verify_chain_message::<OnThisChainBridge>(&source::FromThisChainMessagePayload::<
OnThisChainBridge,
> {
assert!(source::verify_chain_message::<OnThisChainBridge>(
&source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: 5,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: vec![1, 2, 3, 4, 5, 6],
},)
.is_err()
);
},
)
.is_err());
}
#[test]
fn verify_chain_message_rejects_message_with_too_large_declared_weight() {
assert!(
source::verify_chain_message::<OnThisChainBridge>(&source::FromThisChainMessagePayload::<
OnThisChainBridge,
> {
assert!(source::verify_chain_message::<OnThisChainBridge>(
&source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 1,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: vec![1, 2, 3, 4, 5, 6],
},)
.is_err()
);
},
)
.is_err());
}
#[test]
fn verify_chain_message_rejects_message_too_large_message() {
assert!(
source::verify_chain_message::<OnThisChainBridge>(&source::FromThisChainMessagePayload::<
OnThisChainBridge,
> {
assert!(source::verify_chain_message::<OnThisChainBridge>(
&source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as usize + 1],
},)
.is_err()
);
},
)
.is_err());
}
#[test]
fn verify_chain_message_accepts_maximal_message() {
assert_eq!(
source::verify_chain_message::<OnThisChainBridge>(&source::FromThisChainMessagePayload::<
OnThisChainBridge,
> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as _],
},),
source::verify_chain_message::<OnThisChainBridge>(
&source::FromThisChainMessagePayload::<OnThisChainBridge> {
spec_version: 1,
weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
origin: bp_message_dispatch::CallOrigin::SourceRoot,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as _],
},
),
Ok(()),
);
}
@@ -1332,13 +1390,15 @@ mod tests {
#[test]
fn message_proof_is_rejected_if_required_message_is_missing() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(10), 10, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(10),
10,
|_, _| Ok(TestMessageProofParser {
failing: false,
messages: 1..=5,
outbound_lane_data: None,
}
),),
}),
),
Err(target::MessageProofError::MissingRequiredMessage),
);
}
@@ -1346,13 +1406,15 @@ mod tests {
#[test]
fn message_proof_is_rejected_if_message_decode_fails() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(10), 10, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(10),
10,
|_, _| Ok(TestMessageProofParser {
failing: true,
messages: 1..=10,
outbound_lane_data: None,
}
),),
}),
),
Err(target::MessageProofError::FailedToDecodeMessage),
);
}
@@ -1360,8 +1422,10 @@ mod tests {
#[test]
fn message_proof_is_rejected_if_outbound_lane_state_decode_fails() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(0), 0, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(0),
0,
|_, _| Ok(TestMessageProofParser {
failing: true,
messages: no_messages_range(),
outbound_lane_data: Some(OutboundLaneData {
@@ -1369,8 +1433,8 @@ mod tests {
latest_received_nonce: 1,
latest_generated_nonce: 1,
}),
}
),),
}),
),
Err(target::MessageProofError::FailedToDecodeOutboundLaneState),
);
}
@@ -1378,13 +1442,15 @@ mod tests {
#[test]
fn message_proof_is_rejected_if_it_is_empty() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(0), 0, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(0),
0,
|_, _| Ok(TestMessageProofParser {
failing: false,
messages: no_messages_range(),
outbound_lane_data: None,
}
),),
}),
),
Err(target::MessageProofError::Empty),
);
}
@@ -1392,8 +1458,10 @@ mod tests {
#[test]
fn non_empty_message_proof_without_messages_is_accepted() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(0), 0, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(0),
0,
|_, _| Ok(TestMessageProofParser {
failing: false,
messages: no_messages_range(),
outbound_lane_data: Some(OutboundLaneData {
@@ -1401,8 +1469,8 @@ mod tests {
latest_received_nonce: 1,
latest_generated_nonce: 1,
}),
}
),),
}),
),
Ok(vec![(
Default::default(),
ProvedLaneMessages {
@@ -1422,8 +1490,10 @@ mod tests {
#[test]
fn non_empty_message_proof_is_accepted() {
assert_eq!(
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(messages_proof(1), 1, |_, _| Ok(
TestMessageProofParser {
target::verify_messages_proof_with_parser::<OnThisChainBridge, _, _>(
messages_proof(1),
1,
|_, _| Ok(TestMessageProofParser {
failing: false,
messages: 1..=1,
outbound_lane_data: Some(OutboundLaneData {
@@ -1431,8 +1501,8 @@ mod tests {
latest_received_nonce: 1,
latest_generated_nonce: 1,
}),
}
),),
}),
),
Ok(vec![(
Default::default(),
ProvedLaneMessages {
@@ -1442,14 +1512,8 @@ mod tests {
latest_generated_nonce: 1,
}),
messages: vec![Message {
key: MessageKey {
lane_id: Default::default(),
nonce: 1
},
data: MessageData {
payload: 1u64.encode(),
fee: BridgedChainBalance(0)
},
key: MessageKey { lane_id: Default::default(), nonce: 1 },
data: MessageData { payload: 1u64.encode(), fee: BridgedChainBalance(0) },
}],
},
)]
@@ -1488,10 +1552,7 @@ mod tests {
10,
FixedU128::zero(),
|weight| weight,
MessageTransaction {
size: 50,
dispatch_weight: 777
},
MessageTransaction { size: 50, dispatch_weight: 777 },
),
100 + 50 * 10,
);
@@ -1507,10 +1568,7 @@ mod tests {
10,
FixedU128::one(),
|weight| weight,
MessageTransaction {
size: 50,
dispatch_weight: 777
},
MessageTransaction { size: 50, dispatch_weight: 777 },
),
100 + 50 * 10 + 777,
);
@@ -0,0 +1,51 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Helpers for implementing various message-related runtime API mthods.
use crate::messages::{source::FromThisChainMessagePayload, MessageBridge};
use bp_messages::{LaneId, MessageDetails, MessageNonce};
use codec::Decode;
use sp_std::vec::Vec;
/// Implementation of the `To*OutboundLaneApi::message_details`.
pub fn outbound_message_details<Runtime, MessagesPalletInstance, BridgeConfig>(
lane: LaneId,
begin: MessageNonce,
end: MessageNonce,
) -> Vec<MessageDetails<Runtime::OutboundMessageFee>>
where
Runtime: pallet_bridge_messages::Config<MessagesPalletInstance>,
MessagesPalletInstance: 'static,
BridgeConfig: MessageBridge,
{
(begin..=end)
.filter_map(|nonce| {
let message_data =
pallet_bridge_messages::Pallet::<Runtime, MessagesPalletInstance>::outbound_message_data(lane, nonce)?;
let decoded_payload =
FromThisChainMessagePayload::<BridgeConfig>::decode(&mut &message_data.payload[..]).ok()?;
Some(MessageDetails {
nonce,
dispatch_weight: decoded_payload.weight,
size: message_data.payload.len() as _,
delivery_and_dispatch_fee: message_data.fee,
dispatch_fee_payment: decoded_payload.dispatch_fee_payment,
})
})
.collect()
}
@@ -20,8 +20,8 @@
#![cfg(feature = "runtime-benchmarks")]
use crate::messages::{
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, AccountIdOf, BalanceOf,
BridgedChain, HashOf, MessageBridge, ThisChain,
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
AccountIdOf, BalanceOf, BridgedChain, HashOf, MessageBridge, ThisChain,
};
use bp_messages::{LaneId, MessageData, MessageKey, MessagePayload};
@@ -29,13 +29,16 @@ use bp_runtime::ChainId;
use codec::Encode;
use ed25519_dalek::{PublicKey, SecretKey, Signer, KEYPAIR_LENGTH, SECRET_KEY_LENGTH};
use frame_support::weights::Weight;
use pallet_bridge_messages::benchmarking::{MessageDeliveryProofParams, MessageProofParams, ProofSize};
use pallet_bridge_messages::benchmarking::{
MessageDeliveryProofParams, MessageProofParams, ProofSize,
};
use sp_core::Hasher;
use sp_runtime::traits::Header;
use sp_std::prelude::*;
use sp_trie::{record_all_keys, trie_types::TrieDBMut, Layout, MemoryDB, Recorder, TrieMut};
/// Generate ed25519 signature to be used in `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`.
/// Generate ed25519 signature to be used in
/// `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`.
///
/// Returns public key of the signer and the signature itself.
pub fn ed25519_sign(
@@ -47,8 +50,8 @@ pub fn ed25519_sign(
) -> ([u8; 32], [u8; 64]) {
// key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html)
let target_secret = SecretKey::from_bytes(&[
157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073, 197, 105, 123, 050,
105, 025, 112, 059, 172, 003, 028, 174, 127, 096,
157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073,
197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096,
])
.expect("harcoded key is valid");
let target_public: PublicKey = (&target_secret).into();
@@ -56,7 +59,8 @@ pub fn ed25519_sign(
let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH];
target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes());
target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes());
let target_pair = ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid");
let target_pair =
ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid");
let signature_message = pallet_bridge_dispatch::account_ownership_digest(
target_call,
@@ -92,11 +96,8 @@ where
MH: Fn(H::Out) -> <R::BridgedChain as bp_runtime::Chain>::Header,
{
// prepare Bridged chain storage with messages and (optionally) outbound lane state
let message_count = params
.message_nonces
.end()
.saturating_sub(*params.message_nonces.start())
+ 1;
let message_count =
params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1;
let mut storage_keys = Vec::with_capacity(message_count as usize + 1);
let mut root = Default::default();
let mut mdb = MemoryDB::default();
@@ -105,10 +106,7 @@ where
// insert messages
for nonce in params.message_nonces.clone() {
let message_key = MessageKey {
lane_id: params.lane,
nonce,
};
let message_key = MessageKey { lane_id: params.lane, nonce };
let message_data = MessageData {
fee: BalanceOf::<BridgedChain<B>>::from(0),
payload: message_payload.clone(),
@@ -220,7 +218,7 @@ fn grow_trie<H: Hasher>(mut root: H::Out, mdb: &mut MemoryDB<H>, trie_size: Proo
.expect("record_all_keys should not fail in benchmarks");
let size: usize = proof_recorder.drain().into_iter().map(|n| n.data.len()).sum();
if size > minimal_trie_size as _ {
return root;
return root
}
let mut trie = TrieDBMut::<H>::from_existing(mdb, &mut root)